补充风险总览员工列表分页实施计划
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
# Project Detail Risk Overview Risk People Pagination Backend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
>
|
||||
> **Repo note:** 本仓库 `AGENTS.md` 明确禁止开启 subagent,执行本计划时请在当前会话使用 `superpowers:executing-plans`。
|
||||
|
||||
**Goal:** 将 `GET /ccdi/project/overview/risk-people` 改造成标准分页接口,固定默认每页 5 条,保证项目详情“风险总览”员工列表按数据库真分页返回 `rows + total + pageNum + pageSize`。
|
||||
|
||||
**Architecture:** 后端继续沿用 `CcdiProjectOverviewController -> ICcdiProjectOverviewService -> CcdiProjectOverviewServiceImpl -> CcdiProjectOverviewMapper.xml` 这一条结果总览链路,不新增补丁接口。接口路径保持不变,只引入独立分页查询 DTO、分页 VO 和 MyBatis Plus `Page` 查询;数据来源继续使用 `ccdi_project_overview_employee_result`,排序规则保持现状,不新增筛选口径。
|
||||
|
||||
**Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus `Page`, MyBatis XML, Maven, JUnit 5, Mockito, Swagger/OpenAPI
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 建立 `risk-people` 分页接口契约
|
||||
|
||||
**Files:**
|
||||
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectRiskPeopleQueryDTO.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectRiskPeopleOverviewVO.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定 DTO、VO 字段和 Controller / Service 新签名**
|
||||
|
||||
```java
|
||||
assertNotNull(clazz.getMethod(
|
||||
"getRiskPeopleOverview",
|
||||
Class.forName("com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskPeopleQueryDTO")
|
||||
));
|
||||
```
|
||||
|
||||
```java
|
||||
Method method = CcdiProjectOverviewController.class.getMethod(
|
||||
"getRiskPeople",
|
||||
CcdiProjectRiskPeopleQueryDTO.class
|
||||
);
|
||||
assertEquals("/risk-people", method.getAnnotation(GetMapping.class).value()[0]);
|
||||
```
|
||||
|
||||
```java
|
||||
CcdiProjectRiskPeopleOverviewVO overview = new CcdiProjectRiskPeopleOverviewVO();
|
||||
overview.setRows(List.of(item));
|
||||
overview.setTotal(1L);
|
||||
overview.setPageNum(1L);
|
||||
overview.setPageSize(5L);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行结构测试与控制器测试,确认当前仓库仍是旧全量契约**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `CcdiProjectOverviewServiceStructureTest` 因缺少 DTO 签名而失败
|
||||
- `CcdiProjectOverviewControllerTest` 仍断言 `getRiskPeople(Long projectId)`,与新契约不匹配
|
||||
|
||||
- [ ] **Step 3: 写最小 DTO / VO / Controller / Service 契约**
|
||||
|
||||
```java
|
||||
@Data
|
||||
public class CcdiProjectRiskPeopleQueryDTO {
|
||||
private Long projectId;
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@GetMapping("/risk-people")
|
||||
public AjaxResult getRiskPeople(CcdiProjectRiskPeopleQueryDTO queryDTO) {
|
||||
CcdiProjectRiskPeopleOverviewVO overview = overviewService.getRiskPeopleOverview(queryDTO);
|
||||
return AjaxResult.success(overview);
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@Data
|
||||
public class CcdiProjectRiskPeopleOverviewVO {
|
||||
private List<CcdiProjectRiskPeopleOverviewItemVO> rows;
|
||||
private Long total;
|
||||
private Long pageNum;
|
||||
private Long pageSize;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑契约测试,确认分页接口外壳已建立**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- 控制器测试明确返回 `rows + total + pageNum + pageSize`
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectRiskPeopleQueryDTO.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectRiskPeopleOverviewVO.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/CcdiProjectOverviewServiceStructureTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewControllerTest.java
|
||||
git commit -m "改造风险总览员工列表分页接口契约"
|
||||
```
|
||||
|
||||
### Task 2: 将风险人员查询改为数据库分页
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java`
|
||||
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml`
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java`
|
||||
- Test: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定分页查询方法名、排序和分页参数默认值**
|
||||
|
||||
```java
|
||||
String riskPeopleSql = extractSelect(xml, "selectRiskPeopleOverviewPage");
|
||||
assertTrue(riskPeopleSql.contains("from ccdi_project_overview_employee_result"), riskPeopleSql);
|
||||
assertTrue(riskPeopleSql.contains("result.project_id = #{query.projectId}"), riskPeopleSql);
|
||||
assertTrue(
|
||||
riskPeopleSql.contains("order by risk_level_sort asc, result.model_count desc, result.rule_count desc, result.staff_id_card asc"),
|
||||
riskPeopleSql
|
||||
);
|
||||
assertFalse(riskPeopleSql.contains("limit 10"), riskPeopleSql);
|
||||
```
|
||||
|
||||
```java
|
||||
verify(overviewMapper).selectRiskPeopleOverviewPage(
|
||||
argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
|
||||
argThat(query -> query.getProjectId().equals(40L))
|
||||
);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行 SQL 与 Service 测试,确认当前实现仍是全量查询**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- SQL 测试提示缺少 `selectRiskPeopleOverviewPage`
|
||||
- Service 测试因仍调用 `selectRiskPeopleOverviewByProjectId` 而失败
|
||||
|
||||
- [ ] **Step 3: 写最小分页 SQL 与服务实现**
|
||||
|
||||
```java
|
||||
Page<CcdiProjectEmployeeRiskAggregateVO> page = new Page<>(
|
||||
defaultPageNum(queryDTO.getPageNum()),
|
||||
defaultPageSize(queryDTO.getPageSize())
|
||||
);
|
||||
Page<CcdiProjectEmployeeRiskAggregateVO> resultPage =
|
||||
overviewMapper.selectRiskPeopleOverviewPage(page, queryDTO);
|
||||
```
|
||||
|
||||
```java
|
||||
overview.setRows(defaultList(resultPage == null ? null : resultPage.getRecords())
|
||||
.stream()
|
||||
.map(aggregate -> buildRiskPeopleItem(queryDTO.getProjectId(), aggregate))
|
||||
.toList());
|
||||
overview.setTotal(resultPage == null ? 0L : resultPage.getTotal());
|
||||
overview.setPageNum(page.getCurrent());
|
||||
overview.setPageSize(page.getSize());
|
||||
```
|
||||
|
||||
```xml
|
||||
<select id="selectRiskPeopleOverviewPage" resultMap="EmployeeRiskAggregateResultMap">
|
||||
select
|
||||
result.staff_id_card,
|
||||
result.staff_name,
|
||||
result.dept_id,
|
||||
result.dept_name,
|
||||
result.rule_count,
|
||||
result.model_count,
|
||||
result.hit_count,
|
||||
null as top_rule_code,
|
||||
null as top_rule_name,
|
||||
result.risk_point,
|
||||
result.risk_level_code,
|
||||
case
|
||||
when result.risk_level_code = 'HIGH' then '高风险'
|
||||
when result.risk_level_code = 'MEDIUM' then '中风险'
|
||||
else '低风险'
|
||||
end as risk_level_name,
|
||||
case
|
||||
when result.risk_level_code = 'HIGH' then 1
|
||||
when result.risk_level_code = 'MEDIUM' then 2
|
||||
else 3
|
||||
end as risk_level_sort
|
||||
from ccdi_project_overview_employee_result result
|
||||
where result.project_id = #{query.projectId}
|
||||
order by risk_level_sort asc, result.model_count desc, result.rule_count desc, result.staff_id_card asc
|
||||
</select>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑分页相关测试,确认改成真分页且字段映射不变**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- `shouldMapRiskPeopleOverviewRows` 改为断言 `rows`
|
||||
- 新增断言 `total/pageNum/pageSize`
|
||||
- `riskLevel/riskLevelType/modelCount/riskPointTagList` 保持原语义
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java \
|
||||
ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml \
|
||||
ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java
|
||||
git commit -m "实现风险总览员工列表后端分页查询"
|
||||
```
|
||||
|
||||
### Task 3: 补齐分页默认值与项目不存在回归
|
||||
|
||||
**Files:**
|
||||
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java`
|
||||
- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定 `pageNum/pageSize` 缺省回落为 `1/5`**
|
||||
|
||||
```java
|
||||
CcdiProjectRiskPeopleQueryDTO queryDTO = new CcdiProjectRiskPeopleQueryDTO();
|
||||
queryDTO.setProjectId(40L);
|
||||
|
||||
service.getRiskPeopleOverview(queryDTO);
|
||||
|
||||
verify(overviewMapper).selectRiskPeopleOverviewPage(
|
||||
argThat(page -> page.getCurrent() == 1L && page.getSize() == 5L),
|
||||
any(CcdiProjectRiskPeopleQueryDTO.class)
|
||||
);
|
||||
```
|
||||
|
||||
```java
|
||||
CcdiProjectRiskPeopleQueryDTO invalidQuery = new CcdiProjectRiskPeopleQueryDTO();
|
||||
invalidQuery.setProjectId(40L);
|
||||
invalidQuery.setPageNum(0);
|
||||
invalidQuery.setPageSize(-1);
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行 Service 测试,确认当前没有锁死默认值**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 新增默认值断言失败
|
||||
|
||||
- [ ] **Step 3: 在 Service 中复用现有默认分页工具方法或补充最小默认值逻辑**
|
||||
|
||||
```java
|
||||
private long defaultRiskPeoplePageNum(Integer pageNum) {
|
||||
return pageNum == null || pageNum <= 0 ? 1L : pageNum.longValue();
|
||||
}
|
||||
|
||||
private long defaultRiskPeoplePageSize(Integer pageSize) {
|
||||
return pageSize == null || pageSize <= 0 ? 5L : pageSize.longValue();
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑 Service 测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- `项目不存在` 的旧异常断言仍通过
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java \
|
||||
ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImplTest.java
|
||||
git commit -m "补齐风险总览员工列表分页默认值"
|
||||
```
|
||||
|
||||
### Task 4: 补齐后端验证记录与实施记录
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md`
|
||||
- Create: `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md`
|
||||
- Verify: `docs/design/2026-03-29-project-detail-risk-overview-risk-people-pagination-design.md`
|
||||
|
||||
- [ ] **Step 1: 运行本需求后端最小回归**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
mvn -pl ccdi-project -Dtest=CcdiProjectOverviewServiceStructureTest,CcdiProjectOverviewControllerTest,CcdiProjectOverviewMapperSqlTest,CcdiProjectOverviewServiceImplTest test
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- `risk-people` 分页契约、SQL 和服务映射全部通过
|
||||
|
||||
- [ ] **Step 2: 写后端验证记录**
|
||||
|
||||
在 `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md` 记录:
|
||||
|
||||
- 执行命令
|
||||
- 执行日期
|
||||
- 测试结果
|
||||
- 结论:`risk-people` 已改为标准分页接口,默认每页 5 条
|
||||
|
||||
- [ ] **Step 3: 写后端实施记录**
|
||||
|
||||
在 `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md` 记录:
|
||||
|
||||
- 改造的 Controller / Service / Mapper / SQL / 测试文件
|
||||
- 返回结构从 `overviewList` 迁移到 `rows`
|
||||
- 排序规则保持不变
|
||||
- 本次未新增补丁接口
|
||||
|
||||
- [ ] **Step 4: 检查暂存区仅包含本任务文件**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 暂存区只出现本任务相关后端源码、测试和文档
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-verification.md \
|
||||
docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md
|
||||
git commit -m "补充风险总览员工列表后端分页实施记录"
|
||||
```
|
||||
|
||||
## Done When
|
||||
|
||||
- `GET /ccdi/project/overview/risk-people` 已改为接收 `projectId + pageNum + pageSize`
|
||||
- 接口返回 `rows + total + pageNum + pageSize`
|
||||
- SQL 基于 `ccdi_project_overview_employee_result` 实现真分页
|
||||
- 默认分页固定回落为 `1 / 5`
|
||||
- 后端验证记录与实施记录已补齐
|
||||
@@ -0,0 +1,376 @@
|
||||
# Project Detail Risk Overview Risk People Pagination Frontend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
>
|
||||
> **Repo note:** 本仓库 `AGENTS.md` 明确禁止开启 subagent,执行本计划时请在当前会话使用 `superpowers:executing-plans`。
|
||||
|
||||
**Goal:** 让项目详情“风险总览”的员工列表改为固定每页 5 条的真实后端分页,并保证翻页时只刷新该列表,不重载结果总览内其他区块。
|
||||
|
||||
**Architecture:** 前端继续以 `PreliminaryCheck.vue` 作为结果总览入口,首屏加载第一页风险员工数据并透传给 `RiskPeopleSection.vue`。`RiskPeopleSection.vue` 接管分页状态、请求 loading 和翻页动作,直接调用 `projectOverview.js` 中改造后的 `getOverviewRiskPeople(params)`,避免在翻页时重新触发整页 `Promise.all`。
|
||||
|
||||
**Tech Stack:** Vue 2, Element UI, SCSS, axios request 封装, Node `assert` 结构测试
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 改造风险员工分页 API 封装
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/api/ccdi/projectOverview.js`
|
||||
- Test: `ruoyi-ui/tests/unit/project-overview-api.test.js`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定 `getOverviewRiskPeople` 改为参数对象透传**
|
||||
|
||||
```javascript
|
||||
[
|
||||
"getOverviewRiskPeople(params)",
|
||||
"/ccdi/project/overview/risk-people",
|
||||
"projectId: params.projectId",
|
||||
"pageNum: params.pageNum",
|
||||
"pageSize: params.pageSize",
|
||||
].forEach((token) => assert(source.includes(token), token));
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行 API 契约测试,确认当前仍是旧签名**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/project-overview-api.test.js
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- FAIL,提示 `getOverviewRiskPeople(projectId)` 仍是旧写法
|
||||
|
||||
- [ ] **Step 3: 写最小 API 封装**
|
||||
|
||||
```javascript
|
||||
export function getOverviewRiskPeople(params) {
|
||||
return request({
|
||||
url: "/ccdi/project/overview/risk-people",
|
||||
method: "get",
|
||||
params: {
|
||||
projectId: params.projectId,
|
||||
pageNum: params.pageNum,
|
||||
pageSize: params.pageSize,
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑 API 测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/project-overview-api.test.js
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/api/ccdi/projectOverview.js \
|
||||
ruoyi-ui/tests/unit/project-overview-api.test.js
|
||||
git commit -m "改造风险总览员工列表前端分页接口"
|
||||
```
|
||||
|
||||
### Task 2: 让结果总览首屏按分页结构装配风险员工数据
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue`
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js`
|
||||
- Modify: `ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js`
|
||||
- Create: `ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination-load.test.js`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定父组件首屏请求第一页且固定 5 条**
|
||||
|
||||
```javascript
|
||||
[
|
||||
"getOverviewRiskPeople({",
|
||||
"projectId: this.projectId",
|
||||
"pageNum: 1",
|
||||
"pageSize: 5",
|
||||
"riskPeopleData.rows",
|
||||
].forEach((token) => assert(source.includes(token), token));
|
||||
```
|
||||
|
||||
```javascript
|
||||
assert(source.includes("pageNum"), "riskPeople 应保存首屏页码");
|
||||
assert(source.includes("pageSize"), "riskPeople 应保存首屏页长");
|
||||
assert(source.includes("total"), "riskPeople 应保存总数");
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行入口页测试,确认当前还在读取 `overviewList`**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination-load.test.js
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- FAIL,提示首屏没有传 `pageNum/pageSize`
|
||||
- FAIL,提示 `riskPeopleData.rows` 未被使用
|
||||
|
||||
- [ ] **Step 3: 写最小首屏加载与 mock 归一化**
|
||||
|
||||
```javascript
|
||||
const [dashboardRes, riskPeopleRes, riskModelCardsRes, suspiciousRes, creditNegativeRes] = await Promise.all([
|
||||
getOverviewDashboard(this.projectId),
|
||||
getOverviewRiskPeople({ projectId: this.projectId, pageNum: 1, pageSize: 5 }),
|
||||
getOverviewRiskModelCards(this.projectId),
|
||||
getOverviewSuspiciousTransactions({ projectId: this.projectId, suspiciousType: "ALL", pageNum: 1, pageSize: 5 }),
|
||||
getOverviewEmployeeCreditNegative({ projectId: this.projectId, pageNum: 1, pageSize: 5 }),
|
||||
]);
|
||||
```
|
||||
|
||||
```javascript
|
||||
riskPeople: {
|
||||
...mockOverviewData.riskPeople,
|
||||
rows: Array.isArray(riskPeopleData && riskPeopleData.rows) ? riskPeopleData.rows : [],
|
||||
total: riskPeopleData && riskPeopleData.total ? riskPeopleData.total : 0,
|
||||
pageNum: riskPeopleData && riskPeopleData.pageNum ? riskPeopleData.pageNum : 1,
|
||||
pageSize: riskPeopleData && riskPeopleData.pageSize ? riskPeopleData.pageSize : 5,
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑入口页测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination-load.test.js
|
||||
```
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue \
|
||||
ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js \
|
||||
ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js \
|
||||
ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination-load.test.js
|
||||
git commit -m "接通风险总览员工列表首屏分页数据"
|
||||
```
|
||||
|
||||
### Task 3: 在 `RiskPeopleSection` 中接管独立翻页与局部刷新
|
||||
|
||||
**Files:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue`
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskPeopleSection.vue`
|
||||
- Modify: `ruoyi-ui/tests/unit/preliminary-check-risk-people-binding.test.js`
|
||||
- Create: `ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination.test.js`
|
||||
|
||||
- [ ] **Step 1: 先写失败测试,锁定组件读取 `rows`、存在分页条、固定 5 条一页**
|
||||
|
||||
```javascript
|
||||
[
|
||||
"sectionData.rows",
|
||||
"pageNum",
|
||||
"pageSize",
|
||||
"total",
|
||||
"<pagination",
|
||||
':page-sizes="[5]"',
|
||||
"handlePageChange",
|
||||
"loadRiskPeoplePage",
|
||||
"getOverviewRiskPeople",
|
||||
].forEach((token) => assert(source.includes(token), token));
|
||||
```
|
||||
|
||||
```javascript
|
||||
assert(!source.includes("sectionData.overviewList"), "风险人员列表不应再绑定 overviewList");
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 运行风险人员组件测试,确认当前没有分页状态和独立翻页逻辑**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-binding.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination.test.js
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- FAIL,提示缺少 `rows / total / pageNum / pageSize`
|
||||
- FAIL,提示缺少分页组件和翻页方法
|
||||
|
||||
- [ ] **Step 3: 写最小局部分页实现**
|
||||
|
||||
在 `PreliminaryCheck.vue` 里给子组件补传 `project-id`:
|
||||
|
||||
```vue
|
||||
<risk-people-section
|
||||
:project-id="projectId"
|
||||
:section-data="currentData.riskPeople"
|
||||
@view-project-analysis="handleRiskPeopleProjectAnalysis"
|
||||
/>
|
||||
```
|
||||
|
||||
在 `RiskPeopleSection.vue` 里维护局部分页状态与请求:
|
||||
|
||||
```javascript
|
||||
data() {
|
||||
return {
|
||||
pageNum: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
tableLoading: false,
|
||||
localRows: [],
|
||||
};
|
||||
},
|
||||
```
|
||||
|
||||
```javascript
|
||||
watch: {
|
||||
sectionData: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler(data) {
|
||||
this.localRows = normalizeOverviewRows(data && data.rows);
|
||||
this.total = (data && data.total) || 0;
|
||||
this.pageNum = (data && data.pageNum) || 1;
|
||||
this.pageSize = (data && data.pageSize) || 5;
|
||||
},
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
```javascript
|
||||
async loadRiskPeoplePage(pageNum) {
|
||||
this.tableLoading = true;
|
||||
const response = await getOverviewRiskPeople({
|
||||
projectId: this.projectId,
|
||||
pageNum,
|
||||
pageSize: 5,
|
||||
});
|
||||
const data = (response && response.data) || {};
|
||||
this.localRows = normalizeOverviewRows(data.rows);
|
||||
this.total = data.total || 0;
|
||||
this.pageNum = data.pageNum || pageNum;
|
||||
this.pageSize = data.pageSize || 5;
|
||||
this.tableLoading = false;
|
||||
}
|
||||
```
|
||||
|
||||
```javascript
|
||||
handlePageChange({ page }) {
|
||||
if (page === this.pageNum) {
|
||||
return;
|
||||
}
|
||||
this.loadRiskPeoplePage(page);
|
||||
}
|
||||
```
|
||||
|
||||
```vue
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="pageNum"
|
||||
:limit.sync="pageSize"
|
||||
:page-sizes="[5]"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
@pagination="handlePageChange"
|
||||
/>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 回跑风险人员组件测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-binding.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination.test.js
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- PASS
|
||||
- 核心异常点标签逻辑、风险等级标签逻辑和操作列逻辑不回归
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue \
|
||||
ruoyi-ui/src/views/ccdiProject/components/detail/RiskPeopleSection.vue \
|
||||
ruoyi-ui/tests/unit/preliminary-check-risk-people-binding.test.js \
|
||||
ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination.test.js
|
||||
git commit -m "支持风险总览员工列表独立分页翻页"
|
||||
```
|
||||
|
||||
### Task 4: 补齐前端验证记录与实施记录
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-verification.md`
|
||||
- Create: `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-implementation.md`
|
||||
- Verify: `docs/design/2026-03-29-project-detail-risk-overview-risk-people-pagination-design.md`
|
||||
|
||||
- [ ] **Step 1: 运行本需求前端最小回归**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
node ruoyi-ui/tests/unit/project-overview-api.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination-load.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-binding.test.js
|
||||
node ruoyi-ui/tests/unit/preliminary-check-risk-people-pagination.test.js
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 全部 PASS
|
||||
- 风险人员区首屏读取分页结构,翻页逻辑存在
|
||||
|
||||
- [ ] **Step 2: 写前端验证记录**
|
||||
|
||||
在 `docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-verification.md` 记录:
|
||||
|
||||
- 执行命令
|
||||
- 执行日期
|
||||
- 测试结果
|
||||
- 结论:风险总览员工列表已固定 5 条一页,翻页仅刷新当前列表
|
||||
|
||||
- [ ] **Step 3: 写前端实施记录**
|
||||
|
||||
在 `docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-implementation.md` 记录:
|
||||
|
||||
- API 封装如何改造
|
||||
- `PreliminaryCheck.vue` 首屏如何注入分页结构
|
||||
- `RiskPeopleSection.vue` 如何局部翻页
|
||||
- 本次未改动风险模型区和风险明细区
|
||||
|
||||
- [ ] **Step 4: 检查暂存区仅包含本任务文件**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git diff --cached --name-only
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 暂存区只出现本任务相关前端源码、测试和文档
|
||||
|
||||
- [ ] **Step 5: 提交本任务**
|
||||
|
||||
```bash
|
||||
git add docs/tests/records/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-verification.md \
|
||||
docs/reports/implementation/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-implementation.md
|
||||
git commit -m "补充风险总览员工列表前端分页实施记录"
|
||||
```
|
||||
|
||||
## Done When
|
||||
|
||||
- 首屏通过 `getOverviewRiskPeople({ projectId, pageNum: 1, pageSize: 5 })` 获取第一页
|
||||
- `riskPeople` 数据结构改为 `rows + total + pageNum + pageSize`
|
||||
- `RiskPeopleSection.vue` 存在固定 5 条分页条
|
||||
- 翻页只刷新风险总览员工列表,不重载其他结果总览区块
|
||||
- 前端验证记录与实施记录已补齐
|
||||
@@ -0,0 +1,32 @@
|
||||
# 项目详情风险总览员工列表分页计划记录
|
||||
|
||||
## 变更概述
|
||||
|
||||
- 新增风险总览员工列表分页后端实施计划 1 份。
|
||||
- 新增风险总览员工列表分页前端实施计划 1 份。
|
||||
- 本次计划按统一接口改造方案收口为:保留 `GET /ccdi/project/overview/risk-people` 路径,改为标准分页返回 `rows + total + pageNum + pageSize`。
|
||||
- 本轮仅完成实施计划沉淀,尚未进入代码实现阶段。
|
||||
|
||||
## 新增文件
|
||||
|
||||
- `docs/plans/backend/2026-03-29-project-detail-risk-overview-risk-people-pagination-backend-implementation.md`
|
||||
- `docs/plans/frontend/2026-03-29-project-detail-risk-overview-risk-people-pagination-frontend-implementation.md`
|
||||
|
||||
## 计划结论
|
||||
|
||||
- 后端计划聚焦:
|
||||
- 新增 `CcdiProjectRiskPeopleQueryDTO`
|
||||
- 将 `risk-people` 改为分页接口
|
||||
- 使用 MyBatis Plus `Page` 实现数据库真分页
|
||||
- 保持现有排序与业务口径不变
|
||||
- 前端计划聚焦:
|
||||
- `projectOverview.js` 透传分页参数
|
||||
- `PreliminaryCheck.vue` 首屏接入第一页分页结构
|
||||
- `RiskPeopleSection.vue` 增加固定 5 条一页的独立分页
|
||||
- 翻页仅刷新员工列表本身
|
||||
|
||||
## 说明
|
||||
|
||||
- 本次按仓库规范,将实施计划分别落到 `docs/plans/backend/` 与 `docs/plans/frontend/`。
|
||||
- 因本仓库协作约定禁止开启 subagent,计划头部已明确执行时应在当前会话使用 `superpowers:executing-plans`。
|
||||
- 本次补充的是计划文档与计划记录,因此同步新增本计划记录作为本次改动的实施文档。
|
||||
Reference in New Issue
Block a user