旧接口字段更新BUG修复
This commit is contained in:
@@ -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<>();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user