# 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", " 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 ``` 在 `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 ``` - [ ] **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 条分页条 - 翻页只刷新风险总览员工列表,不重载其他结果总览区块 - 前端验证记录与实施记录已补齐