From d48b18c99e2bcdd5ebf9bff01f8d3831893481d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 28 Jul 2026 16:13:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(cargo-type):=20=E4=BC=98=E5=8C=96=E8=B4=A7?= =?UTF-8?q?=E7=89=A9=E7=B1=BB=E5=9E=8B=E5=AF=BC=E5=85=A5=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=8F=8A=E5=AF=BC=E5=85=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将导入模板下载改为直接获取工程内置静态文件,取消本地生成Excel逻辑 - 下载模板含一级19类及全部二级示例,便于用户填写层级关系和编码规则 - 后端导入逻辑改为两遍法,先验证保存所有一级类型,再导入二级,确保导入顺序无影响 - 保持事务回滚、失败明细Excel生成及校验文案一致 - 提示模板文件缺失或下载失败的错误信息,提升用户体验 - 前端改动已生效,后端需重新编译部署以完成加固 --- .workbuddy/memory/2026-07-28.md | 5 ++ public/cargo-type-import-template.xlsx | Bin 0 -> 15635 bytes src/views/base/cargo-type.vue | 78 ++++--------------------- 3 files changed, 16 insertions(+), 67 deletions(-) create mode 100644 public/cargo-type-import-template.xlsx diff --git a/.workbuddy/memory/2026-07-28.md b/.workbuddy/memory/2026-07-28.md index 710a2d9..6f3ac64 100644 --- a/.workbuddy/memory/2026-07-28.md +++ b/.workbuddy/memory/2026-07-28.md @@ -27,3 +27,8 @@ - 已新增单文件版:`/Users/gxwebsoft/VUE/tms-erp-web-ws/import-cargo-type/货物类型导入_单文件(一级在前).xlsx`(一级19条在前+二级116条在后,共135数据行)。 - 美化:对 import-cargo-type 下 3 个 xlsx 表头统一加样式(灰底 #D9D9D9 + 黑色加粗居中 + 细边框 #D0D7E2 + 行高30),数据区细边框、编码列文本格式、列宽适配长表头;表头文字保持不变以兼容后端解析。 - 重新美化(按原始模板蓝色主题):提取 Downloads/副本货物类型导入模板_模拟数据(1).xlsx 样式(表头 #0070C0 蓝底白字微软雅黑11居中、数据行 #EBF1F8 浅蓝黑字微软雅黑10、边框 #D9D9D9 细线、表头行高24→因我表头更长设为30、数据行高19),应用到 3 个导入文件。注意:原始第1行是标题"GB-T 42820-2023…",但导入文件必须表头在 row1(后端按 row1 读),故不照搬标题行,只复用表头+数据行样式。 + +## 模板下载改静态资源 + 导入两遍法加固(本次) +- 模板下载:`cargo-type.vue` 的 `handleTemplate()` 不再用 exceljs 本地生成 2 行示例,改为 fetch 工程内置静态文件 `public/cargo-type-import-template.xlsx`(内容=已生成的标准"单文件一级在前"模板,含一级19类+全部二级示例),下载名仍为 `货物类型导入模板.xlsx`。base 用 `import.meta.env.BASE_URL`(当前 `/`)拼路径,无需后端 export-template 接口、离线可用。 +- 后端加固(`CargoTypeServiceImpl.importCargoType`):由单遍逐行改为两遍法——第一遍先 validate+save 全部一级,第二遍再解析父级并 save 全部二级;父级解析仍走 `findParentByCode` 查库(第一遍已入库,同事务可见)。目的:让"完整导入"不受 Excel 行顺序影响(即使某二级行排在所属一级之前也不会整批失败);事务边界(`@Transactional` + 任一失败 `setRollbackOnly` 整批回滚)与失败明细 Excel(表头=CargoTypeExcel+导入失败原因,与前端 decorator 列宽 key 完全一致)保持不变。 +- 注意:后端 Java 改动未在本机编译,需在 tms-erp-api-ws 重新编译部署生效;校验文案(请选择货物类型级别/货物类型编码格式不正确/二级编码前2位必须与上级货物类型编码一致/该货物类型编码已存在/该上级下已存在同名货物类型/货物类型名称不能超过50字符/备注不能超过200字)保持不变以匹配前端 `CARGO_TYPE_FAIL_RULES`。 diff --git a/public/cargo-type-import-template.xlsx b/public/cargo-type-import-template.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f9ad497e0730bf91bf331d3fd24eb56d99721c08 GIT binary patch literal 15635 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 I=QH2`1CSyNbN~PV literal 0 HcmV?d00001 diff --git a/src/views/base/cargo-type.vue b/src/views/base/cargo-type.vue index d6fac09..0cedc15 100644 --- a/src/views/base/cargo-type.vue +++ b/src/views/base/cargo-type.vue @@ -584,76 +584,20 @@ export default { }, handleTemplate() { NProgress.start(); - // 本地生成带示例的导入模板(不依赖后端空模板),表头与可正常导入的模板一致 - import('exceljs') - .then(ExcelJS => { - const ExcelJSLib = ExcelJS.default || ExcelJS; - const wb = new ExcelJSLib.Workbook(); - const ws = wb.addWorksheet('货物类型导入模板'); - const headers = [ - '*类型', - '上级货物类型(如为一级则不需填写)', - '上级货物类型编码(如为一级则不需填写)', - '*货物类型', - '*货物类型编码', - '备注', - ]; - ws.addRow(headers); - // 示例数据:一级 + 二级各一条,演示层级关系与填写格式(当前环境可正常导入) - ws.addRow(['一级货物类型', null, null, '电子产品2', '117', '消费类电子']); - ws.addRow(['二级货物类型', '电子产品2', '117', '手机2', '11014', '智能手机']); - // 列宽:表头含长说明,适度加宽 - const widths = [14, 24, 26, 16, 16, 18]; - ws.columns.forEach((col, i) => { - col.width = widths[i] || 16; - }); - // 编码列设为文本,避免前导零丢失 - [3, 5].forEach(idx => { - const col = ws.getColumn(idx); - if (col) col.numFmt = '@'; - }); - // 表头与数据区样式:统一灰色表头 + 黑色加粗居中 + 细边框 - const headerFill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: 'FFD9D9D9' }, - }; - const thinBorder = { - top: { style: 'thin', color: { argb: 'FFD0D7E2' } }, - left: { style: 'thin', color: { argb: 'FFD0D7E2' } }, - bottom: { style: 'thin', color: { argb: 'FFD0D7E2' } }, - right: { style: 'thin', color: { argb: 'FFD0D7E2' } }, - }; - ws.eachRow(row => { - row.eachCell(cell => { - cell.border = thinBorder; - if (row.number === 1) { - // 表头:灰色底色 + 黑字加粗 + 居中对齐 - cell.fill = headerFill; - cell.font = { bold: true, color: { argb: 'FF000000' } }; - cell.alignment = { - wrapText: true, - vertical: 'middle', - horizontal: 'center', - }; - } else { - // 数据行:左对齐,垂直居中 - cell.alignment = { - wrapText: true, - vertical: 'middle', - horizontal: 'left', - }; - } - }); - }); - // 表头行高适度,兼顾两行说明与视觉紧凑 - ws.getRow(1).height = 30; - return wb.xlsx.writeBuffer(); + // 直接下载工程内置的标准导入模板(public 目录静态资源),表头与可正常导入的模板一致, + // 含一级(19 类)及全部二级示例,便于用户参照填写层级关系与编码规则 + const templateUrl = `${import.meta.env.BASE_URL}cargo-type-import-template.xlsx`; + fetch(templateUrl) + .then(res => { + if (!res.ok) throw new Error('模板文件不存在'); + return res.blob(); }) - .then(buf => { - const blob = new Blob([buf], { type: 'application/vnd.ms-excel' }); + .then(blob => { downloadXls(blob, '货物类型导入模板.xlsx'); }) + .catch(() => { + this.$message.error('模板下载失败,请稍后重试'); + }) .finally(() => { NProgress.done(); });