# 项目详情风险总览员工列表分页设计文档 **模块**: 项目详情 - 结果总览 - 风险总览员工列表 **日期**: 2026-03-29 ## 一、背景 当前项目详情页 `结果总览 -> 风险总览` 中的员工列表直接消费 `GET /ccdi/project/overview/risk-people` 返回的全量 `overviewList`。页面没有分页能力,项目内风险员工较多时会导致: 1. 单屏信息过长,浏览成本高。 2. 前端一次性渲染全量列表,交互体验不稳定。 3. 接口返回风格与当前结果总览域内其他分页接口不一致。 本轮需求要求为该员工列表增加分页,并固定为每页 5 条。同时,需求明确要求改造现有接口,不采用前端本地切片或新增补丁接口的方式。 ## 二、目标 本次设计目标如下: 1. 将 `GET /ccdi/project/overview/risk-people` 改造成真实分页接口。 2. 风险总览员工列表固定每页展示 5 条。 3. 前端翻页时仅刷新员工列表,不影响结果总览内其他区块。 4. 分页接口返回结构对齐项目现有分页风格,统一为 `rows + total + pageNum + pageSize`。 ## 三、范围 ### 3.1 本次范围 - 改造 `risk-people` 接口入参与返回结构 - 为后端风险人员查询增加数据库分页 - 调整项目详情结果总览首屏数据装配 - 在 `RiskPeopleSection.vue` 增加分页条与翻页请求 - 补充本次设计文档、设计记录,以及后续前后端实施计划入口 ### 3.2 不在本次范围 - 不修改风险仪表盘接口 - 不修改风险模型卡片与模型命中人员查询 - 不修改风险明细区块 - 不新增筛选条件、搜索条件或排序条件 - 不修改风险等级、命中模型数、核心异常点的业务口径 - 不删除现有 `GET /ccdi/project/overview/top-risk-people` ## 四、现状分析 ### 4.1 前端现状 当前 `PreliminaryCheck.vue` 在页面加载时并发请求: - `GET /ccdi/project/overview/dashboard` - `GET /ccdi/project/overview/risk-people` - `GET /ccdi/project/overview/risk-models/cards` - `GET /ccdi/project/overview/suspicious-transactions` - `GET /ccdi/project/overview/employee-credit-negative` 其中 `risk-people` 的返回结果被直接注入 `currentData.riskPeople.overviewList`,`RiskPeopleSection.vue` 直接用该数组渲染表格,没有分页状态,也没有独立二次加载链路。 ### 4.2 后端现状 当前 `CcdiProjectOverviewController.getRiskPeople(Long projectId)` 只接收项目 ID。 `CcdiProjectOverviewServiceImpl.getRiskPeopleOverview(Long projectId)` 的实现为: 1. 校验项目存在 2. 调用 `overviewMapper.selectRiskPeopleOverviewByProjectId(projectId)` 查询全量员工结果 3. 在 Java 层逐行映射为 `overviewList` 4. 返回 `CcdiProjectRiskPeopleOverviewVO { overviewList }` 当前 SQL 直接从 `ccdi_project_overview_employee_result` 查询并排序: - `risk_level_sort asc` - `model_count desc` - `rule_count desc` - `staff_id_card asc` 现状能够提供正确列表语义,但不具备分页能力。 ## 五、方案对比 ### 5.1 方案 A:改造现有 `risk-people` 为标准分页接口 做法: - 保持接口路径不变 - 入参扩展为 `projectId + pageNum + pageSize` - 返回结构改为 `rows + total + pageNum + pageSize` - 后端通过数据库分页查询返回当前页数据 - 前端首屏与翻页统一走该接口 优点: - 满足“改接口”的明确要求 - 与 `risk-models/people`、`employee-credit-negative` 的分页风格一致 - 逻辑单一,没有重复接口 - 数据量增大时性能与语义都正确 缺点: - 需要同步调整前后端契约与测试 ### 5.2 方案 B:新增 `risk-people/page`,保留原接口不动 做法: - 原 `risk-people` 继续返回全量列表 - 新增单独分页接口供前端切换 问题: - 留下两个语义重复的接口 - 不符合“改接口”的要求 - 增加后续维护成本 ### 5.3 方案 C:后端仍全量查,Java 或前端再切页 做法: - 接口表面返回分页结构 - 实际仍走全量查询后截断 问题: - 不是真分页 - 数据量增大时性能与语义都不成立 - 属于补丁式方案,不符合最短路径要求 ### 5.4 结论 采用方案 A。 ## 六、接口设计 ### 6.1 接口路径 - `GET /ccdi/project/overview/risk-people` ### 6.2 入参 - `projectId`: 项目 ID,必填 - `pageNum`: 页码,非必填,默认 `1` - `pageSize`: 每页条数,非必填,默认 `5` 说明: - 前端固定传 `pageSize = 5` - 后端默认值同样收敛为 `5`,避免前端漏传时行为偏移 ### 6.3 返回结构 返回结构统一为: ```json { "rows": [ { "name": "李四", "idNo": "330000000000000001", "department": "信息二部", "riskCount": 5, "riskLevel": "中风险", "riskLevelType": "warning", "modelCount": 4, "riskPoint": "大额单笔收入、疑似兼职", "actionLabel": "查看项目" } ], "total": 18, "pageNum": 1, "pageSize": 5 } ``` 说明: - 原 `overviewList` 字段移除,统一改为 `rows` - 单行字段保持现有页面绑定语义不变 - 本次不引入额外统计字段 ## 七、后端设计 ### 7.1 控制器 `CcdiProjectOverviewController.getRiskPeople` 改为接收独立 DTO,例如: - `CcdiProjectRiskPeopleQueryDTO` DTO 仅包含: - `projectId` - `pageNum` - `pageSize` 不额外引入筛选项,保持最短路径。 ### 7.2 服务层 `ICcdiProjectOverviewService.getRiskPeopleOverview` 改为接收查询 DTO,并返回分页 VO。 服务层职责: 1. 校验项目存在 2. 规范化分页参数,默认 `pageNum=1`、`pageSize=5` 3. 构造 MyBatis Plus `Page` 4. 调用 mapper 分页查询 5. 将记录映射为现有员工列表行结构 6. 返回 `rows + total + pageNum + pageSize` ### 7.3 VO 调整 `CcdiProjectRiskPeopleOverviewVO` 改为标准分页 VO,字段包括: - `List rows` - `Long total` - `Long pageNum` - `Long pageSize` 说明: - `CcdiProjectRiskPeopleOverviewItemVO` 本身字段不做语义调整 - 既有的风险等级映射与异常点标签来源保持不变 ### 7.4 Mapper 与 SQL Mapper 从“全量列表查询”改为“分页查询”,直接在数据库层完成分页。 排序规则保持现状不变: - `risk_level_sort asc` - `model_count desc` - `rule_count desc` - `staff_id_card asc` 数据来源继续使用 `ccdi_project_overview_employee_result`,不新增统计口径,不回退到历史复杂聚合链路。 ### 7.5 默认值与边界 - `projectId` 为空时沿用现有参数校验/项目不存在校验逻辑 - `pageNum <= 0` 时按 `1` 处理 - `pageSize <= 0` 或为空时按 `5` 处理 - 本次不开放前端修改每页条数,接口虽接收 `pageSize`,但页面固定使用 5 ## 八、前端设计 ### 8.1 API 封装 `ruoyi-ui/src/api/ccdi/projectOverview.js` 中: - `getOverviewRiskPeople` 从接收单个 `projectId` 改为接收 `params` - 透传: - `projectId` - `pageNum` - `pageSize` ### 8.2 首屏加载 `PreliminaryCheck.vue` 首次加载结果总览时,请求: - `getOverviewRiskPeople({ projectId, pageNum: 1, pageSize: 5 })` 返回结果注入 `currentData.riskPeople` 时,直接保存分页结构: - `rows` - `total` - `pageNum` - `pageSize` 页面是否进入 `loaded` 状态的判断,从原来的 `overviewList.length` 改为 `rows.length`。 ### 8.3 风险总览员工列表组件 `RiskPeopleSection.vue` 调整为: 1. 表格数据源从 `sectionData.overviewList` 改为 `sectionData.rows` 2. 在表格下方增加分页组件 3. 分页组件固定: - `:page-sizes="[5]"` - `layout="total, prev, pager, next, jumper"` 4. 页码变化时触发独立请求,仅刷新员工列表分页数据 分页条展示规则: - `total > 0` 时展示 - `total = 0` 时隐藏 ### 8.4 页面刷新策略 翻页时只刷新风险总览员工列表,不重新拉取: - 风险仪表盘 - 风险模型卡片 - 风险明细涉疑交易 - 风险明细员工负面征信 这样可以避免其他区块闪动,也避免把简单翻页放大成整页重载。 ### 8.5 交互保持不变 以下内容本次保持不变: - 表格列顺序 - 风险等级标签渲染 - 核心异常点标签拆分与色板逻辑 - 操作列文案与点击事件 - 空态文案 ## 九、测试设计 ### 9.1 后端测试 新增或调整以下验证: 1. Controller 测试 - 断言 `/risk-people` 接口改为接收 DTO - 断言返回 `rows + total + pageNum + pageSize` 2. Service 测试 - 断言服务层使用分页参数构造 `Page` - 断言现有字段映射未变化 - 断言默认分页参数回落为 `1 / 5` 3. Mapper/SQL 测试 - 断言风险人员查询改为分页查询方法 - 断言排序字段未变化 - 断言数据来源仍为 `ccdi_project_overview_employee_result` ### 9.2 前端测试 新增或调整以下验证: 1. API 封装测试 - 断言 `getOverviewRiskPeople(params)` 透传 `projectId/pageNum/pageSize` 2. 页面接入测试 - 断言 `PreliminaryCheck.vue` 首次加载传 `pageNum: 1` - 断言固定传 `pageSize: 5` - 断言风险人员数据改为读取 `rows` 3. 风险总览组件测试 - 断言 `RiskPeopleSection.vue` 存在分页组件 - 断言分页绑定 `rows/total/pageNum/pageSize` - 断言分页大小固定为 5 ## 十、实施文档要求 本次设计确认后,按仓库规范继续产出两份实施计划: - 后端实施计划:`docs/plans/backend/` - 前端实施计划:`docs/plans/frontend/` 实施完成后,补充对应实施记录,记录本次真实改动内容。 ## 十一、结论 本次需求本质是将结果总览中的风险员工列表从“全量列表展示”升级为“标准分页列表展示”。 最终方案为: 1. 保持 `GET /ccdi/project/overview/risk-people` 路径不变 2. 改为标准分页接口,返回 `rows + total + pageNum + pageSize` 3. 后端在数据库层做真分页,默认每页 5 条 4. 前端首屏和翻页统一走该接口 5. 翻页仅刷新员工列表,不重载结果总览其他区块 该方案满足需求边界明确、链路完整、实现路径最短,且不引入额外补丁接口或兼容分支。