补充结果总览异常标签模型归属与联动着色

This commit is contained in:
wkc
2026-03-23 14:08:47 +08:00
parent c23aef0ea0
commit c440427715
19 changed files with 401 additions and 25 deletions

View File

@@ -8,6 +8,10 @@ import lombok.Data;
@Data
public class CcdiProjectRiskHitTagVO {
private String modelCode;
private String modelName;
private String ruleCode;
private String ruleName;

View File

@@ -1,5 +1,6 @@
package com.ruoyi.ccdi.project.domain.vo;
import java.util.List;
import lombok.Data;
/**
@@ -24,5 +25,7 @@ public class CcdiProjectRiskPeopleOverviewItemVO {
private String riskPoint;
private List<CcdiProjectRiskHitTagVO> riskPointTagList;
private String actionLabel;
}

View File

@@ -5,6 +5,7 @@ import com.ruoyi.ccdi.project.domain.dto.CcdiProjectRiskModelPeopleQueryDTO;
import com.ruoyi.ccdi.project.domain.CcdiProject;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectEmployeeRiskAggregateVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelCardVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskHitTagVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleItemVO;
import java.util.List;
import java.util.Map;
@@ -61,6 +62,20 @@ public interface CcdiProjectOverviewMapper {
@Param("query") CcdiProjectRiskModelPeopleQueryDTO query
);
/**
* 按员工范围查询命中标签
*
* @param projectId 项目ID
* @param staffIdCard 员工身份证号
* @param selectedModelCodes 已选模型编码CSV可为空
* @return 命中标签列表
*/
List<CcdiProjectRiskHitTagVO> selectRiskHitTagsByScope(
@Param("projectId") Long projectId,
@Param("staffIdCard") String staffIdCard,
@Param("selectedModelCodes") String selectedModelCodes
);
/**
* 查询项目风险人数汇总
*

View File

@@ -78,7 +78,7 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
List<CcdiProjectRiskPeopleOverviewItemVO> overviewList = overviewMapper.selectRiskPeopleOverviewByProjectId(projectId)
.stream()
.map(this::buildRiskPeopleItem)
.map(aggregate -> buildRiskPeopleItem(projectId, aggregate))
.toList();
CcdiProjectRiskPeopleOverviewVO overview = new CcdiProjectRiskPeopleOverviewVO();
@@ -168,7 +168,7 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
);
}
private CcdiProjectRiskPeopleOverviewItemVO buildRiskPeopleItem(CcdiProjectEmployeeRiskAggregateVO aggregate) {
private CcdiProjectRiskPeopleOverviewItemVO buildRiskPeopleItem(Long projectId, CcdiProjectEmployeeRiskAggregateVO aggregate) {
CcdiProjectRiskPeopleOverviewItemVO item = new CcdiProjectRiskPeopleOverviewItemVO();
item.setName(aggregate.getStaffName());
item.setIdNo(aggregate.getStaffIdCard());
@@ -178,6 +178,9 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
item.setRiskLevelType(resolveRiskLevelType(aggregate.getRiskLevelCode()));
item.setModelCount(defaultZero(aggregate.getModelCount()));
item.setRiskPoint(aggregate.getRiskPoint());
item.setRiskPointTagList(defaultList(
overviewMapper.selectRiskHitTagsByScope(projectId, aggregate.getStaffIdCard(), null)
));
item.setActionLabel(ACTION_LABEL);
return item;
}

View File

@@ -347,12 +347,6 @@
) idx on idx.idx &lt; json_length(result.model_hit_summary_json)
where result.project_id = #{projectId}
and result.staff_id_card = #{staffIdCard}
<if test="selectedModelCodes != null and selectedModelCodes != ''">
and find_in_set(
json_unquote(json_extract(result.model_hit_summary_json, concat('$[', idx.idx, '].modelCode'))),
#{selectedModelCodes}
)
</if>
group by
json_unquote(json_extract(result.model_hit_summary_json, concat('$[', idx.idx, '].modelCode'))),
json_unquote(json_extract(result.model_hit_summary_json, concat('$[', idx.idx, '].modelName')))
@@ -361,6 +355,8 @@
<select id="selectRiskHitTagsByScope" resultType="com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskHitTagVO">
select
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelCode'))) as model_code,
max(json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelName')))) as model_name,
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].ruleCode'))) as rule_code,
max(json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].ruleName')))) as rule_name,
max(json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].riskLevel')))) as risk_level
@@ -370,18 +366,14 @@
) idx on idx.idx &lt; json_length(result.hit_rules_json)
where result.project_id = #{projectId}
and result.staff_id_card = #{staffIdCard}
<if test="selectedModelCodes != null and selectedModelCodes != ''">
and find_in_set(
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelCode'))),
#{selectedModelCodes}
)
</if>
group by json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].ruleCode')))
group by json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelCode'))),
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].ruleCode')))
order by case max(json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].riskLevel'))))
when 'HIGH' then 1
when 'MEDIUM' then 2
else 3
end,
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelCode'))) asc,
json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].ruleCode'))) asc
</select>

View File

@@ -1,6 +1,7 @@
package com.ruoyi.ccdi.project.controller;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewDashboardVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskHitTagVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectTopRiskPeopleVO;
@@ -62,6 +63,11 @@ class CcdiProjectOverviewControllerTest {
item.setRiskLevel("中风险");
item.setRiskLevelType("warning");
item.setModelCount(4);
CcdiProjectRiskHitTagVO riskPointTag = new CcdiProjectRiskHitTagVO();
riskPointTag.setModelCode("SALARY");
riskPointTag.setModelName("产薪异常模型");
riskPointTag.setRuleName("多工资转入");
item.setRiskPointTagList(List.of(riskPointTag));
CcdiProjectRiskPeopleOverviewVO overview = new CcdiProjectRiskPeopleOverviewVO();
overview.setOverviewList(List.of(item));
when(overviewService.getRiskPeopleOverview(40L)).thenReturn(overview);
@@ -73,6 +79,7 @@ class CcdiProjectOverviewControllerTest {
assertEquals("中风险", data.getOverviewList().getFirst().getRiskLevel());
assertEquals("warning", data.getOverviewList().getFirst().getRiskLevelType());
assertEquals(4, data.getOverviewList().getFirst().getModelCount());
assertEquals("SALARY", data.getOverviewList().getFirst().getRiskPointTagList().getFirst().getModelCode());
verify(overviewService).getRiskPeopleOverview(40L);
Method method = CcdiProjectOverviewController.class.getMethod("getRiskPeople", Long.class);

View File

@@ -48,5 +48,8 @@ class CcdiProjectOverviewMapperRiskModelPeopleTest {
assertTrue(xml.contains(".modelName"));
assertTrue(xml.contains(".ruleCode"));
assertTrue(xml.contains(".riskLevel"));
assertTrue(xml.contains("as model_code"));
assertTrue(xml.contains("as model_name"));
assertTrue(xml.contains("group by json_unquote(json_extract(result.hit_rules_json, concat('$[', idx.idx, '].modelCode')))"));
}
}

View File

@@ -9,6 +9,7 @@ import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewDashboardVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewEmployeeHitRowVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelCardVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelCardsVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskHitTagVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleItemVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskModelPeopleVO;
import com.ruoyi.ccdi.project.domain.vo.CcdiProjectRiskPeopleOverviewVO;
@@ -86,6 +87,10 @@ class CcdiProjectOverviewServiceImplTest {
aggregate.setModelCount(3);
aggregate.setRiskPoint("大额单笔收入、疑似兼职");
when(overviewMapper.selectRiskPeopleOverviewByProjectId(40L)).thenReturn(List.of(aggregate));
when(overviewMapper.selectRiskHitTagsByScope(40L, "330000000000000001", null)).thenReturn(List.of(
buildHitTag("LARGE_TRANSACTION", "大额交易模型", "RULE_A", "大额单笔收入", "HIGH"),
buildHitTag("PART_TIME", "兼职取酬模型", "RULE_B", "疑似兼职", "MEDIUM")
));
CcdiProjectRiskPeopleOverviewVO overview = service.getRiskPeopleOverview(40L);
@@ -94,6 +99,9 @@ class CcdiProjectOverviewServiceImplTest {
assertEquals("高风险", overview.getOverviewList().getFirst().getRiskLevel());
assertEquals("danger", overview.getOverviewList().getFirst().getRiskLevelType());
assertEquals(3, overview.getOverviewList().getFirst().getModelCount());
assertEquals(2, overview.getOverviewList().getFirst().getRiskPointTagList().size());
assertEquals("LARGE_TRANSACTION", overview.getOverviewList().getFirst().getRiskPointTagList().getFirst().getModelCode());
assertEquals("大额交易模型", overview.getOverviewList().getFirst().getRiskPointTagList().getFirst().getModelName());
assertEquals("大额单笔收入、疑似兼职", overview.getOverviewList().getFirst().getRiskPoint());
assertEquals("查看详情", overview.getOverviewList().getFirst().getActionLabel());
}
@@ -279,4 +287,20 @@ class CcdiProjectOverviewServiceImplTest {
result.setRiskLevelCode(riskLevelCode);
return result;
}
private CcdiProjectRiskHitTagVO buildHitTag(
String modelCode,
String modelName,
String ruleCode,
String ruleName,
String riskLevel
) {
CcdiProjectRiskHitTagVO hitTag = new CcdiProjectRiskHitTagVO();
hitTag.setModelCode(modelCode);
hitTag.setModelName(modelName);
hitTag.setRuleCode(ruleCode);
hitTag.setRuleName(ruleName);
hitTag.setRiskLevel(riskLevel);
return hitTag;
}
}