From d922682d5ac8b230c7b8a0f190d9d2456aa20c8c Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Thu, 19 Mar 2026 09:04:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B5=81=E6=B0=B4=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E6=A0=87=E7=AD=BE=E5=89=8D=E5=90=8E=E7=AB=AF=E5=AE=9E?= =?UTF-8?q?=E6=96=BD=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...atement-hit-tags-backend-implementation.md | 426 ++++++++++++++++++ ...tement-hit-tags-frontend-implementation.md | 325 +++++++++++++ ...-19-bank-statement-hit-tags-plan-record.md | 23 + 3 files changed, 774 insertions(+) create mode 100644 docs/plans/backend/2026-03-19-bank-statement-hit-tags-backend-implementation.md create mode 100644 docs/plans/frontend/2026-03-19-bank-statement-hit-tags-frontend-implementation.md create mode 100644 docs/reports/implementation/2026-03-19-bank-statement-hit-tags-plan-record.md diff --git a/docs/plans/backend/2026-03-19-bank-statement-hit-tags-backend-implementation.md b/docs/plans/backend/2026-03-19-bank-statement-hit-tags-backend-implementation.md new file mode 100644 index 00000000..217ebb94 --- /dev/null +++ b/docs/plans/backend/2026-03-19-bank-statement-hit-tags-backend-implementation.md @@ -0,0 +1,426 @@ +# Bank Statement Hit Tags Backend Implementation Plan + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 在现有流水明细查询后端链路中补齐“异常标签”读取与组装能力,让列表、详情、导出统一展示当前流水直接命中的流水级标签。 + +**Architecture:** 继续复用现有 `CcdiBankStatementController -> CcdiBankStatementServiceImpl -> CcdiBankStatementMapper` 主链路,不改分页查询入口和筛选协议;新增 `CcdiBankTagResultMapper` 的只读标签查询方法,由 Service 在列表分页、详情查询和导出映射阶段批量补齐 `hitTags` 与导出字符串。所有标签口径统一限定为 `ccdi_bank_statement_tag_result.result_type = 'STATEMENT'` 且 `bank_statement_id` 命中当前流水。 + +**Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus, JUnit 5, Mockito, Maven + +--- + +### Task 1: 补齐流水标签只读查询模型与 Mapper SQL + +**Files:** +- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementHitTagVO.java` +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagResultMapper.java` +- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagResultMapper.xml` +- Create: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagResultMapperXmlTest.java` + +- [ ] **Step 1: Write the failing test** + +先新增 `CcdiBankTagResultMapperXmlTest`,锁定新 SQL 必须只查流水级标签,并按稳定顺序输出: + +```java +class CcdiBankTagResultMapperXmlTest { + + @Test + void selectStatementHitTagsByIds_shouldFilterStatementResultType() throws Exception { + String xml = Files.readString(Path.of( + "ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagResultMapper.xml" + )); + + assertTrue(xml.contains("selectStatementHitTagsByBankStatementIds")); + assertTrue(xml.contains("result_type = 'STATEMENT'")); + assertTrue(xml.contains("bank_statement_id IN")); + } + + @Test + void selectStatementHitTagsByIds_shouldKeepStableOrder() throws Exception { + String xml = Files.readString(Path.of( + "ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagResultMapper.xml" + )); + + assertTrue(xml.contains("ORDER BY")); + assertTrue(xml.contains("rule_code")); + } +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankTagResultMapperXmlTest test +``` + +Expected: + +- `FAIL` +- 原因是标签明细 VO、Mapper 方法和 XML 查询都还不存在 + +- [ ] **Step 3: Write minimal implementation** + +最小实现包含 4 个点: + +1. 新增标签明细 VO: + +```java +@Data +public class CcdiBankStatementHitTagVO { + private Long bankStatementId; + private String ruleName; + private String riskLevel; + private String reasonDetail; + private String ruleCode; +} +``` + +2. 在 `CcdiBankTagResultMapper` 中新增: + +```java +List selectStatementHitTagsByBankStatementIds(@Param("bankStatementIds") List bankStatementIds); + +List selectStatementHitTagsByBankStatementId(@Param("bankStatementId") Long bankStatementId); +``` + +3. 在 `CcdiBankTagResultMapper.xml` 中新增对应 `resultMap` 与查询: + +```xml + +``` + +4. 单条查询直接复用相同过滤条件: + +```xml + +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankTagResultMapperXmlTest test +``` + +Expected: + +- `PASS` +- 说明标签 Mapper 已具备只读查询能力,且不会混入对象级结果 + +- [ ] **Step 5: Commit** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementHitTagVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagResultMapper.java ccdi-project/src/main/resources/mapper/ccdi/project/CcdiBankTagResultMapper.xml ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagResultMapperXmlTest.java +git commit -m "补充流水异常标签结果查询" +``` + +### Task 2: 在列表与详情查询中组装结构化命中标签 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementListVO.java` +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementDetailVO.java` +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImpl.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImplTest.java` + +- [ ] **Step 1: Write the failing test** + +先在 `CcdiBankStatementServiceImplTest` 中补 2 个失败用例,锁定列表分页和详情查询都要回填 `hitTags`: + +```java +@Mock +private CcdiBankTagResultMapper bankTagResultMapper; + +@Test +void selectStatementPage_shouldAssembleStatementHitTags() { + Page page = new Page<>(1, 10); + CcdiBankStatementListVO row = new CcdiBankStatementListVO(); + row.setBankStatementId(8L); + page.setRecords(List.of(row)); + + CcdiBankStatementHitTagVO hitTag = new CcdiBankStatementHitTagVO(); + hitTag.setBankStatementId(8L); + hitTag.setRuleName("大额转账交易"); + + when(bankStatementMapper.selectStatementPage(any(), any())).thenReturn(page); + when(bankTagResultMapper.selectStatementHitTagsByBankStatementIds(List.of(8L))) + .thenReturn(List.of(hitTag)); + + Page result = service.selectStatementPage(new Page<>(1, 10), new CcdiBankStatementQueryDTO()); + + assertEquals(1, result.getRecords().get(0).getHitTags().size()); + assertEquals("大额转账交易", result.getRecords().get(0).getHitTags().get(0).getRuleName()); +} + +@Test +void getStatementDetail_shouldAttachStatementHitTags() { + CcdiBankStatementDetailVO detailVO = new CcdiBankStatementDetailVO(); + detailVO.setBankStatementId(9L); + + CcdiBankStatementHitTagVO hitTag = new CcdiBankStatementHitTagVO(); + hitTag.setBankStatementId(9L); + hitTag.setRuleName("房车消费支出交易"); + hitTag.setRiskLevel("HIGH"); + hitTag.setReasonDetail("摘要命中购买房产首付款"); + + when(bankStatementMapper.selectStatementDetailById(9L)).thenReturn(detailVO); + when(bankTagResultMapper.selectStatementHitTagsByBankStatementId(9L)).thenReturn(List.of(hitTag)); + + CcdiBankStatementDetailVO result = service.getStatementDetail(9L); + + assertEquals(1, result.getHitTags().size()); + assertEquals("HIGH", result.getHitTags().get(0).getRiskLevel()); +} +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankStatementServiceImplTest test +``` + +Expected: + +- `FAIL` +- 原因是 `hitTags` 字段和 Service 组装逻辑尚未实现 + +- [ ] **Step 3: Write minimal implementation** + +按最小范围补齐结构化标签: + +1. `CcdiBankStatementListVO` 新增: + +```java +private List hitTags; +``` + +2. `CcdiBankStatementDetailVO` 新增: + +```java +private List hitTags; +``` + +3. `CcdiBankStatementServiceImpl` 注入 `CcdiBankTagResultMapper` +4. 在 `selectStatementPage()` 中新增批量组装: + +```java +private void fillStatementHitTags(List records) { + List ids = records.stream() + .map(CcdiBankStatementListVO::getBankStatementId) + .filter(Objects::nonNull) + .distinct() + .toList(); + Map> hitTagMap = bankTagResultMapper + .selectStatementHitTagsByBankStatementIds(ids) + .stream() + .collect(Collectors.groupingBy(CcdiBankStatementHitTagVO::getBankStatementId)); + records.forEach(item -> item.setHitTags(hitTagMap.getOrDefault(item.getBankStatementId(), Collections.emptyList()))); +} +``` + +5. 在 `getStatementDetail()` 中按单条流水补齐: + +```java +detail.setHitTags(bankTagResultMapper.selectStatementHitTagsByBankStatementId(bankStatementId)); +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankStatementServiceImplTest test +``` + +Expected: + +- `PASS` +- 说明列表和详情都能拿到结构化标签数据 + +- [ ] **Step 5: Commit** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementListVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiBankStatementDetailVO.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImpl.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImplTest.java +git commit -m "补充流水明细标签组装逻辑" +``` + +### Task 3: 扩展导出列并补齐后端交付记录 + +**Files:** +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiBankStatementExcel.java` +- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImpl.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImplTest.java` +- Modify: `ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiBankStatementControllerTest.java` +- Create: `docs/reports/implementation/2026-03-19-bank-statement-hit-tags-backend-implementation.md` + +- [ ] **Step 1: Write the failing test** + +先在 `CcdiBankStatementServiceImplTest` 里锁定导出内容必须包含标签名与原因摘要: + +```java +@Test +void selectStatementListForExport_shouldMapHitTagsAndReasons() { + CcdiBankStatementListVO row = new CcdiBankStatementListVO(); + row.setBankStatementId(10L); + row.setLeAccountNo("6222"); + + CcdiBankStatementHitTagVO first = new CcdiBankStatementHitTagVO(); + first.setBankStatementId(10L); + first.setRuleName("房车消费支出交易"); + first.setReasonDetail("摘要命中购买房产首付款"); + + CcdiBankStatementHitTagVO second = new CcdiBankStatementHitTagVO(); + second.setBankStatementId(10L); + second.setRuleName("大额转账交易"); + second.setReasonDetail("转账金额 200000.00 元超过阈值"); + + when(bankStatementMapper.selectStatementListForExport(any())).thenReturn(List.of(row)); + when(bankTagResultMapper.selectStatementHitTagsByBankStatementIds(List.of(10L))) + .thenReturn(List.of(first, second)); + + List result = service.selectStatementListForExport(new CcdiBankStatementQueryDTO()); + + assertEquals("房车消费支出交易;大额转账交易", result.get(0).getHitTagNames()); + assertEquals("摘要命中购买房产首付款;转账金额 200000.00 元超过阈值", result.get(0).getHitTagReasons()); +} +``` + +同时在交付记录里先写骨架: + +```markdown +# 流水明细异常标签展示后端实施记录 + +## 修改内容 +- 标签结果只读查询 +- 列表/详情组装 +- 导出列扩展 +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankStatementServiceImplTest,CcdiBankStatementControllerTest test +``` + +Expected: + +- `FAIL` +- 原因是导出对象还没有标签列,Service 也没有做字符串拼装 + +- [ ] **Step 3: Write minimal implementation** + +1. `CcdiBankStatementExcel` 新增两列: + +```java +@Excel(name = "异常标签") +private String hitTagNames; + +@Excel(name = "命中原因摘要") +private String hitTagReasons; +``` + +2. `CcdiBankStatementServiceImpl.toExcel()` 改为接收当前流水标签集合并拼装: + +```java +excel.setHitTagNames(tags.stream().map(CcdiBankStatementHitTagVO::getRuleName).collect(Collectors.joining(";"))); +excel.setHitTagReasons(tags.stream().map(CcdiBankStatementHitTagVO::getReasonDetail).filter(StringUtils::isNotBlank).collect(Collectors.joining(";"))); +``` + +3. 导出查询阶段复用 Task 2 的批量标签查询逻辑,不新增第二套口径 +4. 完成 `docs/reports/implementation/2026-03-19-bank-statement-hit-tags-backend-implementation.md`,记录改动文件、测试命令和结果 + +- [ ] **Step 4: Run tests to verify they pass** + +Run: + +```bash +mvn -pl ccdi-project -Dtest=CcdiBankTagResultMapperXmlTest,CcdiBankStatementServiceImplTest,CcdiBankStatementControllerTest test +``` + +Expected: + +- `PASS` +- 说明标签查询、列表详情组装、导出扩展都已通过回归 + +- [ ] **Step 5: Commit** + +```bash +git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiBankStatementExcel.java ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImpl.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankStatementServiceImplTest.java ccdi-project/src/test/java/com/ruoyi/ccdi/project/controller/CcdiBankStatementControllerTest.java docs/reports/implementation/2026-03-19-bank-statement-hit-tags-backend-implementation.md +git commit -m "补充流水异常标签后端导出能力" +``` + +### Task 4: 进行接口级人工回归并确认无对象级标签串入 + +**Files:** +- Modify: `docs/reports/implementation/2026-03-19-bank-statement-hit-tags-backend-implementation.md` + +- [ ] **Step 1: Prepare the manual verification checklist** + +在实施记录中补充 4 个后端联调点: + +```markdown +## 联调检查 +- [ ] 列表接口返回 `hitTags` +- [ ] 详情接口返回 `hitTags` +- [ ] 导出新增两列 +- [ ] 未混入 `OBJECT` 标签结果 +``` + +- [ ] **Step 2: Run targeted backend verification** + +Run: + +```bash +mvn -pl ccdi-project test -Dtest=CcdiBankTagResultMapperXmlTest,CcdiBankStatementServiceImplTest,CcdiBankStatementControllerTest +``` + +Expected: + +- `PASS` + +- [ ] **Step 3: Verify response shape manually** + +联调时至少检查: + +1. `GET /ccdi/project/bank-statement/list` 返回的每条流水出现 `hitTags` +2. `GET /ccdi/project/bank-statement/detail/{bankStatementId}` 返回 `hitTags[*].ruleName/riskLevel/reasonDetail` +3. 导出文件末尾新增两列且顺序固定 +4. 通过构造仅有对象级结果的样本,确认不会出现在列表和详情里 + +- [ ] **Step 4: Update the implementation record with results** + +把实际命令、结果、异常点补回实施记录,至少包含: + +- 运行日期 +- 测试命令 +- 是否通过 +- 若失败,失败原因和修正方式 + +- [ ] **Step 5: Commit** + +```bash +git add docs/reports/implementation/2026-03-19-bank-statement-hit-tags-backend-implementation.md +git commit -m "补充流水异常标签后端验证记录" +``` diff --git a/docs/plans/frontend/2026-03-19-bank-statement-hit-tags-frontend-implementation.md b/docs/plans/frontend/2026-03-19-bank-statement-hit-tags-frontend-implementation.md new file mode 100644 index 00000000..bb7e7741 --- /dev/null +++ b/docs/plans/frontend/2026-03-19-bank-statement-hit-tags-frontend-implementation.md @@ -0,0 +1,325 @@ +# Bank Statement Hit Tags Frontend Implementation Plan + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 在项目详情“流水明细查询”页面的列表和详情弹窗中展示当前流水命中的异常标签,并保持导出入口与现有筛选、分页、排序交互兼容。 + +**Architecture:** 继续沿用 `DetailQuery.vue` 作为唯一页面组件,不新增页面和接口;前端直接消费后端返回的 `hitTags` 结构,列表只渲染标签名称,详情弹窗渲染标签名称、风险等级和命中原因摘要。由于仓库当前前端单测基建是静态 Node 脚本,本计划以“先补 source 断言 + 再跑 build 验证”为主,不额外引入测试框架。 + +**Tech Stack:** Vue 2, Element UI, Axios request wrapper, Node.js, npm + +--- + +### Task 1: 在列表表格中新增异常标签列 + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue` +- Create: `ruoyi-ui/tests/unit/detail-query-hit-tags-list.test.js` + +- [ ] **Step 1: Write the failing test** + +先新增静态断言脚本,锁定列表必须新增“异常标签”列并读取 `scope.row.hitTags`: + +```js +const assert = require("assert"); +const fs = require("fs"); +const path = require("path"); + +const componentPath = path.resolve( + __dirname, + "../../src/views/ccdiProject/components/detail/DetailQuery.vue" +); +const source = fs.readFileSync(componentPath, "utf8"); + +assert(source.includes('label="异常标签"'), "列表应新增异常标签列"); +assert(source.includes("scope.row.hitTags"), "异常标签列应读取当前行的 hitTags"); +assert(source.includes('v-for="(tag, index) in scope.row.hitTags"'), "异常标签列应逐个渲染命中标签"); +assert(source.includes("tag.ruleName"), "异常标签列应展示标签名称"); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/detail-query-hit-tags-list.test.js +``` + +Expected: + +- `FAIL` +- 原因是当前列表还没有异常标签列和对应格式化方法 + +- [ ] **Step 3: Write minimal implementation** + +在 `DetailQuery.vue` 中做最小范围改动: + +1. 在“摘要 / 交易类型”和“交易金额”之间新增: + +```html + + + +``` + +2. 给 `createEmptyDetailData()` 补 `hitTags: []`,并在列表取数后统一兜底: + +```js +this.list = (res.rows || []).map((item) => ({ + hitTags: [], + ...item, +})); +``` + +3. 新增方法: + +```js +mapRiskLevelToTagType(riskLevel) { + const level = String(riskLevel || "").toUpperCase(); + if (level === "HIGH") return "danger"; + if (level === "MEDIUM") return "warning"; + return "info"; +} +``` + +4. 增加轻量样式: + +```scss +.hit-tag-list { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.empty-text { + color: #909399; +} +``` + +- [ ] **Step 4: Run tests to verify they pass** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/detail-query-hit-tags-list.test.js +node tests/unit/detail-query-filter-layout.test.js +node tests/unit/detail-query-detail-dialog.test.js +``` + +Expected: + +- 3 个脚本都 `PASS` +- 说明列表新增列没有破坏现有静态结构 + +- [ ] **Step 5: Commit** + +```bash +git add ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue ruoyi-ui/tests/unit/detail-query-hit-tags-list.test.js ruoyi-ui/tests/unit/detail-query-filter-layout.test.js ruoyi-ui/tests/unit/detail-query-detail-dialog.test.js +git commit -m "补充流水明细异常标签列表展示" +``` + +### Task 2: 在详情弹窗中新增命中异常标签模块 + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue` +- Modify: `ruoyi-ui/tests/unit/detail-query-detail-dialog.test.js` + +- [ ] **Step 1: Write the failing test** + +在 `detail-query-detail-dialog.test.js` 中追加断言,锁定详情弹窗必须出现“命中异常标签”模块: + +```js +[ + "命中异常标签", + "detail-hit-tag-section", + "detailData.hitTags", + "当前流水未命中异常标签", + "mapRiskLevelToTagType(tag.riskLevel)", +].forEach((token) => { + assert(source.includes(token), `详情弹窗缺少异常标签结构: ${token}`); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/detail-query-detail-dialog.test.js +``` + +Expected: + +- `FAIL` +- 原因是详情弹窗尚未渲染命中异常标签模块 + +- [ ] **Step 3: Write minimal implementation** + +在详情弹窗文件区下方新增独立模块: + +```html +
+
命中异常标签
+
+
+
+ {{ formatField(tag.ruleName) }} + + {{ formatRiskLevel(tag.riskLevel) }} + +
+
{{ formatField(tag.reasonDetail) }}
+
+
+
当前流水未命中异常标签
+
+``` + +并新增方法: + +```js +formatRiskLevel(value) { + const level = String(value || "").toUpperCase(); + if (level === "HIGH") return "高风险"; + if (level === "MEDIUM") return "中风险"; + if (level === "LOW") return "低风险"; + return "未标注"; +} +``` + +同时补充对应样式类,保证详情里纵向展示原因摘要,不把多条命中压成一行。 + +- [ ] **Step 4: Run tests to verify they pass** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/detail-query-detail-dialog.test.js +node tests/unit/detail-query-hit-tags-list.test.js +``` + +Expected: + +- `PASS` +- 说明详情模块和列表模块结构都已具备 + +- [ ] **Step 5: Commit** + +```bash +git add ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue ruoyi-ui/tests/unit/detail-query-detail-dialog.test.js ruoyi-ui/tests/unit/detail-query-hit-tags-list.test.js +git commit -m "补充流水详情异常标签展示" +``` + +### Task 3: 补齐前端回归验证记录并完成构建验证 + +**Files:** +- Create: `docs/tests/records/2026-03-19-bank-statement-hit-tags-frontend-verification.md` +- Create: `docs/reports/implementation/2026-03-19-bank-statement-hit-tags-frontend-implementation.md` +- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue` + +- [ ] **Step 1: Write the verification record skeleton** + +先建立前端验证记录,锁定联调检查项: + +```markdown +# 流水明细异常标签前端验证记录 + +## 验证范围 +- 列表异常标签列 +- 详情异常标签模块 +- 空态展示 +- 导出入口回归 + +## 验证结果 +- [ ] 列表显示命中标签名称 +- [ ] 详情显示名称、风险等级、命中原因摘要 +- [ ] 无标签时显示空态 +- [ ] 导出入口仍可触发下载 +``` + +同时创建前端实施记录骨架: + +```markdown +# 流水明细异常标签前端实施记录 + +## 修改内容 +- 列表异常标签列 +- 详情异常标签模块 +- 静态测试与构建验证 +``` + +- [ ] **Step 2: Run baseline build check before final polish** + +Run: + +```bash +cd ruoyi-ui +npm run build:prod +``` + +Expected: + +- 当前改动后的前端代码可以正常构建 + +- [ ] **Step 3: Write minimal final polish** + +补齐最后的回归点: + +1. 确认 `handleViewDetail()` 在详情返回无 `hitTags` 时仍回填空数组 +2. 确认列表、详情空态文案和样式一致 +3. 若需要,给异常标签模块补最小响应式样式,确保移动端不溢出 +4. 在实施记录中写明本次不改 `ruoyi-ui/src/api/ccdiProjectBankStatement.js` 的原因: + - 复用现有接口 + - 仅扩展响应数据结构 + +- [ ] **Step 4: Run full frontend verification** + +Run: + +```bash +cd ruoyi-ui +node tests/unit/detail-query-filter-layout.test.js +node tests/unit/detail-query-detail-dialog.test.js +node tests/unit/detail-query-hit-tags-list.test.js +npm run build:prod +``` + +Expected: + +- 静态脚本全部 `PASS` +- 构建 `PASS` + +联调时额外检查: + +1. 列表页一条命中多标签的流水是否正确折行 +2. 无标签流水是否显示 `-` +3. 详情页命中原因摘要是否完整可见 +4. 点击“导出流水”按钮仍能正常触发下载 + +- [ ] **Step 5: Commit** + +```bash +git add ruoyi-ui/src/views/ccdiProject/components/detail/DetailQuery.vue docs/tests/records/2026-03-19-bank-statement-hit-tags-frontend-verification.md docs/reports/implementation/2026-03-19-bank-statement-hit-tags-frontend-implementation.md +git commit -m "补充流水异常标签前端验证记录" +``` diff --git a/docs/reports/implementation/2026-03-19-bank-statement-hit-tags-plan-record.md b/docs/reports/implementation/2026-03-19-bank-statement-hit-tags-plan-record.md new file mode 100644 index 00000000..45ed6045 --- /dev/null +++ b/docs/reports/implementation/2026-03-19-bank-statement-hit-tags-plan-record.md @@ -0,0 +1,23 @@ +# 流水明细异常标签实施计划记录 + +## 变更概述 + +- 基于已确认设计文档,新增后端实施计划与前端实施计划各一份。 +- 后端计划聚焦标签结果只读查询、列表详情组装、导出列扩展与后端验证。 +- 前端计划聚焦列表异常标签列、详情异常标签模块、静态测试与构建验证。 +- 两份计划都延续现有仓库规范,未使用通用技能默认目录。 + +## 新增文件 + +- `docs/plans/backend/2026-03-19-bank-statement-hit-tags-backend-implementation.md` +- `docs/plans/frontend/2026-03-19-bank-statement-hit-tags-frontend-implementation.md` + +## 计划结论 + +- 后端按“现有流水查询 + 服务层批量补标签”实施。 +- 前端继续只改 `DetailQuery.vue`,不新增页面、不改接口路径。 +- 实施阶段分别补充前后端实施记录与验证记录。 + +## 后续动作 + +- 待用户确认后,进入实际开发执行阶段。