From 71bb45f6a0ed83a17f3b8044e2a4719f17daa11b Mon Sep 17 00:00:00 2001 From: MHW Date: Mon, 20 Apr 2026 10:31:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E4=BD=93=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/graph/RuleFourBlockDefinition.java | 107 ++++++ .../graph/RuleFourBlockParamMapping.java | 87 +++++ .../graph/RuleFourBlockRuleOutputCatalog.java | 91 ++++++ .../config/graph/RuleParamOutputHint.java | 72 ++++ .../config/vo/RuleFourBlockClusterVO.java | 40 +++ .../config/vo/RuleFourBlockParamRowVO.java | 33 ++ .../config/vo/RuleFourBlocksGraphVO.java | 28 ++ .../rule-config/RuleBlockNeoGraph.vue | 309 ++++++++++++++++++ .../rule-config/RuleFourBlocksPanel.vue | 294 +++++++++++++++++ 9 files changed, 1061 insertions(+) create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockDefinition.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockParamMapping.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockRuleOutputCatalog.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleParamOutputHint.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockClusterVO.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockParamRowVO.java create mode 100644 auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlocksGraphVO.java create mode 100644 modeler/src/views/decision/rule-config/RuleBlockNeoGraph.vue create mode 100644 modeler/src/views/decision/rule-config/RuleFourBlocksPanel.vue diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockDefinition.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockDefinition.java new file mode 100644 index 0000000..10ca821 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockDefinition.java @@ -0,0 +1,107 @@ +package com.solution.rule.domain.config.graph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 与 {@code rules/rule.drl} 中「装备/目标/阵位/航迹」四个主规则一一对应,仅用于知识图谱分块展示(与 module_code 一致)。 + */ +public enum RuleFourBlockDefinition { + + EQUIPMENT( + "equipment", + "装备匹配", + 100, + Arrays.asList( + "抽取蓝方任务与武器文案、红方装备类型与名称等,拼接为可对齐的蓝/红文本特征", + "规则槽关键词与兼容层叠加计分,再乘以全局权重得到每件红装的匹配总分", + "低于最低入选分则丢弃;并列最高分按既定策略决胜,并写入火力输入与任务名后缀"), + "DroolsFact(task != null)", + "mergeDefaultParams(globalParams); equipmentRule($fact, globalParams);"), + TARGET( + "target", + "目标匹配", + 90, + Arrays.asList( + "根据命中率映射、射程解析与分配模式,确定每套红方可承载的目标数量与目标标识", + "向任务 execute 写入目标列表与默认行动类型等执行侧字段", + "命中率低于阈值时,在轮次与件数限制内补充选取装备并更新任务"), + "DroolsFact(task != null)", + "mergeDefaultParams(globalParams); target($fact, globalParams);"), + POSITION( + "position", + "阵位匹配", + 80, + Arrays.asList( + "结合锚点模式、航向与部署距离区间、编队样式与间距,计算红方平台目标点位", + "按平台最小间距离散多个平台坐标,必要时叠加上述默认高度与跟随比例", + "若启用作战区约束,将越界阵位沿策略回拉到战争区内"), + "DroolsFact(task != null)", + "mergeDefaultParams(globalParams); position($fact, globalParams);"), + TRACK( + "track", + "航迹匹配", + 70, + Arrays.asList( + "依据蓝方航迹与数据类型判定空中/地面航迹类别,选择对应变形算法生成航迹折线", + "生成航迹标识并与任务 execute 中的目标绑定移动路由", + "若启用航迹作战区约束,将航迹点约束在战争区多边形内"), + "DroolsFact(task != null)", + "mergeDefaultParams(globalParams); trackRoute($fact, globalParams);"); + + private final String moduleCode; + private final String droolsRuleName; + private final int salience; + private final List computationSteps; + private final String whenExpr; + private final String thenAction; + + RuleFourBlockDefinition(String moduleCode, String droolsRuleName, int salience, + List computationSteps, String whenExpr, String thenAction) { + this.moduleCode = moduleCode; + this.droolsRuleName = droolsRuleName; + this.salience = salience; + this.computationSteps = Collections.unmodifiableList(new ArrayList<>(computationSteps)); + this.whenExpr = whenExpr; + this.thenAction = thenAction; + } + + public String getBlockId() { + return name().toLowerCase(); + } + + public String getModuleCode() { + return moduleCode; + } + + public String getDroolsRuleName() { + return droolsRuleName; + } + + public int getSalience() { + return salience; + } + + /** + * 用于知识图谱的业务运算步骤(中文),非 DRL 字面量。 + */ + public List getComputationSteps() { + return computationSteps; + } + + public String getWhenExpr() { + return whenExpr; + } + + public String getThenAction() { + return thenAction; + } + + public static List ordered() { + return Arrays.stream(values()).collect(Collectors.toList()); + } +} + \ No newline at end of file diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockParamMapping.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockParamMapping.java new file mode 100644 index 0000000..82d8bd0 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockParamMapping.java @@ -0,0 +1,87 @@ +package com.solution.rule.domain.config.graph; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +/** + * 冻结「参数键 → 四大展示块」归属(与 rule.drl / {@code 002_rule_seed_from_drl.sql} 中的 rule_item.module_code 一致)。 + * 图谱优先按库表 rule_item_param.rule_code 所属模块归类;若某键仅存在于 globalParams 快照且无法关联模块时,再用本映射兜底。 + */ +public final class RuleFourBlockParamMapping { + + private static final Set EQUIPMENT = set( + "weight", "minSelectedScore", "tieBreak", "outputDrawNameSuffix", "ruleSlotCount", + "blueRuleKeywords_1", "redRuleKeywords_1", "ruleScore_1", + "blueRuleKeywords_2", "redRuleKeywords_2", "ruleScore_2", + "blueRuleKeywords_3", "redRuleKeywords_3", "ruleScore_3", + "bluePlatformKeywords_air", "redPreferredWhenBlueAir", "airScore", + "airTaskKeywords", "airTaskScore", + "groundTaskKeywords", "redPreferredWhenGround", "groundScore", + "tankKeywords", "redMatchKeywords_tank", "tankScore", + "missileKeywords", "redMatchKeywords_missile", "missileScore"); + private static final Set TARGET = set( + "executeTypeDefault", "targetPickMode", "minTargetsPerRed", "maxTargetsPerRedCap", + "radToTargetsCsv", "rangeParseRegex", "rangeUnit", "minRangeToAllowAssignKm", + "redHitRateThreshold", "maxExtraWeaponsPerTask", "maxSupplementRounds", "extraPickMinScore"); + private static final Set POSITION = set( + "positionRuleEnabled", "positionAnchorMode", "trackPointDirectionMode", + "fallbackBearingDeg", "deployDistanceKmMin", "deployDistanceKmMax", "deployDistanceKmDefault", + "distanceByPlatformCsv", "formationType", "formationSpacingMeters", "formationHeadingOffsetDeg", + "defaultDeployHeight", "heightFollowBlueRatio", "enableWarZoneClamp", "warZoneClampMode", + "minInterPlatformDistanceMeters"); + private static final Set TRACK = set( + "trackRuleEnabled", "trackRouteAlgorithm", "trackRouteNameSuffix", + "trackAirDataTypeCsv", "trackAirKeywordsCsv", "trackGroundTrackType", + "trackFallbackBearingDeg", "enableTrackWarZoneClamp", + "trackExtraNodesMax", "trackShortPathSegments", + "trackFlankOffsetMeters", "trackFlankSideMode", + "trackJamWobbleMeters", "trackJamSegments"); + + private RuleFourBlockParamMapping() { + } + + private static Set set(String... keys) { + return Collections.unmodifiableSet(new HashSet<>(Arrays.asList(keys))); + } + + /** + * @param paramKey 参数键 + * @param slotRuleKeys 形如 blueRuleKeywords_i / redRuleKeywords_i / ruleScore_i,视为装备块 + */ + public static RuleFourBlockDefinition fallbackBlockForKey(String paramKey, boolean slotRuleKeys) { + if (paramKey == null || paramKey.isEmpty()) { + return RuleFourBlockDefinition.EQUIPMENT; + } + String k = paramKey.trim(); + if (slotRuleKeys) { + return RuleFourBlockDefinition.EQUIPMENT; + } + if (EQUIPMENT.contains(k)) { + return RuleFourBlockDefinition.EQUIPMENT; + } + if (TARGET.contains(k)) { + return RuleFourBlockDefinition.TARGET; + } + if (POSITION.contains(k)) { + return RuleFourBlockDefinition.POSITION; + } + if (TRACK.contains(k)) { + return RuleFourBlockDefinition.TRACK; + } + String lower = k.toLowerCase(Locale.ROOT); + if (lower.startsWith("track")) { + return RuleFourBlockDefinition.TRACK; + } + if (lower.startsWith("position") || lower.startsWith("deploy") || lower.startsWith("formation") + || lower.contains("warzone") || lower.contains("platform")) { + return RuleFourBlockDefinition.POSITION; + } + if (lower.contains("target") || lower.contains("execute") || lower.contains("assign") || lower.contains("supplement")) { + return RuleFourBlockDefinition.TARGET; + } + return RuleFourBlockDefinition.EQUIPMENT; + } +} diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockRuleOutputCatalog.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockRuleOutputCatalog.java new file mode 100644 index 0000000..e405b46 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleFourBlockRuleOutputCatalog.java @@ -0,0 +1,91 @@ +package com.solution.rule.domain.config.graph; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 四块图谱展示用:每条 rule_item 对应的「运行时产出/写回」中文说明(静态目录,与 RuleFunction 行为一致即可)。 + */ +public final class RuleFourBlockRuleOutputCatalog { + + private static final Map>> BY_MODULE_AND_RULE = new HashMap<>(); + + static { + Map> equipment = new HashMap<>(); + equipment.put("R_TASK_SELECT_BASE", list( + "汇总匹配结果并写入火力规则输入(fireRuleInputs 等匹配行)", + "为任务名称追加输出后缀(outputDrawNameSuffix)")); + equipment.put("R_TASK_SELECT_SLOT_1", list( + "若槽1蓝红关键词同时命中,为当前候选装备累加 ruleScore_1×weight 分值")); + equipment.put("R_TASK_SELECT_SLOT_2", list( + "若槽2蓝红关键词同时命中,累加 ruleScore_2×weight 分值")); + equipment.put("R_TASK_SELECT_SLOT_3", list( + "若槽3蓝红关键词同时命中,累加 ruleScore_3×weight 分值")); + equipment.put("R_TASK_REL_AIR_PLATFORM", list( + "空中平台关键词命中时累加 airScore×weight 兼容层分值")); + equipment.put("R_TASK_REL_AIR_TASK", list( + "空中任务文案命中时累加 airTaskScore×weight 分值")); + equipment.put("R_TASK_REL_GROUND_TASK", list( + "地面任务与红方偏好同时命中时累加 groundScore×weight 分值")); + equipment.put("R_TASK_REL_TANK", list( + "坦克类关键词匹配时累加 tankScore×weight 分值")); + equipment.put("R_TASK_REL_MISSILE", list( + "导弹类关键词匹配时累加 missileScore×weight 分值")); + BY_MODULE_AND_RULE.put("equipment", Collections.unmodifiableMap(equipment)); + + Map> target = new HashMap<>(); + target.put("R_TASK_ASSIGN_TARGET", list( + "填充任务 execute 中目标列表与默认行动类型(executeTypeDefault 等)", + "按命中率映射与分配模式更新 targetId / 目标数量")); + target.put("R_TASK_LIMIT_SUPPLEMENT", list( + "命中率低于阈值时按轮次与件数上限补充选取装备并回写任务武器列表")); + BY_MODULE_AND_RULE.put("target", Collections.unmodifiableMap(target)); + + Map> position = new HashMap<>(); + position.put("R_PLATFORM_DEPLOY", list( + "计算并写回红方 SubComponents.platform[].positions(部署点、编队间距与高度)")); + position.put("R_PLATFORM_SPACETIME", list( + "在启用作战区约束时,将越界阵位回拉到 warZoneLocation 多边形内")); + BY_MODULE_AND_RULE.put("position", Collections.unmodifiableMap(position)); + + Map> track = new HashMap<>(); + track.put("R_ACTION_TRACK_ROUTE", list( + "生成/更新 TrackParam 中航迹节点,并为 execute 绑定 moveRouteId", + "按算法(followBlue 等)变形蓝方航迹并写航迹名称后缀")); + track.put("R_ACTION_TRACK_SPACETIME", list( + "在启用约束时将航迹点限制在作战区边界内")); + BY_MODULE_AND_RULE.put("track", Collections.unmodifiableMap(track)); + } + + private RuleFourBlockRuleOutputCatalog() { + } + + private static List list(String... lines) { + List l = new ArrayList<>(); + for (String s : lines) { + if (s != null && !s.isEmpty()) { + l.add(s); + } + } + return Collections.unmodifiableList(l); + } + + /** + * @param moduleCode equipment / target / position / track + * @param ruleCode rule_item.rule_code + */ + public static List outputsForRule(String moduleCode, String ruleCode) { + if (moduleCode == null || ruleCode == null) { + return Collections.emptyList(); + } + Map> m = BY_MODULE_AND_RULE.get(moduleCode); + if (m == null) { + return Collections.emptyList(); + } + List list = m.get(ruleCode); + return list != null ? list : Collections.emptyList(); + } +} diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleParamOutputHint.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleParamOutputHint.java new file mode 100644 index 0000000..efca034 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/graph/RuleParamOutputHint.java @@ -0,0 +1,72 @@ +package com.solution.rule.domain.config.graph; + +import cn.hutool.core.util.ObjectUtil; + +/** + * 参数在「产出」列中的一行静态说明(与 globalParams 生效值拼接展示)。 + */ +public final class RuleParamOutputHint { + + private static final String GENERIC = "写入 globalParams 并由当前块对应 Java 算子读取"; + + private RuleParamOutputHint() { + } + + public static String effectLine(String paramKey, String moduleCode) { + if (ObjectUtil.isEmpty(paramKey)) { + return GENERIC; + } + String k = paramKey.trim(); + switch (k) { + case "weight": + return "参与装备/目标等环节的评分加权"; + case "minSelectedScore": + return "低于该分则本规则对应环节不选中/不生效"; + case "tieBreak": + return "同分时的决胜策略(如按装备 ID)"; + case "outputDrawNameSuffix": + return "影响任务/输出名称后缀展示"; + case "ruleSlotCount": + return "规则槽数量上限(装备匹配)"; + case "executeTypeDefault": + return "写入任务 execute 的默认行动类型"; + case "targetPickMode": + return "目标分配挑选模式(轮询/随机等)"; + case "radToTargetsCsv": + return "命中率到目标数量的映射"; + case "redHitRateThreshold": + return "命中率阈值,触发补拿等逻辑"; + case "maxExtraWeaponsPerTask": + case "maxSupplementRounds": + case "extraPickMinScore": + return "补拿装备轮次与分数约束"; + case "positionRuleEnabled": + case "trackRuleEnabled": + case "groupRuleEnabled": + return "控制对应环节是否执行"; + case "deployDistanceKmMin": + case "deployDistanceKmMax": + case "deployDistanceKmDefault": + return "部署距离区间与默认值(阵位)"; + case "formationType": + case "formationSpacingMeters": + return "编队几何与间距"; + case "enableWarZoneClamp": + case "enableTrackWarZoneClamp": + return "作战区约束开关"; + case "trackRouteAlgorithm": + return "航迹生成算法选择"; + default: + if (k.startsWith("blueRuleKeywords_") || k.startsWith("redRuleKeywords_") || k.startsWith("ruleScore_")) { + return "规则槽关键词/分值,参与装备匹配打分"; + } + if (ObjectUtil.isNotEmpty(moduleCode) && "track".equals(moduleCode) && k.toLowerCase().startsWith("track")) { + return "航迹生成与约束相关配置"; + } + if (ObjectUtil.isNotEmpty(moduleCode) && "position".equals(moduleCode)) { + return "阵位/部署与空间约束相关配置"; + } + return GENERIC; + } + } +} diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockClusterVO.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockClusterVO.java new file mode 100644 index 0000000..3653039 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockClusterVO.java @@ -0,0 +1,40 @@ +package com.solution.rule.domain.config.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel("单个分块(环形参数 + If/Then 中枢)") +public class RuleFourBlockClusterVO implements Serializable { + + @ApiModelProperty("块标识:equipment/target/position/track") + private String blockId; + + @ApiModelProperty("模块编码,对应 rule_item.module_code") + private String moduleCode; + + @ApiModelProperty("界面标题(如 装备匹配)") + private String title; + + @ApiModelProperty("Drools 规则名(如 装备匹配)") + private String droolsRuleName; + + @ApiModelProperty("salience") + private Integer salience; + + @ApiModelProperty("Drools when 表达式摘要") + private String whenExpr; + + @ApiModelProperty("then 动作(含 mergeDefaultParams + Java 调用)") + private String thenAction; + + @ApiModelProperty("中枢 + 环形参数节点与边") + private RuleGraphVO graph; + + @ApiModelProperty("该块内每条规则的每个参数:When/Then/产出(表格)") + private List paramRows; +} diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockParamRowVO.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockParamRowVO.java new file mode 100644 index 0000000..fdb7851 --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlockParamRowVO.java @@ -0,0 +1,33 @@ +package com.solution.rule.domain.config.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +@ApiModel("四块分区内单条参数展示行") +public class RuleFourBlockParamRowVO implements Serializable { + + @ApiModelProperty("规则编码") + private String ruleCode; + + @ApiModelProperty("规则名称") + private String ruleName; + + @ApiModelProperty("参数键") + private String paramKey; + + @ApiModelProperty("参数业务名") + private String paramName; + + @ApiModelProperty("When(规则条件或块级回退)") + private String whenText; + + @ApiModelProperty("Then(规则动作或块级回退)") + private String thenText; + + @ApiModelProperty("产出说明(生效值 + 静态提示)") + private String outputText; +} diff --git a/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlocksGraphVO.java b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlocksGraphVO.java new file mode 100644 index 0000000..6056a6f --- /dev/null +++ b/auto-solution-rule/src/main/java/com/solution/rule/domain/config/vo/RuleFourBlocksGraphVO.java @@ -0,0 +1,28 @@ +package com.solution.rule.domain.config.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("四块规则知识图谱(装备/目标/阵位/航迹)") +public class RuleFourBlocksGraphVO implements Serializable { + + @ApiModelProperty("与运行时 KieSession globalParams 一致的参数快照(启用规则与参数合并后)") + private Map globalParamsPreview; + + @ApiModelProperty("四个分块,每块含中枢 If/Then 与子图节点边") + private List blocks; + + public Map safeGlobalParamsPreview() { + if (globalParamsPreview == null) { + globalParamsPreview = new LinkedHashMap<>(); + } + return globalParamsPreview; + } +} diff --git a/modeler/src/views/decision/rule-config/RuleBlockNeoGraph.vue b/modeler/src/views/decision/rule-config/RuleBlockNeoGraph.vue new file mode 100644 index 0000000..6166bc4 --- /dev/null +++ b/modeler/src/views/decision/rule-config/RuleBlockNeoGraph.vue @@ -0,0 +1,309 @@ + + + + + + diff --git a/modeler/src/views/decision/rule-config/RuleFourBlocksPanel.vue b/modeler/src/views/decision/rule-config/RuleFourBlocksPanel.vue new file mode 100644 index 0000000..ef20099 --- /dev/null +++ b/modeler/src/views/decision/rule-config/RuleFourBlocksPanel.vue @@ -0,0 +1,294 @@ + + + + + + + +