调整评分量化表

This commit is contained in:
2026-08-25 03:25:40 +08:00
parent 4698ca34fb
commit 9a4be16c05
10 changed files with 217 additions and 5 deletions
@@ -87,6 +87,13 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
private static final String CATEGORY_BASIC = "basic";
private static final String CATEGORY_PLUS = "plus";
private static final String CATEGORY_MINUS = "minus";
private static final String OPTION_TYPE_OPTION = "option";
private static final String OPTION_TYPE_SCORE = "score";
private static final String CHANGE_TYPE_INCREASE = "increase";
private static final String CHANGE_TYPE_DECREASE = "decrease";
private static final String SCORE_TYPE_ADD = "add";
private static final String SCORE_TYPE_SUBTRACT = "subtract";
private static final Set<String> SCORE_OPTION_UNITS = Set.of("%", "", "", "", "");
private static final String ROW_TYPE_MAIN = "主表";
private static final String ROW_TYPE_ITEM = "评分项目";
private static final String ROW_TYPE_OPTION = "选项";
@@ -253,6 +260,7 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
.collect(Collectors.groupingBy(CreditScoreItemOptionVO::getItemId));
Map<Long, List<CreditScoreItemVO>> itemMap = items.stream().map(item -> {
CreditScoreItemVO itemVO = Objects.requireNonNull(BeanUtil.copyProperties(item, CreditScoreItemVO.class));
itemVO.setBaseValue(normalizeBaseValue(itemVO.getBaseValue()));
itemVO.setOptions(optionMap.getOrDefault(item.getId(), new ArrayList<>()));
return itemVO;
}).collect(Collectors.groupingBy(CreditScoreItemVO::getCategoryId));
@@ -263,6 +271,10 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
}).toList();
}
private BigDecimal normalizeBaseValue(BigDecimal value) {
return value == null ? null : value.stripTrailingZeros();
}
private List<CreditRatingStandardVO> loadStandards(Long quantificationId) {
return standardMapper.selectList(Wrappers.<CreditRatingStandard>lambdaQuery()
.eq(CreditRatingStandard::getQuantificationId, quantificationId)
@@ -335,7 +347,7 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
return category;
}
}
throw new ServiceException("评分分类仅支持基础得分项、加分项目、减分项目");
throw new ServiceException("评分分类仅支持基础得分项、加分项目、减分项目");
}
private CreditScoreItemVO findOrCreateItem(CreditScoreCategoryVO category, CreditScoreQuantificationExcel row, Map<String, CreditScoreItemVO> itemMap) {
@@ -475,6 +487,17 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
Set<String> itemNames = new HashSet<>();
for (CreditScoreItemVO item : items) {
item.setItemName(trimToEmpty(item.getItemName()));
String optionType = trimToEmpty(item.getOptionType());
if (Func.isEmpty(optionType)) {
optionType = OPTION_TYPE_OPTION;
}
if (!OPTION_TYPE_OPTION.equals(optionType) && !OPTION_TYPE_SCORE.equals(optionType)) {
throw new ServiceException(item.getItemName() + "选项类型不正确");
}
item.setOptionType(optionType);
if (OPTION_TYPE_SCORE.equals(optionType) && item.getBaseValue() == null) {
throw new ServiceException(item.getItemName() + "基准数值不能为空");
}
item.setScoreDescription(trimToNull(item.getScoreDescription()));
item.setOptionDescription(trimToNull(item.getOptionDescription()));
if (Func.isEmpty(item.getItemName())) {
@@ -486,7 +509,10 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
if (Func.isEmpty(item.getScore())) {
throw new ServiceException(item.getItemName() + "分值不能为空");
}
validateNonNegative(item.getScore(), item.getItemName() + "分值不能小于0");
if (item.getScore().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException(item.getItemName() + "分值必须大于0");
}
validateScale(item.getScore(), item.getItemName() + "分值最多保留两位小数");
if (!itemNames.add(item.getItemName())) {
throw new ServiceException(category.getCategoryName() + "下评分项目名称不能重复");
}
@@ -494,7 +520,14 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
if (fullValidate && Func.isEmpty(options)) {
throw new ServiceException(item.getItemName() + "至少存在1条档位选项");
}
if (OPTION_TYPE_SCORE.equals(optionType) && options.size() != 1) {
throw new ServiceException(item.getItemName() + "分值类型只能配置1条阶梯配置");
}
for (CreditScoreItemOptionVO option : options) {
if (OPTION_TYPE_SCORE.equals(optionType)) {
validateScoreOption(item, option);
continue;
}
option.setOptionName(trimToEmpty(option.getOptionName()));
if (Func.isEmpty(option.getOptionName())) {
throw new ServiceException(item.getItemName() + "选项描述不能为空");
@@ -503,13 +536,61 @@ public class CreditScoreQuantificationServiceImpl extends BaseServiceImpl<Credit
if (Func.isEmpty(option.getScore())) {
throw new ServiceException(item.getItemName() + "分值不能为空");
}
if (option.getScore().compareTo(BigDecimal.ZERO) < 0) {
throw new ServiceException(item.getItemName() + "分值不能小于0");
if (option.getScore().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException(item.getItemName() + "选项分值必须大于0");
}
validateScale(option.getScore(), item.getItemName() + "选项分值最多保留两位小数");
}
}
}
private void validateScoreOption(CreditScoreItemVO item, CreditScoreItemOptionVO option) {
option.setChangeType(trimToEmpty(option.getChangeType()));
option.setChangeUnit(trimToEmpty(option.getChangeUnit()));
option.setScoreType(trimToEmpty(option.getScoreType()));
if (!CHANGE_TYPE_INCREASE.equals(option.getChangeType()) && !CHANGE_TYPE_DECREASE.equals(option.getChangeType())) {
throw new ServiceException(item.getItemName() + "每增加/每减少类型不正确");
}
if (Func.isEmpty(option.getChangeValue()) || option.getChangeValue().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException(item.getItemName() + "变化数值必须大于0");
}
if (option.getChangeValue().scale() > 2) {
throw new ServiceException(item.getItemName() + "变化数值最多保留两位小数");
}
if (!SCORE_OPTION_UNITS.contains(option.getChangeUnit())) {
throw new ServiceException(item.getItemName() + "变化单位不正确");
}
if (!SCORE_TYPE_ADD.equals(option.getScoreType()) && !SCORE_TYPE_SUBTRACT.equals(option.getScoreType())) {
throw new ServiceException(item.getItemName() + "加减类型不正确");
}
if (Func.isEmpty(option.getScore()) || option.getScore().compareTo(BigDecimal.ZERO) <= 0) {
throw new ServiceException(item.getItemName() + "基础分值必须大于0");
}
if (option.getScore().scale() > 2) {
throw new ServiceException(item.getItemName() + "基础分值最多保留两位小数");
}
// 分值模式的选项名称由规则自动生成,避免从“选项”模式切换后残留旧名称。
option.setOptionName(buildScoreOptionName(option));
validateLength(option.getOptionName(), OPTION_NAME_MAX_LENGTH, "选项描述最多100字符");
}
private String buildScoreOptionName(CreditScoreItemOptionVO option) {
String changeLabel = CHANGE_TYPE_DECREASE.equals(option.getChangeType()) ? "每减少" : "每增加";
String scoreLabel = SCORE_TYPE_SUBTRACT.equals(option.getScoreType()) ? "" : "";
return changeLabel + formatDecimal(option.getChangeValue()) + option.getChangeUnit()
+ scoreLabel + formatDecimal(option.getScore()) + "";
}
private String formatDecimal(BigDecimal value) {
return value == null ? "" : value.stripTrailingZeros().toPlainString();
}
private void validateScale(BigDecimal value, String message) {
if (value != null && value.stripTrailingZeros().scale() > 2) {
throw new ServiceException(message);
}
}
private void validateStandards(List<CreditRatingStandardVO> standards, boolean fullValidate) {
if (!fullValidate && Func.isEmpty(standards)) {
return;
@@ -668,10 +668,17 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
detail.setCategoryCode(category == null ? item.getCategoryCode() : category.getCategoryCode());
detail.setCategoryName(category == null ? item.getCategoryCode() : category.getCategoryName());
detail.setItemName(item.getItemName());
detail.setOptionType(item.getOptionType());
detail.setBaseValue(item.getBaseValue());
detail.setOptionDescription(item.getOptionDescription());
detail.setScoreDescription(item.getScoreDescription());
List<CreditScoreItemOption> itemOptions = optionMap.getOrDefault(item.getId(), new ArrayList<>());
detail.setScore(resolveFullScore(itemOptions));
// 分值模式的项目分值是项目本身配置的基础分,选项中的 score 是阶梯变动分值。
// 其他选项模式仍以选项最高分作为项目满分。
BigDecimal fullScore = "score".equalsIgnoreCase(item.getOptionType())
? item.getScore()
: resolveFullScore(itemOptions);
detail.setScore(fullScore == null ? BigDecimal.ZERO : fullScore);
detail.setOptionsJson(buildOptionsJson(itemOptions));
detail.setSelfScore(BigDecimal.ZERO);
detail.setReviewScore(BigDecimal.ZERO);
@@ -688,6 +695,10 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
map.put("label", option.getOptionName());
map.put("value", option.getOptionName());
map.put("score", option.getScore());
map.put("changeType", option.getChangeType());
map.put("changeValue", option.getChangeValue());
map.put("changeUnit", option.getChangeUnit());
map.put("scoreType", option.getScoreType());
return map;
}).toList();
return JsonUtil.toJson(optionList);