🎨 完善订单页面和文章页
This commit is contained in:
@@ -9,51 +9,213 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="gva-table-box">
|
||||
<Content
|
||||
@changePage="changePage"
|
||||
:total="total"
|
||||
v-model:tabloading="tableLoading"
|
||||
v-model:currentPage="queryParams.page"
|
||||
v-model:pageSize="queryParams.pageSize"
|
||||
:data="tableData"
|
||||
:config="ORDER_TABLE_CONFIG"
|
||||
>
|
||||
<template #status="{ row }">
|
||||
<el-tag :type="tag(row.status).type">{{ tag(row.status).label }}</el-tag>
|
||||
</template>
|
||||
<template #operate="{ row }">
|
||||
<el-button type="text" @click="handleDetail(row)">详情</el-button>
|
||||
<el-button type="text" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</Content>
|
||||
<div class="gva-btn-list">
|
||||
<el-button type="info" @click="exportOrders">导出订单</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 订单统计信息 -->
|
||||
<div style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px;">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #409eff;">{{ getOrderStats().total }}</div>
|
||||
<div style="color: #666;">总订单数</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #e6a23c;">{{ getOrderStats().unpaid }}</div>
|
||||
<div style="color: #666;">未付款</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #67c23a;">{{ getOrderStats().paid }}</div>
|
||||
<div style="color: #666;">已付款</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #f56c6c;">{{ getOrderStats().expired }}</div>
|
||||
<div style="color: #666;">已过期</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #909399;">{{ getOrderStats().course }}</div>
|
||||
<div style="color: #666;">课程订单</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 24px; font-weight: bold; color: #e6a23c;">{{ getOrderStats().vip }}</div>
|
||||
<div style="color: #666;">VIP订单</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<!-- 自定义订单表格 -->
|
||||
<el-table
|
||||
:data="tableData"
|
||||
v-loading="tableLoading"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="order_no" label="订单号" align="center" min-width="180" />
|
||||
<el-table-column prop="title" label="商品名称" align="center" min-width="150" />
|
||||
<el-table-column prop="name" label="用户姓名" align="center" width="100" />
|
||||
<el-table-column label="价格" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<span class="text-green-600 font-bold">{{ formatPrice(row.price) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单类型" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.order_type === 1 ? 'primary' : 'success'">
|
||||
{{ row.order_type === 1 ? '课程' : 'VIP' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="支付方式" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getPayTypeTag(row.pay_type).type">
|
||||
{{ getPayTypeTag(row.pay_type).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单状态" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTag(row.status).type">
|
||||
{{ getStatusTag(row.status).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" width="180">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.CreatedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleDetail(row)">
|
||||
<el-icon style="margin-right: 5px"><InfoFilled /></el-icon>详情
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div style="margin-top: 20px; text-align: right;">
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.page"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="changePage"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 订单详情弹窗 -->
|
||||
<el-dialog
|
||||
v-model="detailVisible"
|
||||
title="订单详情"
|
||||
width="70%"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="订单号">{{ detailData.order_no || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="商品名称">{{ detailData.title || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用户姓名">{{ detailData.name || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用户ID">{{ detailData.user_id || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="价格">{{ formatPrice(detailData.price) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="订单类型">
|
||||
<el-tag :type="detailData.order_type === 1 ? 'primary' : 'success'">
|
||||
{{ detailData.order_type === 1 ? '课程' : 'VIP' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支付方式">
|
||||
<el-tag :type="getPayTypeTag(detailData.pay_type).type">
|
||||
{{ getPayTypeTag(detailData.pay_type).label }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="订单状态">
|
||||
<el-tag :type="getStatusTag(detailData.status).type">
|
||||
{{ getStatusTag(detailData.status).label }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="手机号">{{ detailData.phone || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="讲师ID">{{ detailData.teacher_Id || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="VIP ID">{{ detailData.vip_id || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="微信OpenID">{{ detailData.open_id || EMPTY_STR }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ formatDate(detailData.CreatedAt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">{{ formatDate(detailData.UpdatedAt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="描述" :span="2">{{ detailData.desc || EMPTY_STR }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import searchForm from '@/components/searchForm/index.vue'
|
||||
import Content from '@/components/content/index.vue'
|
||||
import {list} from '@/api/order'
|
||||
import { list } from '@/api/order'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ORDER_SEARCH_CONFIG, ORDER_TABLE_CONFIG } from '@/config'
|
||||
const tableLoading = ref(true), tableData = ref([])
|
||||
import { ORDER_SEARCH_CONFIG } from '@/config'
|
||||
import { formatDate } from '@/utils/format'
|
||||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const tableLoading = ref(true), tableData = ref([])
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref({})
|
||||
|
||||
const queryParams = ref({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
orderId: '',
|
||||
order_no: '',
|
||||
title: '',
|
||||
name: '',
|
||||
order_type: '',
|
||||
pay_type: '',
|
||||
status: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
}), total = ref(0)
|
||||
|
||||
const EMPTY_STR = '- -'
|
||||
const tag = (status) => {
|
||||
|
||||
// 获取订单状态标签
|
||||
const getStatusTag = (status) => {
|
||||
const map = {
|
||||
1: { type: 'success', label: '已完成' },
|
||||
2: { type: 'info', label: '待处理' },
|
||||
3: { type: 'warning', label: '处理中' },
|
||||
4: { type: 'danger', label: '已拒绝' }
|
||||
1: { type: 'warning', label: '未付款' },
|
||||
2: { type: 'success', label: '已付款' },
|
||||
3: { type: 'danger', label: '已过期' }
|
||||
}
|
||||
return map[status] || { type: '', label: EMPTY_STR }
|
||||
}
|
||||
|
||||
// 获取支付方式标签
|
||||
const getPayTypeTag = (payType) => {
|
||||
const map = {
|
||||
1: { type: 'success', label: '微信' },
|
||||
2: { type: 'primary', label: '支付宝' },
|
||||
3: { type: 'info', label: '余额' }
|
||||
}
|
||||
return map[payType] || { type: '', label: EMPTY_STR }
|
||||
}
|
||||
|
||||
// 格式化价格显示(分转元)
|
||||
const formatPrice = (price) => {
|
||||
if (price === null || price === undefined || price === '') return '0.00元'
|
||||
if (price === 0) return '0.00元'
|
||||
const yuan = (Number(price) / 100).toFixed(2)
|
||||
return yuan + '元'
|
||||
}
|
||||
|
||||
const searchData = (data) => {
|
||||
if (data.times) {
|
||||
data.startTime = data.times[0]
|
||||
@@ -64,35 +226,129 @@ const searchData = (data) => {
|
||||
delete queryParams.value.times
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetData = () => {
|
||||
queryParams.value = {
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
order_no: '',
|
||||
title: '',
|
||||
name: '',
|
||||
order_type: '',
|
||||
pay_type: '',
|
||||
status: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
}
|
||||
getList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
async function getList() {
|
||||
const res = await list(queryParams.value)
|
||||
if(res.code === 0) {
|
||||
tableData.value = res.data.list
|
||||
total.value = res.data.total
|
||||
tableLoading.value = true
|
||||
try {
|
||||
const res = await list(queryParams.value)
|
||||
if(res.code === 0) {
|
||||
tableData.value = res.data.list
|
||||
total.value = res.data.total
|
||||
console.log('订单数据获取成功:', {
|
||||
total: res.data.total,
|
||||
list: res.data.list,
|
||||
firstItem: res.data.list[0]
|
||||
})
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取订单列表失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取订单列表失败:', error)
|
||||
ElMessage.error('获取订单列表失败')
|
||||
} finally {
|
||||
tableLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
console.log(row)
|
||||
}
|
||||
function handleDetail(row) {
|
||||
|
||||
detailData.value = { ...row }
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
function changePage(data) {
|
||||
queryParams.value.pageNum = data
|
||||
queryParams.value.page = data
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(val) {
|
||||
queryParams.value.pageSize = val
|
||||
getList()
|
||||
}
|
||||
|
||||
// 导出订单功能
|
||||
function exportOrders() {
|
||||
ElMessage.success('导出功能开发中...')
|
||||
}
|
||||
|
||||
// 获取订单统计信息
|
||||
function getOrderStats() {
|
||||
const stats = {
|
||||
total: total.value, // 总订单数(来自后端)
|
||||
unpaid: tableData.value.filter(item => item.status === 1).length,
|
||||
paid: tableData.value.filter(item => item.status === 2).length,
|
||||
expired: tableData.value.filter(item => item.status === 3).length,
|
||||
course: tableData.value.filter(item => item.order_type === 1).length,
|
||||
vip: tableData.value.filter(item => item.order_type === 2).length
|
||||
}
|
||||
return stats
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.gva-table-box {
|
||||
.gva-btn-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-row {
|
||||
.el-col {
|
||||
.el-statistic {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
|
||||
.el-statistic__number {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.el-statistic__label {
|
||||
color: #666;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.searchForm {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.el-dialog {
|
||||
.el-descriptions {
|
||||
.el-descriptions__body {
|
||||
.el-descriptions__table {
|
||||
.el-descriptions__cell {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Reference in New Issue
Block a user