# 项目详情风险总览人员列表导出设计文档

**模块**: 项目详情 - 结果总览 - 风险总览人员列表导出  
**日期**: 2026-03-30  
**作者**: Codex  
**状态**: 已确认

## 一、背景

当前项目详情页 `结果总览 -> 风险总览` 中的人员列表已经支持分页展示与“查看项目”操作，但列表上方的“导出”按钮仍未接入真实导出能力。

结合现有页面语义与本次确认结果，本轮需求要求：

1. 在 `开发风险总览` 的人员列表中补齐真实导出能力。
2. 导出范围为当前项目下的全部风险人员，而不是当前分页 5 条。
3. 导出字段口径必须与页面表格保持一致。
4. 导出文件中不包含“操作”列。

## 二、目标

本次设计目标如下：

1. 为风险总览人员列表新增独立导出接口。
2. 前端点击“导出”按钮后可直接下载 Excel 文件。
3. 导出字段与页面展示字段保持一致：
   - 姓名
   - 身份证号
   - 所属部门
   - 疑似违规数
   - 风险等级
   - 命中模型数
   - 核心异常点
4. 分页展示与导出逻辑解耦，翻页不影响导出范围。

## 三、范围

### 3.1 本次范围

- 新增风险总览人员列表导出接口
- 新增风险总览人员导出 Excel 对象
- 为前端“导出”按钮绑定真实下载动作
- 补充本次设计文档，以及后续前后端实施计划入口

### 3.2 不在本次范围

- 不新增筛选条件、排序条件、搜索条件
- 不修改风险总览人员列表当前分页查询逻辑
- 不修改风险模型区、风险明细区功能
- 不修改人员详情、项目分析弹窗链路
- 不新增导出确认弹窗、二次筛选或降级方案

## 四、现状分析

### 4.1 前端现状

当前核心组件为：

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

当前组件已经具备：

1. 表格字段展示
2. “查看项目”操作
3. 固定每页 5 条的分页能力
4. 顶部“导出”按钮文案

但当前“导出”按钮尚未绑定点击事件，也未接入下载接口。

### 4.2 后端现状

当前结果总览控制器为：

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

已具备以下相关能力：

1. `GET /ccdi/project/overview/risk-people`：分页查询风险人员总览
2. `POST /ccdi/project/overview/suspicious-transactions/export`：导出涉疑交易明细
3. `POST /ccdi/project/overview/risk-details/export`：统一导出风险明细

说明当前结果总览域内已经存在标准后端导出模式：

- 控制器暴露导出接口
- 服务层返回导出行对象列表
- 使用 `ExcelUtil` 输出 Excel 文件

风险人员列表本身已经有稳定的查询与字段组装逻辑：

1. 服务层通过 `getRiskPeopleOverview(CcdiProjectRiskPeopleQueryDTO queryDTO)` 查询分页数据
2. 使用 `buildRiskPeopleItem(projectId, aggregate)` 统一组装单行字段

因此，本次导出最合理的方式是复用现有字段组装逻辑，而不是重新设计一套独立口径。

## 五、方案对比

### 5.1 方案 A：新增后端导出接口，复用现有人员字段组装逻辑

做法：

- 新增 `POST /ccdi/project/overview/risk-people/export`
- 前端导出按钮直接调用下载接口
- 后端按当前项目查询全部风险人员
- 复用现有人员列表组装逻辑，再映射到 Excel 对象

优点：

- 最符合当前仓库导出模式
- 前端改动最小
- 页面字段与导出口径最容易保持一致
- 不会把分页展示逻辑和导出逻辑耦合在一起

缺点：

- 需要补一个导出 Excel 对象与对应测试

### 5.2 方案 B：前端请求超大分页，自行导出 Excel

做法：

- 点击导出时调用 `risk-people` 接口并传超大 `pageSize`
- 前端拿到全量数据后自行生成文件

问题：

- 不符合当前仓库常用导出模式
- 页面查询接口与导出职责混杂
- 前端文件生成链路与现有维护方式不一致

### 5.3 方案 C：新增导出接口，但单独写一套导出 SQL 和字段组装

做法：

- 后端新写独立导出查询
- 页面查询与导出查询分别维护

问题：

- 页面与导出会形成两套口径
- 后续字段扩展时最容易出现偏移
- 不符合最短路径要求

### 5.4 结论

采用 **方案 A：新增后端导出接口，复用现有人员字段组装逻辑**。

## 六、总体设计

### 6.1 交互链路

点击“导出”后的数据流如下：

1. 用户在 `RiskPeopleSection.vue` 点击“导出”按钮。
2. 前端通过 `this.download(...)` 调用新的后端导出接口。
3. 前端仅传 `projectId`，不传当前页码、页大小等分页参数。
4. 控制器接收请求后调用 `overviewService.exportRiskPeopleOverview(projectId)`。
5. 服务层校验项目存在后，查询当前项目下全部风险人员。
6. 服务层复用现有风险人员字段组装逻辑，生成 Excel 行对象列表。
7. 控制器使用 `ExcelUtil` 输出 `xlsx` 文件。

