# 新系统版 `documents/list` 接口 这份文档专门说明当前 `leaudit-platform` 里已经落地的“新系统版文档列表接口”。 目标很明确: - 前端文档列表只看“最新版本” - 同名文档的历史版本直接归到同一个版本链 - 列表接口直接返回历史版本摘要,前端不用自己再拼版本关系 --- ## 1. 接口路径 ```http GET /api/documents/list ``` --- ## 2. 当前接口语义 这个接口不是“把所有上传记录平铺出来”。 它的语义是: - 每个 `version_group_key` 只返回一条“最新版本文档” - 这条最新版本文档下面附带 `historyVersions` - `historyVersions` 里放的是同组下更老的版本摘要 也就是说,前端主列表看到的是: - 当前版本 - 是否有历史版本 - 一共有多少版本 - 历史版本有哪些 --- ## 3. 请求参数 | 参数 | 类型 | 必填 | 说明 | |---|---|---:|---| | `page` | int | 否 | 页码,从 `1` 开始,默认 `1` | | `pageSize` | int | 否 | 每页数量,默认 `20`,最大 `100` | | `keyword` | string | 否 | 按文件名或归一化名称模糊搜索 | | `typeCode` | string | 否 | 文档类型编码,例如 `contract.sale` | | `region` | string | 否 | 区域 | | `processingStatus` | string | 否 | 文档处理状态 | | `resultStatus` | string | 否 | 最新 run 的结果状态 | 请求示例: ```bash curl 'http://127.0.0.1:8096/api/documents/list?page=1&pageSize=5' ``` 带筛选示例: ```bash curl 'http://127.0.0.1:8096/api/documents/list?page=1&pageSize=2&keyword=版本归档&typeCode=contract.sale®ion=default' ``` --- ## 4. 返回结构 返回模型是分页结构: ```json { "code": 200, "message": "ok", "data": { "total": 1, "page": 1, "pageSize": 20, "totalPages": 1, "documents": [] } } ``` 其中 `documents[]` 的单条结构核心字段如下: | 字段 | 说明 | |---|---| | `documentId` | 当前最新版本文档 ID | | `internalDocumentNo` | 平台内部追踪号 | | `versionGroupKey` | 版本归档组键 | | `versionNo` | 当前版本号 | | `rootVersionId` | 版本链根文档 ID | | `previousVersionId` | 上一版本文档 ID | | `typeId` | 文档类型 ID | | `typeCode` | 文档类型编码 | | `region` | 区域 | | `normalizedName` | 归一化后的名称 | | `fileId` | 当前主文件 ID | | `fileName` | 文件名 | | `fileExt` | 文件扩展名 | | `mimeType` | MIME 类型 | | `fileSize` | 文件大小 | | `ossUrl` | 对象存储路径 | | `processingStatus` | 文档处理状态 | | `currentRunId` | 当前 run ID | | `runStatus` | 当前 run 状态 | | `resultStatus` | 当前 run 结果状态 | | `totalScore` | 总分 | | `passedCount` | 通过数 | | `failedCount` | 失败数 | | `skippedCount` | 跳过数 | | `updatedAt` | 更新时间 | | `hasHistory` | 是否有历史版本 | | `totalVersions` | 总版本数 | | `historyVersions` | 历史版本摘要列表 | `historyVersions[]` 结构: | 字段 | 说明 | |---|---| | `documentId` | 历史版本文档 ID | | `fileId` | 历史版本文件 ID | | `versionNo` | 历史版本号 | | `fileName` | 文件名 | | `fileExt` | 文件扩展名 | | `processingStatus` | 处理状态 | | `runStatus` | 运行状态 | | `resultStatus` | 结果状态 | | `updatedAt` | 更新时间 | --- ## 5. SQL 逻辑 ### 5.1 主列表计数 SQL ```sql SELECT COUNT(*) FROM leaudit_documents d JOIN leaudit_document_files f ON f.document_id = d.id LEFT JOIN leaudit_document_types dt ON dt.id = d.type_id LEFT JOIN leaudit_audit_runs ar ON ar.id = d.current_run_id WHERE d.is_latest_version = true AND d.deleted_at IS NULL AND f.is_active = true AND f.file_role = 'primary' -- 可选过滤: -- AND (f.file_name ILIKE :keyword OR d.normalized_name ILIKE :keyword) -- AND dt.code = :type_code -- AND d.region = :region -- AND d.processing_status = :processing_status -- AND ar.result_status = :result_status ``` ### 5.2 主列表分页 SQL ```sql SELECT d.id AS document_id, d.biz_document_id AS internal_document_no, d.version_group_key, d.version_no, d.root_version_id, d.previous_version_id, d.type_id, dt.code AS type_code, d.region, d.normalized_name, d.processing_status, d.current_run_id, d.updated_at, f.id AS file_id, f.file_name, f.file_ext, f.mime_type, f.file_size, f.oss_url, ar.status AS run_status, ar.result_status, ar.total_score, ar.passed_count, ar.failed_count, ar.skipped_count, vc.total_versions, COALESCE(vc.total_versions, 1) > 1 AS has_history FROM leaudit_documents d JOIN leaudit_document_files f ON f.document_id = d.id LEFT JOIN leaudit_document_types dt ON dt.id = d.type_id LEFT JOIN leaudit_audit_runs ar ON ar.id = d.current_run_id LEFT JOIN ( SELECT version_group_key, COUNT(*) AS total_versions FROM leaudit_documents WHERE deleted_at IS NULL GROUP BY version_group_key ) vc ON vc.version_group_key = d.version_group_key WHERE d.is_latest_version = true AND d.deleted_at IS NULL AND f.is_active = true AND f.file_role = 'primary' ORDER BY d.updated_at DESC, d.id DESC LIMIT :limit OFFSET :offset ``` ### 5.3 历史版本摘要 SQL ```sql SELECT d.version_group_key, d.id AS document_id, d.version_no, d.processing_status, d.updated_at, f.id AS file_id, f.file_name, f.file_ext, ar.status AS run_status, ar.result_status FROM leaudit_documents d JOIN leaudit_document_files f ON f.document_id = d.id AND f.is_active = true AND f.file_role = 'primary' LEFT JOIN leaudit_audit_runs ar ON ar.id = d.current_run_id WHERE d.version_group_key = ANY(:group_keys) AND d.is_latest_version = false AND d.deleted_at IS NULL ORDER BY d.version_group_key, d.version_no DESC, d.id DESC ``` --- ## 6. 为什么新系统要这么做 因为现在我们已经不是老系统那种“文档记录 + 旁路版本信息”的模式了。 当前新系统已经有真正的版本链字段: - `version_group_key` - `version_no` - `previous_version_id` - `root_version_id` - `is_latest_version` - `normalized_name` 所以列表天然应该是: - 主列表 = 最新版本 - 展开项 = 历史版本 而不是把所有版本平铺在一个列表里。 --- ## 7. 当前代码落点 实现代码在这些文件: - 路由:`fastapi_modules/fastapi_leaudit/controllers/documentController.py` - 服务接口:`fastapi_modules/fastapi_leaudit/services/documentService.py` - VO:`fastapi_modules/fastapi_leaudit/domian/vo/documentVo.py` - 具体实现:`fastapi_modules/fastapi_leaudit/services/impl/documentServiceImpl.py` --- ## 8. 当前验证结果 已经实际验证通过: ```bash curl 'http://127.0.0.1:8096/api/documents/list?page=1&pageSize=5' ``` 以及: ```bash curl 'http://127.0.0.1:8096/api/documents/list?page=1&pageSize=2&keyword=版本归档&typeCode=contract.sale®ion=default' ``` 验证结论: - 接口正常返回 - 主列表只返回最新版本 - `historyVersions` 能正确带出历史版本摘要 - 已验证版本组 `4e02e455aa504cb9b75a254727f1bb4c` - `documentId=13` 是当前最新 `v3` - `documentId=12` 是 `v2` - `documentId=11` 是 `v1` --- ## 9. 下一步建议 如果后面前端需要更完整的“版本展开页”,再补一个: ```http GET /api/documents/{documentId}/versions ``` 但当前列表页场景下,`/documents/list` 已经够用了。