From 7fec8e21beab52ec90554896694cb3be8502c86d Mon Sep 17 00:00:00 2001 From: wjj <2069666735@qq.com> Date: Mon, 20 Jul 2026 14:26:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9C=AA=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=E9=A3=8E=E9=99=A9=E6=98=8E=E7=BB=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CcdiProjectOverviewController.java | 22 +- ...CcdiProjectUnsubmittedAccountQueryDTO.java | 10 + ...CcdiProjectSuspiciousTransactionExcel.java | 6 +- .../CcdiProjectUnsubmittedAccountFlowVO.java | 2 + .../mapper/CcdiProjectOverviewMapper.java | 6 +- .../service/ICcdiProjectOverviewService.java | 25 ++ .../impl/CcdiProjectOverviewServiceImpl.java | 24 +- ...CcdiProjectRiskDetailWorkbookExporter.java | 8 +- .../project/CcdiProjectOverviewMapper.xml | 14 +- .../CcdiProjectOverviewMapperSqlTest.java | 5 + ...ProjectRiskDetailWorkbookExporterTest.java | 29 +- ...ubmitted-account-backend-implementation.md | 2 +- .../2026-07-20-unsubmitted-account.md | 53 ++- ruoyi-ui/src/api/ccdi/projectOverview.js | 12 + .../components/detail/RiskDetailSection.vue | 307 +++++++++++++++++- ...isk-detail-abnormal-account-layout.test.js | 23 ++ 16 files changed, 513 insertions(+), 35 deletions(-) diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java index dcb4c3f6..abdc89ab 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectOverviewController.java @@ -26,6 +26,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectUnsubmittedAccountFlowVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectUnsubmittedAccountVO; import com.ruoyi.ccdi.project.service.CcdiProjectAccessService; import com.ruoyi.ccdi.project.service.ICcdiProjectOverviewService; @@ -241,6 +242,18 @@ public class CcdiProjectOverviewController extends BaseController { return AjaxResult.success(result); } + /** + * 查询未提交账户流水 + */ + @GetMapping("/unsubmitted-accounts/flows") + @Operation(summary = "查询未提交账户流水") + @PreAuthorize("@ss.hasPermi('ccdi:project:query')") + public AjaxResult getUnsubmittedAccountFlows(CcdiProjectUnsubmittedAccountQueryDTO queryDTO) { + projectAccessService.assertCanRead(queryDTO.getProjectId()); + List rows = overviewService.getUnsubmittedAccountFlows(queryDTO); + return AjaxResult.success(rows); + } + /** * 导出涉疑交易明细 */ @@ -323,9 +336,12 @@ public class CcdiProjectOverviewController extends BaseController { @PostMapping("/unsubmitted-accounts/export") @Operation(summary = "导出未提交账户流水") @PreAuthorize("@ss.hasPermi('ccdi:project:query')") - public void exportUnsubmittedAccountFlows(HttpServletResponse response, Long projectId) { - projectAccessService.assertCanRead(projectId); - List rows = overviewService.exportUnsubmittedAccountFlows(projectId); + public void exportUnsubmittedAccountFlows( + HttpServletResponse response, + CcdiProjectUnsubmittedAccountQueryDTO queryDTO + ) { + projectAccessService.assertCanRead(queryDTO.getProjectId()); + List rows = overviewService.exportUnsubmittedAccountFlows(queryDTO); ExcelUtil util = new ExcelUtil<>(CcdiProjectUnsubmittedAccountFlowExcel.class); util.exportExcel(response, rows, "未提交账户流水"); diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectUnsubmittedAccountQueryDTO.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectUnsubmittedAccountQueryDTO.java index e2e9ad65..27f321ec 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectUnsubmittedAccountQueryDTO.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/CcdiProjectUnsubmittedAccountQueryDTO.java @@ -12,4 +12,14 @@ public class CcdiProjectUnsubmittedAccountQueryDTO { * 项目ID */ private Long projectId; + + /** + * 主体名称 + */ + private String subjectName; + + /** + * 未提交账号 + */ + private String accountNo; } diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java index 46bce6da..2b8fa1df 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/excel/CcdiProjectSuspiciousTransactionExcel.java @@ -35,9 +35,9 @@ public class CcdiProjectSuspiciousTransactionExcel { @Excel(name = "交易类型") private String cashType; - @Excel(name = "异常标签") - private String hitTags; - @Excel(name = "交易金额") private BigDecimal displayAmount; + + @Excel(name = "异常标签") + private String hitTags; } diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectUnsubmittedAccountFlowVO.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectUnsubmittedAccountFlowVO.java index 75cb59f5..78b187bc 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectUnsubmittedAccountFlowVO.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/CcdiProjectUnsubmittedAccountFlowVO.java @@ -9,6 +9,8 @@ import lombok.Data; @Data public class CcdiProjectUnsubmittedAccountFlowVO { + private Long bankStatementId; + private String subjectName; private String accountNo; diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java index d5f6f72e..e73e07b4 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapper.java @@ -275,10 +275,12 @@ public interface CcdiProjectOverviewMapper { /** * 查询未提交账户流水 * - * @param projectId 项目ID + * @param query 查询条件 * @return 未提交账户流水 */ - List selectUnsubmittedAccountFlowList(@Param("projectId") Long projectId); + List selectUnsubmittedAccountFlowList( + @Param("query") CcdiProjectUnsubmittedAccountQueryDTO query + ); /** * 查询项目员工负面征信导出列表 diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java index 3ec913ce..e7a9b9c2 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectOverviewService.java @@ -28,6 +28,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectSuspiciousTransactionPageVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO; +import com.ruoyi.ccdi.project.domain.vo.CcdiProjectUnsubmittedAccountFlowVO; import com.ruoyi.ccdi.project.domain.vo.CcdiProjectUnsubmittedAccountVO; import jakarta.servlet.http.HttpServletResponse; @@ -293,6 +294,18 @@ public interface ICcdiProjectOverviewService { return new CcdiProjectUnsubmittedAccountVO(); } + /** + * 查询未提交账户流水 + * + * @param queryDTO 查询条件 + * @return 未提交账户流水 + */ + default List getUnsubmittedAccountFlows( + CcdiProjectUnsubmittedAccountQueryDTO queryDTO + ) { + return List.of(); + } + /** * 导出未提交账户流水 * @@ -303,6 +316,18 @@ public interface ICcdiProjectOverviewService { return List.of(); } + /** + * 导出未提交账户流水 + * + * @param queryDTO 查询条件 + * @return 导出列表 + */ + default List exportUnsubmittedAccountFlows( + CcdiProjectUnsubmittedAccountQueryDTO queryDTO + ) { + return List.of(); + } + /** * 重算结果总览员工结果并同步项目风险人数 * diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java index 08c8fe8c..fffd5dcb 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectOverviewServiceImpl.java @@ -506,10 +506,28 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi } @Override - public List exportUnsubmittedAccountFlows(Long projectId) { - ensureProjectExists(projectId); + public List getUnsubmittedAccountFlows( + CcdiProjectUnsubmittedAccountQueryDTO queryDTO + ) { + ensureProjectExists(queryDTO.getProjectId()); - return defaultList(overviewMapper.selectUnsubmittedAccountFlowList(projectId)).stream() + return defaultList(overviewMapper.selectUnsubmittedAccountFlowList(queryDTO)); + } + + @Override + public List exportUnsubmittedAccountFlows(Long projectId) { + CcdiProjectUnsubmittedAccountQueryDTO queryDTO = new CcdiProjectUnsubmittedAccountQueryDTO(); + queryDTO.setProjectId(projectId); + return exportUnsubmittedAccountFlows(queryDTO); + } + + @Override + public List exportUnsubmittedAccountFlows( + CcdiProjectUnsubmittedAccountQueryDTO queryDTO + ) { + ensureProjectExists(queryDTO.getProjectId()); + + return defaultList(overviewMapper.selectUnsubmittedAccountFlowList(queryDTO)).stream() .map(this::buildUnsubmittedAccountFlowExcelRow) .toList(); } diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java index 1fad7491..adcd578c 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporter.java @@ -56,8 +56,8 @@ public class CcdiProjectRiskDetailWorkbookExporter { "关联员工", "摘要", "交易类型", - "异常标签", - "交易金额" + "交易金额", + "异常标签" }; writeHeader(header, headers); @@ -72,8 +72,8 @@ public class CcdiProjectRiskDetailWorkbookExporter { row.createCell(5).setCellValue(safeText(item.getRelatedStaffDisplay())); row.createCell(6).setCellValue(safeText(item.getUserMemo())); row.createCell(7).setCellValue(safeText(item.getCashType())); - row.createCell(8).setCellValue(safeText(item.getHitTags())); - row.createCell(9).setCellValue(safeNumber(item.getDisplayAmount())); + row.createCell(8).setCellValue(safeNumber(item.getDisplayAmount())); + row.createCell(9).setCellValue(safeText(item.getHitTags())); } } diff --git a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml index 42d33791..821f5e33 100644 --- a/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml +++ b/ccdi-project/src/main/resources/mapper/ccdi/project/CcdiProjectOverviewMapper.xml @@ -111,6 +111,7 @@ + @@ -1729,8 +1730,9 @@ diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java index c9695488..b16aae5d 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/mapper/CcdiProjectOverviewMapperSqlTest.java @@ -251,6 +251,11 @@ class CcdiProjectOverviewMapperSqlTest { assertTrue(accountSql.contains("unsubmittedAccountSubjectTotalSql"), accountSql); assertTrue(flowSql.contains("unsubmittedAccountCandidateRowSql"), flowSql); assertTrue(flowSql.contains("unsubmittedAccountAggregateSql"), flowSql); + assertTrue(flowSql.contains("query.projectId"), flowSql); + assertTrue(flowSql.contains("query.subjectName"), flowSql); + assertTrue(flowSql.contains("query.accountNo"), flowSql); + assertTrue(flowSql.contains("candidate.subjectName"), flowSql); + assertTrue(flowSql.contains("candidate.accountNo"), flowSql); assertTrue(candidateSql.contains("bs.project_id = #{unsubmittedProjectId}"), candidateSql); assertTrue(candidateSql.contains("bs.CUSTOMER_ACCOUNT_NAME"), candidateSql); assertTrue(candidateSql.contains("bs.LE_ACCOUNT_NAME"), candidateSql); diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java index ef5fa9dd..a9977f44 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectRiskDetailWorkbookExporterTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.mock.web.MockHttpServletResponse; import java.io.ByteArrayInputStream; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.List; @@ -91,11 +92,12 @@ class CcdiProjectRiskDetailWorkbookExporterTest { assertEquals("关联员工", workbook.getSheetAt(0).getRow(0).getCell(5).getStringCellValue()); assertEquals("摘要", workbook.getSheetAt(0).getRow(0).getCell(6).getStringCellValue()); assertEquals("交易类型", workbook.getSheetAt(0).getRow(0).getCell(7).getStringCellValue()); - assertEquals("异常标签", workbook.getSheetAt(0).getRow(0).getCell(8).getStringCellValue()); - assertEquals("交易金额", workbook.getSheetAt(0).getRow(0).getCell(9).getStringCellValue()); + assertEquals("交易金额", workbook.getSheetAt(0).getRow(0).getCell(8).getStringCellValue()); + assertEquals("异常标签", workbook.getSheetAt(0).getRow(0).getCell(9).getStringCellValue()); assertEquals("测试对手方", workbook.getSheetAt(0).getRow(1).getCell(3).getStringCellValue()); assertEquals("6222000000000001", workbook.getSheetAt(0).getRow(1).getCell(4).getStringCellValue()); - assertEquals("异常标签", workbook.getSheetAt(0).getRow(1).getCell(8).getStringCellValue()); + assertEquals(100D, workbook.getSheetAt(0).getRow(1).getCell(8).getNumericCellValue()); + assertEquals("异常标签", workbook.getSheetAt(0).getRow(1).getCell(9).getStringCellValue()); assertEquals("账号", workbook.getSheetAt(2).getRow(0).getCell(0).getStringCellValue()); assertEquals("开户人", workbook.getSheetAt(2).getRow(0).getCell(1).getStringCellValue()); assertEquals("银行", workbook.getSheetAt(2).getRow(0).getCell(2).getStringCellValue()); @@ -122,4 +124,25 @@ class CcdiProjectRiskDetailWorkbookExporterTest { assertEquals(30000D, workbook.getSheetAt(3).getRow(1).getCell(9).getNumericCellValue()); } } + + @Test + void shouldKeepSuspiciousTransactionExcelAmountBeforeHitTags() { + Field[] fields = CcdiProjectSuspiciousTransactionExcel.class.getDeclaredFields(); + + int amountIndex = findFieldIndex(fields, "displayAmount"); + int hitTagsIndex = findFieldIndex(fields, "hitTags"); + + assertTrue(amountIndex >= 0); + assertTrue(hitTagsIndex >= 0); + assertTrue(amountIndex < hitTagsIndex); + } + + private int findFieldIndex(Field[] fields, String fieldName) { + for (int i = 0; i < fields.length; i++) { + if (fieldName.equals(fields[i].getName())) { + return i; + } + } + return -1; + } } diff --git a/docs/plans/backend/2026-07-20-unsubmitted-account-backend-implementation.md b/docs/plans/backend/2026-07-20-unsubmitted-account-backend-implementation.md index 79617446..7ee9ed74 100644 --- a/docs/plans/backend/2026-07-20-unsubmitted-account-backend-implementation.md +++ b/docs/plans/backend/2026-07-20-unsubmitted-account-backend-implementation.md @@ -16,7 +16,7 @@ 1. 候选账号来自 `ccdi_bank_statement` 当前项目流水。 2. 对手方户名等于本方主体名,对手方账号非空,且清洗后不等于本方账号。 -3. 对手方账号不在本项目已提交账号集合中,已提交账号集合来自上传记录保存的 `account_nos`。 +3. 对手方账号不在本项目已提交账号集合中,已提交账号集合来自当前项目已上传流水的本方账号 `LE_ACCOUNT_NO`。 4. 贷款排除只使用银行贷款/信贷高确定性关键词,不使用 `TRX_TYPE`。 5. 只有候选账号关联流水全部命中贷款/信贷排除条件时,才排除该账号。 diff --git a/docs/reports/implementation/2026-07-20-unsubmitted-account.md b/docs/reports/implementation/2026-07-20-unsubmitted-account.md index ceaeadc8..2f952f2c 100644 --- a/docs/reports/implementation/2026-07-20-unsubmitted-account.md +++ b/docs/reports/implementation/2026-07-20-unsubmitted-account.md @@ -4,17 +4,60 @@ - 新增结果总览“未提交账户”后端查询与导出能力。 - 新增前端风险明细未提交账户卡片展示。 +- 新增未提交账户卡片点击后的本地“流水明细”弹窗,按 `LE_ACCOUNT_NAME + CUSTOMER_ACCOUNT_NO` 当前卡片范围查询,不跳转“流水明细查询”Tab。 +- 新增未提交账户流水查询接口 `GET /ccdi/project/overview/unsubmitted-accounts/flows`;原未提交账户导出接口支持可选 `subjectName/accountNo` 过滤,用于弹窗内导出当前账号流水。 - 风险明细统一导出与结果总览报告接入未提交账户流水。 - 贷款排除仅使用银行贷款/信贷高确定性关键词,未启用内部杂项账号排除。 +- 本地项目 `90342(test拉取行内流水)` 补充未提交账户演示数据,统一流水号标记为 `UNSUBMITTED_ACCOUNT_SEED_90342_20260720%`。 ## 影响范围 -- 后端:`ccdi-project` 结果总览 Controller、Service、Mapper、VO、Excel 与导出器。 -- 前端:`ruoyi-ui` 结果总览风险明细组件与 API。 +- 后端:`ccdi-project` 结果总览 Controller、Service、Mapper、DTO、VO、Excel 与导出器。 +- 前端:`ruoyi-ui` 结果总览风险明细组件与 API,未提交账户卡片新增本地明细弹窗与当前账号导出。 - 文档:后端计划、前端计划、实施记录。 ## 验证情况 -- 后端执行 `mvn -pl ccdi-project -am test "-Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectRiskDetailWorkbookExporterTest,CcdiProjectOverviewReportPdfExporterTest,CcdiProjectOverviewServiceImplTest" "-Dsurefire.failIfNoSpecifiedTests=false"`,32 个测试通过。 -- 前端使用 Node 22.22.3 / npm 10.9.8 执行 `node tests\unit\risk-detail-abnormal-account-layout.test.js`,静态断言通过。 -- 前端使用 Node 22.22.3 / npm 10.9.8 执行 `npm run build:prod`,构建通过;仍存在项目既有资源体积告警。 +- 后端增量测试首次执行通过:`mvn -pl ccdi-project "-Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectRiskDetailWorkbookExporterTest,CcdiProjectOverviewServiceImplTest" test`,共 25 个测试通过。 +- 执行 `mvn -pl ruoyi-admin -am clean package -DskipTests`,后端全链路依赖模块打包成功。 +- Mapper XML well-formed 检查通过。 +- 前端使用 Node `v22.22.3`、npm `10.9.8` 执行 `node tests/unit/risk-detail-abnormal-account-layout.test.js`,静态断言通过。 +- 前端使用 Node `v22.22.3`、npm `10.9.8` 启动 `npm run dev -- --host 127.0.0.1 --port 8088`,编译成功。 +- 本地补数验证:`output/sql/unsubmitted_account_seed_90342.sql` 插入 8 条流水,其中 4 个同名未提交账户聚合展示、1 个同名贷款账户通过“归还贷款/贷款还款”口径被排除;清理脚本为 `output/sql/unsubmitted_account_cleanup_90342.sql`。 +- 浏览器验证:已打开 `http://127.0.0.1:8088/ccdiProject/detail/90342?tab=overview`,页面显示“未提交账户”4 个、流入总额 100.90 万元、流出总额 -1.16 万元、差额 99.74 万元。 + +## 2026-07-20 追加:未提交账户流水弹窗 + +- 后端复用未提交账户候选流水 SQL 与贷款排除口径,增加按主体名称和未提交账号过滤的流水查询能力。 +- 前端未提交账户卡片支持点击/回车打开本地弹窗,弹窗标题展示日期范围、主体和账号,并提供全部/流入/流出切换。 +- 弹窗内“导出流水”只导出当前主体当前未提交账号流水;页面区块右上角“导出流水”仍导出当前项目全部未提交账户流水。 +- 后端验证:`mvn -pl ccdi-project -am "-Dtest=CcdiProjectOverviewMapperSqlTest,CcdiProjectRiskDetailWorkbookExporterTest,CcdiProjectOverviewServiceImplTest" "-Dsurefire.failIfNoSpecifiedTests=false" test` 通过,25 个测试通过。 +- 后端打包:先执行 `mvn -pl ruoyi-admin -am clean package -DskipTests` 时因旧后端进程锁定 `ruoyi-admin.jar` 导致 clean 失败;确认 62318 旧进程结束后执行 `mvn -pl ruoyi-admin -am package -DskipTests` 成功,并重启真实 Java 后端,PID 30896,端口 62318 已监听。 +- 前端验证:`.nvmrc` 指向 Node 14.21.3,但该环境缺少 npm;按项目约定使用 Node `v22.22.3`、npm `10.9.8` 执行 `node tests/unit/risk-detail-abnormal-account-layout.test.js` 通过,并启动 `npm run dev -- --host 127.0.0.1 --port 8088` 编译成功。 +- 浏览器验证:打开 `http://127.0.0.1:8088/ccdiProject/detail/90342?tab=overview`,未提交账户显示 4 个;点击首个账号卡片后弹出本地“流水明细”弹窗,接口 `GET /dev-api/ccdi/project/overview/unsubmitted-accounts/flows?projectId=90342&subjectName=测试主体&accountNo=33001061559364` 返回 200,弹窗显示全部 2、流入 1、流出 1,控制台无错误。 + +## 2026-07-20 追加:多主体展示优化 + +- 前端未提交账户统计栏新增“涉及主体数”,从 `subjects.length` 计算,不改后端接口与 SQL 口径。 +- 主体分组标题继续只展示主体名称,不增加“主体:”前缀;多主体时按主体名称分组列出各自账号卡片。 +- 未提交账户区块右侧导出按钮调整为与本页其他明细导出一致的文字按钮“导出”;弹窗内当前账号导出仍保留“导出流水”。 +- 前端验证:Node `v22.22.3`、npm `10.9.8` 下执行 `node tests/unit/risk-detail-abnormal-account-layout.test.js` 通过。 +- 浏览器验证:打开 `http://127.0.0.1:8088/ccdiProject/detail/90342?tab=overview`,未提交账户区块显示“涉及主体数 1”、主体分组标题显示“测试主体”,区块右侧按钮显示“导出”,控制台无错误。 + +## 2026-07-20 追加:涉疑交易导出位置调整 + +- 移除“风险明细”区块标题右侧的综合导出按钮。 +- 将导出按钮移动到“涉疑交易明细”查询条件行右侧。 +- 导出接口改为 `POST /ccdi/project/overview/suspicious-transactions/export`,只导出涉疑交易明细单独 Excel,不再包含负面征信、异常账户和未提交账户等综合风险明细内容。 +- “交易占比较高”仍使用后端 `highRatio` 字段,判定逻辑保持为未提交账号流入或流出占对应主体总流入/总流出达到 10%。 +- 前端验证:Node `v22.22.3`、npm `10.9.8` 下执行 `node tests/unit/risk-detail-abnormal-account-layout.test.js` 通过。 +- 浏览器验证:打开 `http://127.0.0.1:8088/ccdiProject/detail/90342?tab=overview`,确认“风险明细”标题右侧无导出按钮,“涉疑交易明细”筛选行右侧显示“导出”;点击后请求 `POST /dev-api/ccdi/project/overview/suspicious-transactions/export` 返回 200,控制台无错误。 + +## 2026-07-20 追加:文案与涉疑交易导出列顺序调整 + +- 未提交账户说明文案调整为“被调查主体未提交分析的同名账户”,不再在页面说明中展示“已排除银行贷款类账号”。 +- 涉疑交易明细单独 Excel 导出列顺序调整为“交易金额”在“异常标签”左侧。 +- 综合风险明细工作簿中的“涉疑交易明细”Sheet 同步调整列顺序,保持同类导出字段顺序一致。 +- 后端验证:执行 `mvn -pl ccdi-project -am "-Dtest=CcdiProjectRiskDetailWorkbookExporterTest" "-Dsurefire.failIfNoSpecifiedTests=false" test` 通过,覆盖综合风险明细工作簿列顺序与涉疑交易单独 Excel 字段顺序。 +- 前端验证:Node `v22.22.3`、npm `10.9.8` 下执行 `node tests/unit/risk-detail-abnormal-account-layout.test.js` 通过。 +- 浏览器验证:刷新 `http://127.0.0.1:8088/ccdiProject/detail/90342?tab=overview`,页面显示新说明文案,未出现“已排除银行贷款类账号”;涉疑交易表格列顺序为“交易金额”在“异常标签”左侧,控制台无错误。 diff --git a/ruoyi-ui/src/api/ccdi/projectOverview.js b/ruoyi-ui/src/api/ccdi/projectOverview.js index ad5ffa59..883da2d7 100644 --- a/ruoyi-ui/src/api/ccdi/projectOverview.js +++ b/ruoyi-ui/src/api/ccdi/projectOverview.js @@ -152,6 +152,18 @@ export function getOverviewUnsubmittedAccounts(projectId) { }) } +export function getOverviewUnsubmittedAccountFlows(params) { + return request({ + url: '/ccdi/project/overview/unsubmitted-accounts/flows', + method: 'get', + params: { + projectId: params.projectId, + subjectName: params.subjectName, + accountNo: params.accountNo + } + }) +} + export function exportOverviewReport(projectId) { return request({ url: '/ccdi/project/overview/report/export', diff --git a/ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue b/ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue index 559a0960..0d895b06 100644 --- a/ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue +++ b/ruoyi-ui/src/views/ccdiProject/components/detail/RiskDetailSection.vue @@ -6,31 +6,31 @@
风险明细
展示涉疑交易与异常账户关联人员信息
- - 导出 -
未提交账户
-
被调查主体未提交分析的同名账户,已排除银行贷款类账号
+
被调查主体未提交分析的同名账户
- 导出流水 + 导出