# 项目上传文件列表删除功能设计

## 背景

当前项目详情页“上传数据”中的“上传文件列表”仅展示文件信息和状态，不支持针对单条文件记录执行业务操作。

现有系统已经具备以下基础能力：

- `ccdi_file_upload_record` 已保存每条上传记录的 `id`、`lsfxProjectId`、`logId`、`fileStatus`、`errorMessage`
- `ccdi_bank_statement` 已按 `projectId + batchId(logId)` 关联每次上传入库的流水数据
- 流水分析平台客户端 `LsfxAnalysisClient` 已封装删除文件接口 `deleteFiles`

当前缺失的是：

- 解析失败文件缺少“查看错误原因”入口
- 解析成功文件缺少“删除”入口
- 删除后缺少保留历史记录并展示“已删除”状态的机制

## 目标

- 在项目详情-上传数据-上传文件列表中新增“操作”列
- 当文件状态为 `parsed_failed` 时，支持查看错误原因
- 当文件状态为 `parsed_success` 时，支持删除文件
- 删除时增加二次确认，明确会同步删除平台文件与本地流水
- 删除成功后调用流水分析平台删除接口
- 删除成功后删除本地银行流水表中对应文件的全部流水
- 删除成功后保留上传记录，并将状态更新为 `deleted`
- 删除后的列表状态显示为“已删除”

## 非目标

- 不删除 `ccdi_file_upload_record` 历史记录
- 不新增独立删除标记字段，如 `deleted_flag`、`deleted_time`
- 不调整现有批量上传、轮询解析、本行信息拉取等主流程
- 不改造流水明细查询页面的筛选交互

## 现状分析

### 前端现状

上传文件列表页面位于：

- `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue`

当前列表字段包括：

- 文件名
- 文件大小
- 状态
- 主体名称
- 主体账号
- 上传时间
- 上传人

当前前端已经具备：

- 查询列表：`getFileUploadList`
- 查询统计：`getFileUploadStatistics`
- 查看列表中的 `fileStatus`
- 弹窗提示能力 `this.$alert`
- 二次确认能力 `this.$confirm`

当前前端未具备：

- 操作列渲染
- 按记录 ID 删除文件的 API
- `deleted` 状态映射

### 后端现状

后端上传记录相关接口位于：

- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiFileUploadController.java`

当前已提供：

- `GET /ccdi/file-upload/list`
- `GET /ccdi/file-upload/statistics/{projectId}`
- `GET /ccdi/file-upload/detail/{id}`

服务层位于：

- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiFileUploadServiceImpl.java`

当前已具备：

- 按状态统计上传记录
- 根据 `logId` 拉取并入库银行流水
- 失败时记录 `errorMessage`
- 通过 `CcdiBankStatementMapper.deleteByProjectIdAndBatchId(projectId, logId)` 清理本地流水

流水分析平台客户端位于：

- `ccdi-lsfx/src/main/java/com/ruoyi/lsfx/client/LsfxAnalysisClient.java`

当前已具备：

- `deleteFiles(DeleteFilesRequest)` 删除平台文件

### 状态现状

当前 `file_status` 已存在以下状态：

- `uploading`
- `parsing`
- `parsed_success`
- `parsed_failed`

当前缺少删除后的业务状态，因此无法在保留记录的前提下表达“已删除”。

## 方案对比

### 方案一：基于现有状态字段增加 `deleted`

- 在 `file_status` 中新增 `deleted`
- 删除成功后仅更新记录状态，不删除记录
- 前后端统一基于状态判断操作按钮与文案

优点：

- 最符合“保留并显示为已删除”的需求
- 复用现有查询、展示、统计结构
- 改动范围集中，数据库结构无需新增字段

缺点：

- 需要同步扩展状态映射和统计逻辑

### 方案二：新增独立删除标记字段

- 保留原有 `file_status`
- 额外增加 `deletedFlag` 或 `deletedTime`

优点：

- 删除状态与解析状态语义分离

缺点：

- 查询、展示、统计逻辑更复杂
- 需要新增数据库字段和 Mapper 映射
- 当前需求下属于过度设计

### 方案三：物理删除上传记录

优点：

- 实现最直接

缺点：

- 与“继续保留并显示为已删除”冲突
- 无法追溯文件历史和删除操作结果

## 最终方案

采用方案一：在 `ccdi_file_upload_record.file_status` 中新增 `deleted` 状态，基于现有上传记录做软删除保留。

## 详细设计

### 状态模型

上传记录状态统一定义为：

- `uploading`：上传中
- `parsing`：解析中
- `parsed_success`：解析成功
- `parsed_failed`：解析失败
- `deleted`：已删除

状态驱动前端操作规则：

- `parsed_failed`：显示“查看错误原因”
- `parsed_success`：显示“删除”
- `deleted`：不显示按钮
- `uploading`、`parsing`：不显示按钮

