Files
ccdi/docs/design/2026-03-29-project-detail-risk-overview-risk-people-pagination-design.md

10 KiB
Raw Blame History

项目详情风险总览员工列表分页设计文档

模块: 项目详情 - 结果总览 - 风险总览员工列表 日期: 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.overviewListRiskPeopleSection.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/peopleemployee-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 返回结构

返回结构统一为:

{
  "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=1pageSize=5
  3. 构造 MyBatis Plus Page
  4. 调用 mapper 分页查询
  5. 将记录映射为现有员工列表行结构
  6. 返回 rows + total + pageNum + pageSize

7.3 VO 调整

CcdiProjectRiskPeopleOverviewVO 改为标准分页 VO字段包括

  • List<CcdiProjectRiskPeopleOverviewItemVO> 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. 翻页仅刷新员工列表,不重载结果总览其他区块

该方案满足需求边界明确、链路完整、实现路径最短,且不引入额外补丁接口或兼容分支。