diff --git a/src/modules/overseas-warehouse/utils/relabelSkuDisplay.test.mjs b/src/modules/overseas-warehouse/utils/relabelSkuDisplay.test.mjs new file mode 100644 index 0000000..e4251ce --- /dev/null +++ b/src/modules/overseas-warehouse/utils/relabelSkuDisplay.test.mjs @@ -0,0 +1,14 @@ +import assert from 'node:assert/strict' +import { readFileSync } from 'node:fs' +import test from 'node:test' +import ts from 'typescript' + +const source = readFileSync(new URL('./relabelSkuDisplay.ts', import.meta.url), 'utf8') +const js = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 } }).outputText +const { relabelSkuCodes, relabelSkuCount } = await import(`data:text/javascript;base64,${Buffer.from(js).toString('base64')}`) +test('one box with two SKU mappings shows both and counts unique SKUs across boxes', () => { + const item = { skuCode: 'FIRST', skuItems: [{ skuCode: 'FIRST' }, { skuCode: 'SECOND' }] } + assert.deepEqual(relabelSkuCodes(item), ['FIRST', 'SECOND']) + assert.equal(relabelSkuCount([item, { skuCode: 'SECOND' }]), 2) + assert.deepEqual(relabelSkuCodes({ skuCode: 'FIRST,SECOND', skuItems: [] }), ['FIRST', 'SECOND']) +}) diff --git a/src/modules/overseas-warehouse/utils/relabelSkuDisplay.ts b/src/modules/overseas-warehouse/utils/relabelSkuDisplay.ts new file mode 100644 index 0000000..13bd205 --- /dev/null +++ b/src/modules/overseas-warehouse/utils/relabelSkuDisplay.ts @@ -0,0 +1,13 @@ +interface RelabelSkuSource { + skuCode?: string | null + skuItems?: Array<{ skuCode: string }> | null +} + +export function relabelSkuCodes(item: RelabelSkuSource): string[] { + const codes = item.skuItems?.length ? item.skuItems.map(line => line.skuCode) : (item.skuCode || '').split(',') + return [...new Set(codes.map(code => code.trim()).filter(Boolean))] +} + +export function relabelSkuCount(items: RelabelSkuSource[]): number { + return new Set(items.flatMap(relabelSkuCodes)).size +} diff --git a/src/modules/overseas-warehouse/views/WarehouseServiceView.vue b/src/modules/overseas-warehouse/views/WarehouseServiceView.vue index 3430059..2284e71 100644 --- a/src/modules/overseas-warehouse/views/WarehouseServiceView.vue +++ b/src/modules/overseas-warehouse/views/WarehouseServiceView.vue @@ -26,6 +26,7 @@ import { } from '@/modules/first-leg/api/firstLeg' import { loadAllWarehouseRecords } from '@/modules/first-leg/utils/warehousePagination' import { createIdempotencyKey } from '@/utils/idempotencyKey' +import { relabelSkuCodes, relabelSkuCount } from '../utils/relabelSkuDisplay' type ServiceType = 'labeling' | 'transfer' | 'disposal' | 'relabel' type PageMode = 'list' | 'create' | 'edit' | 'detail' @@ -53,7 +54,7 @@ const canConfirmRelabel = computed(() => auth.hasPermission('merchant:overseas-w const canConfirmTransfer = computed(() => auth.hasPermission('merchant:overseas-warehouse:transfer:confirm')) const canCancelDiscard = computed(() => auth.hasPermission('merchant:overseas-warehouse:discard:cancel')) const configs: Record = { - labeling: { title: '贴标申请', createTitle: '新增贴标申请', numberLabel: '贴标申请单号', emptyText: '暂无贴标申请', columns: ['操作', '贴标申请单号', '客户单号', '海外操作仓', '贴标要求', 'SKU 数', '总箱数', '状态', '审核时间', '贴标完成时间', '贴标出库时间', '创建时间'] }, + labeling: { title: '贴标申请', createTitle: '新增贴标申请', numberLabel: '贴标申请单号', emptyText: '暂无贴标申请', columns: ['操作', '贴标申请单号', '客户单号', '海外操作仓', '贴标要求', 'SKU 数(种)', '总箱数', '状态', '审核时间', '贴标完成时间', '贴标出库时间', '创建时间'] }, transfer: { title: '仓储转运单', createTitle: '新增仓储转运单', numberLabel: '转运单号', emptyText: '暂无仓储转运订单', columns: ['操作', '转运单号', '箱数', '海外仓', 'FBA 目的仓', '入仓方式', '是否换标', '换标单号', '换标状态', '状态', '审核时间', '测量时间', '出库时间', '创建时间'] }, disposal: { title: '货物废弃', createTitle: '新增货物废弃申请', numberLabel: '废弃申请单号', emptyText: '暂无货物废弃申请', columns: ['操作', '废弃申请单号', '废弃出库单号', '进仓编号', '操作仓', 'SKU 汇总', '废弃数量', '预估费用', '状态', '废弃完成时间', '创建时间'] }, relabel: { title: '退货换标', createTitle: '新建退货换标单', numberLabel: '退货换标单号', emptyText: '暂无退货换标订单', columns: ['操作', '退货换标单号', '来源 FBA 仓', '目的 FBA 仓', 'SKU 汇总', '退件总数', '是否换标', '换标状态', '尾程状态', '审核时间', '测量时间', '出库时间', '创建时间'] }, @@ -968,7 +969,7 @@ async function load() { total.value = Number.isFinite(Number(result.total)) ? Number(result.total) : result.records.length submittedRows.value = result.records.map((item) => { const destinationWarehouses = warehouseDisplay(item.overseasWarehouseId) - return { ...row([item.relabelNo, item.customerOrderNo, destinationWarehouses, '—', item.itemCount, item.totalPackageCount, statusLabel(item.status), formatDateTime(item.reviewedAt), formatDateTime(item.relabelCompletedAt), formatDateTime(item.outboundAt), formatDateTime(item.createdAt)]), __status: item.status, __confirmedAt: item.customerConfirmedAt || '' } + return { ...row([item.relabelNo, item.customerOrderNo, destinationWarehouses, '—', new Set(item.skuCodes.split(',').map(code => code.trim()).filter(Boolean)).size, item.totalPackageCount, statusLabel(item.status), formatDateTime(item.reviewedAt), formatDateTime(item.relabelCompletedAt), formatDateTime(item.outboundAt), formatDateTime(item.createdAt)]), __status: item.status, __confirmedAt: item.customerConfirmedAt || '' } }) } else if (props.service === 'disposal') { const result = await listDiscards({ page: page.value, size: pageSize.value, discardNo: filters.number || undefined, inboundCode: filters.inboundNo || undefined, overseasWarehouseId: filters.warehouse || undefined, status: filters.status || undefined, createdFrom: dateTime(filters.start), createdTo: dateTime(filters.end, true), completedFrom: dateTime(filters.completedStart), completedTo: dateTime(filters.completedEnd, true) }) @@ -1640,7 +1641,7 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) { -

订单概览

操作仓{{ warehouseDisplay(selectedRelabelDetail?.application.overseasWarehouseId) }}
客户参考号{{ selectedRelabelDetail?.application.customerOrderNo || '—' }}
SKU 数{{ selectedRelabelDetail?.application.itemCount ?? '—' }}
总箱数{{ selectedRelabelDetail?.application.totalPackageCount ?? '—' }}
贴标截止时间{{ formatDateTime(selectedRelabelDetail?.application.labelDeadline) }}
仓库联系人{{ selectedRelabelDetail?.application.contactName || '—' }}
联系电话{{ selectedRelabelDetail?.application.contactPhone || '—' }}
创建时间{{ formatDateTime(selectedRelabelDetail?.application.createdAt) }}
状态{{ statusLabel(selectedDetail?.status || '') }}
目的去向{{ destinationTypeLabel(selectedDetail?.destinationType, selectedDetail?.fbaWarehouseCode) }}
FBA 目的仓{{ selectedDetail?.destinationWarehouseName || warehouseDisplay(selectedDetail?.destinationWarehouseCode || selectedDetail?.fbaWarehouseCode) }}
FBA 货件号{{ selectedDetail?.fbaShipmentNo || '—' }}
私人仓地址{{ selectedDetail?.privateDestinationAddress || '—' }}
邮编{{ selectedDetail?.privateDestinationPostalCode || '—' }}
私人仓联系人{{ selectedDetail?.privateDestinationContactName || '—' }}
联系电话{{ selectedDetail?.privateDestinationContactPhone || '—' }}
海外仓{{ warehouseDisplay(selectedDetail?.operatingWarehouseId) }}
箱数{{ selectedDetail?.packageCount ?? '—' }}
入仓方式{{ deliveryMethodLabel(selectedDetail?.deliveryMethod || '') }}
期望发货时间{{ formatDateTime(selectedDetail?.estimatedShipAt) }}
实际发货时间{{ formatDateTime(selectedDetail?.actualShipAt) }}
是否换标{{ selectedDetail?.needRelabel ? '是' : '否' }}
换标状态{{ transferRelabelStatus(selectedDetail || {}).label }}
换标单号{{ selectedDetail?.relabelNo || '—' }}
创建时间{{ formatDateTime(selectedDetail?.createdAt) }}
转运单号{{ selectedDetail?.transferNo || '—' }}
{{ column }}{{ selectedDetail?.[String(index)] || '—' }}
+

订单概览

操作仓{{ warehouseDisplay(selectedRelabelDetail?.application.overseasWarehouseId) }}
客户参考号{{ selectedRelabelDetail?.application.customerOrderNo || '—' }}
SKU 数(种){{ selectedRelabelDetail ? relabelSkuCount(selectedRelabelDetail.items) : '—' }}
总箱数{{ selectedRelabelDetail?.application.totalPackageCount ?? '—' }}
贴标截止时间{{ formatDateTime(selectedRelabelDetail?.application.labelDeadline) }}
仓库联系人{{ selectedRelabelDetail?.application.contactName || '—' }}
联系电话{{ selectedRelabelDetail?.application.contactPhone || '—' }}
创建时间{{ formatDateTime(selectedRelabelDetail?.application.createdAt) }}
状态{{ statusLabel(selectedDetail?.status || '') }}
目的去向{{ destinationTypeLabel(selectedDetail?.destinationType, selectedDetail?.fbaWarehouseCode) }}
FBA 目的仓{{ selectedDetail?.destinationWarehouseName || warehouseDisplay(selectedDetail?.destinationWarehouseCode || selectedDetail?.fbaWarehouseCode) }}
FBA 货件号{{ selectedDetail?.fbaShipmentNo || '—' }}
私人仓地址{{ selectedDetail?.privateDestinationAddress || '—' }}
邮编{{ selectedDetail?.privateDestinationPostalCode || '—' }}
私人仓联系人{{ selectedDetail?.privateDestinationContactName || '—' }}
联系电话{{ selectedDetail?.privateDestinationContactPhone || '—' }}
海外仓{{ warehouseDisplay(selectedDetail?.operatingWarehouseId) }}
箱数{{ selectedDetail?.packageCount ?? '—' }}
入仓方式{{ deliveryMethodLabel(selectedDetail?.deliveryMethod || '') }}
期望发货时间{{ formatDateTime(selectedDetail?.estimatedShipAt) }}
实际发货时间{{ formatDateTime(selectedDetail?.actualShipAt) }}
是否换标{{ selectedDetail?.needRelabel ? '是' : '否' }}
换标状态{{ transferRelabelStatus(selectedDetail || {}).label }}
换标单号{{ selectedDetail?.relabelNo || '—' }}
创建时间{{ formatDateTime(selectedDetail?.createdAt) }}
转运单号{{ selectedDetail?.transferNo || '—' }}
{{ column }}{{ selectedDetail?.[String(index)] || '—' }}

PDA 打托实测数据

PDA 作业完成即显示入库完成,客户可确认仓库实测数据
托盘号库位箱数长 × 宽 × 高(cm)毛重(kg)体积(m³)状态完成时间
{{ pallet.palletNo || `第${pallet.sequenceNo || '—'}托` }}{{ pallet.warehouseLocationCode || '—' }}{{ pallet.cartonCount ?? '—' }}{{ [pallet.lengthCm, pallet.widthCm, pallet.heightCm].every((value) => value != null) ? `${pallet.lengthCm} × ${pallet.widthCm} × ${pallet.heightCm}` : '—' }}{{ pallet.grossWeightKg ?? '—' }}{{ pallet.volumeCbm ?? '—' }}{{ statusLabel(pallet.status || '') }}{{ formatDateTime(pallet.completedAt) }}
@@ -1669,14 +1670,14 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {

贴标明细资料

需要补充或替换资料时,可在对应明细行上传 SKU 或箱唛文件。
- +
换标模式仓库唛头SKU明细文件操作
{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}{{ item.cartonMark || '—' }}{{ item.skuCode || '—' }}{{ item.relabelFileName || '未上传' }}上传明细文件
{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}{{ item.cartonMark || '—' }}{{ relabelSkuCodes(item).join('、') || '—' }}{{ item.relabelFileName || '未上传' }}上传明细文件
暂无贴标明细

换标任务明细

- +
换标模式我方箱唛新 FBA 箱唛FBA 目的仓任务箱数商品 SKUSKU 换标明细FBA 货件编号贴标要求备注
{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}{{ item.cartonMark || '—' }}{{ item.fbaCartonMark || '—' }}{{ warehouseDisplay(item.destinationFbaWarehouseCode) }}{{ item.totalPackageCount }} 箱{{ item.skuCode || '—' }}{{ item.newSkuCode || '—' }}{{ item.shipmentNo || '—' }}{{ item.labelRequirement || '—' }}{{ item.remark || '—' }}
{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}{{ item.cartonMark || '—' }}{{ item.fbaCartonMark || '—' }}{{ warehouseDisplay(item.destinationFbaWarehouseCode) }}{{ item.totalPackageCount }} 箱{{ relabelSkuCodes(item).join('、') || '—' }}{{ item.newSkuCode || '—' }}{{ item.shipmentNo || '—' }}{{ item.labelRequirement || '—' }}{{ item.remark || '—' }}
暂无换标任务明细