-- 排水基础数据(工程设施 / 易积水点):菜单、按钮、角色授权 -- -- 覆盖范围: -- 页面菜单(menu_type='C') -- · 工程设施基础数据管理 subSystem/drainage/jcsj/gcssgl -- · 易积水点管理 subSystem/drainage/jcsj/yjsdgl -- 按钮权限(menu_type='F') -- · drainage:facility:add / edit / remove -- · drainage:waterlogging:add / edit / remove -- 角色授权(sys_role_menu) -- · 新建页面菜单 → 授予「已经拥有其父级目录(基础数据)权限」的角色 -- · 新建按钮 → 授予「已经拥有该页面菜单权限」的角色 -- 这样只跟随既有授权扩散,不会把按钮放开给原本没权限的角色。 -- -- 父级定位(多路兜底): -- 1) 用兄弟页面 component='subSystem/drainage/jcsj/psfqgl' 反查 parent_id(最可靠) -- 2) 任意 drainage/jcsj 页面的 parent_id -- 3) menu_type='M' 且 menu_name='基础数据' -- -- 幂等:菜单按 component 判重,按钮按 parent_id + perms 判重,授权按 (role_id, menu_id) 判重, -- 可重复执行;已存在的菜单只更新名称/路径/组件/权限标识,不改排序与父级。 -- 主键:menu_id 显式取 max+1 —— 本库由 MySQL 迁移而来,自增计数器可能未推进。 -- -- 执行后建议重新登录一次,让前端重新拉取菜单与权限。 -- -- 前置:结束上一次失败执行遗留的 aborted 事务(事务外执行只会告警,不报错) ROLLBACK; BEGIN; SET search_path TO app_user, public; DO $$ DECLARE v_parent bigint; v_page bigint; v_next bigint; v_role record; r record; -- 【按需修改】需要直接授予这套菜单/按钮的角色 role_key。 -- 上面的步骤只会「跟随既有授权」扩散(谁原本能进基础数据,谁就拿到新页面; -- 谁原本能进该页面,谁就拿到新按钮)。如果目标角色原本连基础数据目录都没有, -- 就在这里显式列出它的 role_key,脚本会额外给它授权。 -- 先执行 `SELECT role_id, role_key, role_name FROM sys_role;` 查清 role_key 再填。 -- 留空数组表示不做额外授权。 v_extra_role_keys text[] := ARRAY[]::text[]; BEGIN -- ================================================================ -- 1. 定位「基础数据」目录 -- ================================================================ SELECT parent_id INTO v_parent FROM sys_menu WHERE component = 'subSystem/drainage/jcsj/psfqgl' LIMIT 1; IF v_parent IS NULL THEN SELECT parent_id INTO v_parent FROM sys_menu WHERE component LIKE '%drainage/jcsj/%' AND parent_id IS NOT NULL AND parent_id <> 0 LIMIT 1; END IF; IF v_parent IS NULL THEN SELECT menu_id INTO v_parent FROM sys_menu WHERE menu_type = 'M' AND menu_name = '基础数据' LIMIT 1; END IF; IF v_parent IS NULL THEN RAISE NOTICE '未找到「基础数据」目录菜单,请先确认排水子系统菜单结构后手工添加。'; RETURN; END IF; RAISE NOTICE '「基础数据」目录 menu_id = %', v_parent; -- ================================================================ -- 2. 页面菜单(menu_type = 'C') -- ================================================================ FOR r IN SELECT * FROM (VALUES ('工程设施基础数据管理', 'gcssgl', 'subSystem/drainage/jcsj/gcssgl', 'drainage:facility:list', 'guide', 3), ('易积水点管理', 'yjsdgl', 'subSystem/drainage/jcsj/yjsdgl', 'drainage:waterlogging:list', 'location', 4) ) AS x(menu_name, path, component, perms, icon, order_num) LOOP -- 先按「组件 + 基础数据目录」精确定位,避免多子系统复用同一组件时取错记录 SELECT menu_id INTO v_page FROM sys_menu WHERE component = r.component AND parent_id = v_parent LIMIT 1; IF v_page IS NULL THEN SELECT menu_id INTO v_page FROM sys_menu WHERE component = r.component LIMIT 1; END IF; IF v_page IS NULL THEN SELECT COALESCE(MAX(menu_id), 0) + 1 INTO v_next FROM sys_menu; INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES (v_next, r.menu_name, v_parent, r.order_num, r.path, r.component, 1, 0, 'C', '0', '0', r.perms, r.icon, 'admin', CURRENT_TIMESTAMP, r.menu_name); v_page := v_next; RAISE NOTICE '已新增页面菜单:% (menu_id=%)', r.menu_name, v_page; -- 跟随父级授权:拥有「基础数据」目录的角色,一并获得新页面 INSERT INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT rm.role_id, v_page FROM sys_role_menu rm WHERE rm.menu_id = v_parent AND NOT EXISTS ( SELECT 1 FROM sys_role_menu e WHERE e.role_id = rm.role_id AND e.menu_id = v_page ); RAISE NOTICE ' → 已按「基础数据」目录的授权同步给角色'; ELSE UPDATE sys_menu SET menu_name = r.menu_name, path = r.path, component = r.component, menu_type = 'C', visible = '0', status = '0', perms = r.perms, icon = r.icon, update_by = 'admin', update_time = CURRENT_TIMESTAMP WHERE menu_id = v_page; RAISE NOTICE '页面菜单已存在,已同步名称/路径/组件:% (menu_id=%)', r.menu_name, v_page; END IF; END LOOP; -- ================================================================ -- 3. 按钮权限(menu_type = 'F') -- ================================================================ FOR r IN SELECT * FROM (VALUES ('subSystem/drainage/jcsj/gcssgl', '新增工程设施', 'drainage:facility:add', 1), ('subSystem/drainage/jcsj/gcssgl', '修改工程设施', 'drainage:facility:edit', 2), ('subSystem/drainage/jcsj/gcssgl', '删除工程设施', 'drainage:facility:remove', 3), ('subSystem/drainage/jcsj/yjsdgl', '新增易积水点', 'drainage:waterlogging:add', 1), ('subSystem/drainage/jcsj/yjsdgl', '修改易积水点', 'drainage:waterlogging:edit', 2), ('subSystem/drainage/jcsj/yjsdgl', '删除易积水点', 'drainage:waterlogging:remove', 3) ) AS x(parent_component, menu_name, perms, order_num) LOOP SELECT menu_id INTO v_page FROM sys_menu WHERE component = r.parent_component ORDER BY menu_id LIMIT 1; IF v_page IS NULL THEN RAISE NOTICE '跳过按钮 %:未找到页面菜单 %', r.perms, r.parent_component; CONTINUE; END IF; IF EXISTS ( SELECT 1 FROM sys_menu WHERE perms = r.perms AND parent_id = v_page ) THEN RAISE NOTICE '按钮已存在,跳过:%', r.perms; CONTINUE; END IF; SELECT COALESCE(MAX(menu_id), 0) + 1 INTO v_next FROM sys_menu; INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES (v_next, r.menu_name, v_page, r.order_num, '', NULL, 1, 0, 'F', '0', '0', r.perms, '#', 'admin', CURRENT_TIMESTAMP, '页面按钮权限'); RAISE NOTICE '已新增按钮:% (%)', r.menu_name, r.perms; -- 跟随页面授权:拥有该页面菜单的角色,一并获得新按钮 INSERT INTO sys_role_menu (role_id, menu_id) SELECT DISTINCT rm.role_id, v_next FROM sys_role_menu rm WHERE rm.menu_id = v_page AND NOT EXISTS ( SELECT 1 FROM sys_role_menu e WHERE e.role_id = rm.role_id AND e.menu_id = v_next ); END LOOP; -- ================================================================ -- 4. 显式角色授权(按需启用) -- 给 v_extra_role_keys 里列出的角色,一次性授齐: -- 两个页面菜单 + 六个按钮。 -- ================================================================ IF v_extra_role_keys IS NOT NULL AND array_length(v_extra_role_keys, 1) > 0 THEN FOR v_role IN SELECT role_id, role_key, role_name FROM sys_role WHERE role_key = ANY(v_extra_role_keys) LOOP INSERT INTO sys_role_menu (role_id, menu_id) SELECT v_role.role_id, m.menu_id FROM sys_menu m WHERE ( m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl') OR m.perms IN ('drainage:facility:add', 'drainage:facility:edit', 'drainage:facility:remove', 'drainage:waterlogging:add', 'drainage:waterlogging:edit', 'drainage:waterlogging:remove') ) AND NOT EXISTS ( SELECT 1 FROM sys_role_menu e WHERE e.role_id = v_role.role_id AND e.menu_id = m.menu_id ); RAISE NOTICE '已显式授权角色:% (%)', v_role.role_name, v_role.role_key; END LOOP; IF NOT FOUND THEN RAISE NOTICE '警告:v_extra_role_keys 中的 role_key 在 sys_role 里一个都没匹配到,请核对。'; END IF; END IF; RAISE NOTICE '菜单与按钮处理完成。若某个角色仍看不到按钮,请在「角色管理」中手工勾选。'; END $$; -- ===================================================================== -- 结果核验(可选,取消注释执行) -- ===================================================================== -- 页面菜单与按钮(应返回 2 个 'C' + 6 个 'F') -- SELECT m.menu_id, m.menu_name, m.parent_id, m.menu_type, m.perms, m.order_num -- FROM sys_menu m -- WHERE m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl') -- OR m.perms IN ('drainage:facility:add','drainage:facility:edit','drainage:facility:remove', -- 'drainage:waterlogging:add','drainage:waterlogging:edit','drainage:waterlogging:remove') -- ORDER BY m.menu_type DESC, m.order_num; -- 角色授权情况 -- SELECT rm.role_id, r.role_name, m.menu_name, m.menu_type, m.perms -- FROM sys_role_menu rm -- JOIN sys_role r ON r.role_id = rm.role_id -- JOIN sys_menu m ON m.menu_id = rm.menu_id -- WHERE m.perms LIKE 'drainage:facility:%' -- OR m.perms LIKE 'drainage:waterlogging:%' -- OR m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl') -- ORDER BY rm.role_id, m.menu_type DESC, m.order_num; COMMIT;