Files
art-design/docs/superpowers/specs/2026-08-06-stock-item-attachment-upload-design.md
T
2026-08-06 14:34:28 +08:00

6.8 KiB
Raw Blame History

备货单车辆明细附件上传 设计

  • 日期: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 增加:
    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「附件」:

<ElCol :sm="12" :md="12" :lg="6" :xl="4">
  <ElFormItem label="附件" label-width="85px">
    <el-upload
      :action="`${VITE_API_URL}/ticket/upload?scene=stock_orders`"
      :headers="uploadHeaders"
      :show-file-list="false"
      :before-upload="(file) => beforeItemAttachmentUpload(file)"
      :on-success="(res) => handleItemAttachmentUpload(res, idx)"
      multiple
      :accept="itemAttachmentAccept"
    >
      <el-button size="small" type="primary" plain>上传附件</el-button>
    </el-upload>
    <div class="item-attachment-tags" v-if="item.attachment_files?.length">
      <el-tag
        v-for="(f, fIdx) in item.attachment_files"
        :key="fIdx"
        closable
        @close="removeItemAttachment(idx, fIdx)"
        style="margin: 2px 4px 2px 0"
      >
        {{ f.name }}
      </el-tag>
    </div>
  </ElFormItem>
</ElCol>
  • 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)是否需要同等能力,待业务确认。