add order items
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
<script setup lang="ts">
|
||||
import dayjs from 'dayjs'
|
||||
import { api } from '@/utils/request'
|
||||
import {
|
||||
useOrderItemStore,
|
||||
type OrderItemDetail,
|
||||
} from '@/stores/order-item'
|
||||
import type { OrderItemRecord } from '@/stores/order'
|
||||
import CascadeFilter from '@/components/CascadeFilter.vue'
|
||||
import {
|
||||
SearchOutlined,
|
||||
ReloadOutlined,
|
||||
EyeOutlined,
|
||||
} from '@ant-design/icons-vue'
|
||||
|
||||
const store = useOrderItemStore()
|
||||
|
||||
// Detail drawer
|
||||
const drawerVisible = ref(false)
|
||||
const drawerLoading = ref(false)
|
||||
const itemDetail = ref<OrderItemDetail | null>(null)
|
||||
let detailRequestId = 0
|
||||
|
||||
const columns = [
|
||||
{ title: 'ID', dataIndex: 'id', width: 80, fixed: 'left' as const },
|
||||
{ title: '公司', key: 'company', width: 100 },
|
||||
{ title: '平台', key: 'platform', width: 100 },
|
||||
{ title: '店铺', key: 'store', width: 120 },
|
||||
{ title: '平台订单ID', key: 'platform_order_id', width: 160, ellipsis: true },
|
||||
{ title: '子订单ID', dataIndex: 'sub_order_id', width: 140 },
|
||||
{ title: '平台商品ID', key: 'platform_product_id', width: 140, ellipsis: true },
|
||||
{ title: 'SKU', dataIndex: 'product_sku', width: 120 },
|
||||
{ title: '单价', key: 'unit_price', width: 100 },
|
||||
{ title: '数量', dataIndex: 'quantity', width: 80 },
|
||||
{ title: '优惠', key: 'discount', width: 100 },
|
||||
{ title: '小计', key: 'total', width: 100 },
|
||||
{ title: '创建时间', key: 'created_date', width: 140 },
|
||||
{ title: '操作', key: 'action', width: 100, fixed: 'right' as const },
|
||||
]
|
||||
|
||||
const orderStatusMap: Record<number, { text: string; color: string }> = {
|
||||
1: { text: '待付款', color: 'orange' },
|
||||
2: { text: '支付失败', color: 'red' },
|
||||
3: { text: '已支付', color: 'blue' },
|
||||
4: { text: '待发货', color: 'cyan' },
|
||||
5: { text: '已发货', color: 'geekblue' },
|
||||
6: { text: '取消申请中', color: 'volcano' },
|
||||
7: { text: '已取消', color: 'default' },
|
||||
8: { text: '已完成', color: 'green' },
|
||||
9: { text: '发货前取消', color: 'default' },
|
||||
}
|
||||
|
||||
// RangePicker dayjs 桥接
|
||||
const createdDateRange = computed({
|
||||
get: () => {
|
||||
if (!store.filters.created_date_range) return undefined
|
||||
return store.filters.created_date_range.map((d) => dayjs(d)) as [
|
||||
dayjs.Dayjs,
|
||||
dayjs.Dayjs,
|
||||
]
|
||||
},
|
||||
set: (val) => {
|
||||
store.filters.created_date_range = val
|
||||
? [val[0].format('YYYY-MM-DD'), val[1].format('YYYY-MM-DD')]
|
||||
: null
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
store.loadLookups()
|
||||
store.fetchOrderItems()
|
||||
})
|
||||
|
||||
function handleSearch() {
|
||||
store.pagination.page = 1
|
||||
store.fetchOrderItems()
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
store.resetFilters()
|
||||
store.fetchOrderItems()
|
||||
}
|
||||
|
||||
function handlePageChange(page: number, pageSize: number) {
|
||||
store.pagination.page = page
|
||||
store.pagination.per_page = pageSize
|
||||
store.fetchOrderItems()
|
||||
}
|
||||
|
||||
function formatAmount(val: string | null | undefined) {
|
||||
if (!val || val === '0' || val === '0.00') return '-'
|
||||
return val
|
||||
}
|
||||
|
||||
function formatTime(time: string | null) {
|
||||
if (!time) return '-'
|
||||
return time.replace('T', ' ').substring(0, 16)
|
||||
}
|
||||
|
||||
async function handleViewDetail(record: { id: number }) {
|
||||
const currentRequestId = ++detailRequestId
|
||||
drawerVisible.value = true
|
||||
drawerLoading.value = true
|
||||
itemDetail.value = null
|
||||
|
||||
try {
|
||||
const detail = await api.get<OrderItemDetail>(`/api/v1/order-items/${record.id}`)
|
||||
// 竞态保护
|
||||
if (currentRequestId !== detailRequestId) return
|
||||
itemDetail.value = detail
|
||||
} catch {
|
||||
if (currentRequestId !== detailRequestId) return
|
||||
message.error('获取订单项详情失败')
|
||||
} finally {
|
||||
if (currentRequestId === detailRequestId) {
|
||||
drawerLoading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="text-xl font-semibold mb-4">订单子项</h2>
|
||||
|
||||
<!-- Filter area -->
|
||||
<a-card class="mb-4">
|
||||
<a-form layout="inline" @submit.prevent="handleSearch">
|
||||
<a-form-item>
|
||||
<CascadeFilter v-model="store.cascadeValue" />
|
||||
</a-form-item>
|
||||
<a-form-item label="平台订单ID">
|
||||
<a-input
|
||||
v-model:value="store.filters.platform_order_id"
|
||||
placeholder="精确搜索"
|
||||
allow-clear
|
||||
@press-enter="handleSearch"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="平台商品ID">
|
||||
<a-input
|
||||
v-model:value="store.filters.platform_product_id"
|
||||
placeholder="精确搜索"
|
||||
allow-clear
|
||||
@press-enter="handleSearch"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="SKU">
|
||||
<a-input
|
||||
v-model:value="store.filters.product_sku"
|
||||
placeholder="精确搜索"
|
||||
allow-clear
|
||||
@press-enter="handleSearch"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="创建时间">
|
||||
<a-range-picker
|
||||
v-model:value="createdDateRange"
|
||||
format="YYYY-MM-DD"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space>
|
||||
<a-button type="primary" html-type="submit">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
搜索
|
||||
</a-button>
|
||||
<a-button @click="handleReset">
|
||||
<template #icon><ReloadOutlined /></template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
<!-- Table -->
|
||||
<a-card>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data-source="store.orderItems"
|
||||
:loading="store.loading"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 1500 }"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'company'">
|
||||
{{ store.companyMap.get(record.company_id) || record.company_id }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'platform'">
|
||||
{{ store.platformMap.get(record.platform_id) || record.platform_id }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'store'">
|
||||
{{ store.storeMap.get(record.store_id) || record.store_id }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'platform_order_id'">
|
||||
{{ record.platform_order_id }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'platform_product_id'">
|
||||
{{ record.platform_product_id }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'unit_price'">
|
||||
{{ formatAmount(record.unit_price) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'discount'">
|
||||
{{ formatAmount(record.discount) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'total'">
|
||||
{{ formatAmount(record.total) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'created_date'">
|
||||
{{ formatTime(record.created_date) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'action'">
|
||||
<a-button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleViewDetail(record as OrderItemRecord)"
|
||||
>
|
||||
<template #icon><EyeOutlined /></template>
|
||||
查看
|
||||
</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="mt-4 flex justify-end">
|
||||
<a-pagination
|
||||
:current="store.pagination.page"
|
||||
:page-size="store.pagination.per_page"
|
||||
:total="store.pagination.total"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:show-total="(total: number) => `共 ${total} 条`"
|
||||
@change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<!-- Detail drawer -->
|
||||
<a-drawer
|
||||
title="订单项详情"
|
||||
:open="drawerVisible"
|
||||
:width="720"
|
||||
@close="drawerVisible = false"
|
||||
>
|
||||
<a-spin :spinning="drawerLoading">
|
||||
<template v-if="itemDetail">
|
||||
<!-- 父订单摘要 -->
|
||||
<a-descriptions title="父订单摘要" :column="2" bordered class="mb-4">
|
||||
<a-descriptions-item label="平台订单ID">
|
||||
{{ itemDetail.parent_order.platform_order_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="订单状态">
|
||||
<a-tag
|
||||
:color="orderStatusMap[itemDetail.parent_order.order_status_id]?.color || 'default'"
|
||||
>
|
||||
{{
|
||||
orderStatusMap[itemDetail.parent_order.order_status_id]?.text
|
||||
|| `状态 ${itemDetail.parent_order.order_status_id}`
|
||||
}}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="总金额">
|
||||
{{ formatAmount(itemDetail.parent_order.total_amount) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="实付金额">
|
||||
{{ formatAmount(itemDetail.parent_order.total_paid) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">
|
||||
{{ formatTime(itemDetail.parent_order.created_date) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="支付时间">
|
||||
{{ formatTime(itemDetail.parent_order.paid_date) }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- 订单项基本信息 -->
|
||||
<a-descriptions title="订单项信息" :column="2" bordered class="mb-4">
|
||||
<a-descriptions-item label="ID">{{ itemDetail.id }}</a-descriptions-item>
|
||||
<a-descriptions-item label="公司">
|
||||
{{ store.companyMap.get(itemDetail.company_id) || itemDetail.company_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="平台">
|
||||
{{ store.platformMap.get(itemDetail.platform_id) || itemDetail.platform_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="店铺">
|
||||
{{ store.storeMap.get(itemDetail.store_id) || itemDetail.store_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="平台订单ID">
|
||||
{{ itemDetail.platform_order_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="子订单ID">
|
||||
{{ itemDetail.sub_order_id || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="子订单类型">
|
||||
{{ itemDetail.sub_order_type_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="平台商品ID">
|
||||
{{ itemDetail.platform_product_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="商品ID">
|
||||
{{ itemDetail.product_id }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="SKU">
|
||||
{{ itemDetail.product_sku || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="条码">
|
||||
{{ itemDetail.product_barcode || '-' }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="单价">
|
||||
{{ formatAmount(itemDetail.unit_price) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="数量">
|
||||
{{ itemDetail.quantity }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="优惠">
|
||||
{{ formatAmount(itemDetail.discount) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="小计">
|
||||
{{ formatAmount(itemDetail.total) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">
|
||||
{{ formatTime(itemDetail.created_date) }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="更新时间">
|
||||
{{ formatTime(itemDetail.updated_at) }}
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
|
||||
<!-- ext JSON -->
|
||||
<a-descriptions title="扩展数据 (ext)" :column="1" bordered>
|
||||
<a-descriptions-item>
|
||||
<pre v-if="itemDetail.ext" class="m-0 text-xs max-h-80 overflow-auto">{{
|
||||
JSON.stringify(itemDetail.ext, null, 2)
|
||||
}}</pre>
|
||||
<span v-else class="text-gray-400">暂无数据</span>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</template>
|
||||
</a-spin>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user