修正异常标签展示设计文档保存路径

This commit is contained in:
wkc
2026-03-18 17:40:59 +08:00
parent 0233e203b7
commit a70fcb42c7
2 changed files with 364 additions and 0 deletions

View File

@@ -0,0 +1,335 @@
# 流水明细异常标签展示设计
## 背景
当前项目流水标签能力已经会把规则命中结果写入 `ccdi_bank_statement_tag_result`,结果中保留了:
- `rule_name`
- `risk_level`
- `reason_detail`
- `result_type`
- `bank_statement_id`
但现有“流水明细查询”页面和导出能力仍只读取 `ccdi_bank_statement`,列表、详情、导出文件都看不到当前流水命中的异常标签,用户无法直接在查询结果中判断一条流水为何被命中。
本次需求要求在“流水明细查询”页面的流水列表、流水详情和导出文件中,展示当前流水直接命中的异常标签信息。
## 目标
- 在流水列表中展示当前流水命中的异常标签名称。
- 在流水详情中展示当前流水命中的异常标签名称、风险等级、命中原因摘要。
- 在导出文件中追加“异常标签”“命中原因摘要”两列。
- 页面、详情、导出的标签口径保持一致。
## 范围
### In Scope
- `ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue`
- `ruoyi-ui/src/api/ccdiProjectBankStatement.js`
- `ccdi-project` 现有流水查询 Controller / Service / Mapper
- `ccdi_bank_statement_tag_result` 的只读查询与组装
- 流水明细导出列扩展
### Out of Scope
- 新增按异常标签筛选、排序、页签统计
- 对象级标签结果展示
- 标签重算逻辑、规则 SQL、任务调度逻辑调整
- 新增独立标签页面
## 已确认口径
- 列表页只展示标签名称。
- 详情页展示标签名称、风险等级、命中原因摘要。
- 仅展示当前流水直接命中的流水级标签。
- 不把对象级标签混入流水列表、流水详情和导出。
- 导出时需要同时导出异常标签与命中原因摘要。
## 方案对比
### 方案一:服务层二次组装标签
- 列表先按现有分页逻辑查询流水。
- 再按当前页 `bankStatementId` 批量查询标签结果,并回填到列表 VO。
- 详情继续走原有详情查询,再单独补充当前流水标签明细。
- 导出先查导出范围内流水,再批量查询标签结果并拼装导出列。
优点:
- 改动集中在现有查询服务层,最短路径实现。
- 标签查询与主分页 SQL 解耦,便于维护和测试。
- 详情可返回结构化标签数据,适合前端展示。
- 列表、详情、导出口径容易统一。
缺点:
- 列表和导出阶段会增加一次标签批量查询。
### 方案二:在 Mapper 主查询里直接聚合标签
-`CcdiBankStatementMapper.xml` 主查询中左连接标签表,并聚合标签字段。
优点:
- 接口层看起来较简单。
缺点:
- 分页 SQL、详情 SQL、导出 SQL 都会显著变复杂。
- 列表适合聚合字符串,不适合详情返回结构化标签。
- 后续维护成本高。
### 方案三:新增独立标签接口,由前端二次拉取
- 列表接口仍只查流水。
- 前端再调一个“按流水 ID 查询标签”的接口做二次组装。
优点:
- 流水主查询改动少。
缺点:
- 前端需要承担拼装逻辑。
- 导出仍需后端再实现一次同口径查询,容易分叉。
## 选型
采用方案一:服务层二次组装标签。
该方案最符合当前仓库“在既有模块上做局部扩展”的实现方式,不需要引入新的查询页面或复杂聚合 SQL也能保证详情展示与导出口径一致。
## 设计原则
- 标签展示仅来自 `ccdi_bank_statement_tag_result` 中的流水级结果。
- 列表轻量展示,详情完整展示。
- 导出结果与页面口径一致,不额外创造新的标签解释规则。
- 不为本次需求扩展筛选、排序和统计能力。
- 主功能优先,标签展示失败不能拖垮流水列表查询。
## 数据口径设计
标签查询统一限定以下条件:
- `result_type = 'STATEMENT'`
- `bank_statement_id` 命中当前流水
标签结果读取字段:
- `rule_name`
- `risk_level`
- `reason_detail`
- `bank_statement_id`
- `rule_code`
其中:
- `rule_name` 用于列表、详情、导出展示
- `risk_level` 仅用于详情展示和前端标签样式映射
- `reason_detail` 用于详情展示和导出
对象级结果即使与当前流水所属身份证、账户或对象相关,也不参与本次页面与导出口径。
## 后端设计
### 一、VO 与导出模型扩展
建议新增一个统一标签明细 VO例如
- `CcdiBankStatementHitTagVO`
- `ruleName`
- `riskLevel`
- `reasonDetail`
现有 VO 调整:
- `CcdiBankStatementListVO`
- 新增 `hitTags`
- `CcdiBankStatementDetailVO`
- 新增 `hitTags`
- `CcdiBankStatementExcel`
- 新增 `hitTagNames`
- 新增 `hitTagReasons`
列表 VO 中虽然只展示标签名称,但仍保留结构化 `hitTags`,这样可以减少后续再次改模型的成本,并让列表、详情、导出共享同一组装逻辑。
### 二、Mapper 查询设计
保留现有流水查询 Mapper 不做大改,只新增标签结果只读查询能力,建议放在 `CcdiBankTagResultMapper`
1. 按流水 ID 集合批量查询标签结果
- 入参:`List<Long> bankStatementIds`
- 条件:`result_type = 'STATEMENT'`
- 返回:标签明细列表
2. 按单个流水 ID 查询标签结果
- 入参:`Long bankStatementId`
- 条件:`result_type = 'STATEMENT'`
- 返回:标签明细列表
排序建议统一按以下顺序之一稳定输出:
- `risk_level` + `rule_code`
这样同一流水的标签顺序在列表、详情、导出中保持一致。
### 三、Service 组装设计
#### 1. 列表查询
`selectStatementPage()` 调整为两阶段:
1. 调用现有 Mapper 查询分页流水。
2. 收集当前页全部 `bankStatementId`
3. 批量查询这些流水的标签结果。
4.`bankStatementId` 分组后回填到每条 `CcdiBankStatementListVO.hitTags`
列表无标签时返回空集合,不返回 `null`,减少前端判空分支。
#### 2. 详情查询
`getStatementDetail()` 调整为:
1. 查询原有流水详情。
2. 按当前 `bankStatementId` 查询标签结果。
3. 回填到 `CcdiBankStatementDetailVO.hitTags`
#### 3. 导出查询
`selectStatementListForExport()` 调整为:
1. 查询导出范围内全部流水。
2. 批量查询这些流水的标签结果。
3. 按流水 ID 分组。
4. 组装到 `CcdiBankStatementExcel`
- `异常标签`:按标签名称拼接
- `命中原因摘要`:按相同顺序拼接
拼接分隔符建议统一使用全角分号 ``,避免在 Excel 中与金额千分位或英文逗号混淆。
### 四、Controller 设计
不新增接口,继续复用:
- `GET /ccdi/project/bank-statement/list`
- `GET /ccdi/project/bank-statement/detail/{bankStatementId}`
- `POST /ccdi/project/bank-statement/export`
这样不会影响现有菜单入口和前端 API 结构。
## 前端设计
### 一、列表展示
`DetailQuery.vue` 的表格中新增“异常标签”列,位置放在“摘要 / 交易类型”和“交易金额”之间。
展示规则:
- 有标签:逐个渲染轻量标签组件,仅显示 `ruleName`
- 无标签:显示 `-`
- 单条流水命中多个标签:同列换行或折行展示
样式规则:
- 沿用 Element UI `el-tag` 轻量视觉
- 可按 `riskLevel` 映射 `type`,但列表不展示风险等级文案
- 不新增 tooltip、展开收起、二级详情等扩展交互
### 二、详情展示
在现有详情弹窗的基础字段区下方新增“命中异常标签”模块。
展示规则:
- 无标签:显示“当前流水未命中异常标签”
- 有标签:按条展示
- 标签名称
- 风险等级
- 命中原因摘要
详情模块使用纵向结构,优先保证原因摘要可读性,不把多个原因压成单个文本段。
### 三、导出展示
导出 Excel 在现有列后追加:
- `异常标签`
- `命中原因摘要`
导出示例:
- `异常标签``房车消费支出交易;大额转账交易`
- `命中原因摘要``摘要命中购买房产首付款;转账金额 200000.00 元超过阈值`
## 错误处理
### 列表与详情
- 流水主查询成功、标签补充查询失败时,不让整个列表或详情失败。
- 列表标签列回退为空展示。
- 详情标签模块回退为无数据展示。
- 后端记录错误日志,便于排查标签结果查询异常。
### 导出
- 导出属于结果交付场景。
- 若标签结果查询或拼装失败,导出整体失败并返回错误。
- 不允许静默导出缺少标签列内容的文件,避免形成误导。
## 性能考虑
- 列表页只对当前页流水做一次批量标签查询,禁止逐条单查。
- 导出阶段对导出结果范围做一次批量标签查询,再在内存中按流水 ID 分组。
- 不把标签表聚合逻辑直接并入主分页 SQL避免影响现有分页查询稳定性。
## 测试设计
### 后端单测
- 列表查询:无标签、单标签、多标签三种场景
- 详情查询:返回结构化标签明细
- 导出查询:正确拼装“异常标签”“命中原因摘要”
- 仅返回 `STATEMENT` 标签,不混入对象级结果
### Mapper / SQL 测试
- 批量标签查询能按 `bank_statement_id` 正确分组
- 同一流水多个标签返回顺序稳定
### 前端单测
- 列表标签列正确显示多个标签与空值占位
- 详情弹窗正确显示命中异常标签模块
- 不影响现有翻页、排序、详情打开能力
### 人工验证
1. 进入项目详情页的“流水明细查询”
2. 确认列表中异常标签列展示正常
3. 打开一条命中流水详情,确认名称、风险等级、命中原因摘要可见
4. 导出当前筛选结果,确认 Excel 中新增两列且内容与页面口径一致
## 风险与边界
- 若历史标签结果中 `reason_detail` 缺失,详情和导出只能展示空摘要;本次不补历史数据修复。
- 若同一流水命中标签较多,列表列宽可能变高;本次仅做轻量折行展示,不增加复杂交互。
- 本次不新增异常标签筛选,用户仍需通过导出或详情查看具体命中原因。
## 实施拆分建议
后续进入实施计划时,默认拆为两份文档:
- 后端实施计划标签结果查询、VO 扩展、导出扩展、测试
- 前端实施计划:列表标签列、详情标签模块、单测与联调验证
## 结论
本次需求采用“现有流水查询 + 服务层批量补标签”的最短路径方案:
- 列表展示标签名称
- 详情展示标签名称、风险等级、命中原因摘要
- 导出追加异常标签与命中原因摘要
- 仅展示当前流水直接命中的流水级标签
该方案不改变现有流水查询入口、筛选项和标签计算逻辑,能在最小改动范围内补齐页面可读性与导出可交付性。

View File

@@ -0,0 +1,29 @@
# 流水明细异常标签展示设计记录
## 变更概述
- 新增“流水明细异常标签展示”设计文档。
- 明确列表只展示当前流水直接命中的异常标签名称。
- 明确详情展示标签名称、风险等级和命中原因摘要。
- 明确导出文件追加“异常标签”“命中原因摘要”两列。
- 明确本次只使用流水级标签结果,不混入对象级标签。
## 新增文件
- `docs/design/2026-03-18-bank-statement-hit-tags-design.md`
## 设计结论
- 后端采用“现有流水查询 + 服务层批量补标签”的方式实现。
- 列表、详情、导出统一读取 `ccdi_bank_statement_tag_result``result_type = 'STATEMENT'` 的结果。
- 页面不新增异常标签筛选、排序和统计能力。
- 导出失败时不允许静默丢失标签列内容。
## 过程修正
- 设计文档已从通用技能默认目录纠正到仓库规范目录 `docs/design/`
- 后续同类设计文档一律优先以仓库 `AGENTS.md` 与现有目录结构为准,不再使用通用默认 spec 路径。
## 后续动作
- 待用户审阅 spec 后,进入前后端实施计划阶段。