# Risk Detail Employee Credit Negative 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:** 在结果总览“风险明细”中新增“员工负面征信信息”区块，按项目维度展示员工负面征信分页列表，并与现有涉疑交易区块并列呈现。

**Architecture:** 前端继续以 `PreliminaryCheck.vue` 作为结果总览入口，通过 `projectOverview.js` 新增员工负面征信接口封装，并在初次加载时注入 `riskDetails` 初始数据。`RiskDetailSection.vue` 负责渲染员工负面征信表格、空态和独立分页，并在后续翻页时直接调用结果总览专用接口，不复用全局征信维护页面或弹窗链路。

**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: 先写 API 契约测试，锁定接口名、路由和参数透传**

```javascript
[
  "getOverviewEmployeeCreditNegative",
  "/ccdi/project/overview/employee-credit-negative",
  "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，提示缺少 `getOverviewEmployeeCreditNegative`

- [ ] **Step 3: 写最小 API 封装**

```javascript
export function getOverviewEmployeeCreditNegative(params) {
  return request({
    url: "/ccdi/project/overview/employee-credit-negative",
    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-credit-negative-load.test.js`

- [ ] **Step 1: 先写失败测试，锁定父组件并发请求和 `riskDetails` 注入结构**

```javascript
assert(source.includes("getOverviewEmployeeCreditNegative"), "结果总览应加载员工负面征信接口");
assert(source.includes("employeeCreditNegativeList"), "riskDetails 应注入员工负面征信初始列表");
assert(source.includes("employeeCreditNegativeTotal"), "riskDetails 应注入员工负面征信总数");
```

- [ ] **Step 2: 运行测试，确认当前入口页尚未接入该数据源**

Run:

```bash
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
node ruoyi-ui/tests/unit/preliminary-check-credit-negative-load.test.js
```

Expected:

- `preliminary-check-api-integration.test.js` 仍只有 4 个并发请求
- 新测试提示缺少员工负面征信数据装配

- [ ] **Step 3: 在父组件中并行加载新接口，并改造 mock 归一化结构**

```javascript
const [dashboardRes, riskPeopleRes, riskModelCardsRes, suspiciousRes, creditNegativeRes] =
  await Promise.all([
    getOverviewDashboard(this.projectId),
    getOverviewRiskPeople(this.projectId),
    getOverviewRiskModelCards(this.projectId),
    getOverviewSuspiciousTransactions({ projectId: this.projectId, suspiciousType: "ALL", pageNum: 1, pageSize: 5 }),
    getOverviewEmployeeCreditNegative({ projectId: this.projectId, pageNum: 1, pageSize: 5 }),
  ]);
```

```javascript
riskDetails: {
  projectId,
  suspiciousTransactionList: normalizeSuspiciousTransactions(suspiciousData && suspiciousData.rows),
  suspiciousType: "ALL",
  total: suspiciousData && suspiciousData.total ? suspiciousData.total : 0,
  employeeCreditNegativeList: normalizeEmployeeCreditNegativeRows(creditNegativeData && creditNegativeData.rows),
  employeeCreditNegativeTotal: creditNegativeData && creditNegativeData.total ? creditNegativeData.total : 0,
  abnormalAccountList: [],
}
```

- [ ] **Step 4: 回跑入口页相关测试**

Run:

```bash
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
node ruoyi-ui/tests/unit/preliminary-check-credit-negative-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-credit-negative-load.test.js
git commit -m "接通结果总览员工负面征信初始加载"
```

### Task 3: 在 RiskDetailSection 中新增员工负面征信区块与独立分页

**Files:**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue`
- Modify: `ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js`
- Create: `ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js`
- Create: `ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-pagination.test.js`

- [ ] **Step 1: 先写失败测试，锁定新区块标题、列定义、空态和独立分页状态**

```javascript
[
  "员工负面征信信息",
  "展示当前项目员工的负面征信信息",
  "员工姓名",
  "身份证号",
  "最近征信查询日期",
  "民事案件笔数",
  "民事案件金额",
  "强制执行笔数",
  "强制执行金额",
  "行政处罚笔数",
  "行政处罚金额",
  "当前项目暂无员工负面征信信息",
].forEach((token) => assert(source.includes(token), token));
```

```javascript
[
  "employeeCreditNegativeList",
  "employeeCreditNegativeTotal",
  "employeeCreditNegativePageNum",
  "employeeCreditNegativePageSize",
  "loadEmployeeCreditNegative",
  "handleEmployeeCreditNegativePageChange",
].forEach((token) => assert(source.includes(token), token));
```

- [ ] **Step 2: 运行测试，确认当前风险明细组件还没有该区块**

Run:

```bash
node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js
node ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js
node ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-pagination.test.js
```

Expected:

- 新测试 FAIL，提示缺少员工负面征信区块和独立分页状态

- [ ] **Step 3: 写最小 UI 与分页实现**

```vue
<div class="block">
  <div class="block-header">
    <div>
      <div class="block-title">员工负面征信信息</div>
      <div class="block-subtitle">展示当前项目员工的负面征信信息</div>
    </div>
  </div>

  <el-table
    v-loading="employeeCreditNegativeLoading"
    :data="employeeCreditNegativeList"
    class="result-table"
  >
    <template slot="empty">
      <el-empty :image-size="96" description="当前项目暂无员工负面征信信息" />
    </template>
    <el-table-column prop="personName" label="员工姓名" min-width="140" />
    <el-table-column prop="personId" label="身份证号" min-width="180" />
    <el-table-column prop="queryDate" label="最近征信查询日期" min-width="160" />
  </el-table>
</div>
```

```javascript
async loadEmployeeCreditNegative() {
  const response = await getOverviewEmployeeCreditNegative({
    projectId: this.projectId,
    pageNum: this.employeeCreditNegativePageNum,
    pageSize: 5,
  });
  ...
}
```

- [ ] **Step 4: 回跑风险明细相关测试**

Run:

```bash
node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js
node ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js
node ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-pagination.test.js
```

Expected:

- 员工负面征信区块结构、列定义、空态和分页状态测试全部通过
- 不影响现有涉疑交易布局测试

- [ ] **Step 5: 提交本任务**

```bash
git add ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \
  ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-layout.test.js \
  ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js \
  ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-pagination.test.js
git commit -m "新增风险明细员工负面征信列表区块"
```

### Task 4: 做一次结果总览前端最小回归

**Files:**
- Reference: `ruoyi-ui/tests/unit/preliminary-check-layout.test.js`
- Reference: `ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js`
- Reference: `ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js`
- Reference: `ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js`

- [ ] **Step 1: 回跑结果总览关键结构测试**

Run:

```bash
node ruoyi-ui/tests/unit/preliminary-check-layout.test.js
node ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js
node ruoyi-ui/tests/unit/risk-detail-suspicious-transaction-detail-dialog.test.js
node ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js
```

Expected:

- 入口页整体结构不回归
- 涉疑交易详情弹窗仍可用
- 新增员工负面征信区块测试通过

- [ ] **Step 2: 做一次前端静态构建验证**

Run:

```bash
cd ruoyi-ui
npm run build:prod
```

Expected:

- 构建成功
- 没有因新增 API 或组件状态字段导致的编译错误

- [ ] **Step 3: 结束验证时清理本次启动的前端进程**

若本地为验证启动了 `npm run dev`，结束后执行：

```bash
lsof -ti tcp:80 tcp:8080 tcp:8081 | xargs kill -9
```

Expected:

- 不遗留前端调试进程

- [ ] **Step 4: 提交本任务**

```bash
git status --short
git add ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue \
  ruoyi-ui/src/views/ccdiProject/components/detail/PreliminaryCheck.vue \
  ruoyi-ui/src/views/ccdiProject/components/detail/preliminaryCheck.mock.js \
  ruoyi-ui/src/api/ccdi/projectOverview.js \
  ruoyi-ui/tests/unit/preliminary-check-api-integration.test.js \
  ruoyi-ui/tests/unit/preliminary-check-credit-negative-load.test.js \
  ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-layout.test.js \
  ruoyi-ui/tests/unit/risk-detail-employee-credit-negative-pagination.test.js
git commit -m "完成风险明细员工负面征信前端实现"
```