### 6.2 导出范围

导出范围固定为：

- 当前项目下的全部风险人员

说明：

- 不受当前分页影响
- 不只导出当前页 5 条
- 不增加额外筛选条件

### 6.3 导出字段

导出列固定如下：

1. 姓名
2. 身份证号
3. 所属部门
4. 疑似违规数
5. 风险等级
6. 命中模型数
7. 核心异常点

约束：

- 不导出“操作”列
- 不导出页面专用辅助字段，例如 `riskLevelType`
- 核心异常点展示口径需与页面一致

## 七、后端设计

### 7.1 控制器

在 `CcdiProjectOverviewController` 中新增导出接口：

- `POST /ccdi/project/overview/risk-people/export`

接口入参：

- `projectId`

权限控制沿用当前结果总览域的查询权限，不单独新增本轮设计范围外的权限体系。

### 7.2 服务层

在 `ICcdiProjectOverviewService` 与实现类中新增方法：

- `List<CcdiProjectRiskPeopleOverviewExcel> exportRiskPeopleOverview(Long projectId)`

服务层职责：

1. 校验项目存在
2. 查询当前项目全部风险人员
3. 复用现有人员列表字段组装逻辑
4. 将页面字段映射为导出对象
5. 返回 Excel 数据列表

### 7.3 查询策略

导出查询不复用当前分页接口返回值，也不走前端多页聚合。

建议实现方式：

1. 后端直接基于现有风险人员数据来源查询当前项目全部记录
2. 排序口径与分页列表保持一致：
   - `risk_level_sort asc`
   - `model_count desc`
   - `rule_count desc`
   - `staff_id_card asc`

这样可以保证页面与导出的记录顺序一致。

### 7.4 导出对象

新增导出对象：

- `CcdiProjectRiskPeopleOverviewExcel`

字段包含：

- `name`
- `idNo`
- `department`
- `riskCount`
- `riskLevel`
- `modelCount`
- `riskPoint`

其中：

- `riskPoint` 需要输出与页面“核心异常点”一致的文本口径
- 如果页面当前优先使用 `riskPointTagList` 组装展示，则导出时也应使用同样的归并顺序

## 八、前端设计

### 8.1 API 封装

在 `ruoyi-ui/src/api/ccdi/projectOverview.js` 中新增导出调用入口，供组件通过 `this.download(...)` 使用。

接口路径：

- `ccdi/project/overview/risk-people/export`

### 8.2 组件交互

在 `RiskPeopleSection.vue` 中：

1. 为当前“导出”按钮绑定点击事件
2. 点击后调用下载方法
3. 仅传 `projectId`
4. 文件名统一使用时间戳后缀

建议文件名：

- `风险人员总览_<timestamp>.xlsx`

### 8.3 交互约束

- 不新增确认弹窗
- 不新增 loading 外挂交互
- 不修改现有分页逻辑
- 不影响“查看项目”按钮行为

## 九、异常处理

本次导出错误处理遵循结果总览当前后端风格：

1. `projectId` 为空或项目不存在时，导出直接失败。
2. 查询异常或 Excel 生成异常时，导出整体失败。
3. 不生成空白文件作为兜底结果。
4. 不引入静默降级或兼容性补丁分支。

字段空值处理约束：

- 若部分字段为空，按现有页面语义导出为空字符串或统一文本结果
- 不因单行字段为空而跳过整行

## 十、测试口径

### 10.1 后端验证

需要验证：

1. 新增导出接口路径正确，且能委托到服务层
2. 导出服务会校验项目存在
3. 导出结果为当前项目全部风险人员，而不是当前页
4. 导出字段顺序与名称正确
5. 导出数据口径与页面表格一致

### 10.2 前端验证

需要验证：

1. “导出”按钮已绑定下载动作
2. 下载请求只传 `projectId`
3. 翻页功能仍正常
4. “查看项目”功能仍正常

## 十一、实施计划输出要求

根据仓库约定，进入实施阶段时默认同步输出两份实施计划：

1. 后端实施计划：`docs/plans/backend/`
2. 前端实施计划：`docs/plans/frontend/`

同时补充：

- 实施记录：`docs/reports/implementation/`
- 测试记录：`docs/tests/records/`

## 十二、结论

本次功能采用“后端新增导出接口 + 复用现有风险人员字段组装逻辑 + 前端按钮直连下载”的实现方式。

该方案满足以下要求：

1. 导出范围为当前项目全部风险人员
2. 导出字段与页面口径一致
3. 不引入额外筛选、补丁或兼容性分支
4. 改动路径短，符合当前仓库的导出实现风格
