|
|
@@ -6,7 +6,9 @@
|
|
|
-- 在**已存在**的「收付款」目录下,新增:
|
|
|
-- · 1 行页面(type=2)「商户进件」 —— 进件页路由
|
|
|
-- · 2 行按钮(type=3)「建号」「提交入网」 —— 承载两个写权限点
|
|
|
--- 并把这三行授权给 role_id = 1(照 005 / lsy-menu.sql 的先例)。
|
|
|
+-- 并把这三行授权给 role_id 1(管理员角色)**与** 2(租户角色)——
|
|
|
+-- ★ 这与计划/lsy-menu.sql 字面的「role_id = 1」不同,依据是活库现状,见下「★ 授权给谁」。
|
|
|
+-- 只想给 admin 就把授权语句里的 `(2)` 删掉;代价写在那一节。
|
|
|
--
|
|
|
-- ── ★ 与 lsy-menu.sql 的关键差异(照抄它的写法会出错的地方)──────────────
|
|
|
-- lsy-menu.sql 的 `dir` CTE 是**插入**收付款目录;本脚本的 `dir` 是**查**它。
|
|
|
@@ -28,12 +30,16 @@
|
|
|
-- ★ **漏掉按钮行会怎样**:`module_payment:leshouying:onboarding:create` 永远不进入任何角色的
|
|
|
-- 授权集合 ⇒ **普通租户用户点「建号」必 403**;而 **超管直通**(`PermissionCheck` 对
|
|
|
-- `ROLE_SUPERUSER` 直接 `return true`)⇒ **超管测试一个都测不出来**。
|
|
|
--- ★ 先例:`batch-menu.sql` 用 type=3 行承载 `module_payment:batch:authorize` / `:create` /
|
|
|
--- `:detail`(它那 4 行全是 type=3)。本表自己的父子校验也认这个形态:
|
|
|
--- `MenuService.validateParentChildType` —— `pt == 2` 时 `childType != 3` 即抛
|
|
|
--- 「菜单下仅允许新增按钮」(MenuService.java:201-204)。
|
|
|
--- ★ 但 **batch-menu.sql 是坏先例、不可照抄**:它通篇 **没有 `uuid`**(0 处命中),
|
|
|
--- 按字面执行会违反 `uuid NOT NULL`(lsy-menu.sql:22-23 已为此留档)。
|
|
|
+-- ★ 先例不只有文档里的 batch-menu.sql —— **活库实测(2026-09-23)**:
|
|
|
+-- 全库 **186 行 type=3**,**全部(186/186,0 例例外)挂在 type=2 的父行下**,
|
|
|
+-- 没有一例挂在目录(type=1)或按钮(type=3)下。也就是说本脚本要写的形态
|
|
|
+-- **正是库里唯一存在的形态**,不是从文档推出来的。
|
|
|
+-- 本表自己的父子校验也认这个形态:`MenuService.validateParentChildType` ——
|
|
|
+-- `pt == 2` 时 `childType != 3` 即抛「菜单下仅允许新增按钮」(MenuService.java:201-204)。
|
|
|
+-- ★ 但 **batch-menu.sql 是不可照抄的先例**(理由已订正,别再用旧说法):
|
|
|
+-- 它**执行过**(活库实测:id 249「批量付款」+ 250–253 四个按钮,全在),
|
|
|
+-- 可它通篇 **没有 `uuid` 列**(0 处命中)—— 而 uuid 在活库**可空**,
|
|
|
+-- 于是它**不报错地插了 5 行 NULL uuid**,正是全表仅有的那 5 个 NULL。
|
|
|
-- 本脚本的列清单照 `lsy-menu.sql` 的 **20 列**写法,`uuid` 用 `gen_random_uuid()`。
|
|
|
--
|
|
|
-- ── 列名:本表的真实结构(逐字照 lsy-menu.sql 的警告)──────────────────
|
|
|
@@ -46,10 +52,19 @@
|
|
|
-- 在本表上一个都不存在;'M' / 'C' 那种字符枚举也不存在(本表 type 是 integer)。
|
|
|
-- type 的语义(MenuCreateDTO.java:22 逐字):**1=目录 2=菜单 3=按钮 4=外链**。
|
|
|
--
|
|
|
--- ── ★ uuid:NOT NULL 且无任何兜底 ──────────────────────────────────────
|
|
|
--- `uuid character varying(64) NOT NULL`,**无 DEFAULT**(唯一索引 ix_sys_menu_uuid),
|
|
|
+-- ── ★ uuid:可空、无默认 —— 不给值会**静默**插进 NULL,不报错 ─────────────
|
|
|
+-- **活库实测(2026-09-23,查 information_schema.columns + pg_indexes)**:
|
|
|
+-- `uuid character varying(64)`,**is_nullable = YES**,**column_default = 无**。
|
|
|
+-- ★ 这与 `lsy-menu.sql:22-23` 那句「`uuid character varying(64) NOT NULL`」**不一致** ——
|
|
|
+-- 那句照的是 `all_schema.sql`,**活库不是这样**。本文件按活库写,别回去照抄那句。
|
|
|
+-- 唯一索引 `ix_sys_menu_uuid` 确实在(`CREATE UNIQUE INDEX`),但 PostgreSQL 的唯一索引
|
|
|
+-- **允许多个 NULL** ⇒ 不给值既不会报错、也不会撞唯一性,只会静默留下 NULL。
|
|
|
+-- ★ 库里已经有 **5 行是 NULL uuid**(实测:id 249–253,就是 batch-menu.sql 插的那五行;
|
|
|
+-- 全表 237 行 / 232 个 distinct uuid,差额正是这 5 个 NULL)。
|
|
|
+-- 这 5 行目前**不是活的缺陷**(前端菜单树不拿 uuid 当键,`MenuVO.uuid` 只是透传字段,
|
|
|
+-- 且前端类型声明是 `uuid?: string` 可空)—— 但本脚本**不该再往这个集合里加行**。
|
|
|
-- 应用层也不填(AutoFillMetaObjectHandler 只填 createdTime/updatedTime/tenantId)⇒
|
|
|
--- 每条 INSERT 都必须显式给值。本脚本用 gen_random_uuid()(36 字符,≤64;volatile ⇒ 逐行取值)。
|
|
|
+-- 每条 INSERT 都要显式给值。本脚本用 gen_random_uuid()(36 字符,≤64;volatile ⇒ 逐行取值)。
|
|
|
--
|
|
|
-- ── ★ id:不要写死 ────────────────────────────────────────────────────
|
|
|
-- `id` 有默认值 `nextval('public.sys_menu_id_seq'::regclass)` ⇒ 本脚本**省略 id 列**,
|
|
|
@@ -73,23 +88,40 @@
|
|
|
-- frontend/src/views/module_payment/collection/onboarding/index.vue
|
|
|
-- ★ Task 9 若改了页面路径,这里必须同步改,否则**页面存在但点进去是 404**。
|
|
|
--
|
|
|
--- ── 需要人工确认的三处(取值来自先例,不是实测数据)──────────────────
|
|
|
+-- ── 需要人工确认的两处(取值来自先例,不是实测数据)──────────────────
|
|
|
-- 1) route_name:本脚本用 PascalCase `CollectionOnboarding`,照**紧邻**的三个 lsy 页面
|
|
|
-- (CollectionOrder / CollectionRefund / CollectionMerchant,见 lsy-menu.sql:88-93)。
|
|
|
-- 但 batch-menu.sql 用的是 kebab('payment-batch')—— 两套先例不一致。
|
|
|
-- route_name 会成为 vue-router 的 name(菜单高亮与 keep-alive 的 include 都按它匹配),必须唯一。
|
|
|
-- 2) route_path:本脚本用 `/payment/collection/onboarding`(模块前缀式),照同目录三个 lsy 页面。
|
|
|
--- 3) role_id = 1:照 005 与 lsy-menu.sql:65,**请按你库里的实际角色 id 调整**。
|
|
|
--- 本脚本只授权给这一个角色;若进件页要给别的角色用,需另外补 sys_role_menus。
|
|
|
+--
|
|
|
+-- ── ★ 授权给谁:role_id 1 **与** 2(此处偏离计划字面,依据是活库现状)────────
|
|
|
+-- **活库实测(2026-09-23)**:
|
|
|
+-- · `sys_role` 一共两行:**id=1「管理员角色」(code=ADMIN),只被 1 个用户持有(`admin`, tenant_id=1)**;
|
|
|
+-- **id=2「租户角色」(code=tenant),被 17 个用户持有**(tenant_id = 2, 9–18, 21–26)。
|
|
|
+-- · 「收付款」目录(id=268)与它下面**全部三个** lsy 兄弟页(269 支付订单 / 270 退款记录 /
|
|
|
+-- 271 商户映射)**都授给了 role 1 和 role 2 两个角色**(实测 8 行 sys_role_menus,两角色各 4)。
|
|
|
+-- ⇒ 若只授 role 1,**17 个租户用户一个都看不到这个页面**(菜单树按 sys_role_menus 过滤),
|
|
|
+-- 而进件本来就是**租户级**业务、租户用户正是它的使用者;
|
|
|
+-- 更糟的是 `admin` 是超管,`PermissionCheck` 对超管直接放行 ⇒ **本机测不出这个缺口**。
|
|
|
+-- ⇒ 故本脚本授两个角色,与这棵子树**现有的每一行**保持一致。
|
|
|
+-- ★ 如果你的意图是「进件页只给 admin」,把下面 INSERT 里的 `(2)` 一行删掉即可 ——
|
|
|
+-- 那是一个可以做的选择,但请知道它的后果:**17 个租户用户看不到进件菜单**。
|
|
|
+-- (`lsy-menu.sql` 自己写的是 role_id = 1,可活库里那几行**都**带着 role 2 ——
|
|
|
+-- 说明那份脚本的授权行不足以复现现状,别把它的字面当权威。)
|
|
|
--
|
|
|
-- ── 其他 ─────────────────────────────────────────────────────────────
|
|
|
-- · icon 一律留空:图标集是 src/assets/icons/*.svg,经 `i-svg:<name>` 渲染;
|
|
|
-- 缺省时前端回退到 i-svg:menu。要图标请在「菜单管理」界面里选。
|
|
|
-- · 幂等(两种**相反**的情形都要知道;本脚本不是通用 upsert):
|
|
|
--- 1) 页面行已存在 ⇒ `page` 为空 ⇒ **两个按钮也不会插**(buttons 的 FROM 是 page),且**不报错**。
|
|
|
--- 若出现「菜单在、按钮不在」,请手工补两条 type=3 的 INSERT。
|
|
|
+-- 1) 页面行已存在 ⇒ `page` 为空 ⇒ **两个按钮也不会插**(buttons 的 FROM 是 page),
|
|
|
+-- **授权行也不会插**(它们的 FROM 是 page / buttons),且**全程不报错**。
|
|
|
+-- 若出现「菜单在、按钮/授权不在」,请手工补两条 type=3 的 INSERT + 对应的 sys_role_menus。
|
|
|
-- 2) 收付款目录不存在 ⇒ `dir` 为空 ⇒ 三行**都不插**,且**不报错**。
|
|
|
-- 执行前请先跑下面第 1 条只读核对确认目录在。
|
|
|
+-- · `"order"` 实测:收付款目录(id=268)下现有三个子行 order = 1/2/3 ⇒
|
|
|
+-- 本脚本的 `MAX("order") + 1` 会算出 **4**,排在「商户映射」之后(实测于 2026-09-23)。
|
|
|
+-- · `permission` 列是 `varchar(100)`;本脚本三个串最长 43 字符,有余量。
|
|
|
|
|
|
WITH dir AS (
|
|
|
SELECT id FROM sys_menu
|
|
|
@@ -126,10 +158,12 @@ buttons AS (
|
|
|
RETURNING id
|
|
|
)
|
|
|
-- 页面行与两个按钮行都要授权:菜单树按 sys_role_menus 过滤,只授页面会让按钮权限缺席 ⇒ 403。
|
|
|
+-- 两个角色都要(见上「★ 授权给谁」):`page` / `buttons` 各只被引用一次,
|
|
|
+-- 免得依赖「数据修改型 CTE 能否被引用两次」这种我没实测过的语义。
|
|
|
INSERT INTO sys_role_menus (role_id, menu_id)
|
|
|
-SELECT 1, id FROM page
|
|
|
-UNION ALL
|
|
|
-SELECT 1, id FROM buttons;
|
|
|
+SELECT v.role_id, x.id
|
|
|
+ FROM (SELECT id FROM page UNION ALL SELECT id FROM buttons) AS x
|
|
|
+ CROSS JOIN (VALUES (1), (2)) AS v(role_id);
|
|
|
|
|
|
|
|
|
-- ── 只读核对(执行后手工跑一遍;前三条**执行前**也建议先跑)────────────────
|
|
|
@@ -154,11 +188,13 @@ SELECT 1, id FROM buttons;
|
|
|
-- 期望:**2 行**,permission 逐字为
|
|
|
-- 'module_payment:leshouying:onboarding:create' 与 'module_payment:leshouying:onboarding:commit'。
|
|
|
--
|
|
|
--- 4) 授权行
|
|
|
+-- 4) 授权行(**两个角色各 3 行**,见上「★ 授权给谁」)
|
|
|
-- SELECT rm.role_id, m.name, m.permission
|
|
|
-- FROM sys_role_menus rm JOIN sys_menu m ON m.id = rm.menu_id
|
|
|
--- WHERE m.name IN ('商户进件', '建号', '提交入网') AND m.status = '0';
|
|
|
--- 期望:**3 行**,role_id 都是 1。
|
|
|
+-- WHERE m.name IN ('商户进件', '建号', '提交入网') AND m.status = '0'
|
|
|
+-- ORDER BY rm.role_id, m.name;
|
|
|
+-- 期望:**6 行** —— role_id 1 与 2 **各 3 行**。
|
|
|
+-- 若只有 3 行且 role_id 全是 1 ⇒ 17 个租户用户看不到进件菜单。
|
|
|
--
|
|
|
-- 5) 端到端(**唯一能证明权限串没写错的一条**):用一个**非超管**的租户账号登录,
|
|
|
-- 确认三个`module_payment:leshouying:onboarding:*`都出现在
|