import type { WorkAction, WorkItem, WorkType, WorkView, BusinessReference } from './workApi' import { actionCodes, workCommands, type WorkCommandName } from './workApi' export const typeLabels: Record = { PICKUP: '提柜', WAREHOUSE_RECEIPT: '接仓卸柜', DELIVERY: '送仓 / FBA', TRANSPORT: '用车计划', EMPTY_RETURN: '还空柜', ROUTE: '确认路线' } export const flowLabels = { TRANSFER: '海外仓中转', DIRECT: '整柜直送', UNKNOWN: '路线待确认' } export const viewLabels: Record = { ALL: '全部待办', FOLLOW_TODAY: '今日需跟进', OVERDUE: '已超期', UNDATED: '未定日期', REVIEW: '需复核' } export function workReason(reason: string) { switch (reason) { case 'SOURCE_TIMEZONE': return '原业务作业地点时区待核实' case 'SOURCE_CONFIGURATION': return '原货源或仓库配置待核实' case 'LASTLEG_SOURCE': return '尾程货源待建立' case 'READY_WINDOW_UNVERIFIED': return '货物备妥窗口待核实' case 'CARGO_QUANTITY_REVIEW': return '货量或重复关联需要核对。' default: return reason } } export function workStatus(item: WorkItem) { if (item.executionStatus === 'COMPLETED') return '已完成' if (item.reviewRequired) return '需复核' if (item.executionStatus === 'IN_PROGRESS') return '执行中' return { UNPLANNED: '待安排', TARGET_SET: '已有目标日期', AWAITING_REPLY: '等待回复', CONFIRMED: '已落实', NOT_REQUIRED: '无需预约' }[item.planStatus] } export function localInstant(value: string, timezone: string | null) { if (!timezone) return '作业地点时区待核实' try { return new Intl.DateTimeFormat('zh-CN', { timeZone: timezone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }).format(new Date(value)) } catch { return '实际时间待核实' } } export function workDate(item: WorkItem) { if (item.dateBasis === 'ACTUAL') { const actual = item.actual if (actual?.localOccurredAt) return `实际 ${actual.localOccurredAt.replace('T', ' ')}` return actual?.occurredAt ? `实际 ${localInstant(actual.occurredAt, actual.timezone)}` : '实际时间待核实' } if (item.dateBasis === 'NONE' || !item.calendarDate) return '作业日期未定' const slot = item.dateBasis === 'CONFIRMED' ? item.confirmed : item.target const end = slot?.endDate && slot.endTime ? ` → ${slot.endDate} ${slot.endTime}` : '' return `${item.dateBasis === 'CONFIRMED' ? '确认' : '目标'} ${slot?.date || item.calendarDate}${slot?.startTime ? ` ${slot.startTime}${end}` : ' · 时段未定'}` } export function commandName(action: WorkAction): WorkCommandName | null { return action.target.kind === 'WORK_COMMAND' && workCommands.includes(action.target.command as WorkCommandName) ? action.target.command as WorkCommandName : null } export function sameAction(a: WorkAction, b: WorkAction) { return a.code === b.code && a.targetWorkItemKey === b.targetWorkItemKey && JSON.stringify(a.target) === JSON.stringify(b.target) } export function actionAllowed(item: WorkItem, action: WorkAction) { return actionCodes.includes(action.code) && item.allowedActions.some(candidate => sameAction(candidate, action)) } export function referenceRoute(reference: BusinessReference) { if (!reference.businessNo) return null if (reference.kind === 'DISPATCH') return `/overseas-warehouse/dispatches?dispatchNo=${encodeURIComponent(reference.businessNo)}` if (reference.kind === 'DELIVERY') return `/overseas-warehouse/delivery-orders/${encodeURIComponent(reference.businessNo)}` return null } export function actionRoute(action: WorkAction, references: BusinessReference[], item?: WorkItem) { // Only known application routes. No server-provided URL or method is executed. switch (action.target.kind) { case 'FIRSTLEG_CONTAINER': { const path = `/container-loading/overseas/${encodeURIComponent(action.target.containerBookingId)}` if (!item || action.code === 'VIEW_DETAIL' || action.code === 'VIEW_HISTORY') return path if (item.type === 'PICKUP') return `${path}?action=pickup` if (item.type === 'EMPTY_RETURN' && action.code === 'RECORD_EXECUTION') return `${path}?action=empty-return` if (item.type === 'DELIVERY' && item.flow === 'DIRECT' && action.code === 'RECORD_EXECUTION') return `${path}?action=direct-unload${item.requirementKey ? `&requirementKey=${encodeURIComponent(item.requirementKey)}` : ''}` return path } case 'FLEET_TRIP': { const id = action.target.tripId const trip = references.find(ref => ref.kind === 'FLEET_TRIP' && ref.key === id) return trip?.businessNo ? `/overseas-master-data/trips/${encodeURIComponent(trip.businessNo)}` : null } case 'WAREHOUSE_RECEIPT': return action.target.inboundPlanNo && action.target.customerId ? `/overseas-warehouse/inbound-orders/${encodeURIComponent(action.target.inboundPlanNo)}?customerId=${encodeURIComponent(action.target.customerId)}` : null default: return null } }