工单流转记录始终展示操作人并区分涉及打手补充编辑与撤回明细

This commit is contained in:
yml2213
2026-08-22 14:02:52 +08:00
parent 6ac77c0124
commit 665fc9ffa7
@@ -40,6 +40,21 @@ function readPayload(event: WorkOrderEvent, key: string): string {
return String(value).trim()
}
function readPayloadAmount(event: WorkOrderEvent, key: string): number {
return Number(readPayload(event, key) || 0)
}
function formatFenAmount(value: number) {
return `${(value / 100).toFixed(2)}`
}
/** 事件涉及的打手名(管理端接口会附带打手摘要;打手端退回 #id) */
function resolveEventWorkerLabel(event: WorkOrderEvent): string {
if (event.worker?.displayName) return event.worker.displayName
const workerId = readPayload(event, 'workerId')
return workerId ? `打手 #${workerId}` : ''
}
/** 事件类型 → 节点阶段文案与颜色 */
export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
const type = event.eventType
@@ -79,9 +94,9 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
}
}
case 'assigned_by_admin': {
const workerId = readPayload(event, 'workerId')
const workerLabel = resolveEventWorkerLabel(event)
return {
title: `指派打手接手此单${workerId ? `(打手 #${workerId}` : ''}`,
title: workerLabel ? `指派打手接手此单${workerLabel}` : '指派打手接手此单',
description: `订单状态:${formatStatusLabel(event.fromStatus)}${formatStatusLabel(
event.toStatus,
)}`,
@@ -90,11 +105,15 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
}
case 'unassigned_by_admin':
return { title: '取消指派,订单回到未分配状态', color: 'green' }
case 'returned_to_hall_by_admin':
case 'returned_to_hall_by_admin': {
const releaseAmount = readPayloadAmount(event, 'releaseAmount')
return {
title: note ? `撤回订单到抢单大厅(${note}` : '撤回订单到抢单大厅',
description:
releaseAmount > 0 ? `已退回该打手冻结押金 ${formatFenAmount(releaseAmount)}` : undefined,
color: 'green',
}
}
case 'cancelled_by_worker':
return { title: '打手取消接单', color: 'red' }
case 'cancel_request_submitted':
@@ -177,9 +196,9 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
}
}
case 'sharing_share_accepted': {
const workerId = readPayload(event, 'workerId')
const workerLabel = resolveEventWorkerLabel(event)
return {
title: `拼单份额验收通过并已结算${workerId ? `打手 #${workerId}` : ''}`,
title: `拼单份额验收通过并已结算${workerLabel ? `${workerLabel}` : ''}`,
color: 'purple',
}
}
@@ -251,8 +270,23 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
}
// —— 其他 ——
case 'edited':
return { title: '更改了订单信息', color: 'default' }
case 'edited': {
const productName = readPayload(event, 'productName')
const rewardAmount = readPayloadAmount(event, 'rewardAmount')
const requiredDepositAmount = readPayloadAmount(event, 'requiredDepositAmount')
const timeoutMinutes = readPayloadAmount(event, 'timeoutMinutes')
const changes = [
productName ? `品名:${productName}` : '',
rewardAmount > 0 ? `报酬 ${formatFenAmount(rewardAmount)}` : '',
requiredDepositAmount > 0 ? `押金 ${formatFenAmount(requiredDepositAmount)}` : '',
timeoutMinutes > 0 ? `时限 ${Math.round(timeoutMinutes)} 分钟` : '',
].filter(Boolean)
return {
title: '更改了订单信息',
description: changes.length > 0 ? `改为:${changes.join(' · ')}` : undefined,
color: 'default',
}
}
case 'sharing_config_updated':
return { title: '更新了拼单配置', color: 'default' }
case 'price_synced_from_rule': {
@@ -266,10 +300,10 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
}
}
case 'sharing_share_cancelled_by_admin': {
const workerId = readPayload(event, 'workerId')
const workerLabel = resolveEventWorkerLabel(event)
const quantity = readPayload(event, 'quantity')
return {
title: `撤销拼单参与者${workerId ? `打手 #${workerId}` : ''}`,
title: `撤销拼单参与者${workerLabel ? `${workerLabel}` : ''}`,
description: `${quantity ? `撤销 ${quantity} 份;` : ''}${note ? `原因:${note}` : '份数已退回接单大厅'}`,
color: 'red',
}
@@ -351,7 +385,7 @@ export default function WorkOrderEventTimeline({
</Typography.Text>
) : null}
<div className="work-order-event-actor">
{event.worker ? (
{event.worker && event.actorType === 'worker' ? (
<Space size={[4, 4]} wrap>
<Tag
color="blue"
@@ -363,7 +397,7 @@ export default function WorkOrderEventTimeline({
)
}}
>
{event.worker.displayName} #{event.worker.workerId}
· {event.worker.displayName} #{event.worker.workerId}
{canNavigateToWorker ? <LinkOutlined /> : null}
</Tag>
<Typography.Text type="secondary" className="work-order-event-worker-meta">
@@ -373,19 +407,31 @@ export default function WorkOrderEventTimeline({
</Typography.Text>
</Space>
) : (
<Tag
color={
event.actorType === 'system'
? 'default'
: event.actorType === 'worker'
? 'blue'
: event.actorType === 'admin'
? 'green'
: 'default'
}
>
{event.actorName || event.actorType}
</Tag>
<Space size={[4, 4]} wrap>
<Tag color={resolveActorTagColor(event.actorType)}>
· {event.actorName || event.actorType || '未知'}
</Tag>
{event.worker ? (
<Space size={[4, 4]} wrap>
<Typography.Text type="secondary" className="work-order-event-worker-meta">
</Typography.Text>
<Tag
color="blue"
className={canNavigateToWorker ? 'work-order-event-worker-link' : undefined}
onClick={() => {
if (!canNavigateToWorker) return
void navigate(
`/admin/worker-platform?tab=workers&workerId=${event.worker?.workerId}`,
)
}}
>
{event.worker.displayName} #{event.worker.workerId}
{canNavigateToWorker ? <LinkOutlined /> : null}
</Tag>
</Space>
) : null}
</Space>
)}
</div>
</div>
@@ -405,3 +451,10 @@ function formatWorkerStatus(status: string) {
}
return labels[status] || status || '未知状态'
}
function resolveActorTagColor(actorType: string) {
if (actorType === 'admin') return 'green'
if (actorType === 'worker') return 'blue'
if (actorType === 'system') return 'default'
return 'default'
}