|
@@ -3434,6 +3434,15 @@ insertSysConfigSeed("gift_membership_pay_price", "198000", "送会员商品达
|
|
|
|
|
|
|
|
// 迁移444: T38 团队邀请功能 —— supply_system_member 增加个人专属邀请码(幂等,永久有效+唯一)
|
|
// 迁移444: T38 团队邀请功能 —— supply_system_member 增加个人专属邀请码(幂等,永久有效+唯一)
|
|
|
migrateSupplyMemberInviteCode();
|
|
migrateSupplyMemberInviteCode();
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移445: 统一维度体系(P0-T1)—— product_dimension_config 升级为唯一维度注册中心
|
|
|
|
|
+ // 新增 legacy_alias/source_system/wuxing_rule_ref/node_kind 4 列(设计文档 §3.1)
|
|
|
|
|
+ migrateUnifiedDimensionRegistryColumns();
|
|
|
|
|
+ // 迁移446: 统一维度体系(P0-T1)—— indicator_definitions 指标并入维度树混排
|
|
|
|
|
+ // 新增 parent_id/legacy_alias 2 列(设计文档 §3.2,红线 1:id 主键与外键目标不变)
|
|
|
|
|
+ migrateUnifiedIndicatorTreeColumns();
|
|
|
|
|
+ // 迁移447: 统一维度体系(P0-T3)—— 固化 5 根 + 7 body 子维度节点(幂等 seed)
|
|
|
|
|
+ seedUnifiedDimensionRegistry();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -15088,6 +15097,115 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ==================== 迁移445-447:统一维度体系(P0) ====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 迁移445: product_dimension_config 升级为唯一维度注册中心(设计文档 §3.1)。
|
|
|
|
|
+ * 新增 legacy_alias / source_system / wuxing_rule_ref / node_kind 4 列,均幂等。
|
|
|
|
|
+ * 现有 dimension_code VARCHAR(50) NOT NULL UNIQUE 复用为统一 code(body / body.growth 等)。
|
|
|
|
|
+ */
|
|
|
|
|
+ void migrateUnifiedDimensionRegistryColumns() {
|
|
|
|
|
+ ensureColumn("product_dimension_config", "legacy_alias",
|
|
|
|
|
+ "VARCHAR(512) DEFAULT NULL COMMENT '历史别名(JSON数组): 承载现存4套编码, 如 [\"growth\"]'");
|
|
|
|
|
+ ensureColumn("product_dimension_config", "source_system",
|
|
|
|
|
+ "VARCHAR(32) DEFAULT NULL COMMENT '归属子系统: health/energy/indicator/knowledge'");
|
|
|
|
|
+ ensureColumn("product_dimension_config", "wuxing_rule_ref",
|
|
|
|
|
+ "VARCHAR(30) DEFAULT NULL COMMENT '五行规则引用(木/火/金/水/土), 关联EnergyDimension.element'");
|
|
|
|
|
+ ensureColumn("product_dimension_config", "node_kind",
|
|
|
|
|
+ "VARCHAR(16) DEFAULT 'root' COMMENT '节点种类: root(五维根)/sub(子维度)'");
|
|
|
|
|
+ log.info("迁移445: product_dimension_config 注册中心 4 列就绪");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 迁移446: indicator_definitions 指标并入维度树混排(设计文档 §3.2,红线 1)。
|
|
|
|
|
+ * 新增 parent_id / legacy_alias 2 列;不改 id 主键、不改任何外键目标。
|
|
|
|
|
+ */
|
|
|
|
|
+ void migrateUnifiedIndicatorTreeColumns() {
|
|
|
|
|
+ ensureColumn("indicator_definitions", "parent_id",
|
|
|
|
|
+ "BIGINT DEFAULT NULL COMMENT '父节点ID(可指向product_dimension_config.id或本表id, 混排进维度树)'");
|
|
|
|
|
+ ensureColumn("indicator_definitions", "legacy_alias",
|
|
|
|
|
+ "VARCHAR(512) DEFAULT NULL COMMENT '历史别名(JSON数组)'");
|
|
|
|
|
+ log.info("迁移446: indicator_definitions 混排 2 列就绪");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 迁移447: 固化 5 根 + 7 body 子维度节点(设计文档 §2.3 / P0-T3,幂等 seed)。
|
|
|
|
|
+ * 5 根补 source_system='energy';7 维(body.growth..body.exercise)作为维度节点挂 body 下,
|
|
|
|
|
+ * legacy_alias 绑定旧名 growth/sleep/...,source_system='health'。
|
|
|
|
|
+ */
|
|
|
|
|
+ void seedUnifiedDimensionRegistry() {
|
|
|
|
|
+ // 5 根:dimension_type='five',node_kind='root'
|
|
|
|
|
+ upsertDimensionSeed("body", "身体", "five", null, 1, "energy", "root",
|
|
|
|
|
+ "[\"body\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("mind", "心理", "five", null, 2, "energy", "root",
|
|
|
|
|
+ "[\"mind\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("wisdom", "智能", "five", null, 3, "energy", "root",
|
|
|
|
|
+ "[\"wisdom\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("action", "行动", "five", null, 4, "energy", "root",
|
|
|
|
|
+ "[\"action\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("wealth", "财富", "five", null, 5, "energy", "root",
|
|
|
|
|
+ "[\"wealth\"]", null);
|
|
|
|
|
+
|
|
|
|
|
+ Long bodyId = queryDimensionIdByCode("body");
|
|
|
|
|
+ if (bodyId == null) {
|
|
|
|
|
+ log.warn("迁移447: 未找到 body 根节点 id,跳过 7 维子节点 seed");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 7 body 子维度:code=body.{sub},parent=body.id,legacy_alias=旧名
|
|
|
|
|
+ upsertDimensionSeed("body.growth", "生长发育", "health", bodyId, 1, "health", "sub",
|
|
|
|
|
+ "[\"growth\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.sleep", "睡眠质量", "health", bodyId, 2, "health", "sub",
|
|
|
|
|
+ "[\"sleep\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.vision", "视力健康", "health", bodyId, 3, "health", "sub",
|
|
|
|
|
+ "[\"vision\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.immunity", "免疫力", "health", bodyId, 4, "health", "sub",
|
|
|
|
|
+ "[\"immunity\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.nutrition", "营养均衡", "health", bodyId, 5, "health", "sub",
|
|
|
|
|
+ "[\"nutrition\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.gut", "肠胃健康", "health", bodyId, 6, "health", "sub",
|
|
|
|
|
+ "[\"gut\"]", null);
|
|
|
|
|
+ upsertDimensionSeed("body.exercise", "运动活力", "health", bodyId, 7, "health", "sub",
|
|
|
|
|
+ "[\"exercise\"]", null);
|
|
|
|
|
+ log.info("迁移447: 统一维度注册中心 5 根 + 7 body 子维度 seed 完成");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 幂等 upsert 维度种子:按 dimension_code 存在则补 source_system/legacy_alias,不存在则插入。 */
|
|
|
|
|
+ private void upsertDimensionSeed(String code, String name, String dimensionType, Long parentId,
|
|
|
|
|
+ int sort, String sourceSystem, String nodeKind,
|
|
|
|
|
+ String legacyAlias, String wuxingRuleRef) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Long existingId = queryDimensionIdByCode(code);
|
|
|
|
|
+ if (existingId != null) {
|
|
|
|
|
+ jdbcTemplate.update(
|
|
|
|
|
+ "UPDATE product_dimension_config SET source_system=?, node_kind=?, "
|
|
|
|
|
+ + "legacy_alias=COALESCE(legacy_alias, ?), wuxing_rule_ref=COALESCE(wuxing_rule_ref, ?), "
|
|
|
|
|
+ + "updated_at=NOW() WHERE id=?",
|
|
|
|
|
+ sourceSystem, nodeKind, legacyAlias, wuxingRuleRef, existingId);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ jdbcTemplate.update(
|
|
|
|
|
+ "INSERT INTO product_dimension_config "
|
|
|
|
|
+ + "(dimension_code, dimension_name, dimension_type, parent_id, sort, enabled, "
|
|
|
|
|
+ + "source_system, node_kind, legacy_alias, wuxing_rule_ref, created_at, updated_at) "
|
|
|
|
|
+ + "VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?, ?, NOW(), NOW())",
|
|
|
|
|
+ code, name, dimensionType, parentId, sort, sourceSystem, nodeKind, legacyAlias, wuxingRuleRef);
|
|
|
|
|
+ log.info("迁移447: 插入维度种子 {} ({})", code, name);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("迁移447: 维度种子 {} upsert 失败(忽略): {}", code, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Long queryDimensionIdByCode(String code) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<Long> ids = jdbcTemplate.queryForList(
|
|
|
|
|
+ "SELECT id FROM product_dimension_config WHERE dimension_code = ? LIMIT 1",
|
|
|
|
|
+ Long.class, code);
|
|
|
|
|
+ return ids.isEmpty() ? null : ids.get(0);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private static String text(JsonNode row, String field) {
|
|
private static String text(JsonNode row, String field) {
|
|
|
if (row == null) return null;
|
|
if (row == null) return null;
|
|
|
JsonNode n = row.get(field);
|
|
JsonNode n = row.get(field);
|