|
@@ -12,7 +12,9 @@ import org.springframework.util.StreamUtils;
|
|
|
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
|
@@ -8737,5 +8739,201 @@ private void runMigration100() {
|
|
|
// 修改失败,忽略错误(幂等)
|
|
// 修改失败,忽略错误(幂等)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 迁移229: 创建 sys_menu 表(管理后台侧边栏菜单,数据库驱动 + 角色授权)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute(
|
|
|
|
|
+ "CREATE TABLE IF NOT EXISTS sys_menu (" +
|
|
|
|
|
+ " id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ " parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID,0=顶级', " +
|
|
|
|
|
+ " title VARCHAR(50) COMMENT '目录标题(有子菜单时用,对应 el-submenu)', " +
|
|
|
|
|
+ " label VARCHAR(50) COMMENT '叶子菜单显示名(对应 el-menu-item)', " +
|
|
|
|
|
+ " path VARCHAR(200) COMMENT '路由路径(叶子菜单必填,如 /families)', " +
|
|
|
|
|
+ " icon VARCHAR(100) COMMENT 'Element UI 图标类名,如 el-icon-s-custom', " +
|
|
|
|
|
+ " perm VARCHAR(100) COMMENT '权限标识,如 family:list / task:* / system:config', " +
|
|
|
|
|
+ " sort INT DEFAULT 0 COMMENT '排序号,小的在前', " +
|
|
|
|
|
+ " visible TINYINT DEFAULT 1 COMMENT '是否显示 1=显示 0=隐藏', " +
|
|
|
|
|
+ " created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ " updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ " INDEX idx_parent (parent_id)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台侧边栏菜单表'"
|
|
|
|
|
+ );
|
|
|
|
|
+ log.info("已创建sys_menu表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建sys_menu表失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移230: 创建 sys_role_menu 表(角色-菜单授权)
|
|
|
|
|
+ try {
|
|
|
|
|
+ jdbcTemplate.execute(
|
|
|
|
|
+ "CREATE TABLE IF NOT EXISTS sys_role_menu (" +
|
|
|
|
|
+ " id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
|
|
|
|
|
+ " role VARCHAR(50) NOT NULL COMMENT '角色标识: admin/teacher/nutritionist/article_manager/activity_manager/supplier_admin', " +
|
|
|
|
|
+ " menu_id BIGINT NOT NULL COMMENT 'sys_menu.id', " +
|
|
|
|
|
+ " created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
|
|
|
|
+ " UNIQUE KEY uk_role_menu (role, menu_id)" +
|
|
|
|
|
+ ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色-菜单授权表'"
|
|
|
|
|
+ );
|
|
|
|
|
+ log.info("已创建sys_role_menu表");
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("创建sys_role_menu表失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 迁移231: sys_menu 菜单种子数据(对应 Layout.vue 硬编码 menuItems,表为空才插入,幂等)
|
|
|
|
|
+ try {
|
|
|
|
|
+ Integer menuCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM sys_menu", Integer.class);
|
|
|
|
|
+ if (menuCount == null || menuCount == 0) {
|
|
|
|
|
+ seedSysMenus();
|
|
|
|
|
+ log.info("sys_menu 种子数据已插入");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("sys_menu 已有 {} 条数据,跳过种子插入", menuCount);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("初始化sys_menu种子数据失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 迁移231辅助方法: 插入 sys_menu 种子数据
|
|
|
|
|
+ * 结构与 cfc-web/src/views/Layout.vue 的 menuItems 硬编码一致
|
|
|
|
|
+ * 数组格式: {parentKey(空=顶级), key, title(目录), label(叶子), path, icon, perm, sort}
|
|
|
|
|
+ */
|
|
|
|
|
+ private void seedSysMenus() {
|
|
|
|
|
+ Map<String, Long> keyToId = new HashMap<>();
|
|
|
|
|
+ String[][] menus = {
|
|
|
|
|
+ // 顶级叶子
|
|
|
|
|
+ {"", "home", "", "首页", "/dashboard", "el-icon-s-home", "dashboard", "0"},
|
|
|
|
|
+ // 家庭运营
|
|
|
|
|
+ {"", "operation", "家庭运营", "", "", "el-icon-s-custom", "operation", "1"},
|
|
|
|
|
+ {"operation", "families", "", "家庭列表", "/families", "el-icon-s-custom", "family:list", "0"},
|
|
|
|
|
+ {"operation", "children", "", "孩子管理", "/children", "el-icon-user-solid", "family:children", "1"},
|
|
|
|
|
+ {"operation", "points", "", "积分管理", "/points", "el-icon-s-finance", "family:points", "2"},
|
|
|
|
|
+ {"operation", "pointsLog", "", "积分记录", "/points-log", "el-icon-document", "family:points", "3"},
|
|
|
|
|
+ {"operation", "wishes", "", "心愿管理", "/wishes", "el-icon-star-off", "family:wishes", "4"},
|
|
|
|
|
+ {"operation", "rewards", "", "奖励管理", "/rewards", "el-icon-s-goods", "reward:list", "5"},
|
|
|
|
|
+ // 任务中心
|
|
|
|
|
+ {"", "taskCenter", "任务中心", "", "", "el-icon-s-order", "task:*", "2"},
|
|
|
|
|
+ {"taskCenter", "tasks", "", "任务列表", "/tasks", "el-icon-s-order", "task:list", "0"},
|
|
|
|
|
+ {"taskCenter", "taskTemplates", "", "任务模板", "/task-templates", "el-icon-document", "task:templates", "1"},
|
|
|
|
|
+ {"taskCenter", "growthTask", "", "成长任务管理", "/growth-task", "el-icon-s-management", "task:list", "2"},
|
|
|
|
|
+ // 审核中心
|
|
|
|
|
+ {"", "reviewCenter", "", "审核中心", "/review-center", "el-icon-s-check", "audit", "3"},
|
|
|
|
|
+ {"", "serviceRoleApp", "", "服务角色申请审核", "/service-role-applications", "el-icon-s-check", "audit", "4"},
|
|
|
|
|
+ // 商城营销
|
|
|
|
|
+ {"", "commerce", "商城营销", "", "", "el-icon-s-goods", "commerce", "5"},
|
|
|
|
|
+ {"commerce", "productManage", "", "商品管理", "/product-manage", "el-icon-s-goods", "commerce:products", "0"},
|
|
|
|
|
+ {"commerce", "inventory", "", "库存管理", "/inventory", "el-icon-document", "commerce:products", "1"},
|
|
|
|
|
+ {"commerce", "ecomSupplier", "", "供应商管理", "/ecom-supplier", "el-icon-s-shop", "commerce:products", "2"},
|
|
|
|
|
+ {"commerce", "orderManage", "", "订单管理", "/order-manage", "el-icon-s-order", "commerce:orders", "3"},
|
|
|
|
|
+ {"commerce", "pendingRefund", "", "待退款管理", "/pending-refund", "el-icon-warning", "commerce:orders", "4"},
|
|
|
|
|
+ {"commerce", "productProfitRate", "", "产品利润率", "/product-profit-rate", "el-icon-data-line", "commerce:profit", "5"},
|
|
|
|
|
+ {"commerce", "coupon", "", "优惠券管理", "/coupon", "el-icon-ticket", "marketing:coupon", "6"},
|
|
|
|
|
+ {"commerce", "couponGrantLog", "", "发券记录", "/coupon-grant-log", "el-icon-document", "marketing:coupon", "7"},
|
|
|
|
|
+ {"commerce", "promotion", "", "推广管理", "/promotion", "el-icon-s-marketing", "marketing:promotion", "8"},
|
|
|
|
|
+ {"commerce", "familyEarnings", "", "家庭收益", "/family-earnings", "el-icon-s-money", "marketing:promotion", "9"},
|
|
|
|
|
+ {"commerce", "earningWithdraw", "", "收益提现审核", "/family-earnings-withdraw", "el-icon-document-checked", "audit:withdraw", "10"},
|
|
|
|
|
+ // 知识中心
|
|
|
|
|
+ {"", "knowledge", "知识中心", "", "", "el-icon-document", "content", "6"},
|
|
|
|
|
+ {"knowledge", "articleCategories", "", "知识分类", "/article-categories", "el-icon-folder", "articles:categories", "0"},
|
|
|
|
|
+ {"knowledge", "articleManage", "", "知识管理", "/article-manage", "el-icon-document", "articles:manage", "1"},
|
|
|
|
|
+ {"knowledge", "commentReview", "", "评论审核", "/comment-review", "el-icon-chat-dot-round", "articles:manage", "2"},
|
|
|
|
|
+ {"knowledge", "knowledgeTags", "", "知识标签", "/knowledge-tags", "el-icon-price-tag", "articles:categories", "3"},
|
|
|
|
|
+ {"knowledge", "knowledgeBase", "", "知识库", "/knowledge-base", "el-icon-reading", "system:config", "4"},
|
|
|
|
|
+ {"knowledge", "healthKnowledge", "", "健康知识库", "/health-knowledge", "el-icon-first-aid-kit", "system:config", "5"},
|
|
|
|
|
+ // 活动管理
|
|
|
|
|
+ {"", "activity", "活动管理", "", "", "el-icon-date", "activity:*", "7"},
|
|
|
|
|
+ {"activity", "activities", "", "活动列表", "/activities", "el-icon-date", "activity:list", "0"},
|
|
|
|
|
+ {"activity", "activityReview", "", "活动审核", "/activity-review", "el-icon-document-checked", "activity:review", "1"},
|
|
|
|
|
+ {"activity", "activityRegReview", "", "活动报名审核", "/activity-registration-review", "el-icon-document-checked", "activity:review", "2"},
|
|
|
|
|
+ // 健康饮食
|
|
|
|
|
+ {"", "health", "健康饮食", "", "", "el-icon-first-aid-kit", "health", "8"},
|
|
|
|
|
+ {"health", "healthReports", "", "健康报告", "/health-reports", "el-icon-document", "health:reports", "0"},
|
|
|
|
|
+ {"health", "healthIndicators", "", "健康指标", "/health-indicators", "el-icon-data-line", "health:indicators", "1"},
|
|
|
|
|
+ {"health", "healthCheckins", "", "健康打卡", "/health-checkins", "el-icon-s-order", "health:checkins", "2"},
|
|
|
|
|
+ {"health", "emotionAlert", "", "情绪告警", "/emotion-alert", "el-icon-warning", "health:checkins", "3"},
|
|
|
|
|
+ {"health", "nutritionMappings", "", "营养素映射", "/nutrition-mappings", "el-icon-connection", "health:mappings", "4"},
|
|
|
|
|
+ {"health", "energySandbox", "", "五维能量", "/energy-sandbox", "el-icon-data-line", "energy", "5"},
|
|
|
|
|
+ {"health", "energyRule", "", "能量规则管理", "/energy-rule", "el-icon-setting", "energy", "6"},
|
|
|
|
|
+ {"health", "energyBehaviorConfig", "", "能量行为配置", "/energy-behavior-config", "el-icon-edit-outline", "energy", "7"},
|
|
|
|
|
+ {"health", "periodicServiceConfig", "", "周期性服务配置", "/periodic-service-config", "el-icon-refresh", "energy", "8"},
|
|
|
|
|
+ {"health", "foods", "", "食材管理", "/foods", "el-icon-apple", "diet:foods", "9"},
|
|
|
|
|
+ {"health", "recipes", "", "食谱管理", "/recipes", "el-icon-dish", "diet:recipes", "10"},
|
|
|
|
|
+ {"health", "langgraphAdmin", "", "LangGraph 管理", "/langgraph-admin", "el-icon-cpu", "system:config", "11"},
|
|
|
|
|
+ {"health", "nutritionProducts", "", "营养产品", "/nutrition-products", "el-icon-first-aid-kit", "health:*", "12"},
|
|
|
|
|
+ // 报告解析系统
|
|
|
|
|
+ {"", "reportParser", "报告解析系统", "", "", "el-icon-cpu", "system:config", "9"},
|
|
|
|
|
+ {"reportParser", "reportTypes", "", "报告类型管理", "/report-types", "el-icon-collection", "system:config", "0"},
|
|
|
|
|
+ {"reportParser", "reportParserImport", "", "解析器导入", "/report-parser-import", "el-icon-upload2", "system:config", "1"},
|
|
|
|
|
+ {"reportParser", "reportUnknownClusters", "", "未知报告审核", "/report-unknown-clusters", "el-icon-question", "system:config", "2"},
|
|
|
|
|
+ {"reportParser", "reportAutoLearn", "", "报告自学习", "/report-auto-learn", "el-icon-magic-stick", "system:config", "3"},
|
|
|
|
|
+ // 家庭服务(规划师)
|
|
|
|
|
+ {"", "familyService", "家庭服务", "", "", "el-icon-s-custom", "service:*", "10"},
|
|
|
|
|
+ {"familyService", "myFamilies", "", "我的家庭", "/my-families", "el-icon-s-custom", "service:family", "0"},
|
|
|
|
|
+ {"familyService", "teacherTeam", "", "我的团队", "/teacher-team", "el-icon-s-custom", "service:team", "1"},
|
|
|
|
|
+ // 业务管理(规划师)
|
|
|
|
|
+ {"", "biz", "业务管理", "", "", "el-icon-s-marketing", "biz:*", "11"},
|
|
|
|
|
+ {"biz", "teacherPackages", "", "任务模板管理", "/teacher-packages", "el-icon-s-goods", "biz:packages", "0"},
|
|
|
|
|
+ {"biz", "teacherOrders", "", "订单佣金", "/teacher-orders", "el-icon-s-order", "biz:orders", "1"},
|
|
|
|
|
+ // 测评咨询(规划师)
|
|
|
|
|
+ {"", "assessment", "测评咨询", "", "", "el-icon-edit", "assessment:*", "12"},
|
|
|
|
|
+ {"assessment", "teacherAssessment", "", "DAN测评", "/teacher-assessment", "el-icon-edit", "assessment:dan", "0"},
|
|
|
|
|
+ {"assessment", "teacherConsult", "", "家长咨询", "/teacher-consult", "el-icon-chat-dot-round", "assessment:consult", "1"},
|
|
|
|
|
+ {"assessment", "growthRecords", "", "成长记录", "/growth-records", "el-icon-document", "growth:records", "2"},
|
|
|
|
|
+ {"assessment", "growthPlans", "", "成长计划", "/growth-plans", "el-icon-document", "growth:plans", "3"},
|
|
|
|
|
+ // 系统配置(三级)
|
|
|
|
|
+ {"", "system", "系统配置", "", "", "el-icon-s-tools", "system:*", "13"},
|
|
|
|
|
+ {"system", "baseManage", "基础管理", "", "", "el-icon-s-tools", "system:config", "0"},
|
|
|
|
|
+ {"baseManage", "sysConfig", "", "系统配置", "/sys-config", "el-icon-s-tools", "system:config", "0"},
|
|
|
|
|
+ {"baseManage", "users", "", "用户管理", "/users", "el-icon-user", "system:users", "1"},
|
|
|
|
|
+ {"baseManage", "operationLogs", "", "操作日志", "/operation-logs", "el-icon-s-order", "system:logs", "2"},
|
|
|
|
|
+ {"baseManage", "membershipCenter", "", "会员中心", "/membership-center", "el-icon-s-custom", "system:config", "3"},
|
|
|
|
|
+ {"baseManage", "badgeManage", "", "勋章管理", "/badge-manage", "el-icon-medal", "system:config", "4"},
|
|
|
|
|
+ {"baseManage", "virtualGoodsConfig", "", "虚拟支付道具", "/virtual-goods-config", "el-icon-goods", "system:config", "5"},
|
|
|
|
|
+ {"baseManage", "gates", "", "关卡配置", "/gates", "el-icon-key", "system:config", "6"},
|
|
|
|
|
+ {"baseManage", "menuManage", "", "菜单管理", "/menu-manage", "el-icon-menu", "system:menu", "7"},
|
|
|
|
|
+ {"system", "configCenter", "配置中心", "", "", "el-icon-setting", "system:config", "1"},
|
|
|
|
|
+ {"configCenter", "dimensionConfig", "", "维度配置", "/dimension-config", "el-icon-data-line", "system:config", "0"},
|
|
|
|
|
+ {"system", "supplyHierarchy", "供应商体系", "", "", "el-icon-s-management", "system:supply", "2"},
|
|
|
|
|
+ {"supplyHierarchy", "supplySystem", "", "供应商体系", "/supply-system", "el-icon-s-management", "system:supply", "0"},
|
|
|
|
|
+ {"system", "supplierManage", "供应商管理", "", "", "el-icon-s-shop", "supply:manage", "3"},
|
|
|
|
|
+ {"supplierManage", "supplyManage", "", "供应商管理", "/supply-manage", "el-icon-s-shop", "supply:manage", "0"},
|
|
|
|
|
+ {"supplierManage", "supplierProducts", "", "商品管理", "/supplier-products", "el-icon-s-goods", "commerce:product", "1"},
|
|
|
|
|
+ {"system", "healthConfig", "健康配置", "", "", "el-icon-first-aid-kit", "system:config", "4"},
|
|
|
|
|
+ {"healthConfig", "healthNormConfig", "", "健康常模", "/health-norm-config", "el-icon-data-line", "system:config", "0"},
|
|
|
|
|
+ {"healthConfig", "healthDataSource", "", "健康数据源", "/health-data-source", "el-icon-data-line", "system:config", "1"},
|
|
|
|
|
+ {"healthConfig", "healthEnergyConfig", "", "七维能量配置", "/health-energy-config", "el-icon-data-line", "system:config", "2"},
|
|
|
|
|
+ {"system", "lifeDimension", "人生维度", "", "", "el-icon-s-custom", "system:config", "5"},
|
|
|
|
|
+ {"lifeDimension", "zodiacConfigs", "", "星座配置", "/zodiac-configs", "el-icon-s-management", "system:config", "0"},
|
|
|
|
|
+ {"lifeDimension", "baziConfigs", "", "八字配置", "/bazi-configs", "el-icon-s-management", "system:config", "1"},
|
|
|
|
|
+ {"lifeDimension", "bloodTypeConfigs", "", "血型配置", "/blood-type-configs", "el-icon-s-management", "system:config", "2"},
|
|
|
|
|
+ {"system", "assessmentManage", "测评管理", "", "", "el-icon-edit", "assessment:dan", "6"},
|
|
|
|
|
+ {"assessmentManage", "assessmentAdmin", "", "测评管理", "/assessment-admin", "el-icon-edit", "assessment:dan", "0"},
|
|
|
|
|
+ {"assessmentManage", "assessmentOrders", "", "测评订单", "/assessment-orders", "el-icon-s-order", "assessment:dan", "1"},
|
|
|
|
|
+ {"assessmentManage", "assessmentAssign", "", "待分配规划师", "/assessment-assign", "el-icon-user", "assessment:dan", "2"},
|
|
|
|
|
+ {"system", "virtualTeam", "虚拟团队", "", "", "el-icon-s-custom", "system:config", "7"},
|
|
|
|
|
+ {"virtualTeam", "virtualTeams", "", "虚拟团队", "/virtual-teams", "el-icon-s-custom", "system:config", "0"},
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ for (String[] m : menus) {
|
|
|
|
|
+ Long parentId = 0L;
|
|
|
|
|
+ if (m[0] != null && !m[0].isEmpty()) {
|
|
|
|
|
+ parentId = keyToId.get(m[0]);
|
|
|
|
|
+ if (parentId == null) {
|
|
|
|
|
+ parentId = 0L;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ String title = m[2] != null && !m[2].isEmpty() ? m[2] : null;
|
|
|
|
|
+ String label = m[3] != null && !m[3].isEmpty() ? m[3] : null;
|
|
|
|
|
+ String path = m[4] != null && !m[4].isEmpty() ? m[4] : null;
|
|
|
|
|
+ String icon = m[5] != null && !m[5].isEmpty() ? m[5] : null;
|
|
|
|
|
+ String perm = m[6] != null && !m[6].isEmpty() ? m[6] : null;
|
|
|
|
|
+ int sort = Integer.parseInt(m[7]);
|
|
|
|
|
+ jdbcTemplate.update(
|
|
|
|
|
+ "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, ?, ?, ?, ?, ?, ?, 1)",
|
|
|
|
|
+ parentId, title, label, path, icon, perm, sort
|
|
|
|
|
+ );
|
|
|
|
|
+ Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
|
|
|
|
|
+ keyToId.put(m[1], id);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|