新增历史项目导入设计文档

This commit is contained in:
wkc
2026-03-29 09:37:36 +08:00
parent 65f25a9258
commit 26f77bf458
2 changed files with 384 additions and 0 deletions

View File

@@ -0,0 +1,359 @@
# 历史项目导入新项目功能设计文档
## 背景
当前项目管理页已经存在“导入历史项目”前端弹窗壳子,但能力仍停留在演示阶段:
- 仅支持前端 Mock 历史项目数据
- 仅支持单选历史项目
- 没有真实创建新项目与复制流水的后端逻辑
- 没有接通现有打标、结果表生成、统计刷新链路
与此同时,系统已经具备以下基础能力:
- [`CcdiProjectServiceImpl#createProject`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java#L44) 可创建本地项目,并在创建时调用流水分析平台 `getToken` 接口获取并绑定 `lsfxProjectId`
- [`CcdiFileUploadServiceImpl`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiFileUploadServiceImpl.java) 已打通文件上传后自动触发打标的异步链路
- [`CcdiBankTagServiceImpl`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java) 已具备项目状态切换、标签重算、结果表刷新能力
- [`detail.vue`](/Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui/src/views/ccdiProject/detail.vue) 已具备项目状态轮询能力
因此本次需要补齐“从一个或多个历史项目复制流水到新项目”的真实业务闭环。
## 目标
- 在“导入历史项目”弹窗中支持填写新项目名称、备注、交易日期范围,并多选历史项目
- 点击提交后先创建新项目,再异步复制历史流水到新项目
- 若填写时间范围,仅复制 `trxDate` 命中的流水
- 若多个来源项目存在重复流水,按现有流水唯一性口径去重后写入新项目
- 同步复制真正贡献了被导入流水的成功文件上传记录
- 历史导入完成后自动触发打标、结果表生成和统计刷新
- 提交成功后关闭弹窗并跳转到新项目详情页,由详情页承接进度展示
- 历史导入生成的文件记录在新项目中只读展示,不允许删除
## 非目标
- 不支持继承来源项目的参数配置
- 不支持合并多个来源项目的参数规则
- 不支持导入“进行中”项目
- 不支持复制失败或进行中的文件上传记录
- 不支持删除历史导入生成的文件记录
- 不新增独立的“导入任务管理页面”
- 不新增额外复杂导入状态体系或独立进度中心
## 已确认业务口径
- 历史项目可选范围:仅“已完成”“已归档”项目
- 新项目参数来源:固定走现有新建项目默认参数逻辑
- 时间过滤字段:固定按 `trxDate`
- 重复流水处理:按现有唯一性口径去重
- 提交后页面行为:关闭弹窗并跳转到新项目详情页
- 文件记录复制范围:仅复制 `parsed_success` 且确实贡献了被复制流水的记录
- 文件记录展示:保留原文件名,并标记“历史导入来源”
- 删除规则:历史导入生成的文件记录不允许删除
## 方案对比
### 方案一:创建项目后启动独立历史导入异步任务
- 做法:提交接口先调用现有 `createProject`,再在事务提交后启动独立历史导入服务,完成流水复制、文件记录复制、自动打标和结果刷新
- 优点:业务语义清晰,和“上传文件”链路解耦,适合历史复制场景
- 缺点:需要新增历史导入 DTO、接口和异步编排服务
### 方案二:将历史导入伪装成“虚拟上传文件”
- 做法:把来源项目批次伪装为上传任务,强行复用文件上传服务全链路
- 优点:看似能复用更多现有代码
- 缺点:历史导入并不是真实上传,会导致批次、错误信息、来源展示语义混乱
### 方案三:提交接口同步完成流水复制,末尾再触发打标
- 做法:导入接口直接完成所有复制逻辑,再异步触发打标
- 优点:表面上实现路径更短
- 缺点:来源项目多、流水量大时接口耗时过长,和“先创建项目,再后台处理”的需求不符
## 最终方案
采用方案一。
导入接口只负责同步创建新项目和提交异步历史导入任务。历史导入任务在后台完成以下步骤:
1. 校验来源项目和导入条件
2.`trxDate` 过滤并复制流水到新项目
3. 按现有唯一性口径去重
4. 为真正贡献流水的来源批次生成新的文件上传记录
5. 刷新新项目 `targetCount`
6. 自动触发打标、结果表生成和统计刷新
前端提交成功后直接跳转到新项目详情页,复用现有项目状态轮询和上传记录列表。
## 现状分析
## 1. 新建项目现状
[`CcdiProjectServiceImpl#createProject`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java#L44) 会先调用 `callLsfxPlatform(projectName)` 获取流水分析平台项目 ID再将其写入本地项目表的 `lsfxProjectId` 字段。
[`callLsfxPlatform`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java#L247) 当前通过 `lsfxAnalysisClient.getToken(request)` 调用流水分析平台接口,并校验返回的 `projectId` 非空。
这意味着历史项目导入时创建新项目,可以直接复用现有创建逻辑,不需要额外新增“平台建项目”调用路径。
## 2. 文件上传记录现状
[`ccdi_file_upload_record`](/Users/wkc/Desktop/ccdi/ccdi/sql/ccdi_file_upload_record.sql) 当前存储字段包括:
- `project_id`
- `lsfx_project_id`
- `log_id`
- `file_name`
- `file_status`
- `enterprise_names`
- `account_nos`
- `upload_time`
- `upload_user`
[`CcdiBankStatementMapper.xml`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankStatementMapper.xml#L330) 会按 `project_id + log_id(batch_id)` 将流水和文件记录关联起来,用于详情页展示原始文件名。
因此历史导入不能直接复用来源项目原始 `logId`,否则会在新项目维度造成批次语义混乱。新项目内必须对导入批次重新分配新的批次号,并同步写入新项目的文件记录与流水数据。
## 3. 详情页现状
[`UploadData.vue`](/Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue) 已具备:
- 上传记录分页列表
- 项目打标中的只读锁定
- 轮询刷新文件记录与统计
- 删除文件记录入口
[`detail.vue`](/Users/wkc/Desktop/ccdi/ccdi/ruoyi-ui/src/views/ccdiProject/detail.vue) 已具备项目状态轮询。
因此本次只需要让历史导入记录进入现有上传记录列表,并在行操作层和删除接口层增加“历史导入不可删除”的约束。
## 详细设计
## 1. 后端接口设计
### 1.1 查询可导入历史项目
- URL`GET /ccdi/project/history`
- 权限:沿用项目列表查询权限
- 入参:
- `projectName`:可选,按项目名模糊搜索
- 返回:
- 仅返回状态为“已完成”“已归档”的项目
- 返回字段包含项目 ID、项目名称、状态、创建时间、目标人数等弹窗展示所需字段
### 1.2 提交历史导入
- URL`POST /ccdi/project/import`
- 权限:沿用项目新增权限
- 入参建议:
- `projectName`
- `description`
- `sourceProjectIds`
- `startDate`
- `endDate`
- 返回:
- 新项目 `projectId`
- 新项目基础信息
接口执行顺序:
1. 校验入参
2. 调用现有 `createProject`
3. 在事务提交后启动历史导入异步任务
4. 立即返回新项目信息给前端
## 2. 新增导入 DTO 与 VO
新增独立 DTO避免和普通新建项目 DTO 混用:
- `CcdiProjectImportHistoryDTO`
- `projectName`
- `description`
- `List<Long> sourceProjectIds`
- `String startDate`
- `String endDate`
新增历史项目列表 VO
- `CcdiProjectHistoryListItemVO`
- `projectId`
- `projectName`
- `projectStatus`
- `createTime`
- `targetCount`
- `warningCount`
## 3. 历史导入异步服务设计
新增独立历史导入服务,职责单一为“将历史项目流水导入到新项目”。
建议命名示例:
- `ICcdiProjectHistoryImportService`
- `CcdiProjectHistoryImportServiceImpl`
核心步骤:
1. 校验新项目存在且未归档
2. 校验来源项目均为“已完成 / 已归档”
3. 查询来源项目成功文件记录与流水数据
4.`trxDate` 过滤流水
5. 按现有唯一性口径去重
6. 批量写入新项目流水
7. 根据实际贡献流水的批次生成新项目文件记录
8. 刷新 `targetCount`
9. 调用 `bankTagService.submitAutoRebuild(projectId, triggerType)`
## 4. 流水复制规则
### 4.1 复制范围
- 仅处理所选来源项目
- 若未填写时间范围,则复制全部流水
- 若填写时间范围,则仅复制 `trxDate` 位于区间内的流水
### 4.2 去重规则
- 沿用当前 `ccdi_bank_statement` 入库唯一性口径
- 若多个来源项目存在重复流水,新项目中仅保留一份
### 4.3 空导入处理
- 若所有来源项目在过滤后均无可导入流水,则导入任务判定为业务失败
- 新项目保留,但不触发后续打标
- 前端详情页可看到失败结果,不回滚项目
## 5. 文件上传记录复制规则
### 5.1 可复制记录范围
- 仅复制 `parsed_success`
- 仅复制那些“至少贡献了一条被导入流水”的来源批次
- 失败记录、进行中记录一律不复制
### 5.2 批次号重映射
新项目内每个来源批次必须生成新的批次标识,并同步写入:
- 新项目文件上传记录的 `logId`
- 新项目流水表的 `batchId`
这样可以确保:
- 与新项目后续真实上传文件的批次不冲突
- 详情页仍能正确通过 `project_id + log_id(batch_id)` 关联文件与流水
### 5.3 来源标识
为支持前端展示“历史导入来源”,建议在 `ccdi_file_upload_record` 增加最小必要字段:
- `source_type``UPLOAD` / `PULL_BANK_INFO` / `HISTORY_IMPORT`
- `source_project_id`
- `source_project_name`
其中:
- 当前已有上传/拉取记录可回填默认 `source_type`
- 历史导入记录固定写入 `HISTORY_IMPORT`
## 6. 删除约束设计
### 6.1 前端删除约束
历史导入记录在上传列表中只读展示:
- 保留文件名
- 展示“历史导入 · 来源项目名”
- 不显示“删除”按钮
### 6.2 后端删除约束
[`deleteFileUploadRecord`](/Users/wkc/Desktop/ccdi/ccdi/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiFileUploadServiceImpl.java) 需增加后端兜底校验:
- 若记录属于 `HISTORY_IMPORT`,直接拒绝删除
- 返回明确错误信息,例如“历史导入文件不支持删除”
这样可以避免前端绕过行操作约束后误删导入数据。
## 7. 打标与结果刷新衔接
历史导入完成后,不新增单独导入状态机,直接复用现有打标链路:
1. 复制流水成功
2. 刷新新项目 `targetCount`
3. 调用 `bankTagService.submitAutoRebuild(...)`
4. 项目状态进入“打标中”
5. 打标完成后刷新结果表、风险统计和总览数据
6. 项目状态回到“已完成”
导入失败时:
- 项目保留
- 不进入打标
- 通过上传记录或错误提示体现失败结果
## 8. 前端弹窗设计
弹窗采用纵向布局:
### 8.1 新项目配置区
位于弹窗上方,包含:
- 新项目名称
- 备注
- 交易日期范围
### 8.2 历史项目选择区
位于弹窗下方,包含:
- 项目名称搜索
- 多选历史项目列表
- 固定高度滚动区域
列表只显示“已完成”“已归档”项目。
## 9. 提交后交互设计
提交成功后:
1. 关闭弹窗
2. 提示“历史项目导入任务已开始”
3. 跳转到新项目详情页
详情页承接方式:
- 复用现有项目状态轮询
- 复用上传记录列表轮询
- 用户在详情页中观察历史导入记录、项目状态和后续打标完成情况
## 10. 测试关注点
后续实施时需重点验证:
- 多历史项目多选导入
- `trxDate` 时间范围过滤
- 跨项目重复流水去重
- 历史导入记录来源展示
- 历史导入记录删除拦截
- 导入完成后自动打标与结果表刷新
- 无可导入流水时的失败呈现
## 风险与约束
- 现有文件记录与流水关联依赖 `project_id + log_id(batch_id)`,批次号重映射必须保证稳定且唯一
- 历史导入记录一旦允许删除,会破坏“复制数据来源可追溯”的约束,因此本次明确禁止删除
- 本次不引入额外任务中心,导入失败的展示能力依赖现有详情页与记录列表,需要实施时保持错误信息可读
## 结论
本次采用“先创建新项目,再异步导入历史流水并触发现有打标链路”的方案,保持最短路径实现。
该方案满足以下要求:
- 贴合现有项目创建和详情页状态轮询结构
- 不混淆“上传文件”和“复制历史流水”两类业务语义
- 能复用现有打标、结果表和统计刷新能力
- 能明确保证历史导入文件记录不可删除
后续进入实施计划阶段时,需要按仓库约定分别输出前端、后端两份实施计划。

View File

@@ -0,0 +1,25 @@
# 历史项目导入新项目设计记录
## 本次改动
- 新增设计文档 `docs/design/2026-03-29-project-import-history-design.md`
- 明确历史项目导入弹窗采用“新项目配置在上、历史项目列表在下”的纵向布局
- 明确历史项目支持多选,且仅允许选择“已完成”“已归档”项目
- 明确新项目固定走现有 `createProject` 默认参数链路
- 明确时间过滤固定按 `trxDate`
- 明确跨来源项目重复流水按现有唯一性口径去重
- 明确仅复制 `parsed_success` 且实际贡献导入流水的文件记录
- 明确历史导入记录需补充来源标识,并在前端只读展示
- 明确历史导入生成的文件记录不支持删除
## 设计结论
- 采用“同步创建新项目 + 异步历史导入任务”的实现路径
- 不将历史导入伪装为普通文件上传
- 复用现有项目状态轮询、自动打标、结果表刷新和统计刷新链路
- 后续实施阶段需要分别输出前端、后端两份实施计划
## 审阅说明
- 按仓库约束,本次未启用 subagent
- 已按设计文档审阅清单完成人工检查,重点确认了完整性、一致性、范围收敛和无额外兜底方案