界面优化

This commit is contained in:
MHW
2026-05-07 15:40:57 +08:00
parent c597c3c01f
commit 2509b30382
14 changed files with 1809 additions and 9 deletions

View File

@@ -0,0 +1,65 @@
package com.solution.rule.domain.config;
import com.solution.common.annotation.Excel;
import lombok.Data;
@Data
public class RuleConfigExcelRow {
@Excel(name = "规则编码")
private String ruleCode;
@Excel(name = "规则名称")
private String ruleName;
@Excel(name = "层级编码")
private String levelCode;
@Excel(name = "类别编码")
private String kindCode;
@Excel(name = "模块编码")
private String moduleCode;
@Excel(name = "优先级", cellType = Excel.ColumnType.NUMERIC)
private Integer priorityNo;
@Excel(name = "条件表达式", width = 24)
private String conditionExpr;
@Excel(name = "动作表达式", width = 24)
private String actionExpr;
@Excel(name = "版本号", cellType = Excel.ColumnType.NUMERIC)
private Integer versionNo;
@Excel(name = "规则启用", cellType = Excel.ColumnType.NUMERIC, prompt = "1=启用,0=停用")
private Integer enabled;
@Excel(name = "备注", width = 20)
private String remark;
@Excel(name = "任务类型列表", width = 20, prompt = "多个任务类型用英文逗号分隔")
private String taskTypesCsv;
@Excel(name = "参数名称")
private String paramName;
@Excel(name = "参数键")
private String paramKey;
@Excel(name = "参数值", width = 24)
private String paramVal;
@Excel(name = "参数值类型")
private String valType;
@Excel(name = "参数排序", cellType = Excel.ColumnType.NUMERIC)
private Integer sortNo;
@Excel(name = "参数启用", cellType = Excel.ColumnType.NUMERIC, prompt = "1=启用,0=停用")
private Integer paramEnabled;
@Excel(name = "参数备注", width = 20)
private String paramRemark;
}

View File

