-- Migration: expand sys_menus and sys_role_menu_permissions for menu-tree governance -- Created at: 2026-03-03 BEGIN; -- 1) Extend sys_menus table ALTER TABLE `sys_menus` ADD COLUMN `menu_level` tinyint(3) NOT NULL DEFAULT 1 COMMENT '菜单层级(根节点为1)' AFTER `parent_id`, ADD COLUMN `tree_path` varchar(255) DEFAULT NULL COMMENT '树路径(如 /3/6)' AFTER `menu_level`, ADD COLUMN `is_visible` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否在侧边菜单显示' AFTER `is_active`; ALTER TABLE `sys_menus` ADD KEY `idx_menu_level` (`menu_level`), ADD KEY `idx_tree_path` (`tree_path`), ADD KEY `idx_is_visible` (`is_visible`); -- 2) Extend sys_role_menu_permissions table ALTER TABLE `sys_role_menu_permissions` ADD COLUMN `granted_by` int(11) DEFAULT NULL COMMENT '授权操作人ID' AFTER `menu_id`, ADD COLUMN `granted_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '授权时间' AFTER `granted_by`; ALTER TABLE `sys_role_menu_permissions` ADD KEY `idx_granted_by` (`granted_by`), ADD KEY `idx_granted_at` (`granted_at`); -- 3) Backfill tree metadata (supports current 1~2 level menus) UPDATE `sys_menus` SET `menu_level` = 1, `tree_path` = CONCAT('/', `menu_id`) WHERE `parent_id` IS NULL; UPDATE `sys_menus` c JOIN `sys_menus` p ON c.`parent_id` = p.`menu_id` SET c.`menu_level` = p.`menu_level` + 1, c.`tree_path` = CONCAT(p.`tree_path`, '/', c.`menu_id`); -- 4) Add sample child menus under existing modules INSERT INTO `sys_menus` (`menu_code`, `menu_name`, `menu_icon`, `menu_url`, `menu_type`, `parent_id`, `menu_level`, `tree_path`, `sort_order`, `is_active`, `is_visible`, `description`) SELECT 'permission_menu_tree', '菜单树维护', 'AppstoreAdd', '/admin/management/permission-management', 'link', m.`menu_id`, 3, NULL, 20, 1, 0, '权限管理中的菜单树维护入口(隐藏于侧栏)' FROM `sys_menus` m WHERE m.`menu_code` = 'permission_management' AND NOT EXISTS (SELECT 1 FROM `sys_menus` WHERE `menu_code` = 'permission_menu_tree'); -- backfill tree_path for newly inserted rows UPDATE `sys_menus` c JOIN `sys_menus` p ON c.`parent_id` = p.`menu_id` SET c.`menu_level` = p.`menu_level` + 1, c.`tree_path` = CONCAT(p.`tree_path`, '/', c.`menu_id`) WHERE c.`tree_path` IS NULL; -- 5) Align permissions: role 1 owns all active menus INSERT IGNORE INTO `sys_role_menu_permissions` (`role_id`, `menu_id`, `granted_by`) SELECT 1, m.`menu_id`, 1 FROM `sys_menus` m WHERE m.`is_active` = 1; -- role 2 excludes platform admin tree DELETE rmp FROM `sys_role_menu_permissions` rmp JOIN `sys_menus` m ON m.`menu_id` = rmp.`menu_id` WHERE rmp.`role_id` = 2 AND m.`menu_code` IN ( 'platform_admin', 'user_management', 'permission_management', 'dict_management', 'hot_word_management', 'client_management', 'external_app_management', 'terminal_management', 'permission_menu_tree' ); COMMIT;