feat(consignment): 寄售仓库在库列表增加通过审核入库时间并在手动匹配中补全时间展示

- 寄售仓库 (ConsignmentInventoryPanel):表格中增加「通过审核入库时间」列并格式化展示,详情弹窗规范化展示入库时间、出库时间与提报时间
- 手动匹配弹窗 (ConsignmentManualMatchModal):候选订单列表展示工单创建时间,顶部横幅与已选概要展示现货入库时间及订单创建时间;从订单匹配现货时展示现货入库时间
- 内部匹配接口与工单拦截:后端 listInventoryMatchableOrders 返回工单创建时间及平台单号;发布拦截弹窗中增加展示现货入库时间
- 验证方式:运行前后端单元测试全部通过,前端 build 校验通过
This commit is contained in:
yml2213
2026-10-08 15:41:23 +08:00
parent 5978e92370
commit 893388b37f
8 changed files with 162 additions and 8 deletions
@@ -28,6 +28,7 @@ import {
resolveManualMatchRequirement,
type ManualMatchType,
} from '@/utils/consignment-manual-match'
import { formatDateTime } from '@/utils/date-time'
import { notifyVoucherConsume } from '@/utils/voucher-consume'
const { Text, Paragraph } = Typography
@@ -35,8 +36,10 @@ const { Text, Paragraph } = Typography
type Selected = {
workOrderId: number | string
workOrderLabel: string
workOrderCreatedAt?: string
inventoryId: number | string
inventoryLabel: string
inventoryInboundAt?: string
matchType: ManualMatchType
conflicts: string[]
/** 供货打手(用于回显供货来源) */
@@ -48,9 +51,9 @@ export type ConsignmentManualMatchModalProps = {
open: boolean
onClose: () => void
/** 订单侧入口:从订单出发选现货 */
workOrder?: { workOrderId: number | string; label: string } | null
workOrder?: { workOrderId: number | string; label: string; createdAt?: string } | null
/** 库存侧入口:从现货出发选订单 */
inventory?: { inventoryId: number | string; label: string } | null
inventory?: { inventoryId: number | string; label: string; inboundAt?: string } | null
onMatched?: () => void
}
@@ -71,6 +74,7 @@ export default function ConsignmentManualMatchModal({
const [options, setOptions] = useState<ConsignmentMatchOptionView[]>([])
const [orders, setOrders] = useState<ConsignmentMatchableOrder[]>([])
const [inventoryLabel, setInventoryLabel] = useState('')
const [inventoryInboundAt, setInventoryInboundAt] = useState('')
const [inventoryWorker, setInventoryWorker] = useState<{
workerId: number | null
workerName: string
@@ -89,6 +93,7 @@ export default function ConsignmentManualMatchModal({
setConfirmedPartial(false)
setConfirmedMismatch(false)
setMatchNote('')
setInventoryInboundAt('')
}
const load = async () => {
@@ -106,6 +111,7 @@ export default function ConsignmentManualMatchModal({
? `${res.data.inventory.itemName}(${res.data.inventory.sourceSubmissionNo || res.data.inventory.inventoryNo})`
: inventory.label,
)
setInventoryInboundAt(res.data?.inventory?.inboundAt || inventory.inboundAt || '')
setInventoryWorker({
workerId: res.data?.inventory?.workerId ?? null,
workerName: res.data?.inventory?.workerName || '',
@@ -251,7 +257,9 @@ export default function ConsignmentManualMatchModal({
description={
mode === 'order'
? '下面是该订单的全部在库现货(含规格不一致的),核对差异后直接内部履约。'
: `当前现货:${inventoryLabel || inventory?.label || ''}。下面是可匹配的订单列表,核对后直接内部履约。`
: `当前现货:${inventoryLabel || inventory?.label || ''}${
inventoryInboundAt ? `(审核入库:${formatDateTime(inventoryInboundAt)})` : ''
}。下面是可匹配的订单列表,核对后直接内部履约。`
}
/>
@@ -312,6 +320,15 @@ export default function ConsignmentManualMatchModal({
: ''}{' '}
· 货源 {option.inventory.workerName || '未关联打手'} · 结算价 ¥
{(Number(option.inventory.costPriceFen || 0) / 100).toFixed(2)}
{option.inventory.inboundAt || option.inventory.createdAt ? (
<>
{' '}
· 审核入库{' '}
{formatDateTime(
option.inventory.inboundAt || option.inventory.createdAt,
)}
</>
) : null}
</Text>
{option.conflicts.length > 0 ? (
<Text style={{ fontSize: 12, color: '#cf1322' }}>
@@ -330,8 +347,11 @@ export default function ConsignmentManualMatchModal({
setSelected({
workOrderId: workOrder?.workOrderId || 0,
workOrderLabel: workOrder?.label || '',
workOrderCreatedAt: workOrder?.createdAt,
inventoryId: option.inventory.id,
inventoryLabel: option.inventory.itemName,
inventoryInboundAt:
option.inventory.inboundAt || option.inventory.createdAt,
matchType: option.matchType,
conflicts: option.conflicts,
workerId: option.inventory.workerId,
@@ -390,6 +410,9 @@ export default function ConsignmentManualMatchModal({
? `${order.requiredSpec.diamondLevel}钻`
: ''}{' '}
· 报酬 ¥{(order.rewardAmountFen / 100).toFixed(2)}
{order.createdAt ? (
<> · 创建时间 {formatDateTime(order.createdAt)}</>
) : null}
</Text>
{order.conflicts.length > 0 ? (
<Text style={{ fontSize: 12, color: '#cf1322' }}>
@@ -408,8 +431,10 @@ export default function ConsignmentManualMatchModal({
setSelected({
workOrderId: order.workOrderId,
workOrderLabel: `${order.workOrderNo || `#${order.workOrderId}`} · ${order.productName}`,
workOrderCreatedAt: order.createdAt,
inventoryId: inventory?.inventoryId || 0,
inventoryLabel,
inventoryInboundAt,
matchType: order.matchType,
conflicts: order.conflicts,
workerId: inventoryWorker?.workerId ?? null,
@@ -433,8 +458,26 @@ export default function ConsignmentManualMatchModal({
{selected ? (
<div style={{ border: '1px solid #f0f0f0', borderRadius: 8, padding: 12 }}>
<Descriptions size="small" column={1} style={{ marginBottom: 8 }}>
<Descriptions.Item label="订单">{selected.workOrderLabel || '—'}</Descriptions.Item>
<Descriptions.Item label="现货">{selected.inventoryLabel || '—'}</Descriptions.Item>
<Descriptions.Item label="订单">
<Space size={6} wrap>
<span>{selected.workOrderLabel || '—'}</span>
{selected.workOrderCreatedAt ? (
<Text type="secondary" style={{ fontSize: 12 }}>
(创建于 {formatDateTime(selected.workOrderCreatedAt)})
</Text>
) : null}
</Space>
</Descriptions.Item>
<Descriptions.Item label="现货">
<Space size={6} wrap>
<span>{selected.inventoryLabel || '—'}</span>
{selected.inventoryInboundAt ? (
<Text type="secondary" style={{ fontSize: 12 }}>
(审核入库于 {formatDateTime(selected.inventoryInboundAt)})
</Text>
) : null}
</Space>
</Descriptions.Item>
<Descriptions.Item label="供货来源">
{selected.workerId ? (
<Space size={6}>