feat(worker-platform): 接单工单表格「打手」列支持展示寄售供货打手与现货资料

1. 新增 resolveConsignmentWorkerDisplay 工具函数,自动解析工单寄售现货与资料字段(供货打手、游戏角色昵称、游戏ID及联系方式);
2. 优化 renderWorkOrderWorkers 渲染逻辑:当工单为内部寄售现货履约时,打手列带「供货打手」或「内部现货」专属角标,主标题展示打手名/角色名,副标题拼接游戏ID与联系方式,解决原先显示为破折号 - 的问题;
3. 新增 consignment-worker-display 单元测试,更新寄卖库存优化现状与进度追踪文档,前端 57 个测试全绿并通过类型检查。
This commit is contained in:
yml2213
2026-09-21 11:40:25 +08:00
parent c80bd0e337
commit 29589bb9af
4 changed files with 187 additions and 19 deletions
@@ -1,6 +1,7 @@
import { Typography } from 'antd'
import { Space, Tag, Typography } from 'antd'
import type { CollectField, WorkOrder } from '@/types/worker-platform'
import { resolveConsignmentWorkerDisplay } from '@/utils/consignment-display'
import { asRecord, formatMoney } from './shared'
@@ -27,25 +28,58 @@ export function formatUserPaymentAmount(order: WorkOrder): string {
return paymentFen === null ? '-' : formatMoney(paymentFen)
}
/** 拼单母单没有单一 assigned worker,改为展示当前参与打手及其承接份数。 */
/** 渲染工单关联打手:普通打手 / 拼单参与打手 / 寄卖供货打手与现货资料 */
export function renderWorkOrderWorkers(order: WorkOrder) {
if (order.worker) return order.worker.displayName || order.worker.username || '-'
if (!order.sharing?.enabled || !order.sharingWorkers?.length) return '-'
const names = order.sharingWorkers
.map((worker) => worker.displayName || worker.username || `打手#${worker.workerId}`)
.join('、')
const quantity = order.sharingWorkers.reduce(
(sum, worker) => sum + Number(worker.quantity || 0),
0,
)
return (
<div className="cell-stack">
<Typography.Text ellipsis={{ tooltip: names }}>{names}</Typography.Text>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{order.sharingWorkers.length} 人 · {quantity} 份
</Typography.Text>
</div>
)
if (order.sharing?.enabled && order.sharingWorkers?.length) {
const names = order.sharingWorkers
.map((worker) => worker.displayName || worker.username || `打手#${worker.workerId}`)
.join('、')
const quantity = order.sharingWorkers.reduce(
(sum, worker) => sum + Number(worker.quantity || 0),
0,
)
return (
<div className="cell-stack">
<Typography.Text ellipsis={{ tooltip: names }}>{names}</Typography.Text>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{order.sharingWorkers.length} 人 · {quantity} 份
</Typography.Text>
</div>
)
}
// 寄卖库存 / 内部现货履约单:回显供货打手或卖家现货资料
const consignmentDisplay = resolveConsignmentWorkerDisplay(order)
if (consignmentDisplay) {
return (
<div className="cell-stack">
<Space size={4} align="center" wrap>
<Tag
color="cyan"
style={{ margin: 0, fontSize: 11, padding: '0 4px', lineHeight: '18px' }}
>
{consignmentDisplay.tagText}
</Tag>
<Typography.Text ellipsis={{ tooltip: consignmentDisplay.primaryName }}>
{consignmentDisplay.primaryName}
</Typography.Text>
</Space>
{consignmentDisplay.secondaryInfo ? (
<Typography.Text
type="secondary"
style={{ fontSize: 12 }}
ellipsis={{ tooltip: consignmentDisplay.secondaryInfo }}
>
{consignmentDisplay.secondaryInfo}
</Typography.Text>
) : null}
</div>
)
}
return '-'
}
export function getDisplayOrderNo(
@@ -0,0 +1,58 @@
import type { WorkOrder } from '@/types/worker-platform'
function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === 'object' && !Array.isArray(value)
? (value as Record<string, unknown>)
: {}
}
export type ConsignmentWorkerDisplayInfo = {
tagText: '供货打手' | '内部现货'
primaryName: string
secondaryInfo: string
}
/** 解析寄卖库存/内部现货履约单的供货人与现货资料信息 */
export function resolveConsignmentWorkerDisplay(
order: WorkOrder,
): ConsignmentWorkerDisplayInfo | null {
const material = asRecord(order.material)
const consignment = asRecord(material.consignment)
const boosterFields = asRecord(order.gift?.boosterMaterial?.fields)
const hasConsignment =
Object.keys(consignment).length > 0 ||
Boolean(boosterFields.sourceType === 'consignment' || boosterFields.inventoryNo)
if (!hasConsignment) return null
const workerName = String(consignment.workerName || consignment.worker_name || '').trim()
const sellerNickname = String(
boosterFields.gameNickname || consignment.buyerName || consignment.sellerGameNickname || '',
).trim()
const sellerGameId = String(
boosterFields.gameId || consignment.sellerGameId || consignment.seller_game_id || '',
).trim()
const sellerContact = String(
boosterFields.sellerPhone ||
consignment.sellerPhone ||
consignment.workerPhone ||
boosterFields.sellerContact ||
consignment.sellerContact ||
'',
).trim()
const primaryName = workerName || sellerNickname || sellerGameId || '内部现货'
const secondaryInfo = [
workerName && sellerNickname && sellerNickname !== workerName ? sellerNickname : '',
sellerGameId ? `ID:${sellerGameId}` : '',
!sellerGameId && sellerContact ? sellerContact : '',
]
.filter(Boolean)
.join(' · ')
return {
tagText: workerName ? '供货打手' : '内部现货',
primaryName,
secondaryInfo,
}
}