From 988c2d3572ea8513d4db9645c7beb7a7194778c4 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Tue, 31 Mar 2026 16:28:37 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=BC=82=E5=B8=B8=E8=B4=A6?= =?UTF-8?q?=E6=88=B7=E6=A8=A1=E5=9E=8B=E8=A7=84=E5=88=99=E9=AA=A8=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ccdi-project/pom.xml | 6 +++ .../mapper/CcdiBankTagAnalysisMapper.java | 16 ++++++++ .../service/impl/CcdiBankTagServiceImpl.java | 2 + .../impl/CcdiBankTagServiceImplTest.java | 32 ++++++++++++++++ ...cdiAbnormalAccountRuleSqlMetadataTest.java | 30 +++++++++++++++ ...ccount-info-and-abnormal-account-rules.sql | 37 +++++++++++++++++++ 6 files changed, 123 insertions(+) create mode 100644 ccdi-project/src/test/java/com/ruoyi/ccdi/project/sql/CcdiAbnormalAccountRuleSqlMetadataTest.java create mode 100644 sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql diff --git a/ccdi-project/pom.xml b/ccdi-project/pom.xml index d9b29636..77febc35 100644 --- a/ccdi-project/pom.xml +++ b/ccdi-project/pom.xml @@ -43,6 +43,12 @@ springdoc-openapi-starter-webmvc-ui + + + com.alibaba + easyexcel + + org.springframework.boot diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java index 7985cd43..6559dd54 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiBankTagAnalysisMapper.java @@ -292,6 +292,22 @@ public interface CcdiBankTagAnalysisMapper { */ List selectSalaryUnusedObjects(@Param("projectId") Long projectId); + /** + * 突然销户 + * + * @param projectId 项目ID + * @return 对象命中结果 + */ + List selectSuddenAccountClosureObjects(@Param("projectId") Long projectId); + + /** + * 休眠账户大额启用 + * + * @param projectId 项目ID + * @return 对象命中结果 + */ + List selectDormantAccountLargeActivationObjects(@Param("projectId") Long projectId); + /** * 大额炒股 * diff --git a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java index 030e826c..75d879b1 100644 --- a/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java +++ b/ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImpl.java @@ -288,6 +288,8 @@ public class CcdiBankTagServiceImpl implements ICcdiBankTagService { case "WITHDRAW_AMT" -> analysisMapper.selectWithdrawAmtObjects(projectId); case "SALARY_QUICK_TRANSFER" -> analysisMapper.selectSalaryQuickTransferObjects(projectId); case "SALARY_UNUSED" -> analysisMapper.selectSalaryUnusedObjects(projectId); + case "SUDDEN_ACCOUNT_CLOSURE" -> analysisMapper.selectSuddenAccountClosureObjects(projectId); + case "DORMANT_ACCOUNT_LARGE_ACTIVATION" -> analysisMapper.selectDormantAccountLargeActivationObjects(projectId); case "PROXY_ACCOUNT_OPERATION" -> analysisMapper.selectProxyAccountOperationObjects(projectId); default -> List.of(); }; diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java index 4da5cbfc..cecd6727 100644 --- a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/service/impl/CcdiBankTagServiceImplTest.java @@ -406,6 +406,38 @@ class CcdiBankTagServiceImplTest { verify(analysisMapper).selectSalaryUnusedObjects(40L); } + @Test + void rebuildProject_shouldDispatchSuddenAccountClosureObjectRule() { + ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run); + + CcdiBankTagRule rule = buildRule("ABNORMAL_ACCOUNT", "异常账户", + "SUDDEN_ACCOUNT_CLOSURE", "突然销户", "OBJECT"); + + when(ruleMapper.selectEnabledRules("ABNORMAL_ACCOUNT")).thenReturn(List.of(rule)); + when(configResolver.resolve(40L, rule)).thenReturn(buildConfig(40L, rule)); + when(analysisMapper.selectSuddenAccountClosureObjects(40L)).thenReturn(List.of()); + + service.rebuildProject(40L, "ABNORMAL_ACCOUNT", "admin", TriggerType.MANUAL); + + verify(analysisMapper).selectSuddenAccountClosureObjects(40L); + } + + @Test + void rebuildProject_shouldDispatchDormantAccountLargeActivationObjectRule() { + ReflectionTestUtils.setField(service, "tagRuleExecutor", (Executor) Runnable::run); + + CcdiBankTagRule rule = buildRule("ABNORMAL_ACCOUNT", "异常账户", + "DORMANT_ACCOUNT_LARGE_ACTIVATION", "休眠账户大额启用", "OBJECT"); + + when(ruleMapper.selectEnabledRules("ABNORMAL_ACCOUNT")).thenReturn(List.of(rule)); + when(configResolver.resolve(40L, rule)).thenReturn(buildConfig(40L, rule)); + when(analysisMapper.selectDormantAccountLargeActivationObjects(40L)).thenReturn(List.of()); + + service.rebuildProject(40L, "ABNORMAL_ACCOUNT", "admin", TriggerType.MANUAL); + + verify(analysisMapper).selectDormantAccountLargeActivationObjects(40L); + } + private CcdiBankTagRule buildRule(String modelCode, String modelName, String ruleCode, String ruleName, String resultType) { CcdiBankTagRule rule = new CcdiBankTagRule(); rule.setModelCode(modelCode); diff --git a/ccdi-project/src/test/java/com/ruoyi/ccdi/project/sql/CcdiAbnormalAccountRuleSqlMetadataTest.java b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/sql/CcdiAbnormalAccountRuleSqlMetadataTest.java new file mode 100644 index 00000000..3b708fc1 --- /dev/null +++ b/ccdi-project/src/test/java/com/ruoyi/ccdi/project/sql/CcdiAbnormalAccountRuleSqlMetadataTest.java @@ -0,0 +1,30 @@ +package com.ruoyi.ccdi.project.sql; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CcdiAbnormalAccountRuleSqlMetadataTest { + + @Test + void abnormalAccountMetadataSql_shouldContainModelAndRuleDefinitions() throws IOException { + Path path = Path.of("..", "sql", "migration", + "2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql"); + + assertTrue(Files.exists(path), "异常账户模型迁移脚本应存在"); + + String sql = Files.readString(path, StandardCharsets.UTF_8); + assertAll( + () -> assertTrue(sql.contains("ABNORMAL_ACCOUNT")), + () -> assertTrue(sql.contains("SUDDEN_ACCOUNT_CLOSURE")), + () -> assertTrue(sql.contains("DORMANT_ACCOUNT_LARGE_ACTIVATION")), + () -> assertTrue(sql.contains("'OBJECT'")) + ); + } +} diff --git a/sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql b/sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql new file mode 100644 index 00000000..bae497e4 --- /dev/null +++ b/sql/migration/2026-03-31-create-ccdi-account-info-and-abnormal-account-rules.sql @@ -0,0 +1,37 @@ +START TRANSACTION; + +INSERT INTO ccdi_bank_tag_rule ( + model_code, + model_name, + rule_code, + rule_name, + indicator_code, + result_type, + risk_level, + business_caliber, + enabled, + sort_order, + create_by, + remark +) VALUES +('ABNORMAL_ACCOUNT', '异常账户', 'SUDDEN_ACCOUNT_CLOSURE', '突然销户', NULL, 'OBJECT', 'HIGH', + '员工本人账户已销户,且销户日前30天内仍存在交易记录。', 1, 10, 'system', + '异常账户模型规则骨架,后续补充建表与完整业务口径'), +('ABNORMAL_ACCOUNT', '异常账户', 'DORMANT_ACCOUNT_LARGE_ACTIVATION', '休眠账户大额启用', NULL, 'OBJECT', 'HIGH', + '员工本人账户开户后长期未使用,首次启用后出现大额资金流动。', 1, 20, 'system', + '异常账户模型规则骨架,后续补充建表与完整业务口径') +ON DUPLICATE KEY UPDATE + model_code = VALUES(model_code), + model_name = VALUES(model_name), + rule_name = VALUES(rule_name), + indicator_code = VALUES(indicator_code), + result_type = VALUES(result_type), + risk_level = VALUES(risk_level), + business_caliber = VALUES(business_caliber), + enabled = VALUES(enabled), + sort_order = VALUES(sort_order), + update_by = 'system', + update_time = NOW(), + remark = VALUES(remark); + +COMMIT;