### 删除链路

删除流程按以下顺序执行：

1. 前端点击“删除”
2. 前端展示二次确认弹窗
3. 用户确认后调用“按上传记录 ID 删除文件”接口
4. 后端校验记录存在、归属当前项目、状态为 `parsed_success`、且包含 `lsfxProjectId` 与 `logId`
5. 后端调用流水分析平台 `deleteFiles`
6. 平台删除成功后，后端删除本地 `ccdi_bank_statement` 中 `projectId + batchId(logId)` 的全部流水
7. 本地流水删除成功后，后端将 `ccdi_file_upload_record.file_status` 更新为 `deleted`
8. 前端收到成功响应后刷新列表与统计

### 一致性原则

删除必须遵守“先平台、后本地、再改状态”：

- 平台删除失败：不删本地流水，不更新记录状态
- 本地流水删除失败：不更新记录状态为 `deleted`
- 状态更新失败：整体按失败返回，避免界面和数据不一致

### 后端接口设计

新增接口建议：

- `DELETE /ccdi/file-upload/{id}`

接口语义：

- 按上传记录 ID 删除对应文件
- 仅允许删除 `parsed_success` 状态记录

返回规则：

- 成功：`AjaxResult.success("删除成功")`
- 失败：`AjaxResult.error("具体失败原因")`

### 后端服务设计

服务层新增删除方法，职责包括：

- 查询上传记录
- 校验项目归属与状态
- 组装 `DeleteFilesRequest`
- 调用 `LsfxAnalysisClient.deleteFiles`
- 删除本地银行流水
- 更新上传记录状态为 `deleted`

建议保持数据库层面不新增表结构，仅扩展状态值和相关逻辑。

### 前端交互设计

上传文件列表新增“操作”列。

操作规则：

- `parsed_failed`：点击“查看错误原因”，弹出错误信息弹窗
- `parsed_success`：点击“删除”，弹出确认框
- `deleted`：显示状态“已删除”，无操作按钮

删除确认文案建议：

`删除后将同步删除流水分析平台中的文件，并清除本系统中该文件对应的所有银行流水数据，是否继续？`

删除成功后：

- 提示“删除成功”
- 刷新列表
- 刷新统计

### 统计设计

当前统计 VO 仅统计：

- `uploading`
- `parsing`
- `parsedSuccess`
- `parsedFailed`
- `total`

本次建议扩展：

- `deleted`

这样前端统计口径可以完整覆盖全部状态，也便于后续展示已删除数量。

如果短期内页面不展示该数字，也建议后端先统一支持，避免状态被统计遗漏。

## 影响范围

### 后端

- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiFileUploadController.java`
- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiFileUploadService.java`
- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiFileUploadServiceImpl.java`
- `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiFileUploadStatisticsVO.java`
- `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiFileUploadRecordMapper.xml`

### 前端

- `ruoyi-ui/src/api/ccdiProjectUpload.js`
- `ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue`

## 风险与边界

需要重点拦截以下删除场景：

- 记录不存在
- 记录不属于当前项目
- 记录状态不是 `parsed_success`
- 记录已经是 `deleted`
- 记录缺少 `lsfxProjectId`
- 记录缺少 `logId`

需要注意以下业务影响：

- 软删除后，流水明细查询将不再能查到该文件对应流水
- 上传记录会继续保留，便于审计和追溯
- 如果平台删除成功但本地状态更新失败，需要明确作为失败返回并记录日志

## 测试方案

### 后端单元测试

- 删除成功时：平台删除成功、本地流水删除成功、记录状态更新为 `deleted`
- 平台删除失败时：本地流水不删除、记录状态不变
- 本地流水删除失败时：记录状态不变
- 非 `parsed_success` 状态删除时返回失败
- `deleted` 状态重复删除时返回失败
- 缺少 `logId` 或 `lsfxProjectId` 时返回失败

### 控制器测试

- 删除接口成功返回正确消息
- Service 抛出异常时返回错误消息

### 前端测试

- `parsed_failed` 状态显示“查看错误原因”
- `parsed_success` 状态显示“删除”
- `deleted` 状态显示“已删除”且不显示操作按钮
- 删除前弹出二次确认
- 删除成功后刷新列表和统计
- 错误原因弹窗能正确显示 `errorMessage`

## 验收标准

- 上传文件列表新增“操作”列
- 解析失败文件可以查看错误原因
- 解析成功文件可以二次确认后删除
- 删除成功后已调用流水分析平台删除接口
- 删除成功后本地银行流水数据被清理
- 删除成功后上传记录仍保留，状态显示为“已删除”
- 已删除记录不再出现删除按钮

---

**设计日期：** 2026-03-16
**设计人员：** Codex
**审核状态：** 已确认