@@ -1,6 +1,7 @@
package com.solution.rule.service;
import com.solution.rule.domain.config.RuleConfig;
import com.solution.rule.domain.config.RuleConfigExcelRow;
import com.solution.rule.domain.config.RuleConfigQuery;
import com.solution.rule.domain.config.RuleDictItem;
import com.solution.rule.domain.config.RuleParamMeta;
@@ -28,6 +29,10 @@ public interface IRuleConfigService {
List<RuleParamMeta> selectParamMetaList();
List<RuleConfigExcelRow> exportRuleConfigRows(RuleConfigQuery query);
String importRuleConfigRows(List<RuleConfigExcelRow> rows, boolean updateSupport);
/**
* 根据当前页规则主数据构建知识图谱(节点与边),参数与任务类型从库批量加载。
*/

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.solution.common.constant.ExceptionConstants;
import com.solution.rule.domain.config.RuleConfig;
import com.solution.rule.domain.config.RuleConfigExcelRow;
import com.solution.rule.domain.config.RuleConfigParam;
import com.solution.rule.domain.config.RuleConfigQuery;
import com.solution.rule.domain.config.RuleConfigTaskTypeRow;
@@ -131,6 +132,118 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
return new ArrayList<>(metaMap().values());
}
@Override
public List<RuleConfigExcelRow> exportRuleConfigRows(RuleConfigQuery query) {
List<RuleConfig> configs = selectRuleConfigList(query == null ? new RuleConfigQuery() : query);
List<RuleConfigExcelRow> rows = new ArrayList<>();
for (RuleConfig config : configs) {
if (config == null || ObjectUtil.isEmpty(config.getRuleCode())) {
continue;
}
RuleConfig detail = selectRuleConfigByCode(config.getRuleCode());
if (detail == null) {
continue;
}
List<RuleConfigParam> params = CollUtil.isNotEmpty(detail.getParams()) ? detail.getParams() : Collections.singletonList(new RuleConfigParam());
String taskTypesCsv = joinTaskTypes(detail.getTaskTypes());
for (RuleConfigParam param : params) {
RuleConfigExcelRow row = new RuleConfigExcelRow();
row.setRuleCode(detail.getRuleCode());
row.setRuleName(detail.getRuleName());
row.setLevelCode(detail.getLevelCode());
row.setKindCode(detail.getKindCode());
row.setModuleCode(detail.getModuleCode());
row.setPriorityNo(detail.getPriorityNo());
row.setConditionExpr(detail.getConditionExpr());
row.setActionExpr(detail.getActionExpr());
row.setVersionNo(detail.getVersionNo());
row.setEnabled(detail.getEnabled());
row.setRemark(detail.getRemark());
row.setTaskTypesCsv(taskTypesCsv);
if (param != null) {
row.setParamName(param.getParamName());
row.setParamKey(param.getParamKey());
row.setParamVal(param.getParamVal());
row.setValType(param.getValType());
row.setSortNo(param.getSortNo());
row.setParamEnabled(param.getEnabled());
row.setParamRemark(param.getRemark());
}
rows.add(row);
}
}
return rows;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String importRuleConfigRows(List<RuleConfigExcelRow> rows, boolean updateSupport) {
if (CollUtil.isEmpty(rows)) {
throw new RuntimeException("Import data cannot be empty");
}
Map<String, RuleConfig> grouped = new LinkedHashMap<>();
for (RuleConfigExcelRow row : rows) {
if (row == null || isEmptyImportRow(row)) {
continue;
}
String ruleCode = trimmed(row.getRuleCode());
if (ObjectUtil.isEmpty(ruleCode)) {
throw new RuntimeException("Import failed: ruleCode is required");
}
RuleConfig config = grouped.computeIfAbsent(ruleCode, code -> {
RuleConfig rc = new RuleConfig();
rc.setRuleCode(code);
rc.setParams(new ArrayList<>());
rc.setTaskTypes(new ArrayList<>());
return rc;
});
mergeRuleBase(config, row);
if (ObjectUtil.isNotEmpty(trimmed(row.getParamKey()))) {
RuleConfigParam param = new RuleConfigParam();
param.setRuleCode(ruleCode);
param.setParamName(trimmed(row.getParamName()));
param.setParamKey(trimmed(row.getParamKey()));
param.setParamVal(trimmed(row.getParamVal()));
param.setValType(trimmed(row.getValType()));
param.setSortNo(row.getSortNo());
param.setEnabled(row.getParamEnabled());
param.setRemark(trimmed(row.getParamRemark()));
config.getParams().add(param);
}
}
if (grouped.isEmpty()) {
throw new RuntimeException("Import data cannot be empty");
}
int inserted = 0;
int updated = 0;
for (RuleConfig config : grouped.values()) {
fillImportDefaults(config);
validateBase(config);
if (CollUtil.isEmpty(config.getParams())) {
throw new RuntimeException("Rule " + config.getRuleCode() + " must contain at least one param row");
}
boolean exists = ruleConfigMapper.countByRuleCode(config.getRuleCode()) > 0;
if (exists) {
if (!updateSupport) {
throw new RuntimeException("Rule already exists: " + config.getRuleCode());
}
ruleConfigMapper.updateRuleConfig(fillDefault(config));
String[] ruleCodes = {config.getRuleCode()};
ruleConfigMapper.deleteParamsByRuleCodes(ruleCodes);
ruleConfigMapper.deleteTaskTypesByRuleCodes(ruleCodes);
saveChildren(config);
updated++;
} else {
ruleConfigMapper.insertRuleConfig(fillDefault(config));
saveChildren(config);
inserted++;
}
}
syncDrlAfterCrud();
return "Import completed. inserted=" + inserted + ", updated=" + updated;
}
@Override
public RuleGraphVO buildKnowledgeGraph(List<RuleConfig> ruleConfigs) {
RuleGraphVO graph = new RuleGraphVO();
@@ -595,6 +708,107 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
return fallback;
}
private boolean isEmptyImportRow(RuleConfigExcelRow row) {
return ObjectUtil.isAllEmpty(
trimmed(row.getRuleCode()),
trimmed(row.getRuleName()),
trimmed(row.getParamKey()),
trimmed(row.getParamVal()),
trimmed(row.getTaskTypesCsv()));
}
private void mergeRuleBase(RuleConfig config, RuleConfigExcelRow row) {
config.setRuleName(mergeStringField(config.getRuleCode(), "ruleName", config.getRuleName(), row.getRuleName()));
config.setLevelCode(mergeStringField(config.getRuleCode(), "levelCode", config.getLevelCode(), row.getLevelCode()));
config.setKindCode(mergeStringField(config.getRuleCode(), "kindCode", config.getKindCode(), row.getKindCode()));
config.setModuleCode(mergeStringField(config.getRuleCode(), "moduleCode", config.getModuleCode(), row.getModuleCode()));
config.setConditionExpr(mergeStringField(config.getRuleCode(), "conditionExpr", config.getConditionExpr(), row.getConditionExpr()));
config.setActionExpr(mergeStringField(config.getRuleCode(), "actionExpr", config.getActionExpr(), row.getActionExpr()));
config.setRemark(mergeStringField(config.getRuleCode(), "remark", config.getRemark(), row.getRemark()));
config.setPriorityNo(mergeIntegerField(config.getRuleCode(), "priorityNo", config.getPriorityNo(), row.getPriorityNo()));
config.setVersionNo(mergeIntegerField(config.getRuleCode(), "versionNo", config.getVersionNo(), row.getVersionNo()));
config.setEnabled(mergeIntegerField(config.getRuleCode(), "enabled", config.getEnabled(), row.getEnabled()));
String taskTypesCsv = trimmed(row.getTaskTypesCsv());
if (ObjectUtil.isNotEmpty(taskTypesCsv)) {
List<String> parsed = parseTaskTypes(taskTypesCsv);
if (CollUtil.isNotEmpty(config.getTaskTypes()) && !config.getTaskTypes().equals(parsed)) {
throw new RuntimeException("Rule " + config.getRuleCode() + " has conflicting taskTypesCsv values");
}
config.setTaskTypes(parsed);
}
}
private void fillImportDefaults(RuleConfig config) {
if (config.getParams() == null) {
config.setParams(new ArrayList<>());
}
if (config.getTaskTypes() == null) {
config.setTaskTypes(new ArrayList<>());
}
int sortNo = 0;
for (RuleConfigParam param : config.getParams()) {
if (param.getSortNo() == null) {
param.setSortNo(sortNo);
}
if (param.getEnabled() == null) {
param.setEnabled(1);
}
sortNo++;
}
}
private String mergeStringField(String ruleCode, String fieldName, String currentValue, String newValue) {
String current = trimmed(currentValue);
String incoming = trimmed(newValue);
if (ObjectUtil.isEmpty(incoming)) {
return current;
}
if (ObjectUtil.isEmpty(current)) {
return incoming;
}
if (!Objects.equals(current, incoming)) {
throw new RuntimeException("Rule " + ruleCode + " has conflicting values for field " + fieldName);
}
return current;
}
private Integer mergeIntegerField(String ruleCode, String fieldName, Integer currentValue, Integer newValue) {
if (newValue == null) {
return currentValue;
}
if (currentValue == null) {
return newValue;
}
if (!Objects.equals(currentValue, newValue)) {
throw new RuntimeException("Rule " + ruleCode + " has conflicting values for field " + fieldName);
}
return currentValue;
}
private List<String> parseTaskTypes(String taskTypesCsv) {
if (ObjectUtil.isEmpty(taskTypesCsv)) {
return new ArrayList<>();
}
return Arrays.stream(taskTypesCsv.split(","))
.map(this::trimmed)
.filter(ObjectUtil::isNotEmpty)
.distinct()
.collect(Collectors.toList());
}
private String joinTaskTypes(List<String> taskTypes) {
if (CollUtil.isEmpty(taskTypes)) {
return null;
}
return taskTypes.stream()
.filter(ObjectUtil::isNotEmpty)
.collect(Collectors.joining(","));
}
private String trimmed(String value) {
return value == null ? null : value.trim();
}
private void saveChildren(RuleConfig ruleConfig) {
if (CollUtil.isNotEmpty(ruleConfig.getParams())) {
Set<String> keys = new HashSet<>();