265 lines
6.3 KiB
Markdown
265 lines
6.3 KiB
Markdown
# 项目结果总览排除可疑后端实施计划
|
||
|
||
## 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. 不引入恢复接口,避免扩大范围。
|
||
|