From 6ec41b2dbe04f2454954403ce4a17f819811c2e4 Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Thu, 22 Oct 2026 19:05:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=A5=E5=BA=93=E9=A2=84=E6=8A=A5?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E7=BC=96=E8=BE=91=E5=90=88=E4=B8=80=E3=80=81?= =?UTF-8?q?=E7=AE=B1=E5=94=9B/SKU=E6=89=93=E5=8D=B0=E4=B8=8E=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E6=94=B9=E9=94=80=E5=94=AE=E4=BA=A7=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- src/api/order/index.ts | 13 + src/api/warehouse/index.ts | 33 ++ src/constants/pageButtonCatalog.ts | 3 + src/locale/en-US.ts | 15 +- src/locale/zh-CN.ts | 15 +- .../labelDesign/LabelDesignerPanel.vue | 60 ++- src/views/channel/labelDesign/index.vue | 1 + .../myOrders/components/OrderDetailDrawer.vue | 77 +++- .../components/OrderDetailDrawer.vue | 75 +++- src/views/warehouse/inboundNotice/index.vue | 353 +++++++++++++++--- src/views/warehouse/inventory/index.vue | 2 +- src/views/warehouse/sku/index.vue | 70 +++- 12 files changed, 652 insertions(+), 65 deletions(-) diff --git a/src/api/order/index.ts b/src/api/order/index.ts index e9dce91..9938966 100644 --- a/src/api/order/index.ts +++ b/src/api/order/index.ts @@ -2222,6 +2222,19 @@ export async function postOrderUpdate(body: Record): Promise { return res.data?.data ?? res.data?.Data ?? res.data } +/** POST /order/change-product — 改销售产品并自动重排货/重算费 */ +export async function postOrderChangeProduct(body: { + id: number | string + productCode: string +}): Promise { + const res = await axiosInstance.post(orderUrl('/order/change-product'), { + id: Number(body.id), + productCode: String(body.productCode ?? '').trim(), + }) + assertBusinessOk(res.data) + return res.data?.data ?? res.data?.Data ?? res.data +} + /** POST /order/weight/update */ export async function postOrderWeightUpdate(body: { id: number | string diff --git a/src/api/warehouse/index.ts b/src/api/warehouse/index.ts index b62d64a..b4723df 100644 --- a/src/api/warehouse/index.ts +++ b/src/api/warehouse/index.ts @@ -26,6 +26,22 @@ export const deleteWarehouseSku = (id: number) => postOk('/warehouse/sku/delete' export const bindWarehouseSkuMapping = (body: Record) => postOk('/warehouse/sku/bind-mapping', body) +/** POST /warehouse/sku/print-label → TemplateType=sku 单页 PDF */ +export async function postWarehouseSkuPrintLabel(body: { + id: number + customerId?: number +}): Promise<{ printUrl: string; skuCode: string }> { + const data = await postOk('/warehouse/sku/print-label', { + id: body.id, + customerId: body.customerId, + }) + const d = (data ?? {}) as Record + return { + printUrl: String(d.printUrl ?? d.PrintUrl ?? '').trim(), + skuCode: String(d.skuCode ?? d.SkuCode ?? '').trim(), + } +} + /** 上传 SKU 图片:优先 COS 直传,落库存 key;返回 key + 预览 URL */ export async function uploadWarehouseSkuImage( file: File, @@ -119,6 +135,23 @@ export const confirmWarehouseInboundReceive = (body: Record) => export const getWarehouseInboundSummary = (params?: Record) => getData('/warehouse/inbound/summary', params) +/** POST /warehouse/inbound/print-labels → 多箱合并为一个 PDF */ +export async function postWarehouseInboundPrintLabels(body: { + id: number + customerId?: number +}): Promise<{ printUrl: string; noticeNo: string; pageCount: number }> { + const data = await postOk('/warehouse/inbound/print-labels', { + id: body.id, + customerId: body.customerId, + }) + const d = (data ?? {}) as Record + return { + printUrl: String(d.printUrl ?? d.PrintUrl ?? '').trim(), + noticeNo: String(d.noticeNo ?? d.NoticeNo ?? '').trim(), + pageCount: Number(d.pageCount ?? d.PageCount ?? 0) || 0, + } +} + // Parcel export const getWarehouseParcelList = (body: Record) => postList('/warehouse/parcel/list', body) export const getWarehouseParcelSummary = (params?: Record) => diff --git a/src/constants/pageButtonCatalog.ts b/src/constants/pageButtonCatalog.ts index b053b94..02fadf7 100644 --- a/src/constants/pageButtonCatalog.ts +++ b/src/constants/pageButtonCatalog.ts @@ -96,6 +96,7 @@ export const PERMISSION_ACTION_LABELS: Record = { PackVersions: '打包版本', BinDetail: '库位明细', History: '出入库记录', + PrintLabel: '打印箱唛', BatchPay: '批量支付', CreatePickup: '创建揽收', AddMapping: '添加映射', @@ -644,6 +645,7 @@ const CORE_GROUPS: PageButtonGroup[] = [ { code: 'Query', name: '查询' }, { code: 'Save', name: '新增' }, { code: 'Update', name: '编辑' }, + { code: 'PrintLabel', name: '打印标签' }, { code: 'Delete', name: '删除' }, ]), B('Warehouse.Inventory', [ @@ -663,6 +665,7 @@ const CORE_GROUPS: PageButtonGroup[] = [ { code: 'Save', name: '新增' }, { code: 'View', name: '详情' }, { code: 'ConfirmReceive', name: '确认收货' }, + { code: 'PrintLabel', name: '打印箱唛' }, { code: 'Delete', name: '删除' }, ]), B('Warehouse.BinLocation', [ diff --git a/src/locale/en-US.ts b/src/locale/en-US.ts index eba0bc2..4cb84b6 100644 --- a/src/locale/en-US.ts +++ b/src/locale/en-US.ts @@ -213,6 +213,7 @@ export default { 'warehouse.sku.modal.add': 'Add SKU', 'warehouse.sku.modal.edit': 'Edit SKU', 'warehouse.sku.actions.delete': 'Delete SKU', + 'warehouse.sku.actions.printLabel': 'Print Label', 'warehouse.sku.message.loadFailed': 'Failed to load SKU list', 'warehouse.sku.message.saveSuccess': 'Saved', 'warehouse.sku.message.saveFailed': 'Save failed', @@ -220,6 +221,8 @@ export default { 'warehouse.sku.message.deleteFailed': 'Delete failed', 'warehouse.sku.message.deleteConfirm': 'Delete {code}?', 'warehouse.sku.message.required': 'SKU code and name are required', + 'warehouse.sku.message.printFailed': 'Failed to print SKU label', + 'warehouse.sku.message.printEmpty': 'No SKU label file available', 'warehouse.inventory.table.warehouse': 'Warehouse', 'warehouse.inventory.table.binName': 'Bin Name', 'warehouse.inventory.table.skuCode': 'SKU Code', @@ -409,7 +412,7 @@ export default { 'warehouse.inbound.search.keyword': 'Notice / Mark', 'warehouse.inbound.tip': 'Forecast inbound goods. Stock increases after receive & putaway. Status: Forecasted → Received → Completed.', 'warehouse.inbound.tip.currentWarehouse': 'Notice belongs to the current warehouse; switch it from the top bar', - 'warehouse.inbound.tip.markReference': 'Usually the tracking number or master mark for receiving checks', + 'warehouse.inbound.tip.markReference': 'Optional; usually the tracking number or master mark for receiving checks', 'warehouse.inbound.tip.inboundType': 'Normal or return inbound; used for later reporting', 'warehouse.inbound.tip.boxSkuDetail': 'Maintain SKUs and planned qty per box; add one box or five at once', 'warehouse.inbound.tip.markBoxNo': 'Per-box mark / box number (optional)', @@ -419,7 +422,7 @@ export default { 'warehouse.inbound.form.markBoxNoPlaceholder': 'Box mark (optional)', 'warehouse.inbound.form.sku': 'SKU', 'warehouse.inbound.form.plannedQty': 'Planned Qty', - 'warehouse.inbound.form.markPlaceholder': 'Usually the tracking number', + 'warehouse.inbound.form.markPlaceholder': 'Usually the tracking number (optional)', 'warehouse.inbound.form.remarkPlaceholder': 'Optional', 'warehouse.inbound.form.optional': 'Optional', 'warehouse.inbound.form.boxSkuDetail': 'Boxes & SKU lines', @@ -441,6 +444,8 @@ export default { 'warehouse.inbound.actions.removeCurrentBox': 'Remove current box', 'warehouse.inbound.actions.addSku': 'Add SKU line', 'warehouse.inbound.modal.add': 'Add Inbound', + 'warehouse.inbound.modal.edit': 'Edit Inbound', + 'warehouse.inbound.modal.view': 'View Inbound', 'warehouse.inbound.drawer.detail': 'Inbound Detail', 'warehouse.inbound.box': 'Box', 'warehouse.inbound.line.skuCode': 'SKU', @@ -450,6 +455,9 @@ export default { 'warehouse.inbound.form.selectBin': 'Select bin', 'warehouse.inbound.actions.delete': 'Delete', 'warehouse.inbound.actions.confirmReceive': 'Confirm Receive', + 'warehouse.inbound.actions.printLabel': 'Print Box Label', + 'warehouse.inbound.message.printFailed': 'Failed to print box label', + 'warehouse.inbound.message.printEmpty': 'No box label file available', 'warehouse.inbound.modal.confirmReceive': 'Confirm Receive & Putaway', 'warehouse.inbound.message.loadFailed': 'Failed to load inbound list', 'warehouse.inbound.message.saveSuccess': 'Saved', @@ -2533,6 +2541,8 @@ export default { 'order.myOrders.drawer.editBasicTitle': 'Edit Order Details', 'order.myOrders.drawer.editWeightTitle': 'Edit Weight & Dimensions', 'order.myOrders.drawer.message.saveSuccess': 'Saved successfully', + 'order.myOrders.drawer.message.changeProductSuccess': 'Sales product updated', + 'order.myOrders.drawer.placeholder.productName': 'Select sales product', 'order.myOrders.drawer.message.recalculateSuccess': 'Recalculated successfully', 'order.myOrders.drawer.costItem': 'Cost Item', 'order.myOrders.drawer.amount': 'Amount', @@ -4248,6 +4258,7 @@ export default { 'operation.printLabel.labelTemplate.inbound': 'Inbound Label', 'operation.printLabel.labelTemplate.outbound': 'Outbound Label', 'operation.printLabel.labelTemplate.sku': 'SKU Label', + 'operation.printLabel.labelTemplate.box': 'Box Mark Label', 'operation.printLabel.preview.title': 'Label preview', 'operation.printLabel.preview.empty': 'Scan a number to show order info; open Preview when needed', 'operation.printLabel.preview.product': 'Product', diff --git a/src/locale/zh-CN.ts b/src/locale/zh-CN.ts index c403cf9..e80d0ab 100644 --- a/src/locale/zh-CN.ts +++ b/src/locale/zh-CN.ts @@ -214,6 +214,7 @@ export default { 'warehouse.sku.modal.add': '新增 SKU', 'warehouse.sku.modal.edit': '编辑 SKU', 'warehouse.sku.actions.delete': '删除 SKU', + 'warehouse.sku.actions.printLabel': '打印标签', 'warehouse.sku.message.loadFailed': '加载 SKU 列表失败', 'warehouse.sku.message.saveSuccess': '保存成功', 'warehouse.sku.message.saveFailed': '保存失败', @@ -221,6 +222,8 @@ export default { 'warehouse.sku.message.deleteFailed': '删除失败', 'warehouse.sku.message.deleteConfirm': '确定删除 {code}?', 'warehouse.sku.message.required': '请填写 SKU 编码和名称', + 'warehouse.sku.message.printFailed': '打印 SKU 标签失败', + 'warehouse.sku.message.printEmpty': '未获取到 SKU 标签文件', 'warehouse.inventory.table.warehouse': '仓库', 'warehouse.inventory.table.binName': '库位名称', 'warehouse.inventory.table.skuCode': 'SKU 编码', @@ -410,7 +413,7 @@ export default { 'warehouse.inbound.search.keyword': '单号/唛头', 'warehouse.inbound.tip': '预报到仓货物;收货上架后库存会增加。关注状态:预报 → 待入库 → 已完成。', 'warehouse.inbound.tip.currentWarehouse': '预报归属当前仓库;可在顶部切换仓库', - 'warehouse.inbound.tip.markReference': '一般填物流快递单号或主唛头,便于到仓核对', + 'warehouse.inbound.tip.markReference': '选填;一般填物流快递单号或主唛头,便于到仓核对', 'warehouse.inbound.tip.inboundType': '普通入库或退货入库,影响后续统计分类', 'warehouse.inbound.tip.boxSkuDetail': '按箱维护 SKU 与计划数量;可加箱或一次加 5 箱', 'warehouse.inbound.tip.markBoxNo': '单箱唛头/箱号,选填', @@ -420,7 +423,7 @@ export default { 'warehouse.inbound.form.markBoxNoPlaceholder': '箱唛/箱号(选填)', 'warehouse.inbound.form.sku': 'SKU', 'warehouse.inbound.form.plannedQty': '计划数量', - 'warehouse.inbound.form.markPlaceholder': '一般填写物流快递单号', + 'warehouse.inbound.form.markPlaceholder': '一般填写物流快递单号(选填)', 'warehouse.inbound.form.remarkPlaceholder': '选填', 'warehouse.inbound.form.optional': '选填', 'warehouse.inbound.form.boxSkuDetail': '箱子与 SKU 明细', @@ -442,6 +445,8 @@ export default { 'warehouse.inbound.actions.removeCurrentBox': '删除当前箱', 'warehouse.inbound.actions.addSku': '选择库内 SKU', 'warehouse.inbound.modal.add': '新增入库预报', + 'warehouse.inbound.modal.edit': '编辑入库预报', + 'warehouse.inbound.modal.view': '查看入库预报', 'warehouse.inbound.drawer.detail': '入库详情', 'warehouse.inbound.box': '箱', 'warehouse.inbound.line.skuCode': 'SKU', @@ -451,6 +456,9 @@ export default { 'warehouse.inbound.form.selectBin': '请选择库位', 'warehouse.inbound.actions.delete': '删除预报', 'warehouse.inbound.actions.confirmReceive': '确认收货', + 'warehouse.inbound.actions.printLabel': '打印箱唛', + 'warehouse.inbound.message.printFailed': '打印箱唛失败', + 'warehouse.inbound.message.printEmpty': '未获取到箱唛文件', 'warehouse.inbound.modal.confirmReceive': '确认收货上架', 'warehouse.inbound.message.loadFailed': '加载入库预报失败', 'warehouse.inbound.message.saveSuccess': '保存成功', @@ -2392,6 +2400,8 @@ export default { 'order.myOrders.drawer.editBasicTitle': '编辑订单详情', 'order.myOrders.drawer.editWeightTitle': '编辑件重尺', 'order.myOrders.drawer.message.saveSuccess': '保存成功', + 'order.myOrders.drawer.message.changeProductSuccess': '销售产品已更新', + 'order.myOrders.drawer.placeholder.productName': '请选择销售产品', 'order.myOrders.drawer.message.recalculateSuccess': '重算成功', 'order.myOrders.drawer.costItem': '费用项', 'order.myOrders.drawer.amount': '金额', @@ -4273,6 +4283,7 @@ export default { 'operation.printLabel.labelTemplate.inbound': '入库标签', 'operation.printLabel.labelTemplate.outbound': '出库标签', 'operation.printLabel.labelTemplate.sku': 'sku标签', + 'operation.printLabel.labelTemplate.box': '箱唛标签', 'operation.printLabel.preview.title': '面单预览', 'operation.printLabel.preview.empty': '扫描单号后显示订单信息,需要时可点预览查看面单', 'operation.printLabel.preview.product': '销售产品', diff --git a/src/views/channel/labelDesign/LabelDesignerPanel.vue b/src/views/channel/labelDesign/LabelDesignerPanel.vue index bb5194d..8321764 100644 --- a/src/views/channel/labelDesign/LabelDesignerPanel.vue +++ b/src/views/channel/labelDesign/LabelDesignerPanel.vue @@ -73,13 +73,27 @@ const EMPTY_LABEL_TEMPLATE = { const initialTemplate = ref(EMPTY_LABEL_TEMPLATE) -const BARCODE_FIELDS = new Set(['serviceNo', 'trackNo', 'clientNo', 'requestId']) +const BARCODE_FIELDS = new Set([ + 'serviceNo', + 'trackNo', + 'clientNo', + 'requestId', + 'noticeNo', + 'markReference', + 'markBoxNo', + 'boxSeqNo', + 'barcode', + 'skuCode', +]) const LONGTEXT_FIELDS = new Set([ 'recipientAddressFull', 'senderAddressFull', 'recipientStreet1', 'recipientStreet2', 'recipientStreet3', + 'skuSummary', + 'declareElement', + 'remark', ]) const MOCK_BY_FIELD: Record = { @@ -93,6 +107,40 @@ const MOCK_BY_FIELD: Record = { actualWeight: '1.25', salesProductName: '专线-普货', warehouseName: 'SZ-01', + noticeNo: 'IN202610220001', + markReference: 'SF1234567890', + markBoxNo: 'BOX-001', + boxSeqNo: '1', + barcode: 'BOX-001', + boxIndexText: '1/2', + skuSummary: 'SKU001 T-Shirt×2\nSKU002 Pants×1', + skuCode: 'SKU001', + skuName: 'T-Shirt', + skuNameEn: 'T-Shirt', + skuQty: '2', + unitPrice: '9.90', + exHsCode: '610910', + imHsCode: '610910', + declareElement: '棉质 T 恤', + weightG: '200', + lengthCm: '30', + widthCm: '20', + heightCm: '15', + dimensions: '30×20×15', + remark: 'fragile', + printTime: '2026-10-22 18:00:00', + operatorName: 'preview', + pageIndex: '1', + pageCount: '2', + customerCode: 'AF0A1', + customerName: 'Demo Customer', +} + +function groupPanelTitle(g: LabelFieldGroup): string { + if (g.code === 'inboundBox') return '入库预报' + if (g.code === 'warehouseSku') return '库内SKU' + if (g.code === 'system') return '系统' + return `订单·${g.title}` } let hiprintRegistered = false @@ -183,12 +231,14 @@ function buildFieldElements(groups: LabelFieldGroup[]) { for (const g of normalizeFieldGroups(groups)) { const items: any[] = [] + const groupKey = g.code || 'default' for (const f of g.fields) { const testData = MOCK_BY_FIELD[f.field] || f.title const isLong = LONGTEXT_FIELDS.has(f.field) + const tidBase = `omsLabelFields.${groupKey}.${f.field}` items.push({ - tid: `omsLabelFields.${f.field}`, + tid: tidBase, title: f.title, type: isLong ? 'longText' : 'text', options: { @@ -204,7 +254,7 @@ function buildFieldElements(groups: LabelFieldGroup[]) { if (BARCODE_FIELDS.has(f.field)) { items.push({ - tid: `omsLabelFields.${f.field}.barcode`, + tid: `${tidBase}.barcode`, title: `${f.title}·条码`, type: 'text', options: { @@ -218,7 +268,7 @@ function buildFieldElements(groups: LabelFieldGroup[]) { }, }) items.push({ - tid: `omsLabelFields.${f.field}.qrcode`, + tid: `${tidBase}.qrcode`, title: `${f.title}·二维码`, type: 'text', options: { @@ -236,7 +286,7 @@ function buildFieldElements(groups: LabelFieldGroup[]) { if (items.length) { if (!hiprint?.PrintElementTypeGroup) continue - typeGroups.push(new hiprint.PrintElementTypeGroup(`订单·${g.title}`, items)) + typeGroups.push(new hiprint.PrintElementTypeGroup(groupPanelTitle(g), items)) } } diff --git a/src/views/channel/labelDesign/index.vue b/src/views/channel/labelDesign/index.vue index 75cc9b6..16c236f 100644 --- a/src/views/channel/labelDesign/index.vue +++ b/src/views/channel/labelDesign/index.vue @@ -200,6 +200,7 @@ const typeOptions = computed(() => [ { value: 'inbound', label: t('operation.printLabel.labelTemplate.inbound') }, { value: 'outbound', label: t('operation.printLabel.labelTemplate.outbound') }, { value: 'sku', label: t('operation.printLabel.labelTemplate.sku') }, + { value: 'box', label: t('operation.printLabel.labelTemplate.box') }, ]) function typeLabel(type?: string) { diff --git a/src/views/order/myOrders/components/OrderDetailDrawer.vue b/src/views/order/myOrders/components/OrderDetailDrawer.vue index 13eb790..696212a 100644 --- a/src/views/order/myOrders/components/OrderDetailDrawer.vue +++ b/src/views/order/myOrders/components/OrderDetailDrawer.vue @@ -143,7 +143,23 @@