| src/main/java/com/zy/asrs/controller/BasStationPathPolicyController.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/entity/BasStationPathProfile.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/java/com/zy/asrs/service/impl/StationPathPolicyServiceImpl.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/sql/20260313_create_station_path_policy_tables.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/resources/sql/20260319_migrate_station_path_default_profile_to_profile_table.sql | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/main/webapp/static/js/stationPathPolicy/stationPathPolicy.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/main/java/com/zy/asrs/controller/BasStationPathPolicyController.java
@@ -18,11 +18,7 @@ import com.zy.asrs.service.StationPathPolicyService; import com.zy.common.model.NavigateNode; import com.zy.common.utils.NavigateUtils; import com.zy.common.utils.RedisUtil; import com.zy.common.web.BaseController; import com.zy.core.enums.RedisKeyType; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -41,16 +37,10 @@ @RequestMapping("/basStationPathPolicy") public class BasStationPathPolicyController extends BaseController { private static final String CFG_DEFAULT_PROFILE_CODE = "stationPathDefaultProfileCode"; @Autowired private BasStationPathProfileService basStationPathProfileService; @Autowired private BasStationPathRuleService basStationPathRuleService; @Autowired private ConfigService configService; @Autowired private RedisUtil redisUtil; @Autowired private StationPathPolicyService stationPathPolicyService; @Autowired @@ -63,11 +53,14 @@ @RequestMapping("/data/auth") @ManagerAuth public R data() { List<BasStationPathProfile> profileList = basStationPathProfileService.list(new QueryWrapper<BasStationPathProfile>() .orderByDesc("is_default") .orderByAsc("priority", "id")); Map<String, Object> data = new HashMap<>(); data.put("profiles", basStationPathProfileService.list(new QueryWrapper<BasStationPathProfile>().orderByAsc("priority", "id"))); data.put("profiles", profileList); data.put("rules", basStationPathRuleService.list(new QueryWrapper<BasStationPathRule>().orderByAsc("priority", "id"))); data.put("scoreMode", "twoStage"); data.put("defaultProfileCode", getSystemConfig(CFG_DEFAULT_PROFILE_CODE, "default")); data.put("defaultProfileCode", resolveDefaultProfileCode(profileList)); data.put("stations", buildStationSummaryList()); data.put("levList", basMapService.getLevList()); return R.ok(data); @@ -78,11 +71,6 @@ public R save(@RequestBody JSONObject payload) { JSONArray profiles = payload.getJSONArray("profiles"); JSONArray rules = payload.getJSONArray("rules"); upsertSystemConfig("站点路径默认模板编码", CFG_DEFAULT_PROFILE_CODE, defaultIfBlank(payload.getString("defaultProfileCode"), "default"), "String"); basStationPathProfileService.remove(new QueryWrapper<>()); basStationPathRuleService.remove(new QueryWrapper<>()); List<BasStationPathProfile> profileList = new ArrayList<>(); if (profiles != null) { @@ -99,6 +87,7 @@ profile.setProfileName(defaultIfBlank(item.getString("profileName"), item.getString("profileCode"))); profile.setPriority(item.getInteger("priority") == null ? 100 : item.getInteger("priority")); profile.setStatus(item.getShort("status") == null ? (short) 1 : item.getShort("status")); profile.setIsDefault((short) 0); profile.setMemo(item.getString("memo")); Object configObj = item.get("config"); if (configObj != null) { @@ -109,6 +98,29 @@ profileList.add(profile); } } if (profileList.isEmpty()) { return R.error("至少需要保留一个模板"); } String defaultProfileCode = defaultIfBlank(payload.getString("defaultProfileCode"), profileList.get(0).getProfileCode()); BasStationPathProfile defaultProfile = null; for (BasStationPathProfile profile : profileList) { if (profile != null && defaultProfileCode.equals(profile.getProfileCode())) { profile.setIsDefault((short) 1); defaultProfile = profile; break; } } if (defaultProfile == null) { return R.error("默认模板编码没有对应模板"); } if (!Short.valueOf((short) 1).equals(defaultProfile.getStatus())) { return R.error("默认模板必须启用"); } basStationPathProfileService.remove(new QueryWrapper<>()); basStationPathRuleService.remove(new QueryWrapper<>()); if (!profileList.isEmpty()) { basStationPathProfileService.saveBatch(profileList); } @@ -143,8 +155,6 @@ if (!ruleList.isEmpty()) { basStationPathRuleService.saveBatch(ruleList); } refreshSystemConfigCache(); stationPathPolicyService.evictCache(); return R.ok(); } @@ -265,44 +275,28 @@ return result; } private void upsertSystemConfig(String name, String code, String value, String selectType) { String finalValue = value == null ? "" : value.trim(); Config config = configService.getOne(new QueryWrapper<Config>().eq("code", code)); if (config == null) { config = new Config(name, code, finalValue, (short) 1, (short) 1); config.setSelectType(selectType); configService.save(config); } else { config.setName(name); config.setValue(finalValue); config.setType((short) 1); config.setStatus((short) 1); config.setSelectType(selectType); configService.updateById(config); private String resolveDefaultProfileCode(List<BasStationPathProfile> profileList) { if (profileList == null || profileList.isEmpty()) { return "default"; } } private void refreshSystemConfigCache() { HashMap<String, String> systemConfigMap = new HashMap<>(); List<Config> configList = configService.list(new QueryWrapper<>()); for (Config config : configList) { systemConfigMap.put(config.getCode(), config.getValue()); } redisUtil.set(RedisKeyType.SYSTEM_CONFIG_MAP.key, systemConfigMap); } private String getSystemConfig(String code, String defaultValue) { Object mapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); if (mapObj instanceof Map) { Object value = ((Map<?, ?>) mapObj).get(code); if (value != null) { String text = String.valueOf(value).trim(); if (!text.isEmpty()) { return text; } for (BasStationPathProfile profile : profileList) { if (profile != null && Short.valueOf((short) 1).equals(profile.getIsDefault()) && !isBlank(profile.getProfileCode())) { return profile.getProfileCode(); } } return defaultValue; for (BasStationPathProfile profile : profileList) { if (profile != null && "default".equals(profile.getProfileCode())) { return profile.getProfileCode(); } } for (BasStationPathProfile profile : profileList) { if (profile != null && !isBlank(profile.getProfileCode())) { return profile.getProfileCode(); } } return "default"; } private List<Integer> parseStationIdArray(JSONArray array) { src/main/java/com/zy/asrs/entity/BasStationPathProfile.java
@@ -27,6 +27,9 @@ private Short status; @TableField("is_default") private Short isDefault; @TableField("config_json") private String configJson; src/main/java/com/zy/asrs/service/impl/StationPathPolicyServiceImpl.java
@@ -10,8 +10,6 @@ import com.zy.asrs.service.BasStationPathProfileService; import com.zy.asrs.service.BasStationPathRuleService; import com.zy.asrs.service.StationPathPolicyService; import com.zy.common.utils.RedisUtil; import com.zy.core.enums.RedisKeyType; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -32,8 +30,6 @@ private BasStationPathProfileService basStationPathProfileService; @Autowired private BasStationPathRuleService basStationPathRuleService; @Autowired private RedisUtil redisUtil; private volatile CacheSnapshot cacheSnapshot = new CacheSnapshot(); private volatile long cacheTime = 0L; @@ -42,9 +38,9 @@ public StationPathResolvedPolicy resolvePolicy(Integer startStationId, Integer endStationId) { StationPathResolvedPolicy resolved = new StationPathResolvedPolicy(); resolved.setScoreMode("twoStage"); resolved.setDefaultProfileCode(getSystemConfig("stationPathDefaultProfileCode", "default")); CacheSnapshot snapshot = getCacheSnapshot(); resolved.setDefaultProfileCode(snapshot.defaultProfileCode); BasStationPathRule matchedRule = matchRule(snapshot.ruleList, startStationId, endStationId); BasStationPathProfile matchedProfile = null; if (matchedRule != null && notBlank(matchedRule.getProfileCode())) { @@ -95,6 +91,7 @@ try { List<BasStationPathProfile> profiles = basStationPathProfileService.list(new QueryWrapper<BasStationPathProfile>() .eq("status", 1) .orderByDesc("is_default") .orderByAsc("priority", "id")); if (profiles != null) { snapshot.profileList.addAll(profiles); @@ -103,6 +100,7 @@ snapshot.profileMap.put(profile.getProfileCode(), profile); } } snapshot.defaultProfileCode = resolveDefaultProfileCode(profiles); } } catch (Exception e) { log.warn("加载站点路径模板失败,回退默认配置: {}", e.getMessage()); @@ -230,21 +228,28 @@ return config; } private String getSystemConfig(String code, String defaultValue) { try { Object mapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key); if (mapObj instanceof Map) { Object value = ((Map<?, ?>) mapObj).get(code); if (value != null) { String text = String.valueOf(value).trim(); if (!text.isEmpty()) { return text; } } } } catch (Exception ignore) { private String resolveDefaultProfileCode(List<BasStationPathProfile> profiles) { if (profiles == null || profiles.isEmpty()) { return "default"; } return defaultValue; for (BasStationPathProfile profile : profiles) { if (profile != null && Short.valueOf((short) 1).equals(profile.getIsDefault()) && notBlank(profile.getProfileCode())) { return profile.getProfileCode(); } } for (BasStationPathProfile profile : profiles) { if (profile != null && "default".equals(profile.getProfileCode())) { return profile.getProfileCode(); } } for (BasStationPathProfile profile : profiles) { if (profile != null && notBlank(profile.getProfileCode())) { return profile.getProfileCode(); } } return "default"; } private boolean notBlank(String value) { @@ -257,6 +262,7 @@ private static class CacheSnapshot { private boolean loaded = false; private String defaultProfileCode = "default"; private final List<BasStationPathProfile> profileList = new ArrayList<>(); private final List<BasStationPathRule> ruleList = new ArrayList<>(); private final Map<String, BasStationPathProfile> profileMap = new HashMap<>(); src/main/resources/sql/20260313_create_station_path_policy_tables.sql
@@ -4,6 +4,7 @@ `profile_name` VARCHAR(128) NOT NULL COMMENT '模板名称', `priority` INT NOT NULL DEFAULT 100 COMMENT '优先级,越小越优先', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态 1启用 0禁用', `is_default` TINYINT NOT NULL DEFAULT 0 COMMENT '默认模板 1是 0否', `config_json` LONGTEXT NULL COMMENT '模板参数JSON', `memo` VARCHAR(255) NULL COMMENT '备注', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', @@ -37,22 +38,16 @@ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='输送站点路径人工规则'; INSERT INTO `asr_bas_station_path_profile` (`profile_code`, `profile_name`, `priority`, `status`, `config_json`, `memo`) (`profile_code`, `profile_name`, `priority`, `status`, `is_default`, `config_json`, `memo`) SELECT 'default', '默认模板', 100, 1, 1, '{"calcMaxDepth":120,"calcMaxPaths":500,"calcMaxCost":300,"s1TopK":5,"s1LenWeight":1.0,"s1TurnWeight":3.0,"s1LiftWeight":8.0,"s1SoftDeviationWeight":4.0,"s1MaxLenRatio":1.15,"s1MaxTurnDiff":1,"s2BusyWeight":2.0,"s2RunBlockWeight":10.0,"s2LoopLoadWeight":12.0,"stationPathLenWeightPercent":50.0,"stationPathCongWeightPercent":50.0,"stationPathPassOtherOutStationWeightPercent":100.0,"stationPathPassOtherOutStationForceSkip":false}', '默认模板' FROM dual WHERE NOT EXISTS ( SELECT 1 FROM `asr_bas_station_path_profile` WHERE `profile_code` = 'default' ); INSERT INTO `sys_config`(`name`, `code`, `value`, `type`, `status`, `select_type`) SELECT '站点路径默认模板编码', 'stationPathDefaultProfileCode', 'default', 1, 1, 'system' FROM dual WHERE NOT EXISTS ( SELECT 1 FROM `sys_config` WHERE `code` = 'stationPathDefaultProfileCode' ); src/main/resources/sql/20260319_migrate_station_path_default_profile_to_profile_table.sql
New file @@ -0,0 +1,69 @@ SET @current_db := DATABASE(); SET @column_exists := ( SELECT COUNT(1) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @current_db AND TABLE_NAME = 'asr_bas_station_path_profile' AND COLUMN_NAME = 'is_default' ); SET @add_column_sql := IF( @column_exists = 0, 'ALTER TABLE asr_bas_station_path_profile ADD COLUMN is_default TINYINT NOT NULL DEFAULT 0 COMMENT ''默认模板 1是 0否'' AFTER status', 'SELECT ''column is_default already exists'' ' ); PREPARE stmt_add_column FROM @add_column_sql; EXECUTE stmt_add_column; DEALLOCATE PREPARE stmt_add_column; SET @default_profile_code := ( SELECT COALESCE(MAX(TRIM(`value`)), 'default') FROM `sys_config` WHERE `code` = 'stationPathDefaultProfileCode' ); UPDATE `asr_bas_station_path_profile` SET `is_default` = 0; UPDATE `asr_bas_station_path_profile` SET `is_default` = 1 WHERE `profile_code` = @default_profile_code AND `status` = 1; UPDATE `asr_bas_station_path_profile` SET `is_default` = 1 WHERE `profile_code` = 'default' AND `status` = 1 AND NOT EXISTS ( SELECT 1 FROM ( SELECT `id` FROM `asr_bas_station_path_profile` WHERE `is_default` = 1 ) t ); UPDATE `asr_bas_station_path_profile` SET `is_default` = 1 WHERE `id` = ( SELECT `id` FROM ( SELECT `id` FROM `asr_bas_station_path_profile` WHERE `status` = 1 ORDER BY `priority` ASC, `id` ASC LIMIT 1 ) t ) AND NOT EXISTS ( SELECT 1 FROM ( SELECT `id` FROM `asr_bas_station_path_profile` WHERE `is_default` = 1 ) t ); DELETE FROM `sys_config` WHERE `code` = 'stationPathDefaultProfileCode'; src/main/webapp/static/js/stationPathPolicy/stationPathPolicy.js
@@ -365,6 +365,17 @@ this.$message.warning('默认模板编码没有对应模板') return } var defaultProfile = null for (var i = 0; i < this.profiles.length; i++) { if (this.profiles[i].profileCode === this.defaultProfileCode) { defaultProfile = this.profiles[i] break } } if (!defaultProfile || Number(defaultProfile.status) !== 1) { this.$message.warning('默认模板必须启用') return } var payload = { defaultProfileCode: this.defaultProfileCode, profiles: this.profiles.map(this.sanitizeProfileForSave),