222 lines
7.6 KiB
Markdown
222 lines
7.6 KiB
Markdown
|
|
# 生产流水上传后卡片人数异常排查方案
|
|||
|
|
|
|||
|
|
## 背景
|
|||
|
|
|
|||
|
|
- 问题现象:生产环境上传了一个人的流水后,结果总览卡片仍显示两个人。
|
|||
|
|
- 排查目标:确认卡片显示的“两个人”来自项目总人数、风险人员数,还是风险模型卡片命中人数,并定位数据来源是否符合当前项目真实流水范围。
|
|||
|
|
- 本方案只做排查,不直接修改生产数据。
|
|||
|
|
|
|||
|
|
## 已确认的数据链路
|
|||
|
|
|
|||
|
|
1. 前端结果总览页面 `PreliminaryCheck.vue` 会并行请求:
|
|||
|
|
- `/ccdi/project/overview/dashboard`
|
|||
|
|
- `/ccdi/project/overview/risk-people`
|
|||
|
|
- `/ccdi/project/overview/risk-models/cards`
|
|||
|
|
- `/ccdi/project/overview/suspicious-transactions`
|
|||
|
|
- `/ccdi/project/overview/employee-credit-negative`
|
|||
|
|
|
|||
|
|
2. 顶部统计卡片 `总人数 / 高风险 / 中风险 / 低风险 / 无风险人员` 来自 `ccdi_project`:
|
|||
|
|
- `target_count`
|
|||
|
|
- `high_risk_count`
|
|||
|
|
- `medium_risk_count`
|
|||
|
|
- `low_risk_count`
|
|||
|
|
|
|||
|
|
3. 风险模型卡片的人数来自 `ccdi_project_overview_employee_result`:
|
|||
|
|
- 按 `staff_id_card` 去重统计模型命中人员数。
|
|||
|
|
|
|||
|
|
4. 上传流水成功后,系统会:
|
|||
|
|
- 将流水写入 `ccdi_bank_statement`
|
|||
|
|
- 根据项目内已入库流水重新计算 `ccdi_project.target_count`
|
|||
|
|
- 批处理完成后触发流水标签重算
|
|||
|
|
- 重算完成后刷新 `ccdi_project_overview_employee_result` 和风险人数统计
|
|||
|
|
|
|||
|
|
5. 经业务确认,项目总人数口径应为“当前项目内所有已入库流水的 `cret_no` 直接匹配员工主数据后的去重人数”。不纳入家属关系归属员工,也不纳入本方账号账户库归属员工。
|
|||
|
|
|
|||
|
|
## 排查步骤
|
|||
|
|
|
|||
|
|
### 1. 确认异常卡片类型
|
|||
|
|
|
|||
|
|
先在浏览器 Network 中打开结果总览页面,记录以下接口返回:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
GET /ccdi/project/overview/dashboard?projectId={projectId}
|
|||
|
|
GET /ccdi/project/overview/risk-models/cards?projectId={projectId}
|
|||
|
|
GET /ccdi/project/overview/risk-people?projectId={projectId}&pageNum=1&pageSize=5
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
判断口径:
|
|||
|
|
|
|||
|
|
- 如果 `dashboard.stats` 里的 `people` 为 2,问题在 `ccdi_project.target_count` 或项目流水范围。
|
|||
|
|
- 如果某个 `risk-models/cards.cardList[].peopleCount` 为 2,问题在 `ccdi_project_overview_employee_result` 或标签重算结果。
|
|||
|
|
- 如果 `risk-people.rows` 有 2 条,问题在风险人员汇总结果。
|
|||
|
|
|
|||
|
|
### 2. 核对项目基础统计字段
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT
|
|||
|
|
project_id,
|
|||
|
|
project_name,
|
|||
|
|
status,
|
|||
|
|
target_count,
|
|||
|
|
high_risk_count,
|
|||
|
|
medium_risk_count,
|
|||
|
|
low_risk_count,
|
|||
|
|
update_time
|
|||
|
|
FROM ccdi_project
|
|||
|
|
WHERE project_id = {projectId}
|
|||
|
|
AND del_flag = '0';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
结论判断:
|
|||
|
|
|
|||
|
|
- `target_count = 2`:继续查项目内 `cret_no` 实际匹配到的员工范围。
|
|||
|
|
- `target_count = 1` 但页面显示 2:继续查接口缓存、浏览器缓存或前端请求的 `projectId` 是否错误。
|
|||
|
|
|
|||
|
|
### 3. 核对上传记录是否只剩一个人的文件
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT
|
|||
|
|
id,
|
|||
|
|
project_id,
|
|||
|
|
log_id,
|
|||
|
|
file_name,
|
|||
|
|
file_status,
|
|||
|
|
enterprise_names,
|
|||
|
|
account_nos,
|
|||
|
|
error_message,
|
|||
|
|
upload_time,
|
|||
|
|
upload_user
|
|||
|
|
FROM ccdi_file_upload_record
|
|||
|
|
WHERE project_id = {projectId}
|
|||
|
|
ORDER BY upload_time DESC, id DESC;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
重点看:
|
|||
|
|
|
|||
|
|
- 是否存在历史上传成功文件仍在该项目下。
|
|||
|
|
- 是否存在本次上传文件之外的 `parsed_success` 记录。
|
|||
|
|
- `enterprise_names`、`account_nos` 是否出现多个主体或多个本方账号。
|
|||
|
|
|
|||
|
|
### 4. 核对项目内流水 cret_no 实际匹配了几个人
|
|||
|
|
|
|||
|
|
先看项目流水批次和本方主体:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT
|
|||
|
|
batch_id,
|
|||
|
|
COUNT(*) AS statement_count,
|
|||
|
|
GROUP_CONCAT(DISTINCT TRIM(LE_ACCOUNT_NAME) ORDER BY TRIM(LE_ACCOUNT_NAME) SEPARATOR '、') AS le_names,
|
|||
|
|
GROUP_CONCAT(DISTINCT TRIM(LE_ACCOUNT_NO) ORDER BY TRIM(LE_ACCOUNT_NO) SEPARATOR '、') AS le_accounts,
|
|||
|
|
GROUP_CONCAT(DISTINCT TRIM(cret_no) ORDER BY TRIM(cret_no) SEPARATOR '、') AS cret_nos
|
|||
|
|
FROM ccdi_bank_statement
|
|||
|
|
WHERE project_id = {projectId}
|
|||
|
|
GROUP BY batch_id
|
|||
|
|
ORDER BY batch_id DESC;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
再按总人数口径展开员工范围:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT DISTINCT
|
|||
|
|
TRIM(bs.cret_no) AS id_card,
|
|||
|
|
staff.name,
|
|||
|
|
staff.staff_id
|
|||
|
|
FROM ccdi_bank_statement bs
|
|||
|
|
INNER JOIN ccdi_base_staff staff
|
|||
|
|
ON staff.id_card = TRIM(bs.cret_no)
|
|||
|
|
WHERE bs.project_id = {projectId}
|
|||
|
|
AND bs.cret_no IS NOT NULL
|
|||
|
|
AND TRIM(bs.cret_no) != ''
|
|||
|
|
ORDER BY id_card;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
结论判断:
|
|||
|
|
|
|||
|
|
- 如果这里确实查出 2 个 `id_card`,页面显示 2 符合当前口径,继续确认多出的人员来自哪个批次或哪条流水的 `cret_no`。
|
|||
|
|
- 如果这里只查出 1 个 `id_card`,但 `ccdi_project.target_count = 2`,说明项目统计字段未刷新或刷新失败。
|
|||
|
|
|
|||
|
|
### 5. 核对风险人员汇总是否仍有两个人
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT
|
|||
|
|
project_id,
|
|||
|
|
staff_id_card,
|
|||
|
|
staff_name,
|
|||
|
|
risk_level_code,
|
|||
|
|
rule_count,
|
|||
|
|
model_count,
|
|||
|
|
hit_count,
|
|||
|
|
model_codes_csv,
|
|||
|
|
update_time
|
|||
|
|
FROM ccdi_project_overview_employee_result
|
|||
|
|
WHERE project_id = {projectId}
|
|||
|
|
ORDER BY staff_id_card;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
如果这里有 2 条,再查标签原始结果:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
SELECT
|
|||
|
|
tr.project_id,
|
|||
|
|
tr.object_type,
|
|||
|
|
tr.object_key,
|
|||
|
|
tr.bank_statement_id,
|
|||
|
|
tr.model_code,
|
|||
|
|
tr.rule_code,
|
|||
|
|
bs.batch_id,
|
|||
|
|
bs.cret_no,
|
|||
|
|
bs.LE_ACCOUNT_NO,
|
|||
|
|
bs.LE_ACCOUNT_NAME
|
|||
|
|
FROM ccdi_bank_statement_tag_result tr
|
|||
|
|
LEFT JOIN ccdi_bank_statement bs
|
|||
|
|
ON bs.bank_statement_id = tr.bank_statement_id
|
|||
|
|
WHERE tr.project_id = {projectId}
|
|||
|
|
ORDER BY tr.id DESC
|
|||
|
|
LIMIT 200;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
结论判断:
|
|||
|
|
|
|||
|
|
- 汇总表有 2 人且标签结果能追溯到 2 人:需要确认多出人员是否来自历史流水、家属归属或账号归属。
|
|||
|
|
- 汇总表有 2 人但标签结果已不是 2 人:说明 `ccdi_project_overview_employee_result` 未随最新重算刷新。
|
|||
|
|
|
|||
|
|
### 6. 核对打标任务是否完成
|
|||
|
|
|
|||
|
|
从日志中按 `projectId` 搜索:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
【流水标签】自动重算任务已异步提交
|
|||
|
|
【流水标签】任务执行成功
|
|||
|
|
【流水标签】任务执行失败
|
|||
|
|
【流水标签】任务执行结束
|
|||
|
|
【文件上传】批处理完成,准备触发自动重算
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
结论判断:
|
|||
|
|
|
|||
|
|
- 上传成功但没有自动重算提交日志:排查上传批处理完成回调。
|
|||
|
|
- 有提交但任务失败:优先处理失败原因。
|
|||
|
|
- 任务成功但汇总未更新:排查 `refreshOverviewEmployeeResults` 是否执行完成。
|
|||
|
|
|
|||
|
|
## 最可能原因排序
|
|||
|
|
|
|||
|
|
1. 项目下仍存在历史成功上传流水,本次只上传了一个人的流水,但项目统计按项目全量流水的 `cret_no` 计算,所以仍显示两个人。
|
|||
|
|
2. 本次文件中只有一个主体,但流水明细里存在两个不同的有效 `cret_no`。
|
|||
|
|
3. 上传后 `target_count` 已变为 1,但风险汇总表 `ccdi_project_overview_employee_result` 仍是旧数据,导致风险模型卡片或风险人员列表显示 2。
|
|||
|
|
4. 自动打标重算失败或尚未完成,页面刷新时读到了重算前的风险统计。
|
|||
|
|
5. 前端打开的不是预期项目,或结果总览接口请求的 `projectId` 与上传页面项目不一致。
|
|||
|
|
|
|||
|
|
## 排查结束判定
|
|||
|
|
|
|||
|
|
满足以下任一条件即可闭环:
|
|||
|
|
|
|||
|
|
- 查明第二个人来自项目内哪条流水的 `cret_no`,并能定位到具体 `batch_id`、`log_id`、文件名或身份证号。
|
|||
|
|
- 查明统计字段或汇总表未刷新,并能定位到上传后刷新目标人数或自动打标重算的失败日志。
|
|||
|
|
- 查明页面请求了错误项目,接口返回和数据库统计一致。
|
|||
|
|
|
|||
|
|
## 后续处理原则
|
|||
|
|
|
|||
|
|
- 如果第二个人来自历史上传文件,需要先确认业务上是否应删除该文件;删除必须走页面或正式删除接口,让系统同步清理流水并触发重算。
|
|||
|
|
- 如果第二个人只来自账号库或家属关系,而流水 `cret_no` 未直接匹配该员工,则不应计入项目总人数。
|
|||
|
|
- 如果是统计刷新或重算失败,先保留现场日志和相关 SQL 查询结果,再进入缺陷修复流程。
|