diff --git a/apps/backend/src/routes/admin/worker-platform.ts b/apps/backend/src/routes/admin/worker-platform.ts index d7c40d4c..92ada148 100644 --- a/apps/backend/src/routes/admin/worker-platform.ts +++ b/apps/backend/src/routes/admin/worker-platform.ts @@ -325,7 +325,7 @@ router.post( router.put( '/worker-platform/orders/:workOrderId', - requireAdminRoles(['admin', 'operator']), + requireAdminRoles(['admin', 'operator', 'support']), createJsonHandler( (req) => updateAdminWorkOrder(String(req.params.workOrderId || ''), req.body || {}), { diff --git a/apps/backend/src/services/worker-platform/admin-service.ts b/apps/backend/src/services/worker-platform/admin-service.ts index 0a1f4fdc..2a3175db 100644 --- a/apps/backend/src/services/worker-platform/admin-service.ts +++ b/apps/backend/src/services/worker-platform/admin-service.ts @@ -834,6 +834,9 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) { orderAmountFen: paymentFen, syncSource: 'mock', mock: true, + provider: 'mock', + platform: 'mock', + shopName: '模拟店铺', }, } const workOrder = await createWorkOrder({ diff --git a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx index 1f4b70b5..c1eafcb0 100644 --- a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx +++ b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx @@ -483,24 +483,38 @@ export default function WorkOrdersPanel() { { title: '订单', minWidth: 300, - render: (_, row) => ( -
- openDetailDrawer(row)}> - {row.productName || row.workOrderNo} - - - {row.categoryName ? {row.categoryName} : null} - {row.orderId ? ( - - 源订单 #{row.orderId} + render: (_, row) => { + const source = asRecord(row.material?.source) + const shopName = String(source.shopName || '').trim() + const provider = String(source.provider || '').trim() + return ( +
+ openDetailDrawer(row)} + onSaved={refreshAll} + /> + + {row.categoryName ? {row.categoryName} : null} + {row.orderId ? ( + + 源订单 #{row.orderId} + + ) : null} + + {shopName || provider ? ( + + {provider ? `来源:${provider}` : ''} + {provider && shopName ? ' · ' : ''} + {shopName ? `店铺:${shopName}` : ''} ) : null} - - - {row.platformOrderId} · {row.workOrderNo} - -
- ), + + {row.platformOrderId} · {row.workOrderNo} + +
+ ) + }, }, { title: '用户付款金额', @@ -1438,6 +1452,92 @@ function getUserPaymentFen(order: WorkOrder): number | null { return Number.isFinite(paymentFen) ? paymentFen : null } +/** 商品名:单击看详情,双击原地修改(仅未接走工单) */ +function ProductNameEditableCell({ + order, + onOpenDetail, + onSaved, +}: { + order: WorkOrder + onOpenDetail: () => void + onSaved: () => Promise | void +}) { + const { message } = App.useApp() + const [editing, setEditing] = useState(false) + const [draft, setDraft] = useState('') + const savingRef = useRef(false) + const clickTimerRef = useRef(null) + + const editable = + ['pending_material', 'unassigned', 'open'].includes(order.status) && !order.worker + + function handleClick() { + if (clickTimerRef.current) window.clearTimeout(clickTimerRef.current) + clickTimerRef.current = window.setTimeout(() => onOpenDetail(), 260) + } + + function handleDoubleClick() { + if (clickTimerRef.current) { + window.clearTimeout(clickTimerRef.current) + clickTimerRef.current = null + } + if (!editable) return + setDraft(order.productName || order.workOrderNo) + setEditing(true) + } + + async function save() { + if (savingRef.current) return + const next = draft.trim() + if (!next) { + message.error('商品名不能为空') + return + } + if (next === order.productName) { + setEditing(false) + return + } + savingRef.current = true + try { + await updateAdminWorkOrder(order.workOrderId, { productName: next }) + message.success('商品名已更新') + setEditing(false) + await onSaved() + } catch (error) { + message.error(error instanceof Error ? error.message : '保存失败') + } finally { + savingRef.current = false + } + } + + if (!editing) { + return ( + + {order.productName || order.workOrderNo} + + ) + } + + return ( + setDraft(event.target.value)} + onPressEnter={() => void save()} + onBlur={() => void save()} + onKeyDown={(event) => { + if (event.key === 'Escape') setEditing(false) + }} + /> + ) +} + function AmountEditableCell({ order, field,