diff --git a/docs/superpowers/specs/2026-09-14-reimburse-apply-attachment-display-name-design.md b/docs/superpowers/specs/2026-09-14-reimburse-apply-attachment-display-name-design.md new file mode 100644 index 000000000..c14d9a4b7 --- /dev/null +++ b/docs/superpowers/specs/2026-09-14-reimburse-apply-attachment-display-name-design.md @@ -0,0 +1,85 @@ +# 报销申请附件展示名使用整单备注 — 设计 + +**日期**:2026-09-14 +**状态**:已确认待实现 +**范围**:Web 管理端 + 小程序;仅报销「申请附件」展示层 + +## 背景 + +报销申请附件区域当前展示库表/上传时的原始 `fileName`(Web 为用户选中文件名,小程序多为临时名)。用户希望在有整单「备注说明」时,附件区用备注作为更易读的展示名。 + +## 决策摘要 + +| 项 | 决策 | +|----|------| +| 文案来源 | 整单「备注说明」`remark`(非明细报销事由) | +| 备注为空 | 回退为文件原始名称 | +| 多附件 | `{备注}_{序号}{扩展名}`,序号从 1 起,按当前列表顺序 | +| 落库 | **不写** `file_name`;对象存储路径不变;下载仍用原始名 | +| 端与界面 | Web + 小程序;新增/编辑表单 + 详情查看 | +| 方案 | 前端展示层映射(纯函数),不改上传 API | + +## 命名规则 + +展示名计算(纯前端,不改库): + +1. 取整单 `remark`,`trim` +2. 为空 → 返回原始 `fileName`(空则可用「申请附件」等既有兜底,与现网一致) +3. 非空: + - 去掉不适合文件名的字符:`/ \ : * ? " < > |` 及控制字符 + - 空白压成单个 `_`(或等价规范化) + - 截断至 ≤ 40 个字符(截断在扩展名拼接之前,仅对备注基名) + - 扩展名取自原始 `fileName` 的 `ext`(含点);无扩展名则不加 + - 第 `i` 个附件(1-based):`{base}_{i}{ext}` + +备注在表单中变更时,附件区展示名立即重算,无需重新上传。 + +示例:备注 `差旅说明`,两文件 `a.pdf`、`b.jpg` → `差旅说明_1.pdf`、`差旅说明_2.jpg`。 + +## 作用范围 + +### 要改 + +| 端 | 位置 | +|----|------| +| Web | 报销申请新增/编辑弹窗「申请附件」`BxAttachmentUpload` | +| Web | 报销申请详情「申请附件」`BxAttachmentReadonly` | +| 小程序 | `pages/bx/reimburse/apply` 申请附件列表 | +| 小程序 | `pages/bx/reimburse/detail` 申请附件列表 | + +若 Web 审批详情等页同样展示该单「申请附件」且能拿到 `remark`,应复用同一工具函数,避免不一致;不因此扩大到发票/发放/冲抵附件。 + +### 不做 + +- 关联发票附件、发放附件、冲抵附件 +- 修改 `POST /attachments/upload`、`file_name` 落库、MinIO object key +- 下载文件名改为备注名 +- 备用金及其他业务单据 +- 强制先填备注再上传 + +## 实现落点(建议) + +| 层 | 文件 | +|----|------| +| Web 工具 | `web-admin/src/utils/bx/attachment-display-name.ts`(或并入既有 `format.ts` 旁独立小文件) | +| Web 上传/只读 | `BxAttachmentUpload.vue` / `BxAttachmentReadonly.vue`:支持按 remark 映射展示,或父组件传入已映射的展示字段;**下载仍用原始 fileName** | +| Web 页 | `web-admin/src/views/bx/reimburse/apply/index.vue`(及若有的审批详情申请附件区) | +| Mini 工具 | `miniprogram/utils/bxAttachmentDisplayName.js`(对称逻辑) | +| Mini 页 | `miniprogram/pages/bx/reimburse/apply.vue`、`detail.vue` | + +组件契约建议:保留数据上的原始 `fileName`;另设 `displayName` 仅用于 UI 文案与 `title`,避免误用于 download。 + +## 验收标准 + +1. 填写备注后,申请附件区显示 `备注_1.ext`、`备注_2.ext` … +2. 清空备注后,立即恢复原始文件名展示 +3. 保存后打开详情:展示名随单据备注计算;下载/预览文件名仍为原始 `fileName` +4. Web 与小程序规则一致 +5. 发票附件区不受影响 +6. 备注含非法文件名字符时展示名被清理且不报错;超长备注被截断 + +## 明确不做(本期) + +- 后端改写列表返回的 `fileName` +- 保存时回写附件 `file_name` +- 批量导入场景的附件命名(无申请附件上传则无关)