([\s\S]*?)<\/template>/)?.[1] || ''
expect(template).not.toContain('租户')
@@ -46,7 +46,7 @@ describe('WeightOcrPanel contract', () => {
expect(source).toContain('库位 item.recognitionStatus === 'CONFIRMED') === true")
})
it('matches backend image limits and keeps technical OCR data out of the list', () => {
diff --git a/src/modules/inbounds/weight/components/WeightOcrPanel.vue b/src/modules/inbounds/weight/components/WeightOcrPanel.vue
index c91019fd..f649fb4a 100644
--- a/src/modules/inbounds/weight/components/WeightOcrPanel.vue
+++ b/src/modules/inbounds/weight/components/WeightOcrPanel.vue
@@ -41,7 +41,7 @@ const props = withDefaults(defineProps<{
})
const emit = defineEmits<{
changed: []
- summaryChanged: [actualGrossWeightKg: number | null, actualNetWeightKg: number | null]
+ summaryChanged: [actualGrossWeightKg: number | null, actualNetWeightKg: number | null, hasConfirmedWeight: boolean]
}>()
const access = useAccessPreviewStore()
@@ -213,7 +213,12 @@ function buildAdjustmentReason(row: WeightResultResource) {
}
function emitWorkspaceChanged() {
- emit('summaryChanged', workspace.value?.actualGrossWeightKg ?? null, workspace.value?.actualNetWeightKg ?? null)
+ emit(
+ 'summaryChanged',
+ workspace.value?.actualGrossWeightKg ?? null,
+ workspace.value?.actualNetWeightKg ?? null,
+ workspace.value?.weightResults.some((item) => item.recognitionStatus === 'CONFIRMED') === true,
+ )
emit('changed')
}
diff --git a/src/modules/overseas-warehouse/lastMilePresentation.ts b/src/modules/overseas-warehouse/lastMilePresentation.ts
index 12b98694..fdedad3c 100644
--- a/src/modules/overseas-warehouse/lastMilePresentation.ts
+++ b/src/modules/overseas-warehouse/lastMilePresentation.ts
@@ -112,7 +112,7 @@ export function toLastMileOrderListItem(dto: LastMileOrderSummaryDto): LastMileO
transferWarehouse: text(dto.transferWarehouseName),
fbaWarehouse: text(dto.fbaWarehouseCode),
containerNo: text(dto.containerNo),
- containerStatus: text(dto.containerStatus),
+ containerNode: text(dto.containerNode),
abnormal: yesNo(dto.abnormal),
held: yesNo(dto.detained),
detained: Boolean(dto.detained),
diff --git a/src/modules/overseas-warehouse/pages/LastMileOrderDetailView.vue b/src/modules/overseas-warehouse/pages/LastMileOrderDetailView.vue
index 6886a3a6..a533aaa4 100644
--- a/src/modules/overseas-warehouse/pages/LastMileOrderDetailView.vue
+++ b/src/modules/overseas-warehouse/pages/LastMileOrderDetailView.vue
@@ -39,6 +39,15 @@ const feeForm = reactive({ itemCode: '', itemName: '', direction: 'RECEIVABLE' a
const feeItemOptions = [{ code: 'STORAGE_FEE', name: '仓租' }, { code: 'INBOUND_OPERATION', name: '入库操作费' }, { code: 'OUTBOUND_OPERATION', name: '出库操作费' }, { code: 'RELABEL_FEE', name: '换标费' }, { code: 'REBOX_FEE', name: '换箱费' }, { code: 'PALLET_FEE', name: '托盘费' }, { code: 'DELIVERY_FEE', name: '派送费' }, { code: 'TRANSFER_FEE', name: '转仓费' }, { code: 'EXCEPTION_FEE', name: '异常处理费' }, { code: 'OTHER', name: '其他' }]
function text(value: unknown) { return String(value ?? '').trim() || '—' }
+function containerNodeLabel(value: unknown) {
+ const code = String(value ?? '').trim()
+ return ({
+ DEPARTED_WAREHOUSE: '已离开国内仓库', AT_ORIGIN_PORT: '重箱已进入起运港',
+ LOADED_ON_VESSEL: '已装船', DEPARTED_ORIGIN_PORT: '船舶已离开起运港', IN_TRANSIT: '海运途中',
+ ARRIVED_DESTINATION_PORT: '船舶已到目的港', DISCHARGED_FROM_VESSEL: '已卸船、未清关',
+ PICKUP_READY: '已清关、可提柜', PICKED_UP: '已提柜', EMPTY_RETURNED: '已还柜',
+ } as Record)[code] || text(code)
+}
function yesNo(value: boolean | null | undefined) { return value == null ? '—' : value ? '是' : '否' }
function feeStatusLabel(value: string) { return ({ PENDING_REVIEW: '待审核', APPROVED: '审核通过', REJECTED: '已驳回' } as Record)[value] || value }
function isSingleLineBusinessField(field: DetailField) { return field.label === '入仓码' || field.label === '集装箱号' }
@@ -70,7 +79,7 @@ const containerFields = computed(() => {
{ label: '预计到港时间', value: formatOverseasDateTime(order?.estimatedArrivalAt) },
{ label: '实际到港时间', value: formatOverseasDateTime(order?.actualArrivalAt) },
{ label: '预计到仓时间', value: formatOverseasDateTime(order?.estimatedWarehouseAt) },
- { label: '清关状态', value: text(order?.containerStatus) },
+ { label: '货柜节点', value: containerNodeLabel(order?.containerNode) },
]
})
const planFields = computed(() => {
diff --git a/src/modules/overseas-warehouse/pages/realApiMount.test.ts b/src/modules/overseas-warehouse/pages/realApiMount.test.ts
index c573d0fc..72127e22 100644
--- a/src/modules/overseas-warehouse/pages/realApiMount.test.ts
+++ b/src/modules/overseas-warehouse/pages/realApiMount.test.ts
@@ -34,7 +34,7 @@ describe('overseas warehouse mounted real API pages', () => {
vi.mocked(listInboundOrders).mockReset().mockResolvedValue({ records: [], page: 1, size: 10, total: 0, pages: 0 })
vi.mocked(getInboundPlan).mockReset().mockResolvedValue({ id: '9007199254740993', planNo: 'IP-1', customerId: '10001', sourceOrderId: '9007199254740995', sourceOrderNo: 'FL-WH-20260911-000001', customerName: '客户甲', orderType: 'ONE_CLICK_DROPSHIP', overseasWarehouseCode: 'US-LAX-01', overseasWarehouseName: '洛杉矶接柜仓', status: 'PENDING_ASSIGNMENT', lineCount: 1, palletCount: 1, totalVolumeCbm: 2, createdAt: '2026-09-11T10:00:00', updatedAt: '2026-09-11T10:10:00', remark: '页面验收', lines: [{ id: '1', orderId: '9007199254740995', inboundCode: 'IN-1', fbaWarehouseCode: 'ABE3', destinationWarehouseCode: 'ABE3', destinationWarehouseName: 'ABE3目的仓', volumeCbm: 2, requiredPackageCount: 10, plannedPalletCount: 1 }], pallets: [], allocations: [] })
vi.mocked(listInventoryLedger).mockReset().mockResolvedValue({ records: [{ id: '9007199254740997', customerId: '10001', customerName: '客户甲', destinationWarehouseCode: 'LAX', inboundCode: 'NYEXX2608300001', inboundOrderNo: 'IP-1', businessType: 'STOCK_IN', beforePackages: 0, deltaPackages: 10, afterPackages: 10, occurredAt: '2026-08-20T10:00:00' }], page: 1, size: 20, total: 1, pages: 1 })
- vi.mocked(getLastMileOrder).mockReset().mockResolvedValue({ order: { id: '9007199254740999', customerId: '10001', customerName: '华远贸易', orderNo: 'LMO-260827-0001', inboundCode: 'NYEXX2608280033', containerNo: 'TSTU0000061', currentStatus: 'PENDING_ASSIGNMENT' }, cargo: [], statusHistory: [], fees: [], operationHistory: [] })
+ vi.mocked(getLastMileOrder).mockReset().mockResolvedValue({ order: { id: '9007199254740999', customerId: '10001', customerName: '华远贸易', orderNo: 'LMO-260827-0001', inboundCode: 'NYEXX2608280033', containerNo: 'TSTU0000061', containerNode: 'PICKUP_READY', currentStatus: 'PENDING_ASSIGNMENT' }, cargo: [], statusHistory: [], fees: [], operationHistory: [] })
})
it('keeps receiving warehouse and FBA warehouse independent in the inbound-plan list', async () => {
vi.mocked(listInboundOrders).mockResolvedValue({
@@ -80,5 +80,5 @@ describe('overseas warehouse mounted real API pages', () => {
expect(wrapper.text()).not.toContain('9007199254740995')
})
it('mounts inventory ledger as localized read-only business facts without exposing internal ids', async () => { const wrapper = mount(InventoryTransactionsView, { global: { plugins: [createPinia(), ElementPlus] } }); await flushPromises(); expect(listInventoryLedger).toHaveBeenCalledWith(expect.objectContaining({ page: 1, size: 10 })); expect(listInventoryLedger).not.toHaveBeenCalledWith(expect.objectContaining({ customerId: expect.anything() })); expect(wrapper.text()).toContain('客户甲'); expect(wrapper.text()).toContain('NYEXX2608300001'); expect(wrapper.text()).not.toContain('10001'); expect(wrapper.text()).toContain('IP-1'); expect(wrapper.text()).toContain('10'); expect(wrapper.text()).toContain('入库'); expect(wrapper.text()).not.toContain('STOCK_IN'); expect(wrapper.text()).toContain('不提供出库单跳转'); expect(wrapper.text()).not.toContain('当前流水 DTO'); expect(wrapper.text()).not.toContain('操作人名称待补充') })
- it('renders complete business references with single-line ellipsis and titles', async () => { routing.route.params = { orderId: '9007199254740999' }; const wrapper = mount(LastMileOrderDetailView, { global: { plugins: [createPinia(), ElementPlus] } }); await flushPromises(); expect(getLastMileOrder).toHaveBeenCalledWith('9007199254740999'); expect(wrapper.text()).toContain('华远贸易'); expect(wrapper.text()).toContain('LMO-260827-0001'); expect(wrapper.get('.order-reference-text').attributes('title')).toBe('LMO-260827-0001'); const businessValues = wrapper.findAll('.detail-field-value--business'); expect(businessValues.map((item) => item.attributes('title'))).toEqual(expect.arrayContaining(['NYEXX2608280033', 'TSTU0000061'])); expect(businessValues.every((item) => item.text().length > 0)).toBe(true) })
+ it('renders complete business references with single-line ellipsis and titles', async () => { routing.route.params = { orderId: '9007199254740999' }; const wrapper = mount(LastMileOrderDetailView, { global: { plugins: [createPinia(), ElementPlus] } }); await flushPromises(); expect(getLastMileOrder).toHaveBeenCalledWith('9007199254740999'); expect(wrapper.text()).toContain('华远贸易'); expect(wrapper.text()).toContain('LMO-260827-0001'); expect(wrapper.text()).toContain('货柜节点'); expect(wrapper.text()).toContain('已清关、可提柜'); expect(wrapper.text()).not.toContain('清关状态'); expect(wrapper.get('.order-reference-text').attributes('title')).toBe('LMO-260827-0001'); const businessValues = wrapper.findAll('.detail-field-value--business'); expect(businessValues.map((item) => item.attributes('title'))).toEqual(expect.arrayContaining(['NYEXX2608280033', 'TSTU0000061'])); expect(businessValues.every((item) => item.text().length > 0)).toBe(true) })
})
diff --git a/src/modules/overseas-warehouse/types.ts b/src/modules/overseas-warehouse/types.ts
index 3efb0cf0..38cd703e 100644
--- a/src/modules/overseas-warehouse/types.ts
+++ b/src/modules/overseas-warehouse/types.ts
@@ -20,7 +20,7 @@ export interface LastMileOrderListItem {
transferWarehouse: string
fbaWarehouse: string
containerNo: string
- containerStatus: string
+ containerNode: string
abnormal: string
held: string
detained: boolean
diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts
index cd7f72c5..c2dbe52f 100644
--- a/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts
+++ b/src/modules/unified-orders/pages/UnifiedOrdersView.test.ts
@@ -134,7 +134,12 @@ describe('UnifiedOrdersView contract', () => {
for (const uncontractedKey of [
'internalOrderStatus', 'holdCargo', 'companyName', 'pickupMethod', 'associatedFiles', 'createdBy',
]) expect(columnSource).not.toContain(`key: '${uncontractedKey}'`)
- expect(columnSource.indexOf("key: 'actions'")).toBeLessThan(columnSource.indexOf("key: 'inboundCode'"))
+ const actionsColumnIndex = columnSource.indexOf("key: 'actions'")
+ const selectionColumnIndex = columnSource.indexOf("key: 'selection'")
+ const inboundCodeColumnIndex = columnSource.indexOf("key: 'inboundCode'")
+ expect(actionsColumnIndex).toBeGreaterThanOrEqual(0)
+ expect(selectionColumnIndex).toBeGreaterThan(actionsColumnIndex)
+ expect(inboundCodeColumnIndex).toBeGreaterThan(selectionColumnIndex)
expect(columnSource).not.toContain("key: 'coLoadGroup'")
expect(columnSource).not.toContain("key: 'orderNo'")
expect(columnSource).toContain("key: 'inboundCode', prop: 'inboundCode', label: '入仓码', minWidth: 160, slotName: 'inboundCode'")
diff --git a/src/modules/unified-orders/pages/UnifiedOrdersView.vue b/src/modules/unified-orders/pages/UnifiedOrdersView.vue
index 6e4b639a..b4623157 100644
--- a/src/modules/unified-orders/pages/UnifiedOrdersView.vue
+++ b/src/modules/unified-orders/pages/UnifiedOrdersView.vue
@@ -621,6 +621,7 @@ const queryFields = computed(() => showAdvancedFilters.value
: primaryQueryFields.value)
const columns = computed(() => [
+ // 业务表格保持操作列第一;批量选择列仅在有对应权限时紧随其后。
{ key: 'actions', label: '操作', width: 290, fixed: 'left', slotName: 'actions' },
...(can('platform:order:approve') || can('platform:firstleg:smart-loading:assign') || can('platform:order:export') || can('platform:firstleg:inbound:view') ? [{
key: 'selection', type: 'selection', width: 48, fixed: 'left',