migration_drainage_jcsj_menu_perms.sql 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. -- 排水基础数据(工程设施 / 易积水点):菜单、按钮、角色授权
  2. --
  3. -- 覆盖范围:
  4. -- 页面菜单(menu_type='C')
  5. -- · 工程设施基础数据管理 subSystem/drainage/jcsj/gcssgl
  6. -- · 易积水点管理 subSystem/drainage/jcsj/yjsdgl
  7. -- 按钮权限(menu_type='F')
  8. -- · drainage:facility:add / edit / remove
  9. -- · drainage:waterlogging:add / edit / remove
  10. -- 角色授权(sys_role_menu)
  11. -- · 新建页面菜单 → 授予「已经拥有其父级目录(基础数据)权限」的角色
  12. -- · 新建按钮 → 授予「已经拥有该页面菜单权限」的角色
  13. -- 这样只跟随既有授权扩散,不会把按钮放开给原本没权限的角色。
  14. --
  15. -- 父级定位(多路兜底):
  16. -- 1) 用兄弟页面 component='subSystem/drainage/jcsj/psfqgl' 反查 parent_id(最可靠)
  17. -- 2) 任意 drainage/jcsj 页面的 parent_id
  18. -- 3) menu_type='M' 且 menu_name='基础数据'
  19. --
  20. -- 幂等:菜单按 component 判重,按钮按 parent_id + perms 判重,授权按 (role_id, menu_id) 判重,
  21. -- 可重复执行;已存在的菜单只更新名称/路径/组件/权限标识,不改排序与父级。
  22. -- 主键:menu_id 显式取 max+1 —— 本库由 MySQL 迁移而来,自增计数器可能未推进。
  23. --
  24. -- 执行后建议重新登录一次,让前端重新拉取菜单与权限。
  25. --
  26. -- 前置:结束上一次失败执行遗留的 aborted 事务(事务外执行只会告警,不报错)
  27. ROLLBACK;
  28. BEGIN;
  29. SET search_path TO app_user, public;
  30. DO $$
  31. DECLARE
  32. v_parent bigint;
  33. v_page bigint;
  34. v_next bigint;
  35. v_role record;
  36. r record;
  37. -- 【按需修改】需要直接授予这套菜单/按钮的角色 role_key。
  38. -- 上面的步骤只会「跟随既有授权」扩散(谁原本能进基础数据,谁就拿到新页面;
  39. -- 谁原本能进该页面,谁就拿到新按钮)。如果目标角色原本连基础数据目录都没有,
  40. -- 就在这里显式列出它的 role_key,脚本会额外给它授权。
  41. -- 先执行 `SELECT role_id, role_key, role_name FROM sys_role;` 查清 role_key 再填。
  42. -- 留空数组表示不做额外授权。
  43. v_extra_role_keys text[] := ARRAY[]::text[];
  44. BEGIN
  45. -- ================================================================
  46. -- 1. 定位「基础数据」目录
  47. -- ================================================================
  48. SELECT parent_id INTO v_parent
  49. FROM sys_menu
  50. WHERE component = 'subSystem/drainage/jcsj/psfqgl'
  51. LIMIT 1;
  52. IF v_parent IS NULL THEN
  53. SELECT parent_id INTO v_parent
  54. FROM sys_menu
  55. WHERE component LIKE '%drainage/jcsj/%'
  56. AND parent_id IS NOT NULL
  57. AND parent_id <> 0
  58. LIMIT 1;
  59. END IF;
  60. IF v_parent IS NULL THEN
  61. SELECT menu_id INTO v_parent
  62. FROM sys_menu
  63. WHERE menu_type = 'M'
  64. AND menu_name = '基础数据'
  65. LIMIT 1;
  66. END IF;
  67. IF v_parent IS NULL THEN
  68. RAISE NOTICE '未找到「基础数据」目录菜单,请先确认排水子系统菜单结构后手工添加。';
  69. RETURN;
  70. END IF;
  71. RAISE NOTICE '「基础数据」目录 menu_id = %', v_parent;
  72. -- ================================================================
  73. -- 2. 页面菜单(menu_type = 'C')
  74. -- ================================================================
  75. FOR r IN
  76. SELECT * FROM (VALUES
  77. ('工程设施基础数据管理', 'gcssgl', 'subSystem/drainage/jcsj/gcssgl',
  78. 'drainage:facility:list', 'guide', 3),
  79. ('易积水点管理', 'yjsdgl', 'subSystem/drainage/jcsj/yjsdgl',
  80. 'drainage:waterlogging:list', 'location', 4)
  81. ) AS x(menu_name, path, component, perms, icon, order_num)
  82. LOOP
  83. -- 先按「组件 + 基础数据目录」精确定位,避免多子系统复用同一组件时取错记录
  84. SELECT menu_id INTO v_page
  85. FROM sys_menu
  86. WHERE component = r.component AND parent_id = v_parent
  87. LIMIT 1;
  88. IF v_page IS NULL THEN
  89. SELECT menu_id INTO v_page
  90. FROM sys_menu
  91. WHERE component = r.component
  92. LIMIT 1;
  93. END IF;
  94. IF v_page IS NULL THEN
  95. SELECT COALESCE(MAX(menu_id), 0) + 1 INTO v_next FROM sys_menu;
  96. INSERT INTO sys_menu
  97. (menu_id, menu_name, parent_id, order_num, path, component,
  98. is_frame, is_cache, menu_type, visible, status, perms, icon,
  99. create_by, create_time, remark)
  100. VALUES
  101. (v_next, r.menu_name, v_parent, r.order_num, r.path, r.component,
  102. 1, 0, 'C', '0', '0', r.perms, r.icon,
  103. 'admin', CURRENT_TIMESTAMP, r.menu_name);
  104. v_page := v_next;
  105. RAISE NOTICE '已新增页面菜单:% (menu_id=%)', r.menu_name, v_page;
  106. -- 跟随父级授权:拥有「基础数据」目录的角色,一并获得新页面
  107. INSERT INTO sys_role_menu (role_id, menu_id)
  108. SELECT DISTINCT rm.role_id, v_page
  109. FROM sys_role_menu rm
  110. WHERE rm.menu_id = v_parent
  111. AND NOT EXISTS (
  112. SELECT 1 FROM sys_role_menu e
  113. WHERE e.role_id = rm.role_id AND e.menu_id = v_page
  114. );
  115. RAISE NOTICE ' → 已按「基础数据」目录的授权同步给角色';
  116. ELSE
  117. UPDATE sys_menu
  118. SET menu_name = r.menu_name,
  119. path = r.path,
  120. component = r.component,
  121. menu_type = 'C',
  122. visible = '0',
  123. status = '0',
  124. perms = r.perms,
  125. icon = r.icon,
  126. update_by = 'admin',
  127. update_time = CURRENT_TIMESTAMP
  128. WHERE menu_id = v_page;
  129. RAISE NOTICE '页面菜单已存在,已同步名称/路径/组件:% (menu_id=%)', r.menu_name, v_page;
  130. END IF;
  131. END LOOP;
  132. -- ================================================================
  133. -- 3. 按钮权限(menu_type = 'F')
  134. -- ================================================================
  135. FOR r IN
  136. SELECT * FROM (VALUES
  137. ('subSystem/drainage/jcsj/gcssgl', '新增工程设施', 'drainage:facility:add', 1),
  138. ('subSystem/drainage/jcsj/gcssgl', '修改工程设施', 'drainage:facility:edit', 2),
  139. ('subSystem/drainage/jcsj/gcssgl', '删除工程设施', 'drainage:facility:remove', 3),
  140. ('subSystem/drainage/jcsj/yjsdgl', '新增易积水点', 'drainage:waterlogging:add', 1),
  141. ('subSystem/drainage/jcsj/yjsdgl', '修改易积水点', 'drainage:waterlogging:edit', 2),
  142. ('subSystem/drainage/jcsj/yjsdgl', '删除易积水点', 'drainage:waterlogging:remove', 3)
  143. ) AS x(parent_component, menu_name, perms, order_num)
  144. LOOP
  145. SELECT menu_id INTO v_page
  146. FROM sys_menu
  147. WHERE component = r.parent_component
  148. ORDER BY menu_id
  149. LIMIT 1;
  150. IF v_page IS NULL THEN
  151. RAISE NOTICE '跳过按钮 %:未找到页面菜单 %', r.perms, r.parent_component;
  152. CONTINUE;
  153. END IF;
  154. IF EXISTS (
  155. SELECT 1 FROM sys_menu
  156. WHERE perms = r.perms AND parent_id = v_page
  157. ) THEN
  158. RAISE NOTICE '按钮已存在,跳过:%', r.perms;
  159. CONTINUE;
  160. END IF;
  161. SELECT COALESCE(MAX(menu_id), 0) + 1 INTO v_next FROM sys_menu;
  162. INSERT INTO sys_menu
  163. (menu_id, menu_name, parent_id, order_num, path, component,
  164. is_frame, is_cache, menu_type, visible, status, perms, icon,
  165. create_by, create_time, remark)
  166. VALUES
  167. (v_next, r.menu_name, v_page, r.order_num, '', NULL,
  168. 1, 0, 'F', '0', '0', r.perms, '#',
  169. 'admin', CURRENT_TIMESTAMP, '页面按钮权限');
  170. RAISE NOTICE '已新增按钮:% (%)', r.menu_name, r.perms;
  171. -- 跟随页面授权:拥有该页面菜单的角色,一并获得新按钮
  172. INSERT INTO sys_role_menu (role_id, menu_id)
  173. SELECT DISTINCT rm.role_id, v_next
  174. FROM sys_role_menu rm
  175. WHERE rm.menu_id = v_page
  176. AND NOT EXISTS (
  177. SELECT 1 FROM sys_role_menu e
  178. WHERE e.role_id = rm.role_id AND e.menu_id = v_next
  179. );
  180. END LOOP;
  181. -- ================================================================
  182. -- 4. 显式角色授权(按需启用)
  183. -- 给 v_extra_role_keys 里列出的角色,一次性授齐:
  184. -- 两个页面菜单 + 六个按钮。
  185. -- ================================================================
  186. IF v_extra_role_keys IS NOT NULL AND array_length(v_extra_role_keys, 1) > 0 THEN
  187. FOR v_role IN
  188. SELECT role_id, role_key, role_name FROM sys_role WHERE role_key = ANY(v_extra_role_keys)
  189. LOOP
  190. INSERT INTO sys_role_menu (role_id, menu_id)
  191. SELECT v_role.role_id, m.menu_id
  192. FROM sys_menu m
  193. WHERE (
  194. m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl')
  195. OR m.perms IN ('drainage:facility:add', 'drainage:facility:edit', 'drainage:facility:remove',
  196. 'drainage:waterlogging:add', 'drainage:waterlogging:edit',
  197. 'drainage:waterlogging:remove')
  198. )
  199. AND NOT EXISTS (
  200. SELECT 1 FROM sys_role_menu e
  201. WHERE e.role_id = v_role.role_id AND e.menu_id = m.menu_id
  202. );
  203. RAISE NOTICE '已显式授权角色:% (%)', v_role.role_name, v_role.role_key;
  204. END LOOP;
  205. IF NOT FOUND THEN
  206. RAISE NOTICE '警告:v_extra_role_keys 中的 role_key 在 sys_role 里一个都没匹配到,请核对。';
  207. END IF;
  208. END IF;
  209. RAISE NOTICE '菜单与按钮处理完成。若某个角色仍看不到按钮,请在「角色管理」中手工勾选。';
  210. END $$;
  211. -- =====================================================================
  212. -- 结果核验(可选,取消注释执行)
  213. -- =====================================================================
  214. -- 页面菜单与按钮(应返回 2 个 'C' + 6 个 'F')
  215. -- SELECT m.menu_id, m.menu_name, m.parent_id, m.menu_type, m.perms, m.order_num
  216. -- FROM sys_menu m
  217. -- WHERE m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl')
  218. -- OR m.perms IN ('drainage:facility:add','drainage:facility:edit','drainage:facility:remove',
  219. -- 'drainage:waterlogging:add','drainage:waterlogging:edit','drainage:waterlogging:remove')
  220. -- ORDER BY m.menu_type DESC, m.order_num;
  221. -- 角色授权情况
  222. -- SELECT rm.role_id, r.role_name, m.menu_name, m.menu_type, m.perms
  223. -- FROM sys_role_menu rm
  224. -- JOIN sys_role r ON r.role_id = rm.role_id
  225. -- JOIN sys_menu m ON m.menu_id = rm.menu_id
  226. -- WHERE m.perms LIKE 'drainage:facility:%'
  227. -- OR m.perms LIKE 'drainage:waterlogging:%'
  228. -- OR m.component IN ('subSystem/drainage/jcsj/gcssgl', 'subSystem/drainage/jcsj/yjsdgl')
  229. -- ORDER BY rm.role_id, m.menu_type DESC, m.order_num;
  230. COMMIT;