|
|
@@ -1,119 +1,127 @@
|
|
|
<template>
|
|
|
- <div class="container">
|
|
|
- <Breadcrumb />
|
|
|
+ <div class="admin-order-page">
|
|
|
+ <Breadcrumb />
|
|
|
|
|
|
- <a-card title="订单管理">
|
|
|
- <a-row>
|
|
|
- <a-col :flex="1">
|
|
|
- <a-form :model="queryData" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
|
|
|
- label-align="left">
|
|
|
- <a-row :gutter="16">
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="orderId" label="订单号">
|
|
|
- <a-input v-model="queryData.orderId" placeholder="支持模糊搜索" allow-clear />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="goods_name" label="商品名称">
|
|
|
- <a-input v-model="queryData.goods_name" placeholder="支持模糊搜索" allow-clear />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="username" label="用户名">
|
|
|
- <a-input v-model="queryData.username" placeholder="支持模糊搜索" allow-clear />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="user_email" label="用户邮箱">
|
|
|
- <EmailAutoComplete v-model="queryData.user_email" placeholder="支持模糊搜索" allow-clear />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="state" label="订单状态">
|
|
|
- <a-select v-model="queryData.state" :options="stateOptions" placeholder="请选择状态" />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="pay_type" label="支付方式">
|
|
|
- <a-select v-model="queryData.pay_type" placeholder="全部方式" allow-clear>
|
|
|
- <a-option value="">全部</a-option>
|
|
|
- <a-option v-for="item in payTypeOptions" :key="item.value" :value="item.value">
|
|
|
- {{ item.label }}
|
|
|
- </a-option>
|
|
|
- </a-select>
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- <a-col :span="6">
|
|
|
- <a-form-item field="queryTime" label="下单时间">
|
|
|
- <a-range-picker v-model="queryData.queryTime" show-time format="YY-MM-DD HH:mm"
|
|
|
- value-format="x" @ok="search()" />
|
|
|
- </a-form-item>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-form>
|
|
|
- </a-col>
|
|
|
- <a-divider style="height: 84px" direction="vertical" />
|
|
|
- <a-col :flex="'86px'" style="text-align: right">
|
|
|
- <a-space direction="vertical" :size="18">
|
|
|
- <a-button type="primary" @click="search">
|
|
|
- <template #icon>
|
|
|
- <icon-search />
|
|
|
- </template>
|
|
|
- 搜索
|
|
|
- </a-button>
|
|
|
- <a-button @click="reset">
|
|
|
- <template #icon>
|
|
|
- <icon-refresh />
|
|
|
- </template>
|
|
|
- 重置
|
|
|
- </a-button>
|
|
|
- </a-space>
|
|
|
- </a-col>
|
|
|
+ <a-card :bordered="false" class="page-card" title="订单管理">
|
|
|
+ <a-collapse :default-active-key="['filter']" :bordered="false" class="filter-collapse">
|
|
|
+ <a-collapse-item key="filter" header="筛选条件">
|
|
|
+ <a-form :model="queryData" layout="vertical" class="filter-grid">
|
|
|
+ <a-row :gutter="16">
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="订单号">
|
|
|
+ <a-input v-model="queryData.orderId" placeholder="模糊搜索" allow-clear />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="商品名称">
|
|
|
+ <a-input v-model="queryData.goods_name" placeholder="模糊搜索" allow-clear />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="用户名">
|
|
|
+ <a-input v-model="queryData.username" placeholder="模糊搜索" allow-clear />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="用户邮箱">
|
|
|
+ <EmailAutoComplete v-model="queryData.user_email" placeholder="模糊搜索" allow-clear />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="订单状态">
|
|
|
+ <a-select v-model="queryData.state" :options="stateOptions" placeholder="全部" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="12" :md="8" :lg="6">
|
|
|
+ <a-form-item label="支付方式">
|
|
|
+ <a-select v-model="queryData.pay_type" placeholder="全部" allow-clear>
|
|
|
+ <a-option value="">全部</a-option>
|
|
|
+ <a-option v-for="item in payTypeOptions" :key="item.value" :value="item.value">
|
|
|
+ {{ item.label }}
|
|
|
+ </a-option>
|
|
|
+ </a-select>
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
+ <a-col :xs="24" :sm="24" :md="16" :lg="12">
|
|
|
+ <a-form-item label="下单时间">
|
|
|
+ <a-range-picker
|
|
|
+ v-model="queryData.queryTime"
|
|
|
+ show-time
|
|
|
+ format="YY-MM-DD HH:mm"
|
|
|
+ value-format="x"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </a-form-item>
|
|
|
+ </a-col>
|
|
|
</a-row>
|
|
|
+ <a-space>
|
|
|
+ <a-button type="primary" @click="search">
|
|
|
+ <template #icon><icon-search /></template>
|
|
|
+ 搜索
|
|
|
+ </a-button>
|
|
|
+ <a-button @click="reset">
|
|
|
+ <template #icon><icon-refresh /></template>
|
|
|
+ 重置
|
|
|
+ </a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-form>
|
|
|
+ </a-collapse-item>
|
|
|
+ </a-collapse>
|
|
|
|
|
|
- <a-table :bordered="false" :data="data" stripe hoverable class="table" :loading="loading" :columns="columns" :pagination="{
|
|
|
- showPageSize: true,
|
|
|
- showJumper: true,
|
|
|
- showTotal: true,
|
|
|
- pageSize: pagination.pagesize,
|
|
|
- current: pagination.current,
|
|
|
- total: pagination.total
|
|
|
- }" @page-change="handlePageChange" @page-size-change="handlePageSizeChange">
|
|
|
- <template #username="{ record }">
|
|
|
- <a-space>
|
|
|
- <a-avatar :size="28">
|
|
|
- <img v-if="record.avatar" :alt="record.username ?? ''" :src="record.avatar" />
|
|
|
- <icon-user v-else />
|
|
|
- </a-avatar>
|
|
|
- {{ record.username || '-' }}
|
|
|
- </a-space>
|
|
|
- </template>
|
|
|
- <template #price="{ record }">
|
|
|
- ¥{{ record.price }}
|
|
|
- </template>
|
|
|
- <template #pay_type="{ record }">
|
|
|
- <a-space>
|
|
|
- <icon-wechatpay v-if="record.pay_type === 'wxpay'" />
|
|
|
- <icon-alipay-circle v-else-if="record.pay_type === 'alipay'" />
|
|
|
- <icon-qq v-else-if="record.pay_type === 'qqpay'" />
|
|
|
- <span>{{ getPayTypeLabel(record.pay_type) }}</span>
|
|
|
- </a-space>
|
|
|
- </template>
|
|
|
- <template #state="{ record }">
|
|
|
- <a-tag :color="getStateColor(record.state)">{{ getStateLabel(record.state) }}</a-tag>
|
|
|
- </template>
|
|
|
- <template #create_time="{ record }">
|
|
|
- {{ stramptoTime(record.create_time) }}
|
|
|
- </template>
|
|
|
- <template #pay_time="{ record }">
|
|
|
- {{ record.pay_time ? stramptoTime(record.pay_time) : '-' }}
|
|
|
- </template>
|
|
|
- <template #optional="{ record }">
|
|
|
- <a-button @click="goDetail(record.orderId)">查看详情</a-button>
|
|
|
- </template>
|
|
|
- </a-table>
|
|
|
- </a-card>
|
|
|
- </div>
|
|
|
+ <a-table
|
|
|
+ :bordered="false"
|
|
|
+ :data="data"
|
|
|
+ stripe
|
|
|
+ :loading="loading"
|
|
|
+ :columns="columns"
|
|
|
+ class="data-table"
|
|
|
+ :scroll="{ x: 1200 }"
|
|
|
+ :pagination="{
|
|
|
+ showPageSize: true,
|
|
|
+ showJumper: true,
|
|
|
+ showTotal: true,
|
|
|
+ pageSize: pagination.pagesize,
|
|
|
+ current: pagination.current,
|
|
|
+ total: pagination.total
|
|
|
+ }"
|
|
|
+ @page-change="handlePageChange"
|
|
|
+ @page-size-change="handlePageSizeChange"
|
|
|
+ >
|
|
|
+ <template #username="{ record }">
|
|
|
+ <a-space>
|
|
|
+ <a-avatar :size="28">
|
|
|
+ <img v-if="record.avatar" :alt="record.username ?? ''" :src="record.avatar" />
|
|
|
+ <icon-user v-else />
|
|
|
+ </a-avatar>
|
|
|
+ {{ record.username || '-' }}
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ <template #price="{ record }">
|
|
|
+ <span class="price-cell">¥{{ record.price }}</span>
|
|
|
+ </template>
|
|
|
+ <template #pay_type="{ record }">
|
|
|
+ <a-space size="mini">
|
|
|
+ <icon-wechatpay v-if="record.pay_type === 'wxpay'" />
|
|
|
+ <icon-alipay-circle v-else-if="record.pay_type === 'alipay'" />
|
|
|
+ <icon-qq v-else-if="record.pay_type === 'qqpay'" />
|
|
|
+ <span>{{ getPayTypeLabel(record.pay_type) }}</span>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ <template #state="{ record }">
|
|
|
+ <a-tag :color="getStateColor(record.state)">{{ getStateLabel(record.state) }}</a-tag>
|
|
|
+ </template>
|
|
|
+ <template #create_time="{ record }">
|
|
|
+ {{ formatStoreTimeFull(record.create_time) }}
|
|
|
+ </template>
|
|
|
+ <template #pay_time="{ record }">
|
|
|
+ {{ record.pay_time ? formatStoreTimeFull(record.pay_time) : '-' }}
|
|
|
+ </template>
|
|
|
+ <template #optional="{ record }">
|
|
|
+ <a-button type="text" size="small" @click="goDetail(record.orderId)">详情</a-button>
|
|
|
+ </template>
|
|
|
+ </a-table>
|
|
|
+ </a-card>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
@@ -122,165 +130,140 @@ import { useRouter } from 'vue-router'
|
|
|
import { adminOrderList } from '@/api/order'
|
|
|
import { Notification } from '@arco-design/web-vue'
|
|
|
import { getSemesterTimestamps } from '@/utils/util'
|
|
|
+import { formatStoreTimeFull, getPayTypeLabel, getOrderStateMeta } from '@/utils/storeFormat'
|
|
|
|
|
|
const router = useRouter()
|
|
|
-
|
|
|
-const pagination = reactive({
|
|
|
- total: 0,
|
|
|
- current: 1,
|
|
|
- pagesize: 20
|
|
|
-})
|
|
|
+const pagination = reactive({ total: 0, current: 1, pagesize: 20 })
|
|
|
|
|
|
const stateOptions = [
|
|
|
- { label: '全部', value: -1 },
|
|
|
- { label: '待支付', value: 0 },
|
|
|
- { label: '待处理', value: 1 },
|
|
|
- { label: '已完成', value: 2 },
|
|
|
- { label: '已关闭', value: 3 },
|
|
|
- { label: '处理异常', value: 4 }
|
|
|
+ { label: '全部', value: -1 },
|
|
|
+ { label: '待支付', value: 0 },
|
|
|
+ { label: '待处理', value: 1 },
|
|
|
+ { label: '已完成', value: 2 },
|
|
|
+ { label: '已关闭', value: 3 },
|
|
|
+ { label: '处理异常', value: 4 }
|
|
|
]
|
|
|
|
|
|
const payTypeOptions = [
|
|
|
- { label: '微信支付', value: 'wxpay' },
|
|
|
- { label: '支付宝', value: 'alipay' },
|
|
|
- { label: 'QQ支付', value: 'qqpay' }
|
|
|
+ { label: '微信支付', value: 'wxpay' },
|
|
|
+ { label: '支付宝', value: 'alipay' },
|
|
|
+ { label: 'QQ支付', value: 'qqpay' }
|
|
|
]
|
|
|
|
|
|
const queryData = reactive({
|
|
|
- orderId: '',
|
|
|
- goods_name: '',
|
|
|
- username: '',
|
|
|
- user_email: '',
|
|
|
- state: -1,
|
|
|
- pay_type: '',
|
|
|
- queryTime: []
|
|
|
+ orderId: '',
|
|
|
+ goods_name: '',
|
|
|
+ username: '',
|
|
|
+ user_email: '',
|
|
|
+ state: -1,
|
|
|
+ pay_type: '',
|
|
|
+ queryTime: []
|
|
|
})
|
|
|
|
|
|
const loading = ref(false)
|
|
|
const data = ref([])
|
|
|
|
|
|
const columns = [
|
|
|
- { title: '订单号', dataIndex: 'orderId', width: 180, ellipsis: true, tooltip: true },
|
|
|
- { title: '商品名称', dataIndex: 'goods_name', width: 160, ellipsis: true, tooltip: true },
|
|
|
- { title: '用户', slotName: 'username', width: 160 },
|
|
|
- { title: '用户邮箱', dataIndex: 'user_email', width: 180, ellipsis: true, tooltip: true },
|
|
|
- { title: '金额', slotName: 'price', width: 100 },
|
|
|
- { title: '支付方式', slotName: 'pay_type', width: 130 },
|
|
|
- { title: '订单状态', slotName: 'state', width: 110 },
|
|
|
- { title: '下单时间', slotName: 'create_time', width: 170 },
|
|
|
- { title: '支付时间', slotName: 'pay_time', width: 170 },
|
|
|
- { title: '操作', slotName: 'optional', fixed: 'right', width: 110 }
|
|
|
+ { title: '订单号', dataIndex: 'orderId', width: 180, ellipsis: true, tooltip: true },
|
|
|
+ { title: '商品', dataIndex: 'goods_name', width: 140, ellipsis: true, tooltip: true },
|
|
|
+ { title: '用户', slotName: 'username', width: 150 },
|
|
|
+ { title: '邮箱', dataIndex: 'user_email', width: 180, ellipsis: true, tooltip: true },
|
|
|
+ { title: '金额', slotName: 'price', width: 90 },
|
|
|
+ { title: '支付', slotName: 'pay_type', width: 120 },
|
|
|
+ { title: '状态', slotName: 'state', width: 100 },
|
|
|
+ { title: '下单时间', slotName: 'create_time', width: 165 },
|
|
|
+ { title: '支付时间', slotName: 'pay_time', width: 165 },
|
|
|
+ { title: '操作', slotName: 'optional', fixed: 'right', width: 80 }
|
|
|
]
|
|
|
|
|
|
-const getPayTypeLabel = (type) => {
|
|
|
- const map = { wxpay: '微信支付', alipay: '支付宝', qqpay: 'QQ支付' }
|
|
|
- return map[type] || '-'
|
|
|
-}
|
|
|
-
|
|
|
-const getStateLabel = (state) => {
|
|
|
- const map = {
|
|
|
- 0: '待支付',
|
|
|
- 1: '待处理',
|
|
|
- 2: '已完成',
|
|
|
- 3: '已关闭',
|
|
|
- 4: '处理异常'
|
|
|
- }
|
|
|
- return map[state] ?? '未知'
|
|
|
-}
|
|
|
-
|
|
|
-const getStateColor = (state) => {
|
|
|
- const map = {
|
|
|
- 0: 'orangered',
|
|
|
- 1: 'arcoblue',
|
|
|
- 2: 'green',
|
|
|
- 3: 'gray',
|
|
|
- 4: 'red'
|
|
|
- }
|
|
|
- return map[state] ?? 'gray'
|
|
|
-}
|
|
|
-
|
|
|
-const stramptoTime = (time) => {
|
|
|
- if (!time) return '-'
|
|
|
- return new Date(time).toLocaleString('zh-CN', {
|
|
|
- year: 'numeric',
|
|
|
- month: '2-digit',
|
|
|
- day: '2-digit',
|
|
|
- hour: '2-digit',
|
|
|
- minute: '2-digit',
|
|
|
- second: '2-digit'
|
|
|
- })
|
|
|
-}
|
|
|
+const getStateLabel = (state) => getOrderStateMeta(state).label
|
|
|
+const getStateColor = (state) => getOrderStateMeta(state).color
|
|
|
|
|
|
const search = () => {
|
|
|
- pagination.current = 1
|
|
|
- getList()
|
|
|
+ pagination.current = 1
|
|
|
+ getList()
|
|
|
}
|
|
|
|
|
|
const reset = () => {
|
|
|
- queryData.orderId = ''
|
|
|
- queryData.goods_name = ''
|
|
|
- queryData.username = ''
|
|
|
- queryData.user_email = ''
|
|
|
- queryData.state = -1
|
|
|
- queryData.pay_type = ''
|
|
|
- queryData.queryTime = getSemesterTimestamps()
|
|
|
- pagination.current = 1
|
|
|
- getList()
|
|
|
+ queryData.orderId = ''
|
|
|
+ queryData.goods_name = ''
|
|
|
+ queryData.username = ''
|
|
|
+ queryData.user_email = ''
|
|
|
+ queryData.state = -1
|
|
|
+ queryData.pay_type = ''
|
|
|
+ queryData.queryTime = getSemesterTimestamps()
|
|
|
+ pagination.current = 1
|
|
|
+ getList()
|
|
|
}
|
|
|
|
|
|
const getList = async () => {
|
|
|
- try {
|
|
|
- loading.value = true
|
|
|
- const res = await adminOrderList({
|
|
|
- ...queryData,
|
|
|
- pagesize: pagination.pagesize,
|
|
|
- current: pagination.current
|
|
|
- })
|
|
|
- if (!res || res.code !== 0) {
|
|
|
- return Notification.error({
|
|
|
- title: '获取订单列表失败',
|
|
|
- content: res?.msg ?? '请稍后再试'
|
|
|
- })
|
|
|
- }
|
|
|
- data.value = res.data || []
|
|
|
- pagination.total = res.pagination?.total ?? 0
|
|
|
- } catch (error) {
|
|
|
- Notification.error({
|
|
|
- title: '获取订单列表失败',
|
|
|
- content: error.message || '请稍后再试'
|
|
|
- })
|
|
|
- } finally {
|
|
|
- loading.value = false
|
|
|
+ try {
|
|
|
+ loading.value = true
|
|
|
+ const res = await adminOrderList({
|
|
|
+ ...queryData,
|
|
|
+ pagesize: pagination.pagesize,
|
|
|
+ current: pagination.current
|
|
|
+ })
|
|
|
+ if (!res || res.code !== 0) {
|
|
|
+ return Notification.error({
|
|
|
+ title: '获取订单列表失败',
|
|
|
+ content: res?.msg ?? '请稍后再试'
|
|
|
+ })
|
|
|
}
|
|
|
+ data.value = res.data || []
|
|
|
+ pagination.total = res.pagination?.total ?? 0
|
|
|
+ } catch (error) {
|
|
|
+ Notification.error({
|
|
|
+ title: '获取订单列表失败',
|
|
|
+ content: error.message || '请稍后再试'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-const goDetail = (orderId) => {
|
|
|
- router.push(`/goodsManage/goods/orderDetail/${orderId}`)
|
|
|
-}
|
|
|
+const goDetail = (orderId) => router.push(`/goodsManage/goods/orderDetail/${orderId}`)
|
|
|
|
|
|
const handlePageChange = (page) => {
|
|
|
- pagination.current = page
|
|
|
- getList()
|
|
|
+ pagination.current = page
|
|
|
+ getList()
|
|
|
}
|
|
|
|
|
|
const handlePageSizeChange = (size) => {
|
|
|
- pagination.pagesize = size
|
|
|
- pagination.current = 1
|
|
|
- getList()
|
|
|
+ pagination.pagesize = size
|
|
|
+ pagination.current = 1
|
|
|
+ getList()
|
|
|
}
|
|
|
|
|
|
onMounted(() => {
|
|
|
- queryData.queryTime = getSemesterTimestamps()
|
|
|
- getList()
|
|
|
+ queryData.queryTime = getSemesterTimestamps()
|
|
|
+ getList()
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.container {
|
|
|
- padding: 0 20px 20px 20px;
|
|
|
+.admin-order-page {
|
|
|
+ padding: 0 20px 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.page-card {
|
|
|
+ border-radius: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-collapse {
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.filter-grid {
|
|
|
+ padding-top: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.data-table {
|
|
|
+ margin-top: 8px;
|
|
|
}
|
|
|
|
|
|
-.table {
|
|
|
- margin-top: 15px;
|
|
|
+.price-cell {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #e85d04;
|
|
|
}
|
|
|
</style>
|