|
|
@ -19,6 +19,7 @@ import org.springframework.stereotype.Component; |
|
|
import java.util.HashSet; |
|
|
import java.util.HashSet; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
import java.util.Set; |
|
|
import java.util.Set; |
|
|
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 内置字典幂等初始化(T08,ADR-0015) |
|
|
* 内置字典幂等初始化(T08,ADR-0015) |
|
|
@ -91,16 +92,77 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
new ItemSeed("potential", "潜在客户", "potential", 1, null, true), |
|
|
new ItemSeed("potential", "潜在客户", "potential", 1, null, true), |
|
|
new ItemSeed("active", "合作中", "active", 2, null, false), |
|
|
new ItemSeed("active", "合作中", "active", 2, null, false), |
|
|
new ItemSeed("lost", "已流失", "lost", 3, null, false))), |
|
|
new ItemSeed("lost", "已流失", "lost", 3, null, false))), |
|
|
new GroupSeed("industry", "所属行业", 3, "客户所属行业", |
|
|
new GroupSeed("industry", "所属行业", 3, "全系统通用两级行业树(客户选二级/商机选一级,产品 20260825)", |
|
|
List.of( |
|
|
List.of( |
|
|
new ItemSeed("manufacturing", "制造业", "manufacturing", 1, null, false), |
|
|
// 一级 1 政府机关
|
|
|
new ItemSeed("it", "信息技术", "it", 2, null, false), |
|
|
new ItemSeed("gov", "政府机关", "gov", 1, null, false), |
|
|
new ItemSeed("finance", "金融", "finance", 3, null, false), |
|
|
new ItemSeed("gov_1", "人大政协", "gov_1", 1, null, false, "gov"), |
|
|
new ItemSeed("healthcare", "医疗健康", "healthcare", 4, null, false), |
|
|
new ItemSeed("gov_2", "应急局", "gov_2", 2, null, false, "gov"), |
|
|
new ItemSeed("education", "教育", "education", 5, null, false), |
|
|
new ItemSeed("gov_3", "烟草局", "gov_3", 3, null, false, "gov"), |
|
|
new ItemSeed("retail", "零售", "retail", 6, null, false), |
|
|
new ItemSeed("gov_4", "疾控中心", "gov_4", 4, null, false, "gov"), |
|
|
new ItemSeed("real_estate", "房地产", "real_estate", 7, null, false), |
|
|
new ItemSeed("gov_5", "大数据中心", "gov_5", 5, null, false, "gov"), |
|
|
new ItemSeed("other", "其他", "other", 8, null, false))), |
|
|
new ItemSeed("gov_6", "税务局", "gov_6", 6, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_7", "教育局", "gov_7", 7, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_8", "民政局", "gov_8", 8, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_9", "人社局", "gov_9", 9, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_10", "财政局", "gov_10", 10, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_11", "国土局", "gov_11", 11, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_12", "水利局", "gov_12", 12, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_13", "林业局", "gov_13", 13, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_14", "商务局", "gov_14", 14, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_15", "文体旅局", "gov_15", 15, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_16", "气象局", "gov_16", 16, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_17", "退役军人事务部", "gov_17", 17, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_18", "融媒体中心", "gov_18", 18, null, false, "gov"), |
|
|
|
|
|
new ItemSeed("gov_19", "人防办", "gov_19", 19, null, false, "gov"), |
|
|
|
|
|
// 一级 2 政法国防
|
|
|
|
|
|
new ItemSeed("law", "政法国防", "law", 2, null, false), |
|
|
|
|
|
new ItemSeed("law_1", "公安", "law_1", 1, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_2", "检察院", "law_2", 2, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_3", "法院", "law_3", 3, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_4", "司法厅", "law_4", 4, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_5", "监狱", "law_5", 5, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_6", "海关-边检站", "law_6", 6, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_7", "武警", "law_7", 7, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_8", "特警", "law_8", 8, null, false, "law"), |
|
|
|
|
|
new ItemSeed("law_9", "消防", "law_9", 9, null, false, "law"), |
|
|
|
|
|
// 一级 3 教育
|
|
|
|
|
|
new ItemSeed("edu", "教育", "edu", 3, null, false), |
|
|
|
|
|
new ItemSeed("edu_1", "普教", "edu_1", 1, null, false, "edu"), |
|
|
|
|
|
new ItemSeed("edu_2", "职校", "edu_2", 2, null, false, "edu"), |
|
|
|
|
|
new ItemSeed("edu_3", "党校", "edu_3", 3, null, false, "edu"), |
|
|
|
|
|
// 一级 4 医疗健康
|
|
|
|
|
|
new ItemSeed("health", "医疗健康", "health", 4, null, false), |
|
|
|
|
|
new ItemSeed("health_1", "医院", "health_1", 1, null, false, "health"), |
|
|
|
|
|
new ItemSeed("health_2", "康养中心", "health_2", 2, null, false, "health"), |
|
|
|
|
|
// 一级 5 金融
|
|
|
|
|
|
new ItemSeed("finance", "金融", "finance", 5, null, false), |
|
|
|
|
|
new ItemSeed("finance_1", "银行", "finance_1", 1, null, false, "finance"), |
|
|
|
|
|
new ItemSeed("finance_2", "保险公司", "finance_2", 2, null, false, "finance"), |
|
|
|
|
|
// 一级 6 交通
|
|
|
|
|
|
new ItemSeed("transport", "交通", "transport", 6, null, false), |
|
|
|
|
|
new ItemSeed("transport_1", "轨道交通", "transport_1", 1, null, false, "transport"), |
|
|
|
|
|
new ItemSeed("transport_2", "机场", "transport_2", 2, null, false, "transport"), |
|
|
|
|
|
new ItemSeed("transport_3", "高铁", "transport_3", 3, null, false, "transport"), |
|
|
|
|
|
new ItemSeed("transport_4", "高速公路", "transport_4", 4, null, false, "transport"), |
|
|
|
|
|
// 一级 7 能源与制造
|
|
|
|
|
|
new ItemSeed("energy", "能源与制造", "energy", 7, null, false), |
|
|
|
|
|
new ItemSeed("energy_1", "石化-能源-矿业", "energy_1", 1, null, false, "energy"), |
|
|
|
|
|
new ItemSeed("energy_2", "发电站-核电站", "energy_2", 2, null, false, "energy"), |
|
|
|
|
|
new ItemSeed("energy_3", "电力实训基地", "energy_3", 3, null, false, "energy"), |
|
|
|
|
|
new ItemSeed("energy_4", "工厂", "energy_4", 4, null, false, "energy"), |
|
|
|
|
|
// 一级 8 文化旅游
|
|
|
|
|
|
new ItemSeed("tourism", "文化旅游", "tourism", 8, null, false), |
|
|
|
|
|
new ItemSeed("tourism_1", "文旅", "tourism_1", 1, null, false, "tourism"), |
|
|
|
|
|
new ItemSeed("tourism_2", "酒店", "tourism_2", 2, null, false, "tourism"), |
|
|
|
|
|
new ItemSeed("tourism_3", "展馆-博物馆", "tourism_3", 3, null, false, "tourism"), |
|
|
|
|
|
// 一级 9 园区与基建
|
|
|
|
|
|
new ItemSeed("park", "园区与基建", "park", 9, null, false), |
|
|
|
|
|
new ItemSeed("park_1", "智慧园区", "park_1", 1, null, false, "park"), |
|
|
|
|
|
new ItemSeed("park_2", "集团大楼", "park_2", 2, null, false, "park"), |
|
|
|
|
|
new ItemSeed("park_3", "商业中心", "park_3", 3, null, false, "park"), |
|
|
|
|
|
new ItemSeed("park_4", "智算中心", "park_4", 4, null, false, "park"), |
|
|
|
|
|
new ItemSeed("park_5", "低空飞行基地", "park_5", 5, null, false, "park"))), |
|
|
new GroupSeed("brand", "品牌", 4, "线索品牌(对齐蓝湖原型)", |
|
|
new GroupSeed("brand", "品牌", 4, "线索品牌(对齐蓝湖原型)", |
|
|
List.of( |
|
|
List.of( |
|
|
new ItemSeed("itc", "itc", "itc", 1, null, false), |
|
|
new ItemSeed("itc", "itc", "itc", 1, null, false), |
|
|
@ -276,6 +338,7 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
for (ItemSeed item : group.items()) { |
|
|
for (ItemSeed item : group.items()) { |
|
|
upsertItem(persisted, item); |
|
|
upsertItem(persisted, item); |
|
|
} |
|
|
} |
|
|
|
|
|
pruneStaleBuiltinItems(persisted, group); |
|
|
for (ItemSeed item : group.items()) { |
|
|
for (ItemSeed item : group.items()) { |
|
|
if (item.defaultItem()) { |
|
|
if (item.defaultItem()) { |
|
|
setDefaultIfAbsent(persisted, item); |
|
|
setDefaultIfAbsent(persisted, item); |
|
|
@ -366,6 +429,18 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
DictItem exist = dictItemMapper.selectOne(new LambdaQueryWrapper<DictItem>() |
|
|
DictItem exist = dictItemMapper.selectOne(new LambdaQueryWrapper<DictItem>() |
|
|
.eq(DictItem::getGroupId, group.getId()) |
|
|
.eq(DictItem::getGroupId, group.getId()) |
|
|
.eq(DictItem::getCode, seed.code())); |
|
|
.eq(DictItem::getCode, seed.code())); |
|
|
|
|
|
// 两级树形:解析父项 id(同组、按 parentCode 查;一级先于二级入库故可查到)
|
|
|
|
|
|
Long parentId = null; |
|
|
|
|
|
if (seed.parentCode() != null) { |
|
|
|
|
|
DictItem parent = dictItemMapper.selectOne(new LambdaQueryWrapper<DictItem>() |
|
|
|
|
|
.eq(DictItem::getGroupId, group.getId()) |
|
|
|
|
|
.eq(DictItem::getCode, seed.parentCode())); |
|
|
|
|
|
if (parent == null) { |
|
|
|
|
|
throw new BusinessErrorException(DictConstants.CODE_DICT_INVALID, |
|
|
|
|
|
"种子二级项父未先入库(检查种子顺序):" + group.getCode() + "/" + seed.code()); |
|
|
|
|
|
} |
|
|
|
|
|
parentId = parent.getId(); |
|
|
|
|
|
} |
|
|
if (exist == null) { |
|
|
if (exist == null) { |
|
|
DictItem created = new DictItem(); |
|
|
DictItem created = new DictItem(); |
|
|
created.setGroupId(group.getId()); |
|
|
created.setGroupId(group.getId()); |
|
|
@ -374,6 +449,7 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
created.setValue(seed.value()); |
|
|
created.setValue(seed.value()); |
|
|
created.setSortNo(seed.sortNo()); |
|
|
created.setSortNo(seed.sortNo()); |
|
|
created.setDescription(seed.description()); |
|
|
created.setDescription(seed.description()); |
|
|
|
|
|
created.setParentId(parentId); |
|
|
created.setStatus(DictConstants.STATUS_ENABLED); |
|
|
created.setStatus(DictConstants.STATUS_ENABLED); |
|
|
created.setBuiltin(true); |
|
|
created.setBuiltin(true); |
|
|
created.setDeleteKey(0L); |
|
|
created.setDeleteKey(0L); |
|
|
@ -388,10 +464,11 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
if (Boolean.TRUE.equals(exist.getBuiltin())) { |
|
|
if (Boolean.TRUE.equals(exist.getBuiltin())) { |
|
|
// 只加/改不删:更新名称/描述/排序号;不碰编码/状态/内置标记/字典值(值属业务契约,管理员本地化后不被种子覆盖)
|
|
|
// 只加/改不删:更新名称/描述/排序号 + 父项归属(两级树);不碰编码/状态/内置标记/字典值
|
|
|
exist.setName(seed.name()); |
|
|
exist.setName(seed.name()); |
|
|
exist.setSortNo(seed.sortNo()); |
|
|
exist.setSortNo(seed.sortNo()); |
|
|
exist.setDescription(seed.description()); |
|
|
exist.setDescription(seed.description()); |
|
|
|
|
|
exist.setParentId(parentId); |
|
|
dictItemMapper.updateById(exist); |
|
|
dictItemMapper.updateById(exist); |
|
|
} else { |
|
|
} else { |
|
|
log.warn("字典项 {}/{} 非内置(builtin=false),跳过种子更新(绝不触碰用户字典)", |
|
|
log.warn("字典项 {}/{} 非内置(builtin=false),跳过种子更新(绝不触碰用户字典)", |
|
|
@ -399,6 +476,31 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 剪除内置项中已不在种子的项(使种子对内置项权威,支持口径改版如 industry 旧 8 项→新树)。 |
|
|
|
|
|
* <p>仅硬删 builtin=true 且未被引用的项;用户项(builtin=false)绝不触碰(US-41); |
|
|
|
|
|
* 同事务清理其引用计数行。一级/二级一并删除(无外键,无顺序要求)。</p> |
|
|
|
|
|
*/ |
|
|
|
|
|
private void pruneStaleBuiltinItems(DictGroup group, GroupSeed seed) { |
|
|
|
|
|
if (!Boolean.TRUE.equals(group.getBuiltin())) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
Set<String> seedCodes = seed.items().stream().map(ItemSeed::code).collect(Collectors.toSet()); |
|
|
|
|
|
List<DictItem> builtinItems = dictItemMapper.selectList(new LambdaQueryWrapper<DictItem>() |
|
|
|
|
|
.eq(DictItem::getGroupId, group.getId()) |
|
|
|
|
|
.eq(DictItem::getBuiltin, true)); |
|
|
|
|
|
for (DictItem item : builtinItems) { |
|
|
|
|
|
if (seedCodes.contains(item.getCode())) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
dictItemMapper.deleteById(item.getId()); |
|
|
|
|
|
dictRefCountMapper.delete(new LambdaQueryWrapper<DictRefCount>() |
|
|
|
|
|
.eq(DictRefCount::getGroupCode, group.getCode()) |
|
|
|
|
|
.eq(DictRefCount::getItemCode, item.getCode())); |
|
|
|
|
|
log.info("剪除旧内置字典项(已不在种子):{}/{}", group.getCode(), item.getCode()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 种子默认项:仅分组尚无默认且默认项自身启用时设置。 |
|
|
* 种子默认项:仅分组尚无默认且默认项自身启用时设置。 |
|
|
* <p>管理员已设默认(或停用默认项后自动取消)都不会被种子覆盖/复活。</p> |
|
|
* <p>管理员已设默认(或停用默认项后自动取消)都不会被种子覆盖/复活。</p> |
|
|
@ -430,7 +532,12 @@ public class DictDataInitializer implements CommandLineRunner { |
|
|
/*-------- 种子结构(Excel 替换口的数据契约,包私有供测试注入)--------*/ |
|
|
/*-------- 种子结构(Excel 替换口的数据契约,包私有供测试注入)--------*/ |
|
|
|
|
|
|
|
|
record ItemSeed(String code, String name, String value, |
|
|
record ItemSeed(String code, String name, String value, |
|
|
Integer sortNo, String description, boolean defaultItem) { |
|
|
Integer sortNo, String description, boolean defaultItem, String parentCode) { |
|
|
|
|
|
/** 便捷构造:无父项(顶层/扁平项),parentCode=null */ |
|
|
|
|
|
ItemSeed(String code, String name, String value, |
|
|
|
|
|
Integer sortNo, String description, boolean defaultItem) { |
|
|
|
|
|
this(code, name, value, sortNo, description, defaultItem, null); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
record GroupSeed(String code, String name, Integer sortNo, |
|
|
record GroupSeed(String code, String name, Integer sortNo, |
|
|
|