旧接口字段更新BUG修复

This commit is contained in:
MHW
2026-04-20 09:38:58 +08:00
parent 39b04d8b73
commit ae01a2aa01
9 changed files with 509 additions and 36 deletions

View File

@@ -18,6 +18,12 @@ public class RuleGraphVO implements Serializable {
@ApiModelProperty("边列表")
private List<RuleGraphEdgeVO> edges;
@ApiModelProperty("前端布局提示:如 radial_hub 使用径向圆心布局")
private String layoutHint;
@ApiModelProperty("径向布局时的中心节点 id通常为 drools_facade")
private String focusNodeId;
public List<RuleGraphNodeVO> safeNodes() {
if (nodes == null) {
nodes = new ArrayList<>();

View File

@@ -4,6 +4,7 @@ import com.solution.rule.domain.config.RuleConfig;
import com.solution.rule.domain.config.RuleConfigQuery;
import com.solution.rule.domain.config.RuleDictItem;
import com.solution.rule.domain.config.RuleParamMeta;
import com.solution.rule.domain.config.vo.RuleFourBlocksGraphVO;
import com.solution.rule.domain.config.vo.RuleGraphVO;
import java.util.List;
@@ -31,4 +32,9 @@ public interface IRuleConfigService {
* 根据当前页规则主数据构建知识图谱(节点与边),参数与任务类型从库批量加载。
*/
RuleGraphVO buildKnowledgeGraph(List<RuleConfig> ruleConfigs);
/**
* 四块规则知识图谱(装备/目标/阵位/航迹):中枢 If/Then + 环形参数,参数值与 {@link #loadEnabledGlobalParams()} 一致。
*/
RuleFourBlocksGraphVO buildFourBlocksKnowledgeGraph();
}

View File

@@ -9,6 +9,12 @@ import com.solution.rule.domain.config.RuleConfigQuery;
import com.solution.rule.domain.config.RuleConfigTaskTypeRow;
import com.solution.rule.domain.config.RuleDictItem;
import com.solution.rule.domain.config.RuleParamMeta;
import com.solution.rule.domain.config.graph.RuleFourBlockDefinition;
import com.solution.rule.domain.config.graph.RuleFourBlockRuleOutputCatalog;
import com.solution.rule.domain.config.graph.RuleParamOutputHint;
import com.solution.rule.domain.config.vo.RuleFourBlockClusterVO;
import com.solution.rule.domain.config.vo.RuleFourBlockParamRowVO;
import com.solution.rule.domain.config.vo.RuleFourBlocksGraphVO;
import com.solution.rule.domain.config.vo.RuleGraphEdgeVO;
import com.solution.rule.domain.config.vo.RuleGraphNodeVO;
import com.solution.rule.domain.config.vo.RuleGraphVO;
@@ -20,6 +26,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -29,18 +36,6 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
private static final Pattern RULE_SLOT_KEYS = Pattern.compile("^(blueRuleKeywords|redRuleKeywords|ruleScore)_\\d+$");
private static final boolean ALLOW_UNKNOWN_PARAM_KEY = false;
private static final Map<String, String> MODULE_LABELS;
static {
Map<String, String> m = new LinkedHashMap<>();
m.put("equipment", "装备匹配");
m.put("target", "目标分配");
m.put("position", "阵位部署");
m.put("track", "航迹生成");
m.put("group", "编组");
MODULE_LABELS = Collections.unmodifiableMap(m);
}
@Autowired
private RuleConfigMapper ruleConfigMapper;
@Autowired
@@ -187,19 +182,20 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
Map<String, Object> levelPayload = new LinkedHashMap<>();
levelPayload.put("dictType", "level");
levelPayload.put("dictCode", levelCode);
putNode(nodeById, levelId, node(levelId, dictLabel(levelDict, levelCode, levelCode), "level", levelPayload));
levelPayload.put("dictName", dictLabel(levelDict, levelCode, null));
putNode(nodeById, levelId, node(levelId, levelCode, "level", levelPayload));
String kindId = "kind:" + levelCode + ":" + kindCode;
Map<String, Object> kindPayload = new LinkedHashMap<>();
kindPayload.put("levelCode", levelCode);
kindPayload.put("kindCode", kindCode);
putNode(nodeById, kindId, node(kindId, dictLabel(kindDict, kindCode, kindCode), "kind", kindPayload));
kindPayload.put("dictName", dictLabel(kindDict, kindCode, null));
putNode(nodeById, kindId, node(kindId, kindCode, "kind", kindPayload));
String moduleId = "module:" + moduleCode;
String moduleLabel = MODULE_LABELS.getOrDefault(moduleCode, moduleCode);
Map<String, Object> modulePayload = new LinkedHashMap<>();
modulePayload.put("moduleCode", moduleCode);
putNode(nodeById, moduleId, node(moduleId, moduleLabel, "module", modulePayload));
putNode(nodeById, moduleId, node(moduleId, moduleCode, "module", modulePayload));
String ruleId = "rule:" + ruleCode;
String ruleLabel = ObjectUtil.defaultIfBlank(rule.getRuleName(), ruleCode);
@@ -248,7 +244,8 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
String taskId = "task:" + tt;
Map<String, Object> taskPayload = new LinkedHashMap<>();
taskPayload.put("taskTypeCode", tt);
putNode(nodeById, taskId, node(taskId, dictLabel(taskTypeDict, tt, tt), "taskType", taskPayload));
taskPayload.put("dictName", dictLabel(taskTypeDict, tt, null));
putNode(nodeById, taskId, node(taskId, tt, "taskType", taskPayload));
addEdge(edges, edgeIds, "applies_task:" + ruleCode + ":" + tt, ruleId, taskId, "rule_applies_task", null);
}
}
@@ -279,6 +276,281 @@ public class RuleConfigServiceImpl implements IRuleConfigService {
return graph;
}
@Override
public RuleFourBlocksGraphVO buildFourBlocksKnowledgeGraph() {
RuleFourBlocksGraphVO out = new RuleFourBlocksGraphVO();
Map<String, Object> globalPreview = loadEnabledGlobalParams();
out.setGlobalParamsPreview(new LinkedHashMap<>(globalPreview));
RuleConfigQuery q = new RuleConfigQuery();
q.setEnabled(1);
List<RuleConfig> allEnabled = ruleConfigMapper.selectRuleConfigList(q);
if (CollUtil.isEmpty(allEnabled)) {
out.setBlocks(new ArrayList<>());
return out;
}
Set<String> fourModules = new HashSet<>(Arrays.asList("equipment", "target", "position", "track"));
Map<String, List<RuleConfig>> byModule = allEnabled.stream()
.filter(r -> r != null && ObjectUtil.isNotEmpty(r.getModuleCode()) && fourModules.contains(r.getModuleCode()))
.collect(Collectors.groupingBy(RuleConfig::getModuleCode, LinkedHashMap::new, Collectors.toList()));
List<RuleFourBlockClusterVO> blocks = new ArrayList<>();
for (RuleFourBlockDefinition def : RuleFourBlockDefinition.ordered()) {
List<RuleConfig> moduleRules = new ArrayList<>(byModule.getOrDefault(def.getModuleCode(), Collections.emptyList()));
moduleRules.sort(Comparator.comparing(RuleConfig::getPriorityNo, Comparator.nullsLast(Integer::compareTo)));
List<String> ruleCodes = moduleRules.stream().map(RuleConfig::getRuleCode).filter(ObjectUtil::isNotEmpty).collect(Collectors.toList());
List<RuleConfigParam> plist = ruleCodes.isEmpty()
? Collections.emptyList()
: ruleConfigMapper.selectParamsByRuleCodes(ruleCodes);
Map<String, Integer> priByRule = moduleRules.stream()
.filter(r -> ObjectUtil.isNotEmpty(r.getRuleCode()))
.collect(Collectors.toMap(RuleConfig::getRuleCode, RuleConfig::getPriorityNo, (a, b) -> a));
plist.sort(Comparator
.comparing((RuleConfigParam p) -> priByRule.getOrDefault(p.getRuleCode(), Integer.MAX_VALUE))
.thenComparing(p -> p.getSortNo() == null ? Integer.MAX_VALUE : p.getSortNo())
.thenComparing(RuleConfigParam::getParamKey, Comparator.nullsLast(String::compareTo)));
Map<String, RuleConfig> ruleByCode = moduleRules.stream()
.filter(r -> r != null && ObjectUtil.isNotEmpty(r.getRuleCode()))
.collect(Collectors.toMap(RuleConfig::getRuleCode, Function.identity(), (a, b) -> a));
RuleFourBlockClusterVO cluster = new RuleFourBlockClusterVO();
cluster.setBlockId(def.getBlockId());
cluster.setModuleCode(def.getModuleCode());
cluster.setTitle(def.getDroolsRuleName());
cluster.setDroolsRuleName(def.getDroolsRuleName());
cluster.setSalience(def.getSalience());
cluster.setWhenExpr(def.getWhenExpr());
cluster.setThenAction(def.getThenAction());
cluster.setParamRows(buildFourBlockParamRows(def, ruleByCode, plist, globalPreview));
cluster.setGraph(buildFourBlockNeoStyleGraph(def, moduleRules, plist, globalPreview, ruleByCode));
blocks.add(cluster);
}
out.setBlocks(blocks);
return out;
}
private List<RuleFourBlockParamRowVO> buildFourBlockParamRows(RuleFourBlockDefinition def,
Map<String, RuleConfig> ruleByCode,
List<RuleConfigParam> plist,
Map<String, Object> globalPreview) {
List<RuleFourBlockParamRowVO> rows = new ArrayList<>();
if (CollUtil.isEmpty(plist)) {
return rows;
}
String moduleCode = def.getModuleCode();
for (RuleConfigParam p : plist) {
if (p == null || ObjectUtil.isEmpty(p.getParamKey()) || ObjectUtil.isEmpty(p.getRuleCode())) {
continue;
}
if (p.getEnabled() != null && p.getEnabled() == 0) {
continue;
}
RuleConfig r = ruleByCode.get(p.getRuleCode());
if (r == null) {
continue;
}
RuleFourBlockParamRowVO row = new RuleFourBlockParamRowVO();
row.setRuleCode(r.getRuleCode());
row.setRuleName(r.getRuleName());
row.setParamKey(p.getParamKey());
row.setParamName(ObjectUtil.defaultIfBlank(p.getParamName(), p.getParamKey()));
row.setWhenText(formatParamWhenForRow(r, def));
row.setThenText(formatParamThenForRow(r, def));
row.setOutputText(formatParamOutputForRow(p, globalPreview, moduleCode));
rows.add(row);
}
return rows;
}
private static String formatParamWhenForRow(RuleConfig r, RuleFourBlockDefinition def) {
if (r != null && ObjectUtil.isNotEmpty(r.getConditionExpr())) {
return r.getConditionExpr();
}
return ObjectUtil.defaultIfBlank(def.getWhenExpr(), "");
}
private static String formatParamThenForRow(RuleConfig r, RuleFourBlockDefinition def) {
if (r != null && ObjectUtil.isNotEmpty(r.getActionExpr())) {
return r.getActionExpr();
}
return ObjectUtil.defaultIfBlank(def.getThenAction(), "");
}
private static String formatParamOutputForRow(RuleConfigParam p, Map<String, Object> globalPreview, String moduleCode) {
Object ev = globalPreview != null ? globalPreview.get(p.getParamKey()) : null;
String hint = RuleParamOutputHint.effectLine(p.getParamKey(), moduleCode);
if (ev == null) {
return hint;
}
return "生效值:" + String.valueOf(ev) + "" + hint;
}
/**
* Neo4j 风格子图:门面节点、多条 rule_item、参数按归属规则展开含 drools_contains / rule_priority_next / rule_has_param 边。
*/
private RuleGraphVO buildFourBlockNeoStyleGraph(RuleFourBlockDefinition def,
List<RuleConfig> moduleRules,
List<RuleConfigParam> plist,
Map<String, Object> globalPreview,
Map<String, RuleConfig> ruleByCode) {
RuleGraphVO graph = new RuleGraphVO();
List<RuleGraphNodeVO> nodes = graph.safeNodes();
List<RuleGraphEdgeVO> edges = graph.safeEdges();
Set<String> edgeIds = new LinkedHashSet<>();
String bid = def.getBlockId();
String droolsId = "four:block:" + bid + ":drools";
List<String> stepLabels = def.getComputationSteps();
String lastStepId = null;
for (int i = 0; i < stepLabels.size(); i++) {
String text = stepLabels.get(i);
if (ObjectUtil.isEmpty(text)) {
continue;
}
String sid = "four:block:" + bid + ":step:" + i;
Map<String, Object> sp = new LinkedHashMap<>();
sp.put("stepIndex", i);
sp.put("blockId", bid);
nodes.add(node(sid, text, "compute_step", sp));
if (lastStepId != null) {
addEdge(edges, edgeIds, "four:compute_flow:" + bid + ":" + (i - 1),
lastStepId, sid, "compute_flow", "");
}
lastStepId = sid;
}
Map<String, Object> droolsPayload = new LinkedHashMap<>();
droolsPayload.put("blockId", bid);
droolsPayload.put("salience", def.getSalience());
droolsPayload.put("droolsRuleName", def.getDroolsRuleName());
droolsPayload.put("computationHint", def.getDroolsRuleName() + ":业务步骤汇总后与库表规则项、参数一并展示");
nodes.add(node(droolsId, def.getDroolsRuleName(), "drools_facade", droolsPayload));
if (lastStepId != null) {
addEdge(edges, edgeIds, "four:compute_flow:to_drools:" + bid,
lastStepId, droolsId, "compute_flow", "汇总");
}
Set<String> ruleCodeSet = new HashSet<>();
List<String> ruleNodeIds = new ArrayList<>();
for (RuleConfig r : moduleRules) {
if (r == null || ObjectUtil.isEmpty(r.getRuleCode())) {
continue;
}
ruleCodeSet.add(r.getRuleCode());
String rid = "four:block:" + bid + ":rule:" + r.getRuleCode();
ruleNodeIds.add(rid);
String ruleLabel = ObjectUtil.defaultIfBlank(r.getRuleName(), r.getRuleCode());
Map<String, Object> rp = new LinkedHashMap<>();
rp.put("ruleCode", r.getRuleCode());
rp.put("ruleName", r.getRuleName());
rp.put("priorityNo", r.getPriorityNo());
rp.put("levelCode", r.getLevelCode());
rp.put("kindCode", r.getKindCode());
rp.put("moduleCode", r.getModuleCode());
if (ObjectUtil.isNotEmpty(r.getConditionExpr())) {
rp.put("conditionExpr", r.getConditionExpr());
}
if (ObjectUtil.isNotEmpty(r.getActionExpr())) {
rp.put("actionExpr", r.getActionExpr());
}
if (ObjectUtil.isNotEmpty(r.getRemark())) {
rp.put("remark", r.getRemark());
}
nodes.add(node(rid, ruleLabel, "rule_row", rp));
addEdge(edges, edgeIds, "four:drools_contains:" + bid + ":" + r.getRuleCode(),
droolsId, rid, "drools_contains", "包含");
}
for (int i = 0; i < ruleNodeIds.size() - 1; i++) {
addEdge(edges, edgeIds, "four:priority_next:" + bid + ":" + i,
ruleNodeIds.get(i), ruleNodeIds.get(i + 1), "rule_priority_next", "优先级顺序");
}
for (RuleConfig r : moduleRules) {
if (r == null || ObjectUtil.isEmpty(r.getRuleCode()) || !ruleCodeSet.contains(r.getRuleCode())) {
continue;
}
String rid = "four:block:" + bid + ":rule:" + r.getRuleCode();
List<String> outs = RuleFourBlockRuleOutputCatalog.outputsForRule(def.getModuleCode(), r.getRuleCode());
for (int j = 0; j < outs.size(); j++) {
String full = outs.get(j);
if (ObjectUtil.isEmpty(full)) {
continue;
}
String oid = "four:block:" + bid + ":out:" + r.getRuleCode() + ":" + j;
Map<String, Object> op = new LinkedHashMap<>();
op.put("detail", full);
op.put("ruleCode", r.getRuleCode());
op.put("outputIndex", j);
String lab = full.length() > 42 ? full.substring(0, 42) + "" : full;
nodes.add(node(oid, lab, "rule_output", op));
addEdge(edges, edgeIds, "four:produces:" + bid + ":" + r.getRuleCode() + ":" + j,
rid, oid, "rule_produces", "产出");
}
}
for (RuleConfigParam p : plist) {
if (p == null || ObjectUtil.isEmpty(p.getParamKey()) || ObjectUtil.isEmpty(p.getRuleCode())) {
continue;
}
if (p.getEnabled() != null && p.getEnabled() == 0) {
continue;
}
if (!ruleCodeSet.contains(p.getRuleCode())) {
continue;
}
String pk = p.getParamKey();
String pid = "four:block:" + bid + ":param:" + p.getRuleCode() + ":" + pk;
RuleParamMeta pm = resolveMeta(pk);
String pLabel = ObjectUtil.defaultIfBlank(p.getParamName(), pk);
Map<String, Object> pl = new LinkedHashMap<>();
pl.put("paramKey", pk);
pl.put("storedRaw", p.getParamVal());
pl.put("effectiveValue", globalPreview != null ? globalPreview.get(pk) : null);
pl.put("ruleCode", p.getRuleCode());
if (pm != null) {
pl.put("metaLabel", pm.getLabel());
pl.put("valueType", pm.getValueType());
pl.put("description", pm.getDescription());
}
nodes.add(node(pid, pLabel, "param", pl));
String rid = "four:block:" + bid + ":rule:" + p.getRuleCode();
addEdge(edges, edgeIds, "four:has_param:" + bid + ":" + p.getRuleCode() + ":" + pk,
rid, pid, "rule_has_param", "参数");
RuleConfig rr = ruleByCode.get(p.getRuleCode());
String fullWhen = formatParamWhenForRow(rr, def);
String cid = "four:block:" + bid + ":cond:" + p.getRuleCode() + ":" + pk;
String shortLab;
if (ObjectUtil.isEmpty(fullWhen)) {
shortLab = "(无条件)";
} else {
shortLab = fullWhen.length() > 36 ? fullWhen.substring(0, 36) + "" : fullWhen;
}
Map<String, Object> cp = new LinkedHashMap<>();
cp.put("fullWhenText", fullWhen);
cp.put("paramKey", pk);
cp.put("ruleCode", p.getRuleCode());
nodes.add(node(cid, shortLab, "param_condition", cp));
addEdge(edges, edgeIds, "four:cond_to_param:" + bid + ":" + p.getRuleCode() + ":" + pk,
cid, pid, "condition_applies", "条件");
}
graph.setLayoutHint("radial_hub");
graph.setFocusNodeId(droolsId);
return graph;
}
private List<RuleDictItem> safeDict(String dictType) {
List<RuleDictItem> list = ruleConfigMapper.selectDictByType(dictType);
return list != null ? list : Collections.emptyList();