调整评分量化表
This commit is contained in:
+10
@@ -72,6 +72,16 @@ public class CreditScoreItem extends TenantEntity {
|
||||
*/
|
||||
@Schema(description = "评分项目")
|
||||
private String itemName;
|
||||
/**
|
||||
* 选项类型:option-选项,score-分值
|
||||
*/
|
||||
@Schema(description = "选项类型:option-选项,score-分值")
|
||||
private String optionType;
|
||||
/**
|
||||
* 分值模式基准数值
|
||||
*/
|
||||
@Schema(description = "分值模式基准数值")
|
||||
private BigDecimal baseValue;
|
||||
/**
|
||||
* 分值
|
||||
*/
|
||||
|
||||
+20
@@ -67,6 +67,26 @@ public class CreditScoreItemOption extends TenantEntity {
|
||||
*/
|
||||
@Schema(description = "选项描述")
|
||||
private String optionName;
|
||||
/**
|
||||
* 变化类型:increase-每增加,decrease-每减少
|
||||
*/
|
||||
@Schema(description = "变化类型:increase-每增加,decrease-每减少")
|
||||
private String changeType;
|
||||
/**
|
||||
* 变化数值
|
||||
*/
|
||||
@Schema(description = "变化数值")
|
||||
private BigDecimal changeValue;
|
||||
/**
|
||||
* 变化单位:%、件、次、项、天
|
||||
*/
|
||||
@Schema(description = "变化单位:%、件、次、项、天")
|
||||
private String changeUnit;
|
||||
/**
|
||||
* 分值类型:add-加,subtract-减
|
||||
*/
|
||||
@Schema(description = "分值类型:add-加,subtract-减")
|
||||
private String scoreType;
|
||||
/**
|
||||
* 分值
|
||||
*/
|
||||
|
||||
+9
@@ -68,6 +68,15 @@ public class CustomerCreditScoreDetail extends TenantEntity {
|
||||
@Schema(description = "评分项目")
|
||||
private String itemName;
|
||||
|
||||
@Schema(description = "选项类型:option-选项,score-分值")
|
||||
private String optionType;
|
||||
|
||||
@Schema(description = "分值模式基准数值")
|
||||
private BigDecimal baseValue;
|
||||
|
||||
@Schema(description = "分值模式用户输入数值")
|
||||
private BigDecimal scoreInput;
|
||||
|
||||
@Schema(description = "评分标准")
|
||||
private String optionDescription;
|
||||
|
||||
|
||||
+85
-4
@@ -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;
|
||||
|
||||
+12
-1
@@ -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);
|
||||
|
||||
@@ -54,6 +54,8 @@ CREATE TABLE `blade_credit_score_item` (
|
||||
`category_id` bigint NOT NULL COMMENT '评分分类ID',
|
||||
`category_code` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '分类编码',
|
||||
`item_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评分项目',
|
||||
`option_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'option' COMMENT '选项类型:option-选项,score-分值',
|
||||
`base_value` decimal(30,10) NULL DEFAULT NULL COMMENT '分值模式基准数值',
|
||||
`score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值',
|
||||
`score_description` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '得分说明',
|
||||
`option_description` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '选项描述',
|
||||
@@ -80,6 +82,10 @@ CREATE TABLE `blade_credit_score_item_option` (
|
||||
`quantification_id` bigint NOT NULL COMMENT '评分量化表ID',
|
||||
`item_id` bigint NOT NULL COMMENT '评分项目ID',
|
||||
`option_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '选项描述',
|
||||
`change_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '变化类型:increase-每增加,decrease-每减少',
|
||||
`change_value` decimal(10,2) NULL DEFAULT NULL COMMENT '变化数值',
|
||||
`change_unit` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '变化单位:%、件、次、项、天',
|
||||
`score_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分值类型:add-加,subtract-减',
|
||||
`score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值',
|
||||
`sort` int NULL DEFAULT 0 COMMENT '排序',
|
||||
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- 适用于已执行评分选项字段补丁、且数据库已存在 option_type 的环境
|
||||
-- 执行前请确认 base_value 尚不存在,避免重复添加字段
|
||||
|
||||
ALTER TABLE `blade_credit_score_item`
|
||||
ADD COLUMN `base_value` decimal(30,10) NULL DEFAULT NULL COMMENT '分值模式基准数值' AFTER `option_type`;
|
||||
|
||||
ALTER TABLE `blade_credit_score_item`
|
||||
MODIFY COLUMN `score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值';
|
||||
|
||||
ALTER TABLE `blade_credit_score_item_option`
|
||||
MODIFY COLUMN `score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值';
|
||||
@@ -0,0 +1,13 @@
|
||||
-- 评分量化表项目“分值”选项配置字段补丁
|
||||
|
||||
ALTER TABLE `blade_credit_score_item`
|
||||
ADD COLUMN `option_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'option' COMMENT '选项类型:option-选项,score-分值' AFTER `item_name`,
|
||||
ADD COLUMN `base_value` decimal(30,10) NULL DEFAULT NULL COMMENT '分值模式基准数值' AFTER `option_type`,
|
||||
MODIFY COLUMN `score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值';
|
||||
|
||||
ALTER TABLE `blade_credit_score_item_option`
|
||||
ADD COLUMN `change_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '变化类型:increase-每增加,decrease-每减少' AFTER `option_name`,
|
||||
ADD COLUMN `change_value` decimal(10,2) NULL DEFAULT NULL COMMENT '变化数值' AFTER `change_type`,
|
||||
ADD COLUMN `change_unit` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '变化单位:%、件、次、项、天' AFTER `change_value`,
|
||||
ADD COLUMN `score_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分值类型:add-加,subtract-减' AFTER `change_unit`,
|
||||
MODIFY COLUMN `score` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '分值';
|
||||
@@ -192,6 +192,9 @@ CREATE TABLE `blade_customer_credit_score_detail` (
|
||||
`category_code` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '评分分类编码',
|
||||
`category_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '评分分类名称',
|
||||
`item_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '评分项目',
|
||||
`option_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'option' COMMENT '选项类型:option-选项,score-分值',
|
||||
`base_value` decimal(30,10) NULL DEFAULT NULL COMMENT '分值模式基准数值',
|
||||
`score_input` decimal(30,10) NULL DEFAULT NULL COMMENT '分值模式用户输入数值',
|
||||
`option_description` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '评分标准',
|
||||
`options_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '选项JSON',
|
||||
`selected_option` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '已选选项',
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
-- 客商评分明细支持“分值”模式用户输入数值。
|
||||
-- 使用 INFORMATION_SCHEMA 判断字段是否存在,重复执行不会报重复列错误。
|
||||
SET @score_detail_schema = DATABASE();
|
||||
|
||||
SET @score_detail_sql = (
|
||||
SELECT IF(
|
||||
COUNT(*) = 0,
|
||||
'ALTER TABLE `blade_customer_credit_score_detail` ADD COLUMN `option_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT ''option'' COMMENT ''选项类型:option-选项,score-分值'' AFTER `item_name`',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @score_detail_schema
|
||||
AND table_name = 'blade_customer_credit_score_detail'
|
||||
AND column_name = 'option_type'
|
||||
);
|
||||
PREPARE score_detail_stmt FROM @score_detail_sql;
|
||||
EXECUTE score_detail_stmt;
|
||||
DEALLOCATE PREPARE score_detail_stmt;
|
||||
|
||||
SET @score_detail_sql = (
|
||||
SELECT IF(
|
||||
COUNT(*) = 0,
|
||||
'ALTER TABLE `blade_customer_credit_score_detail` ADD COLUMN `base_value` decimal(30,10) NULL DEFAULT NULL COMMENT ''分值模式基准数值'' AFTER `option_type`',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @score_detail_schema
|
||||
AND table_name = 'blade_customer_credit_score_detail'
|
||||
AND column_name = 'base_value'
|
||||
);
|
||||
PREPARE score_detail_stmt FROM @score_detail_sql;
|
||||
EXECUTE score_detail_stmt;
|
||||
DEALLOCATE PREPARE score_detail_stmt;
|
||||
|
||||
SET @score_detail_sql = (
|
||||
SELECT IF(
|
||||
COUNT(*) = 0,
|
||||
'ALTER TABLE `blade_customer_credit_score_detail` ADD COLUMN `score_input` decimal(30,10) NULL DEFAULT NULL COMMENT ''分值模式用户输入数值'' AFTER `base_value`',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @score_detail_schema
|
||||
AND table_name = 'blade_customer_credit_score_detail'
|
||||
AND column_name = 'score_input'
|
||||
);
|
||||
PREPARE score_detail_stmt FROM @score_detail_sql;
|
||||
EXECUTE score_detail_stmt;
|
||||
DEALLOCATE PREPARE score_detail_stmt;
|
||||
Reference in New Issue
Block a user