This commit is contained in:
魔方熊成祥
2026-04-29 21:38:18 +08:00
commit ba0458abe2
56 changed files with 10300 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
import { useEffect, useState } from 'react'
import { Card, Descriptions, Drawer, Space, Spin, Table, Tag, Typography } from 'antd'
import { toast } from 'sonner'
import { merchantOrderDetail } from '@/apis/mallMerchant'
import type { OrderDetailInfo } from '@/types/mall'
import { formatUnixTime, getStatusColor, getStatusLabel, prettyJsonText } from '@/utils/mall'
interface OrderDetailDrawerProps {
open: boolean
merchantId: string
orderId?: number
refreshToken?: number
onClose: () => void
}
export default function OrderDetailDrawer({
open,
merchantId,
orderId,
refreshToken,
onClose,
}: OrderDetailDrawerProps) {
const [loading, setLoading] = useState(false)
const [data, setData] = useState<OrderDetailInfo | null>(null)
useEffect(() => {
if (!open || !orderId) {
return
}
let cancelled = false
const run = async () => {
try {
setLoading(true)
const result = await merchantOrderDetail({
merchantId,
orderId,
})
if (!cancelled) {
setData(result.data)
}
} catch (error) {
const message = error instanceof Error ? error.message : '加载订单详情失败'
toast.error(message)
} finally {
if (!cancelled) {
setLoading(false)
}
}
}
void run()
return () => {
cancelled = true
}
}, [merchantId, open, orderId, refreshToken])
return (
<Drawer title={orderId ? `订单详情 #${orderId}` : '订单详情'} width={920} open={open} onClose={onClose}>
<Spin spinning={loading}>
{!data ? null : (
<Space direction="vertical" size={16} style={{ width: '100%' }}>
<Card className="page-card" title="基础信息">
<Descriptions column={2} size="small">
<Descriptions.Item label="订单号">{data.orderNo}</Descriptions.Item>
<Descriptions.Item label="交易号">{data.tradeNo}</Descriptions.Item>
<Descriptions.Item label="订单 ID">{data.id}</Descriptions.Item>
<Descriptions.Item label="会员 ID">{data.uid}</Descriptions.Item>
<Descriptions.Item label="商家 ID">{data.merchantId}</Descriptions.Item>
<Descriptions.Item label="商家名称">{data.merchantName || '-'}</Descriptions.Item>
<Descriptions.Item label="订单状态">
<Tag color={getStatusColor(data.orderStatus)}>{getStatusLabel(data.orderStatus)}</Tag>
</Descriptions.Item>
<Descriptions.Item label="售后状态">
<Tag color={getStatusColor(data.afterSaleStatus)}>
{getStatusLabel(data.afterSaleStatus)}
</Tag>
</Descriptions.Item>
<Descriptions.Item label="商品金额">{data.goodsAmount}</Descriptions.Item>
<Descriptions.Item label="支付金额">{data.payAmount}</Descriptions.Item>
<Descriptions.Item label="运费">{data.freightAmount}</Descriptions.Item>
<Descriptions.Item label="优惠金额">{data.discountAmount}</Descriptions.Item>
<Descriptions.Item label="币种">{data.currency || '-'}</Descriptions.Item>
<Descriptions.Item label="支付时间">{formatUnixTime(data.payTime)}</Descriptions.Item>
<Descriptions.Item label="发货时间">{formatUnixTime(data.shipTime)}</Descriptions.Item>
<Descriptions.Item label="完成时间">{formatUnixTime(data.finishTime)}</Descriptions.Item>
<Descriptions.Item label="取消时间">{formatUnixTime(data.cancelTime)}</Descriptions.Item>
<Descriptions.Item label="自动确认">{formatUnixTime(data.autoConfirmAt)}</Descriptions.Item>
<Descriptions.Item label="支付渠道">{data.payChannel || '-'}</Descriptions.Item>
<Descriptions.Item label="创建时间">{formatUnixTime(data.createdAt)}</Descriptions.Item>
<Descriptions.Item label="更新时间">{formatUnixTime(data.updatedAt)}</Descriptions.Item>
<Descriptions.Item label="扩展 JSON" span={2}>
<Typography.Text style={{ whiteSpace: 'pre-wrap' }}>
{prettyJsonText(data.extraInfoJson) || '-'}
</Typography.Text>
</Descriptions.Item>
</Descriptions>
</Card>
<Card className="page-card" title="收货与物流">
<Descriptions column={2} size="small">
<Descriptions.Item label="收货人">{data.receiverName}</Descriptions.Item>
<Descriptions.Item label="手机号">{data.receiverMobile}</Descriptions.Item>
<Descriptions.Item label="国家区号">{data.receiverCountryCode || '-'}</Descriptions.Item>
<Descriptions.Item label="省份">{data.receiverProvince || '-'}</Descriptions.Item>
<Descriptions.Item label="城市">{data.receiverCity || '-'}</Descriptions.Item>
<Descriptions.Item label="区县">{data.receiverDistrict || '-'}</Descriptions.Item>
<Descriptions.Item label="完整地址" span={2}>
{[data.receiverProvince, data.receiverCity, data.receiverDistrict, data.receiverAddress]
.filter(Boolean)
.join(' ')}
</Descriptions.Item>
<Descriptions.Item label="邮编">{data.receiverZipCode || '-'}</Descriptions.Item>
<Descriptions.Item label="物流公司">{data.deliveryCompany || '-'}</Descriptions.Item>
<Descriptions.Item label="运单号">{data.deliveryNo || '-'}</Descriptions.Item>
<Descriptions.Item label="商家备注" span={2}>
{data.sellerRemark || '-'}
</Descriptions.Item>
<Descriptions.Item label="买家备注" span={2}>
{data.buyerRemark || '-'}
</Descriptions.Item>
</Descriptions>
</Card>
<Card className="page-card" title="商品明细">
<Table
rowKey="id"
pagination={false}
dataSource={data.items}
columns={[
{
title: '商品',
dataIndex: 'spuName',
render: (_, record) => (
<Space direction="vertical" size={2}>
<Typography.Text strong>{record.spuName}</Typography.Text>
<Typography.Text type="secondary">{record.skuName}</Typography.Text>
</Space>
),
},
{
title: '规格 JSON',
dataIndex: 'skuSpecJson',
width: 260,
render: value => (
<Typography.Text style={{ whiteSpace: 'pre-wrap' }}>
{prettyJsonText(value) || '-'}
</Typography.Text>
),
},
{
title: '数量',
dataIndex: 'buyNum',
width: 90,
},
{
title: '单价',
dataIndex: 'salePrice',
width: 100,
},
{
title: '原价',
dataIndex: 'originPrice',
width: 100,
},
{
title: '金额',
dataIndex: 'itemAmount',
width: 120,
},
{
title: '优惠',
dataIndex: 'discountAmount',
width: 100,
},
{
title: '退款',
dataIndex: 'refundAmount',
width: 100,
},
{
title: '售后状态',
dataIndex: 'afterSaleStatus',
width: 120,
render: value => <Tag color={getStatusColor(value)}>{getStatusLabel(value)}</Tag>,
},
]}
/>
</Card>
</Space>
)}
</Spin>
</Drawer>
)
}