- 增加合同专用 PDF 上传、鉴权预览和失败清理接口 - 支持草稿附件替换移除、并发保护和启用完整性校验 - 修复循环模板引用导致文件选择器无法打开的问题 - 补充专项测试、中文项目文档和操作日志
103 lines
6.3 KiB
Markdown
103 lines
6.3 KiB
Markdown
# 操作日志:配送合同附件上传
|
||
|
||
操作时间:2026-08-12 20:42:47
|
||
操作类型:扩展
|
||
影响模块:平台总后台配送合同、后端合同业务、受控文件存储
|
||
|
||
## 操作前状态
|
||
|
||
- 合同表单将 `file_uri` 渲染为普通“附件地址”文本框,允许手工填写任意字符串。
|
||
- 合同接口仅校验 URI 长度,没有专用 PDF 上传、预览或清理能力。
|
||
- 通用 `/upload/file` 支持多种图片、PDF 和视频,不能直接收紧而不影响其他模块。
|
||
- 合同详情会过滤 `file_uri`,页面无法安全查看附件。
|
||
- 合同启用流程不检查签署附件。
|
||
|
||
## 具体操作
|
||
|
||
1. 新增合同专用 PDF 上传、临时清理和鉴权预览接口。
|
||
2. 使用 HMAC 签名收据绑定上传人与临时 URI,有效期为 30 分钟。
|
||
3. 创建或更新合同时将临时文件移动到正式目录,并在失败时回滚文件。
|
||
4. 使用不透明附件版本和旧 URI 条件处理草稿并发更新。
|
||
5. 草稿替换或移除成功后删除旧文件,失败最多重试三次并记录日志。
|
||
6. 合同启用前验证受控 URI 和磁盘 PDF 文件。
|
||
7. 将前端文本框替换为支持点击和拖拽的 PDF 控件,保存时上传。
|
||
8. 新增详情预览、旧地址重新上传提示、移除二次确认和离开页面未保存检测。
|
||
9. 补充安全边界、签名凭证、路由注册等自动化测试。
|
||
|
||
## 操作后状态
|
||
|
||
- 合同草稿可无附件保存;启用前必须具备真实有效的受控 PDF。
|
||
- 单个附件最大 10 MiB,仅允许 PDF。
|
||
- 草稿可替换和移除,非草稿只可鉴权预览。
|
||
- 页面不暴露内部 URI,不保存原始文件名,统一显示“合同附件.pdf”。
|
||
- 历史外部 URI 不删除,但不可预览且不能满足启用条件。
|
||
- 不修改数据库表和模型,不新增定时扫描任务。
|
||
|
||
## 代码变更
|
||
|
||
- `backend/api/internal/logic/platform/gasorder/contract_attachment.go`:新增 349 行,合同附件核心服务。
|
||
- `backend/api/internal/logic/platform/gasorder/contract_attachment_test.go`:新增 83 行,安全与边界测试。
|
||
- `backend/api/internal/logic/platform/gasorder/gasorder.go`:约新增 88 行、删除 7 行,接入创建、更新、并发和启用校验。
|
||
- `backend/api/internal/routers/platform.go`:新增 3 条专用路由。
|
||
- `backend/api/internal/routers/platform_contract_attachment_test.go`:新增 25 行,路由测试。
|
||
- `frontend/platform_admin/src/api/contract-attachment.ts`:新增 73 行,附件 API 客户端。
|
||
- `frontend/platform_admin/src/views/resource/use-contract-attachment.ts`:新增 147 行,附件页面状态与保存编排。
|
||
- `frontend/platform_admin/src/views/resource/ResourceFieldForm.vue`:约新增 145 行、删除 1 行,上传控件和样式。
|
||
- `frontend/platform_admin/src/views/resource/ResourceRecordPage.vue`:约新增 81 行、删除 2 行,详情预览和保存集成。
|
||
- `frontend/platform_admin/src/api/resources.ts`、`ResourceDetailContent.vue`:字段类型、动作状态和详情隐藏调整。
|
||
|
||
## 行为变化
|
||
|
||
- 变更前:管理员手工输入附件地址;无受控上传和下载。
|
||
- 变更后:管理员选择 PDF,保存时自动上传并绑定;通过合同标识鉴权预览。
|
||
- 变更前:无附件也可启用合同。
|
||
- 变更后:无有效 PDF 时拒绝启用。
|
||
- 兼容性:原 `file_uri` 数据库字段、合同 JSON 字段和通用上传接口保持不变。
|
||
|
||
## 验证结果
|
||
|
||
- `go test ./...`:通过。
|
||
- `npm.cmd run type:check`:通过。
|
||
- `npm.cmd run build`:通过。
|
||
- `npm.cmd run contract:check`:通过,48 个资源。
|
||
- `npm.cmd run resource-pages:check`:通过,详情 46 类、新建 25 类、编辑 23 类。
|
||
- `git diff --check`:通过。
|
||
- 本地页面只读检查:应用可正常打开且无控制台错误;独立测试浏览器因未登录被重定向至登录页,因此未执行需要平台账号和测试合同数据的交互式保存、替换及预览验证。
|
||
- `npm.cmd run lint`:未通过;项目已有 2 个错误、165 个警告和 12 个提示,诊断集中在既有文件。对本次 6 个前端改动文件单独执行 Biome lint 无错误,仅有项目现存的模板变量识别类警告。
|
||
- 边界测试:伪装 PDF、错误 MIME、缺少结束标记、过期或篡改凭证、跨操作人凭证、路径穿越、外部 URL 和附件版本变化均覆盖。
|
||
|
||
## 风险评估
|
||
|
||
- 存储仍为本地文件系统;多实例部署必须共享 `HEQI_UPLOAD_DIR`,否则下载和启用校验可能找不到文件。
|
||
- 不运行孤儿文件定时扫描;浏览器关闭或最终删除失败时依赖应用日志由运维人工处理。
|
||
- JWT 密钥同时用于附件签名;密钥轮换会使尚未绑定的 30 分钟临时收据失效,已绑定附件不受影响。
|
||
- 原始文件名未持久化,这是“不改数据库”约束下的明确取舍。
|
||
- 项目已有前后端合同状态展示不一致,本次仅把启用动作可见状态修正为后端支持的草稿和终止状态,未扩展其他状态改动。
|
||
|
||
## 运行时异常修复补充(2026-08-12)
|
||
|
||
### 操作前状态
|
||
|
||
- `ResourceFieldForm.vue` 在字段 `v-for` 内为文件 input 使用同一个 `attachmentInput` 模板引用。
|
||
- Vue 将循环内模板引用解析为元素数组,点击上传区域调用 `.click()` 时抛出 `TypeError: attachmentInput.value?.click is not a function`。
|
||
|
||
### 具体操作
|
||
|
||
- 新增 `ContractAttachmentField.vue`,将文件 input 和单一模板引用移出字段循环。
|
||
- 通用字段表单只负责渲染独立组件并转发选择、预览、移除和取消选择事件。
|
||
- 上传区域增加按钮语义、Tab 焦点、Enter/空格键入口和可见焦点样式。
|
||
- 操作按钮同时阻止点击与键盘事件冒泡,避免预览或移除时误打开选择器。
|
||
- 新增 `scripts/check-contract-attachment-control.mjs` 和 `contract-attachment:check` 命令。
|
||
|
||
### 验证结果
|
||
|
||
- `npm.cmd run contract-attachment:check`:通过。
|
||
- `npm.cmd run type:check`:通过。
|
||
- `npm.cmd run build`:通过。
|
||
- 独立测试浏览器没有后台登录会话,未执行真实文件选择器弹窗的浏览器交互验证。
|
||
|
||
### 风险评估
|
||
|
||
- 未新增测试框架或运行依赖,沿用项目现有静态契约检查方式。
|
||
- 修复仅调整前端控件边界,不修改后端、数据库、上传接口或合同保存载荷。
|