-
计划状态{{ plan?.status || '尚未创建' }}
+
计划状态{{ planStatusLabel(plan?.status) }}
已装箱数{{ totalPackages }}
容积{{ formatNumber(usedVolume) }} / {{ formatNumber(container.capacityCbm || 0) }} m³{{ volumeRate == null ? '容量待配置' : `${volumeRate}%` }}
重量{{ formatNumber(usedWeight) }} / {{ formatNumber(container.maxWeightKg || 0) }} kg{{ weightRate == null ? '承重待配置' : `${weightRate}%` }}
diff --git a/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.test.ts b/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.test.ts
index 7b4f522c..82fb576a 100644
--- a/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.test.ts
+++ b/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.test.ts
@@ -7,6 +7,7 @@ import UnifiedOrderWorkflowPanel from './UnifiedOrderWorkflowPanel.vue'
import {
getEvidence,
getOutboundDispatch,
+ getPicking,
getPreload,
smartSplit,
voidEvidence,
@@ -18,6 +19,7 @@ vi.mock('../api', async (importOriginal) => {
...original,
getEvidence: vi.fn(),
getOutboundDispatch: vi.fn(),
+ getPicking: vi.fn(),
getPreload: vi.fn(),
smartSplit: vi.fn(),
voidEvidence: vi.fn(),
@@ -50,6 +52,7 @@ describe('UnifiedOrderWorkflowPanel preload editor', () => {
beforeEach(() => {
vi.mocked(getOutboundDispatch).mockReset().mockResolvedValue(null as never)
vi.mocked(getEvidence).mockReset().mockResolvedValue({ inboundId: '2086085512165634051', evidences: [] })
+ vi.mocked(getPicking).mockReset().mockResolvedValue({ id: '51', inboundId: '2086085512165634051', status: 'PICKING', version: 2, expectedCount: 10, pickedCount: 4, remark: null })
vi.mocked(getPreload).mockReset().mockResolvedValue(preload('REF-OLD'))
vi.mocked(smartSplit).mockReset()
vi.mocked(voidEvidence).mockReset()
@@ -156,4 +159,37 @@ describe('UnifiedOrderWorkflowPanel preload editor', () => {
)
prompt.mockRestore()
})
+
+ it('renders booking, trucking and picking backend statuses as business Chinese', async () => {
+ vi.mocked(getOutboundDispatch).mockResolvedValue({
+ orderId: '1', orderNo: 'ORD-1', inboundId: '2', inboundCode: 'IN-2', containerBookingId: '3', containerNo: 'CONT-3',
+ loadingPlanId: '4', loadingPlanStatus: 'LOADING', oceanBookingId: '5', oceanBookingStatus: 'RELEASED',
+ truckAppointmentId: '6', truckAppointmentStatus: 'PICKUP_IN_PROGRESS', gate: { passed: false, items: [] },
+ })
+ const wrapper = mountPanel(['platform:firstleg:inbound:picking:view'], 'LOADING')
+ await flushPromises()
+
+ expect(wrapper.text()).toContain('已放舱')
+ expect(wrapper.text()).toContain('提柜中')
+ expect(wrapper.text()).toContain('拣货中')
+ expect(wrapper.text()).not.toContain('RELEASED')
+ expect(wrapper.text()).not.toContain('PICKUP_IN_PROGRESS')
+ expect(wrapper.text()).not.toContain('PICKING')
+ })
+
+ it('does not expose unknown backend enum values', async () => {
+ vi.mocked(getOutboundDispatch).mockResolvedValue({
+ orderId: '1', orderNo: 'ORD-1', inboundId: '2', inboundCode: 'IN-2', containerBookingId: null, containerNo: null,
+ loadingPlanId: null, loadingPlanStatus: null, oceanBookingId: '5', oceanBookingStatus: 'NEW_BOOKING_STATE',
+ truckAppointmentId: '6', truckAppointmentStatus: 'NEW_TRUCK_STATE', gate: { passed: false, items: [] },
+ })
+ vi.mocked(getPicking).mockResolvedValue({ id: '51', inboundId: '2', status: 'NEW_PICK_STATE', version: 2, expectedCount: null, pickedCount: null, remark: null })
+ const wrapper = mountPanel(['platform:firstleg:inbound:picking:view'], 'LOADING')
+ await flushPromises()
+
+ expect(wrapper.text()).toContain('未知状态')
+ expect(wrapper.text()).not.toContain('NEW_BOOKING_STATE')
+ expect(wrapper.text()).not.toContain('NEW_TRUCK_STATE')
+ expect(wrapper.text()).not.toContain('NEW_PICK_STATE')
+ })
})
diff --git a/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.vue b/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.vue
index 2a71fdbd..1d6529b4 100644
--- a/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.vue
+++ b/src/modules/unified-orders/workflows/components/UnifiedOrderWorkflowPanel.vue
@@ -9,6 +9,8 @@ import AppDialog from '@/shared/components/AppDialog.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
import SmartLoadingWorkbench from '@/modules/unified-orders/workflows/components/SmartLoadingWorkbench.vue'
+import { oceanBookingStatusLabel } from '@/modules/ocean-bookings'
+import { truckAppointmentStatusLabel } from '@/modules/trucking'
import { sanitizePreloadItem, validatePreloadItem, validatePreloadItems } from '@/modules/unified-orders/workflows/preloadForm'
import {
completeLoading,
@@ -146,7 +148,19 @@ function removeItem(index: number) {
}
function preloadStatusLabel(status?: string | null) {
- return ({ PENDING: '待提交', CONFIRMING: '确认中', CONFIRMED: '已确认' } as Record
)[status || ''] || '尚未生成'
+ return workflowStatusLabel(status, { PENDING: '待提交', CONFIRMING: '确认中', CONFIRMED: '已确认' }, '尚未生成')
+}
+
+function workflowStatusLabel(value: string | null | undefined, labels: Record, emptyLabel: string) {
+ if (!value) return emptyLabel
+ return labels[value] || '未知状态'
+}
+
+function pickingStatusLabel(status?: string | null) {
+ return workflowStatusLabel(status, {
+ PENDING: '待拣货', PICKING: '拣货中', IN_PROGRESS: '拣货中', AWAITING_REVIEW: '待复核',
+ COMPLETED: '已完成', CANCELLED: '已取消',
+ }, '暂无数据')
}
function formatVolume(value: number | null) {
@@ -423,8 +437,8 @@ onMounted(() => { void refresh() })
子流程与门禁摘要{{ dispatch.gate?.passed ? '已通过' : '待补齐' }}
-
订舱{{ dispatch.oceanBookingStatus || '暂无数据' }}
-
拖车{{ dispatch.truckAppointmentStatus || '暂无数据' }}
+
订舱{{ oceanBookingStatusLabel(dispatch.oceanBookingStatus, '未关联') }}
+
拖车{{ truckAppointmentStatusLabel(dispatch.truckAppointmentStatus, '未关联') }}
柜号{{ dispatch.containerNo || '暂无数据' }}
{{ gateItemName(item.code, item.name) }}{{ item.passed ? '已满足' : '待补齐' }}
@@ -473,7 +487,7 @@ onMounted(() => { void refresh() })
拣货与装柜装柜中
- {{ picking.status || '—' }}
+ {{ pickingStatusLabel(picking.status) }}
{{ picking.version }}
{{ picking.expectedCount ?? '—' }}
{{ picking.pickedCount ?? '—' }}
diff --git a/src/shared/components/StatusBadge.vue b/src/shared/components/StatusBadge.vue
index 09991de3..eccde1e7 100644
--- a/src/shared/components/StatusBadge.vue
+++ b/src/shared/components/StatusBadge.vue
@@ -4,10 +4,10 @@ import { computed } from 'vue'
const props = defineProps<{ status: string }>()
const tone = computed(() => {
- if (['正常', '启用', '已完成', '已审核', '审核通过', '已入库', '装柜完成', '派送完成'].includes(props.status)) return 'success'
- if (['待审核', '草稿', '待处理', '未提交', '未录入', '待测量数据', '待分柜'].includes(props.status)) return 'warning'
- if (['已受理', '已订舱', '运输中', '处理中', '装柜中'].includes(props.status)) return 'info'
- if (['停用', '已取消', '已驳回', '审核驳回', '失败'].includes(props.status)) return 'danger'
+ if (['正常', '启用', '已完成', '已审核', '审核通过', '已入库', '装柜完成', '派送完成', '已确认', '已放舱'].includes(props.status)) return 'success'
+ if (['待审核', '草稿', '待处理', '未提交', '未录入', '待测量数据', '待分柜', '变更中'].includes(props.status)) return 'warning'
+ if (['已受理', '已订舱', '已提交', '运输中', '处理中', '装柜中'].includes(props.status)) return 'info'
+ if (['停用', '已取消', '已驳回', '审核驳回', '失败', '订舱失败'].includes(props.status)) return 'danger'
return 'neutral'
})