# 风险总览无风险人员负数修复记录

## 问题现象

- 生产项目结果总览出现“无风险人员”为负数。
- 页面展示中“高风险 + 中风险 + 低风险”人数大于“总人数”。

## 根因

- `ccdi_project.target_count` 原口径只统计 `ccdi_bank_statement.cret_no` 直接匹配到员工主数据的去重人数。
- 风险人员结果表 `ccdi_project_overview_employee_result` 的生成口径会把关系人流水、对象规则命中、账户归属等结果归并回员工。
- 当项目存在“关系人流水归属员工”或“项目流水账号归属员工”时，风险人数的员工范围大于总人数范围，导致 `target_count - high - medium - low` 出现负数。

## 修改内容

- 调整 `CcdiBankStatementMapper.countMatchedStaffCountByProjectId`：
  - 直接员工：流水 `cret_no` 匹配员工身份证。
  - 关系人归属员工：流水 `cret_no` 匹配员工关系人证件号后归属到员工。
  - 账号归属员工：项目流水账号匹配员工账户信息后归属到员工。
- 调整 `CcdiProjectOverviewServiceImpl`：
  - 标签重算刷新结果总览员工结果后，同步刷新项目总人数和风险人数。
  - 手动刷新项目风险人数时，同步刷新项目总人数。
- 调整 `CcdiProjectMapper.updateRiskCountsByProjectId`：
  - 更新风险人数时同时写回 `target_count`，保证总人数与风险人数使用同一项目员工范围口径。
- 新增生产回填脚本：
  - `sql/migration/2026-05-22-fix-project-target-count-employee-scope.sql`
  - 用新口径回填既有项目的 `target_count`。

## 影响范围

- 后端结果总览统计。
- 项目列表中的目标人数。
- 生产既有项目需要执行新增 SQL 回填脚本，后续上传、历史导入、标签重算会自动按新口径刷新。

## 验证

- 已补充 `CcdiBankStatementMapperXmlTest.targetCount_shouldUseResolvedProjectEmployeeScope`，约束总人数 SQL 必须包含直接员工、关系人归属员工、账号归属员工三类范围。
- 已更新 `CcdiProjectOverviewServiceImplTest`，约束刷新风险人数时同步写回总人数。
