From b5d414d9af026e2768601f4dc5fac384791242a5 Mon Sep 17 00:00:00 2001 From: mzl Date: Thu, 6 Aug 2026 14:34:28 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=A4=87=E8=B4=A7=E5=8D=95=E8=BD=A6?= =?UTF-8?q?=E8=BE=86=E6=98=8E=E7=BB=86=E9=99=84=E4=BB=B6=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude --- ...-06-stock-item-attachment-upload-design.md | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-06-stock-item-attachment-upload-design.md diff --git a/docs/superpowers/specs/2026-08-06-stock-item-attachment-upload-design.md b/docs/superpowers/specs/2026-08-06-stock-item-attachment-upload-design.md new file mode 100644 index 0000000..aaee8cd --- /dev/null +++ b/docs/superpowers/specs/2026-08-06-stock-item-attachment-upload-design.md @@ -0,0 +1,120 @@ +# 备货单车辆明细附件上传 设计 + +- 日期:2026-08-06 +- 分支:feature/crm_pc +- 涉及前端:`src/views/crmpc/stocking/Add.vue`、`src/composables/useStockingForm.ts` +- 涉及后端:`stock_order_items.attachment`(已加字段)、备货单 store/update/show 接口 + +## 1. 背景 + +添加备货单(`Add.vue`)时,车辆明细(`items`,每行一辆车)目前只能录入车型 / 颜色 / 价格等字段,**没有附件**。业务需要每辆车能上传若干附件(如该车相关文件),随车辆一起保存。 + +后端 `stock_order_items` 表已新增 `attachment` 字段(本次由后端同事完成)。 + +## 2. 需求 + +- 添加备货单时,车辆明细**每辆车**可上传**多个**附件。 +- UI 为**行内紧凑**形态:每行一个「上传附件」入口,已传文件以文件名标签列出、可删除,不撑高行高。 +- 附件随车辆数据一起提交,存入 `stock_order_items.attachment`。 +- 字段名统一用 `attachment`,值为 `file_name` 字符串数组(与备货单级 `contract`/`pi_doc`/`transaction_slip` 的存储模式一致)。 + +## 3. 现状(复用基础) + +- 车辆明细 `items` 由 `useStockingForm(false)` 提供,每行 `item` 是 `ItemRow`。 +- 备货单级文件已有成熟模式:前端维护 `FileItem[]`(`{name, url, file_name}`,带 url 供预览/下载),提交时映射成 `file_name[]` 存入 `baseForm.contract` 等。 +- 上传走通用接口 `${VITE_API_URL}/ticket/upload?scene=stock_orders`,header 带 token(`useUploadHeaders`),成功返回 `{ data: { original_name, file_url, file_name } }`。**此接口无需改动。** +- 现成组件 `MultiFileUpload`(120px 大拖拽区)适合整页文件区,不适合塞进行内——故行内用 `el-upload` 直接内联。 + +## 4. 设计 + +### 4.1 数据层 `useStockingForm.ts` + +- `ItemRow` 类型增加 `attachment_files: { name: string; url: string; file_name: string }[]`。 +- `newItem()` 初始化 `attachment_files: []`。 +- 提交映射 `mappedItems` 增加: + ```ts + attachment: (it.attachment_files || []).map((f) => f.file_name) + ``` +- 详情回填 `populateFromDetail`:从后端返回的 `it.attachment` 反解为 `attachment_files`(格式见 4.4,Add 为新建不走回填,但 composable 与 edit 共享,一并支持)。 +- `copyRow` 已是 `JSON.parse(JSON.stringify(...))`,自动带上附件,无需改。 +- 草稿 `pickDraftPayload` 已含 `items: toRaw(items.value)`,附件自然入草稿,无需改。 +- 新增车辆附件上传/删除方法(仿现有 `handleContractUpload` 等): + - `handleItemAttachmentUpload(response: any, idx: number)`:校验 `response.code===200`,把 `{ name: data.original_name, url: data.file_url, file_name: data.file_name }` push 进 `items.value[idx].attachment_files`。 + - `removeItemAttachment(idx: number, fileIdx: number)`:从 `items.value[idx].attachment_files` 删除指定项。 + +### 4.2 UI 层 `Add.vue` + +在车辆明细 `v-for="(item, idx) in items"` 的行内末尾增加一个 `ElCol`「附件」: + +```html + + + + 上传附件 + +
+ + {{ f.name }} + +
+
+
+``` + +- `VITE_API_URL`、`uploadHeaders`(`useUploadHeaders`)、`beforeItemAttachmentUpload`(类型/大小校验,复用 `MultiFileUpload` 的 accept 与 10MB 限制)、`handleItemAttachmentUpload`、`removeItemAttachment` 均由 `useStockingForm` return,模板解构使用,与现有 `contractFiles` 等用法一致。 + +### 4.3 后端配合 + +- `stock_order_items.attachment` 字段已加(DB 就绪)。 +- 接口层需对接: + - **store / update**:接收 `items[].attachment`(`file_name` 数组),写入 `stock_order_items.attachment`(按 json/序列化存储)。 + - **show / detail**:返回 `items[].attachment`(`file_name` 数组,或含 `original_name`/`file_url` 的对象数组——见 4.4 约定)。 + +### 4.4 回填格式约定(需与后端对齐) + +详情接口返回的 `items[].attachment` 有两种可能,择一与后端确认: +- **A**:`file_name` 字符串数组(如 `["xxx.pdf"]`)——前端回填时 `url` 需另行拼接,预览受限。 +- **B(推荐)**:对象数组(如 `[{ original_name, file_url, file_name }]`,与 `/ticket/upload` 返回一致)——前端直接还原成 `attachment_files`,预览/下载可用。 + +实现(plan)阶段以前端实际请求详情接口的返回为准;若为 A,前端按现有 `populateFromDetail` 中文件字段的拼 url 方式处理。 + +## 5. 安全 / 限制 + +- 复用 `beforeUpload`:类型限制 `.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt`,单文件 ≤ 10MB。 +- 上传 header 带 token(`useUploadHeaders`),鉴权由后端 `/ticket/upload` 既有机制处理。 +- `attachment` 只存 `file_name`,不含敏感信息。 + +## 6. 改动清单 + +| 端 | 文件 | 改动 | +|---|---|---| +| 前端 | `src/composables/useStockingForm.ts` | `ItemRow` 加 `attachment_files`;`newItem` 初始化;`mappedItems` 映射 `attachment`;`populateFromDetail` 回填;新增 `handleItemAttachmentUpload`/`removeItemAttachment`/`beforeItemAttachmentUpload`/暴露 `uploadHeaders` | +| 前端 | `src/views/crmpc/stocking/Add.vue` | 车辆明细行末尾加「附件」`ElCol`(`el-upload` + 标签列表);解构新方法 | +| 后端 | store/update/show 接口 | 对接 `items[].attachment`(DB 字段已就绪) | + +## 7. 验收标准 + +1. 添加备货单:每辆车行有「上传附件」按钮,点选多文件逐个上传成功后,文件名以标签列出。 +2. 标签可点 × 删除;删除后提交不包含该文件。 +3. 提交备货单,Network 里 `items[].attachment` 为对应 `file_name` 数组;后端 `stock_order_items.attachment` 落库正确。 +4. (后端 show 返回后)进入编辑/详情,已存附件能回显为标签列表。 +5. 超格式 / 超 10MB 文件被拦截并提示。 + +## 8. 未做项 / 后续 + +- 本次只改 `Add.vue` 模板;`stocking_edit.vue` 共用 `useStockingForm`,数据层已支持,如需在编辑页也展示附件上传,后续加同款 `ElCol` 即可。 +- 终版(final_add/final_edit)是否需要同等能力,待业务确认。