Files
ccdi/docs/plans/backend/2026-07-09-project-risk-exclusion-backend-implementation.md

265 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目结果总览排除可疑后端实施计划
## 1. 目标
后端提供“排除可疑”持久化接口,并在结果总览所有预警查询、统计、导出链路中统一过滤已排除命中。排除粒度为单条规则命中,不删除原始打标结果。
## 2. 涉及范围
模块:
1. `ccdi-project`
2. `ruoyi-admin` 装配依赖无需调整
3. `sql/migration/`
重点文件:
1. `CcdiProjectOverviewController`
2. `ICcdiProjectOverviewService`
3. `CcdiProjectOverviewServiceImpl`
4. `CcdiProjectOverviewMapper`
5. `CcdiBankTagResultMapper`
6. 新增排除记录实体、DTO、Mapper
## 3. 数据库实施
### 3.1 增量脚本
新增 SQL
```text
sql/migration/2026-07-09-create-project-risk-exclusion.sql
```
内容使用 `CREATE TABLE IF NOT EXISTS ccdi_project_risk_exclusion`,字段与 `sql/ccdi_prod_init.sql` 保持一致,并显式声明:
```sql
DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
```
### 3.2 表用途
`ccdi_project_risk_exclusion` 保存排除记录:
1. `STATEMENT`:单笔流水上的单个规则标签。
2. `OBJECT`:某个对象或人员上的单个规则预警。
## 4. 后端对象
### 4.1 新增 Entity
新增:
```text
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/entity/CcdiProjectRiskExclusion.java
```
字段对应表结构,实体类使用 Lombok `@Data`,不继承 `BaseEntity`
### 4.2 新增 DTO
新增:
```text
ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectRiskExclusionSaveDTO.java
```
字段:
1. `projectId`
2. `staffIdCard`
3. `ruleCode`
4. `exclusionType`
5. `bankStatementId`
6. `excludeReason`
校验:
1. `projectId` 必填。
2. `ruleCode` 必填。
3. `exclusionType` 必填且只允许 `STATEMENT``OBJECT`
4. `excludeReason` 必填且最大 1000 字符。
5. `STATEMENT` 要求 `bankStatementId`
6. `OBJECT` 要求 `staffIdCard`
### 4.3 新增 Mapper
新增:
```text
ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectRiskExclusionMapper.java
ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectRiskExclusionMapper.xml
```
方法:
1. `upsertExclusion`
2. `selectByProjectId`
3. `selectStatementExclusions`
4. `selectObjectExclusions`
`upsertExclusion` 使用唯一键实现幂等写入;重复排除时更新 `exclude_reason/update_by/update_time`
## 5. 接口实施
`CcdiProjectOverviewController` 新增:
```text
POST /ccdi/project/overview/risk-exclusions
```
返回:
```java
AjaxResult.success("排除成功")
```
权限:
1. `@PreAuthorize("@ss.hasPermi('ccdi:project:query')")`
2. 使用 `projectAccessService.assertCanRead(projectId)` 校验项目访问。
3. 使用项目状态或访问服务校验当前项目可操作;归档或只读项目返回错误。
## 6. Service 实施
`ICcdiProjectOverviewService` 增加:
```java
void excludeRisk(CcdiProjectRiskExclusionSaveDTO dto);
```
`CcdiProjectOverviewServiceImpl` 实现流程:
1. 校验 DTO。
2. 校验规则是否存在于当前项目有效命中中,避免写入无效排除记录。
3. 写入 `ccdi_project_risk_exclusion`
4. 触发当前项目结果总览员工快照重算。
5. 返回成功。
## 7. 查询过滤实施
### 7.1 统一过滤 SQL
`CcdiProjectOverviewMapper.xml` 中新增复用 SQL 片段:
```xml
not exists (
select 1
from ccdi_project_risk_exclusion ex
where ex.project_id = tr.project_id
and ex.rule_code = tr.rule_code
and (
(ex.exclusion_type = 'STATEMENT' and ex.bank_statement_id = tr.bank_statement_id)
or
(ex.exclusion_type = 'OBJECT' and ex.staff_id_card = resolved_staff_id_card)
)
)
```
实际实现时根据不同查询上下文替换 `resolved_staff_id_card`
### 7.2 员工风险基础 SQL
修改 `resolvedEmployeeRiskBaseSql`
1. 先解析 `staff_id_card`
2.`STATEMENT``OBJECT` 分别过滤。
3. 被排除命中不进入员工风险聚合。
### 7.3 风险模型卡片
修改模型统计查询:
1. `warning_count` 按未排除命中统计。
2. `people_count` 按未排除命中涉及人员去重。
### 7.4 风险模型命中人员
修改命中人员查询:
1. `hitTagList` 不包含已排除规则。
2. `modelNames` 按剩余命中规则组装。
3. 过滤后无有效规则的人员不返回。
### 7.5 人员项目分析详情
修改详情组装:
1. `BANK_STATEMENT` 记录的 `hitTags` 排除已排除标签。
2. 如果一条流水没有剩余 `hitTags`,不进入流水异常明细。
3. `OBJECT` 记录排除已排除对象规则。
### 7.6 涉疑交易明细与导出
修改涉疑交易查询:
1. 已排除流水标签不进入 `hitTags`
2. 过滤后无有效标签的流水不作为可疑流水展示。
3. Excel 导出和 PDF 报告复用同一过滤口径。
### 7.7 外部人员预警
外部人员使用证件号作为对象键:
1. `OBJECT` 类型按 `staff_id_card = cert_no` 过滤。
2. `STATEMENT` 类型按 `bank_statement_id` 过滤。
3. 外部人员列表、模型卡片、详情、报告口径一致。
## 8. 快照重算
如果当前已有员工结果快照重算逻辑,排除成功后复用该逻辑。
若没有可复用入口,新增内部方法:
```java
refreshOverviewEmployeeResult(Long projectId)
```
要求:
1. 使用过滤排除后的有效命中重算。
2. 删除或更新当前项目 `ccdi_project_overview_employee_result`
3. 确保列表、模型统计和详情口径一致。
## 9. 测试计划
### 9.1 后端编译
```bash
mvn -pl ccdi-project -am compile -DskipTests
```
### 9.2 单接口验证
验证接口:
```text
POST /ccdi/project/overview/risk-exclusions
```
场景:
1. 缺少原因返回错误。
2. `STATEMENT` 缺少 `bankStatementId` 返回错误。
3. `OBJECT` 缺少 `staffIdCard` 返回错误。
4. 重复排除幂等成功。
5. 归档项目或只读项目不允许排除。
### 9.3 数据口径验证
场景:
1. 一笔流水多个标签,排除一个后另一个仍存在。
2. 人员多个对象型预警,排除一个后人员仍存在。
3. 人员唯一预警被排除后,风险人员列表不再展示该人员。
4. 模型预警次数和命中人数减少。
5. PDF/Excel 不输出已排除预警。
## 10. 风险控制
1. 排除表只影响展示和统计,不影响原始命中结果。
2. 所有新增 SQL 使用 `utf8mb4_general_ci`
3. `rule_code` 保持全大写。
4. 不引入恢复接口,避免扩大范围。