From 969c3aaf3510f7bb0dfa408e270dc84e5958d357 Mon Sep 17 00:00:00 2001 From: wren <“porlong@qq.com”> Date: Thu, 30 Apr 2026 12:29:00 +0800 Subject: [PATCH] docs: add document upload/list API analysis and integration plan --- docs/接口/文档上传与列表接口分析.md | 294 ++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 docs/接口/文档上传与列表接口分析.md diff --git a/docs/接口/文档上传与列表接口分析.md b/docs/接口/文档上传与列表接口分析.md new file mode 100644 index 0000000..c8bf291 --- /dev/null +++ b/docs/接口/文档上传与列表接口分析.md @@ -0,0 +1,294 @@ +# 文档上传与列表 — 接口分析 & 接入方案 + +> 所有信息已逐文件验证。源代码位置均已标注。 + +--- + +## 一、后端接口(已验证) + +### 1.1 POST /api/upload — 文档上传 + +**源码**: `fastapi_modules/fastapi_leaudit/controllers/documentController.py:20-45` +**实现**: `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py:44-246` + +``` +URL: POST /api/upload +格式: multipart/form-data (扁平字段) +``` + +| 字段 | 类型 | 必填 | 默认值 | 说明 | +|------|------|------|--------|------| +| `file` | UploadFile | **是** | — | 文件二进制 | +| `typeId` | int | typeId/typeCode 二选一 | None | 文档类型 ID | +| `typeCode` | str | typeId/typeCode 二选一 | None | 文档类型编码,如 `contract.construction` | +| `region` | str | 否 | `"default"` | 地区标识 | +| `fileRole` | str | 否 | `"primary"` | 文件角色:primary/attachment/template | +| `createdBy` | int | 否 | None | 上传用户 ID | +| `autoRun` | bool | 否 | `false` | 是否上传后自动触发评查 | +| `speed` | str | 否 | `"normal"` | urgent / normal | + +**内部流程**: +1. 校验文件名/内容非空 → 解析文档类型(查 `leaudit_document_types`) +2. SHA-256 去重(仅 primary 文件):同名+同类型+同区域+同 hash → 复用已有记录,`duplicateUpload=true` +3. 非重复:生成 `internalDocumentNo`,匹配前一版本,递增 `versionNo`,写 `leaudit_documents` +4. 存 MinIO OSS,路径 `bdocs/{Region}/{TypeCode}/{Year}/...` +5. 写 `leaudit_document_files` +6. 若 `autoRun=true` → 调 `AuditService.Run()` 触发评查 + +**响应** `Result[DocumentUploadVO]` (`domian/vo/documentVo.py:8-27`): + +```json +{ + "code": 200, + "message": "ok", + "data": { + "documentId": 1, + "internalDocumentNo": 1712345678000000001, + "versionGroupKey": "abc123...", + "versionNo": 2, + "previousVersionId": 1, + "rootVersionId": 1, + "duplicateUpload": false, + "fileId": 5, + "typeId": 1, + "typeCode": "contract.construction", + "region": "meizhou", + "fileName": "建设工程合同.pdf", + "ossUrl": "http://minio/bdocs/...", + "speed": "normal", + "processingStatus": "waiting", + "autoRunTriggered": true, + "run": { "runId": 10, "status": "pending", ... } + } +} +``` + +--- + +### 1.2 GET /api/documents/list — 文档列表 + +**源码**: `controllers/documentController.py:47-67` +**实现**: `documentServiceImpl.py:248-443` + +``` +URL: GET /api/documents/list +格式: query params +``` + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| `page` | int | 否 (1) | 页码 | +| `pageSize` | int | 否 (20, max 100) | 每页条数 | +| `keyword` | str | 否 | 搜索文件名或归一化名 | +| `typeCode` | str | 否 | 文档类型编码过滤 | +| `region` | str | 否 | 地区过滤 | +| `processingStatus` | str | 否 | waiting/processing/completed/failed | +| `resultStatus` | str | 否 | pass/fail/partial/review/error | + +**内部流程**: +1. `leaudit_documents d` JOIN `leaudit_document_files f` ON `f.document_id = d.id` +2. 条件: `d.is_latest_version=true`, `d.deleted_at IS NULL`, `f.is_active=true`, `f.file_role='primary'` +3. LEFT JOIN `leaudit_document_types dt`, `leaudit_audit_runs ar` +4. 子查询统计 `total_versions`(按 `version_group_key` 分组) +5. 批量加载历史版本(`is_latest_version=false` 的同组文档) + +**响应** `Result[DocumentListPageVO]` (`domian/vo/documentVo.py:77-84`): + +```json +{ + "code": 200, "message": "ok", + "data": { + "total": 100, "page": 1, "pageSize": 20, "totalPages": 5, + "documents": [ + { + "documentId": 1, "internalDocumentNo": 1712345678000000001, + "versionGroupKey": "abc123", "versionNo": 2, + "typeId": 1, "typeCode": "contract.construction", + "region": "meizhou", "normalizedName": "建设工程合同", + "fileId": 5, "fileName": "建设工程合同.pdf", + "fileExt": ".pdf", "mimeType": "application/pdf", + "fileSize": 1048576, "ossUrl": "http://minio/...", + "processingStatus": "completed", + "runStatus": "completed", "resultStatus": "pass", + "totalScore": 85, "passedCount": 10, + "failedCount": 2, "skippedCount": 0, + "hasHistory": true, "totalVersions": 2, + "historyVersions": [ + { "documentId": 1, "versionNo": 1, "fileName": "...", ... } + ] + } + ] + } +} +``` + +--- + +### 1.3 缺失的后端接口 + +| 操作 | 当前 | 需要 | +|------|------|------| +| 删除文档 | ❌ | `DELETE /api/documents/{id}` — 软删除 | +| 编辑元数据 | ❌ | `PUT /api/documents/{id}` — 更新备注、测试标记等 | +| 文档详情 | ❌ | `GET /api/documents/{id}` — 单文档查询 | +| 附件追加 | ❌ | `POST /api/documents/{id}/attachments` — fileRole=attachment | + +--- + +## 二、前端调用现状(已验证) + +### 2.1 上传 — `uploadDocumentToServer()` + +**源码**: `new_doc_review/app/api/files/files-upload.ts:374-443` + +``` +URL: ${UPLOAD_URL}/upload (例: http://172.16.0.59:8096/upload) +格式: FormData { file: Blob, upload_info: JSON字符串 } +``` + +前端实际发送的 FormData: + +``` +file: Blob (文件二进制) +upload_info: '{"type_id":1,"evaluation_level":"normal","document_number":null,"remark":null,"is_test_document":false,"document_id":null,"is_reupload":false,"attribute_type":null}' +``` + +**❌ 与后端完全不兼容。** 后端期望扁平字段 `typeId`/`typeCode`/`region`/`fileRole`/`autoRun`/`speed`,不接受嵌套的 `upload_info` JSON。 + +### 2.2 附件追加 — `appendContractAttachments()` + +**源码**: `files-upload.ts:320-336` + +``` +URL: ${UPLOAD_URL}/contracts/{documentId}/append_attachments +格式: FormData { attachments: File[] } +``` + +后端没有对应接口,需要补。 + +### 2.3 合同模板上传 — `uploadContractTemplate()` + +**源码**: `files-upload.ts:244-259` + +``` +URL: ${UPLOAD_URL}/upload_contract_template +格式: FormData { file: Blob } +``` + +后端没有对应接口。 + +### 2.4 列表 — `getDocumentsListFromAPI()` + +**源码**: `new_doc_review/app/api/files/documents.ts:627-784` + +``` +URL: ${API_BASE_URL}/api/documents/list ✅ 正确 +``` + +✅ 列表已接入新后端,但存在两个问题: +1. **字段映射层太厚**:`LeauditListItem → DocumentUI` 转换 50+ 行,且把 `fileExt` 映射为 `fileType`、`ossUrl` 映射为 `path` 等 +2. **筛选项不全**:`documentNumber`、`auditStatus`、`dateFrom/dateTo` 在后端列表接口未支持,前端写了 `void` 占位 + +### 2.5 删除 — `deleteDocument()` + +**源码**: `documents.ts:540-560` + +``` +URL: /api/postgrest/proxy/documents?id=eq.{id}&user_id=eq.{userId} +方法: DELETE +``` + +❌ 走 PostgREST 直删,未接入新后端。 + +### 2.6 编辑 — `updateDocument()` + +**源码**: `documents.ts:485-510` + +``` +URL: /api/postgrest/proxy/documents?id=eq.{id} +方法: PATCH +``` + +❌ 走 PostgREST,未接入新后端。 + +--- + +## 三、接入方案 + +### 第 1 步:上传接口对齐 ⭐ 最高优先级 + +**前端改造** `uploadDocumentToServer()`: + +``` +改前: FormData { file, upload_info: JSON.stringify({ type_id, evaluation_level, ... }) } + POST ${UPLOAD_URL}/upload + +改后: FormData { file, typeId, typeCode, region, fileRole, createdBy, autoRun, speed } + POST ${API_BASE_URL}/api/upload +``` + +字段映射: + +| 前端旧参数 | 新后端参数 | 说明 | +|-----------|-----------|------| +| `upload_info.type_id` | `typeId` | 直接传 | +| — | `typeCode` | 补充,从 document types 查 | +| — | `region` | 从 sessionStorage / user info 取当前用户地区 | +| — | `fileRole` | `"primary"` | +| — | `createdBy` | 从 JWT payload 取 user_id | +| `evaluation_level` | `speed` | urgent/normal 映射 | +| — | `autoRun` | 默认 true(参考前端现有流程:上传后自动 treatment) | + +附件和模板上传合并方案: +- 主文件:`POST /api/upload` + `fileRole=primary` +- 附件:`POST /api/upload` + `fileRole=attachment`(或批量复用主上传) +- 模板:`POST /api/upload` + `fileRole=template` + +影响文件: +- `new_doc_review/app/api/files/files-upload.ts` — `uploadDocumentToServer()` 重写 +- `new_doc_review/app/routes/files.upload.tsx` — `startUpload()` 适配新参数 + +### 第 2 步:列表字段精简 + +**前端字段直接对齐**,逐步去掉 `mapLeauditDocToAuditStatus`、`mapProcessingStatusToFileStatus` 等映射函数。`DocumentUI` 接口增加新字段,旧字段保留兼容。 + +影响文件: +- `new_doc_review/app/api/files/documents.ts` — 简化 `LeauditListItem → DocumentUI` 转换 + +### 第 3 步:补后端 CRUD + +后端新增: + +``` +DELETE /api/documents/{id} → 软删除 (deleted_at = now()) +PUT /api/documents/{id} → 更新元数据 (备注、测试标记) +GET /api/documents/{id} → 文档详情(含所有版本) +POST /api/documents/{id}/attachments → 追加附件 +``` + +影响文件: +- `fastapi_modules/fastapi_leaudit/controllers/documentController.py` +- `fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py` + +### 第 4 步:前端切割 PostgREST + +`deleteDocument`、`updateDocument` 从前端 PostgREST 调用改为走新后端 `/api/documents/...`。 + +### 第 5 步:清理旧依赖 + +确认无其他 PostgREST 调用后,移除旧 RPC 函数。 + +--- + +## 四、涉及文件清单 + +| 层 | 文件 | 改动类型 | +|----|------|---------| +| 后端 | `documentController.py` | 新增 3 个端点 | +| 后端 | `documentServiceImpl.py` | 新增 Delete/Update/GetById/AppendAttachments | +| 后端 | `documentVo.py` | 可能新增 VO | +| 前端 | `files-upload.ts` | 重写 uploadDocumentToServer | +| 前端 | `files.upload.tsx` | 适配新上传参数 | +| 前端 | `documents.ts` | 简化列表映射 + 切割删除/编辑到新后端 | +| 前端 | `documents.list.tsx` | 小改适配新字段 | +| 前端 | `documents.edit.tsx` | 切割到新后端 PUT |