- 新增 school_admin/form_admin 两表(sql/t10_admin_domain.sql,含 answer.submitter_sch_id 加列)与 AdminDomainController/AdminDomainService/SchoolUserTreeService - DataScopeService 范围体系按 P80 验收口径落地:入口只认模块行、查询域=会话校、两表只升范围;新增 SchoolScopeImplementor - fc:scope:all / SCOPE_ALL_CUSTOM_ID / anchorCustomIds / MODULE_DICT 锚点全链路退役,全仓引用归零;h2 登记脚本 6→5 行(快应用段逐字未动) - AnswerScopeQueryBuilder 校域不变式:answer.sch_id 恒=会话校,基础过滤 sch_id+app_code+code+is_deleted 不变 - FormAdminGuard:targetSchId=0(基础表单)仅超管可维护;FormAdminController/AnswerReadController 等按管理员范围收口 - 测试基线 190→219/0/0/0:DataScopeServiceTest 22、FormAdminGuardTest 14、AdminScopeIT 8、AdminDomainIT 10、AnswerReadIT 改写 1、FormBaseControllerTest 7 等
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
-- ============================================================================
|
||||
-- 表单中心 H2 + 第一个快应用:UserBase 侧应用行/模块行/授权登记脚本
|
||||
-- 编制:Qoder(T9 联调轮)|日期:2026-10-15
|
||||
-- 依据:《表单中心执行手册》§2.2(中心应用六条模块行表 + 验证口径)、
|
||||
-- 《表单中心建设方案 v1.4》§6.2(快应用登记 checklist R8)、§6.4(customId=fc:scope:all)、
|
||||
-- §6.5(中心=BUSINESS 应用,模块行与快应用模块行两棵树不混)
|
||||
-- 编制:Qoder(T9 联调轮)|日期:2026-10-15|改版:T10 中心段 6→5 行(手册 §2.2 v1.5,锚点行退役)
|
||||
-- 依据:《表单中心执行手册》§2.2(中心应用 v1.5 五条模块行表 + 验证口径)、
|
||||
-- 《表单中心建设方案 v1.4》§6.2(快应用登记 checklist R8)、§6.5(中心=BUSINESS 应用,
|
||||
-- 模块行与快应用模块行两棵树不混)
|
||||
-- 《表单中心管理员体系方案-20261015》§3/§7(T10 改版:中心 6→5 行,customId 数据范围锚点退役)
|
||||
-- 先例:D:\SoftProject\yunhai\UserBase\flow-center接入UserBase菜单.sql(同一套形态与幂等写法)
|
||||
--
|
||||
-- ⚠ 纪律:本脚本**不由 AI 执行**(沿 flow-center 先例"AI 不代跑,交由你在 dev / prod 各自执行")。
|
||||
@@ -37,14 +38,17 @@ SET @operator = 0; -- create_user 占位(0=系统)
|
||||
-- WHERE @center_app_id = 0;
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- 步骤 1:中心应用六条模块行(执行手册 §2.2 表;path 必须逐字等于 front/src/router/routes.ts)
|
||||
-- 步骤 1:中心应用五条模块行(执行手册 §2.2 v1.5 表;path 必须逐字等于 front/src/router/routes.ts)
|
||||
-- ①表单设计 /admin/forms ②数据管理 /admin/data ③统计 /admin/stats
|
||||
-- ④字典管理 /admin/dicts ⑤我的填写 /my(全员) ⑥数据全量【path 留空 + customId=fc:scope:all】
|
||||
-- 第⑥行=纯权限锚点:导航不渲染、后端 DataScopeService 只扫 path 空节点的 customId(P47 收紧后口径),
|
||||
-- 授权给哪个组,该组的数据范围即升级为"全部"(方案 §6.4)。
|
||||
-- 子页面路由(/admin/forms/designer、/admin/data/detail、/app/:appCode/data/detail)
|
||||
-- ④应用设置 /admin/app(页内 tab:角色设置/字典管理,字典 API 摊这一行把关) ⑤我的填写 /my(全员)
|
||||
-- v1.5 改版(T10,2026-10-15 用户裁决):
|
||||
-- · 原「字典管理 /admin/dicts」独立行撤销,迁入应用设置页内 tab(不占 modId、不进导航);
|
||||
-- · 原「数据全量」path 空锚点行撤销——UserBase 侧 customId 数据范围协议退役,
|
||||
-- 升级载体改为中心自建的管理员两表(school_admin / form_admin,见《管理员体系方案》§4/§5.1)。
|
||||
-- **中心应用自此不再有 path 空行**;前端 menuNav 的"path 空跳过"规则保留给快应用面的按钮锚点。
|
||||
-- 子页面路由(/admin/forms/designer、/admin/data/detail、/app/:appCode/data/detail、/admin/app 的页内 tab)
|
||||
-- **不建模块行**(手册 §2.2 注记 + P63/P77):不占 modId、不进导航,前端按 meta.parentPath 归位。
|
||||
-- custom_id 用 200~205 段(避开 flow-center 的 100~105;后端 resolveModId 只认数字 customId)
|
||||
-- custom_id 用 200~204 段(避开 flow-center 的 100~105;后端 resolveModId 只认数字 customId)
|
||||
-- ----------------------------------------------------------------------------
|
||||
INSERT INTO app_module
|
||||
(app_id, parent_id, name, custom_id, path, icon, level, sort_no, create_user, create_time)
|
||||
@@ -53,10 +57,8 @@ SELECT * FROM (
|
||||
'/admin/forms' AS path, 'word' AS icon, 1 AS level, 200 AS sort_no, @operator AS create_user, NOW() AS create_time
|
||||
UNION ALL SELECT @center_app_id, NULL, '数据管理', '201', '/admin/data', 'category', 1, 201, @operator, NOW()
|
||||
UNION ALL SELECT @center_app_id, NULL, '统计', '202', '/admin/stats','tongji', 1, 202, @operator, NOW()
|
||||
UNION ALL SELECT @center_app_id, NULL, '字典管理', '203', '/admin/dicts','zidingyi', 1, 203, @operator, NOW()
|
||||
UNION ALL SELECT @center_app_id, NULL, '应用设置', '203', '/admin/app', 'zidingyi', 1, 203, @operator, NOW()
|
||||
UNION ALL SELECT @center_app_id, NULL, '我的填写', '204', '/my', '', 1, 204, @operator, NOW()
|
||||
-- 锚点行:path 空 + customId 协议值(非数字 customId 是刻意的,前端 modId 会回退主键 id,不影响消费)
|
||||
UNION ALL SELECT @center_app_id, NULL, '数据全量', 'fc:scope:all', '', '', 1, 205, @operator, NOW()
|
||||
) t
|
||||
WHERE @center_app_id > 0
|
||||
AND NOT EXISTS (SELECT 1 FROM app_module m WHERE m.app_id = t.app_id AND m.custom_id = t.custom_id);
|
||||
@@ -124,12 +126,13 @@ SELECT g.group_id, a.app_id, @operator, NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_group_app_rel r
|
||||
WHERE r.group_id = a.group_id AND r.app_id = a.app_id);
|
||||
|
||||
-- 3.3 中心模块授权:管理员组=前五行(除锚点),全员组=只"我的填写",
|
||||
-- 要看全校数据的组=额外勾"数据全量"锚点行(customId=fc:scope:all)
|
||||
-- 3.3 中心模块授权:管理员组=四个管理行(表单设计/数据管理/统计/应用设置),全员组=只"我的填写"。
|
||||
-- v1.5 起**没有"要看全校数据就多勾一行"这回事**:数据范围升级改由中心的管理员两表给
|
||||
-- (/admin/app 的角色设置 tab 加校级表单管理员,或表单列表/设计器给单表单管理员)。
|
||||
INSERT INTO sys_group_module_perm (group_id, module_id, inherit_flag, create_user, create_time)
|
||||
SELECT @grp_admin, m.id, 0, @operator, NOW()
|
||||
FROM app_module m
|
||||
WHERE m.app_id = @center_app_id AND @grp_admin > 0 AND COALESCE(m.custom_id,'') <> 'fc:scope:all'
|
||||
WHERE m.app_id = @center_app_id AND @grp_admin > 0 AND m.path <> '/my'
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_group_module_perm p WHERE p.group_id = @grp_admin AND p.module_id = m.id);
|
||||
|
||||
INSERT INTO sys_group_module_perm (group_id, module_id, inherit_flag, create_user, create_time)
|
||||
@@ -138,13 +141,6 @@ SELECT @grp_all, m.id, 0, @operator, NOW()
|
||||
WHERE m.app_id = @center_app_id AND @grp_all > 0 AND m.path = '/my'
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_group_module_perm p WHERE p.group_id = @grp_all AND p.module_id = m.id);
|
||||
|
||||
-- 数据全量锚点(V42 的授权动作;只给确实要看全校数据的组)
|
||||
INSERT INTO sys_group_module_perm (group_id, module_id, inherit_flag, create_user, create_time)
|
||||
SELECT @grp_admin, m.id, 0, @operator, NOW()
|
||||
FROM app_module m
|
||||
WHERE m.app_id = @center_app_id AND @grp_admin > 0 AND m.custom_id = 'fc:scope:all'
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_group_module_perm p WHERE p.group_id = @grp_admin AND p.module_id = m.id);
|
||||
|
||||
-- 3.4 快应用模块授权:教师组=数据查看+统计+导出锚点(不给填报也算得出数据);学生组=只给填报行
|
||||
INSERT INTO sys_group_module_perm (group_id, module_id, inherit_flag, create_user, create_time)
|
||||
SELECT @grp_teacher, m.id, 0, @operator, NOW()
|
||||
@@ -172,21 +168,26 @@ SELECT @grp_teacher, m.id, 0, @operator, NOW()
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
-- 步骤 4:验收(对应任务书 T9 演练清单与手册 §2.2"验证"行)
|
||||
-- ①超管登录中心:/form-center/api/base/GetUserMod 返回步骤 1 的树(前端导航恰 5 项,锚点行不出现)
|
||||
-- ①超管登录中心:/form-center/api/base/GetUserMod 返回步骤 1 的树(前端导航恰 5 项)
|
||||
-- ②无授权用户:只见"我的填写"
|
||||
-- ③快应用上下文:/form-center/api/base/GetUserMod?appCode=fc-drill 返回步骤 2 那棵树
|
||||
-- ⚠ 这条要 **H4 上线**(UserBase /oapi/user/modules 的可选 appCode 参数)+ 中心消费侧接线才通;
|
||||
-- 中心侧当前按 P3 返回空树+warn,见 T9 报告问题单 P78。
|
||||
-- ④教师组账号进 /form-center/app/fc-drill/data:导出按钮出现(锚点判定生效,P76)
|
||||
-- ④教师组账号进 /form-center/app/fc-drill/data:导出按钮出现(快应用按钮锚点判定生效,P76)
|
||||
-- ⑤学生组账号:V16 门户可见性由开通闸门决定;进应用只见填报
|
||||
-- ⑥中心应用管理端进 /form-center/#/admin/app:应用设置页出两个 tab(角色设置/字典管理),
|
||||
-- 角色设置里加的人落 school_admin(数据范围升级,不是菜单行)——T10 V43/V46
|
||||
-- ----------------------------------------------------------------------------
|
||||
SELECT '中心模块行数(期望 6)' AS chk, COUNT(*) AS n FROM app_module WHERE app_id = @center_app_id
|
||||
SELECT '中心模块行数(期望 5)' AS chk, COUNT(*) AS n FROM app_module WHERE app_id = @center_app_id
|
||||
UNION ALL
|
||||
SELECT '快应用模块行数(期望 5)', COUNT(*) FROM app_module WHERE app_id = @quick_app_id
|
||||
UNION ALL
|
||||
SELECT '中心 path 空锚点数(期望 1)', COUNT(*) FROM app_module
|
||||
SELECT '中心 path 空行数(期望 0,锚点已退役)', COUNT(*) FROM app_module
|
||||
WHERE app_id = @center_app_id AND (path IS NULL OR path = '')
|
||||
UNION ALL
|
||||
SELECT '快应用 path 空锚点数(期望 2=导入/导出)', COUNT(*) FROM app_module
|
||||
WHERE app_id = @quick_app_id AND (path IS NULL OR path = '')
|
||||
UNION ALL
|
||||
SELECT '已开通中心应用的组数', COUNT(*) FROM sys_group_app_rel WHERE app_id = @center_app_id
|
||||
UNION ALL
|
||||
SELECT '已授权中心模块的组-行对数', COUNT(*) FROM sys_group_module_perm p
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
-- ============================================================
|
||||
-- 表单中心 T10 · 管理员体系 DDL(MySQL 5.7 兼容复核版)
|
||||
-- 范围:《管理员体系方案-20261015》§4 三笔 = school_admin / form_admin / answer 加列+加索引
|
||||
-- 用途:生产 ddl-auto=none 时的升级脚本;开发期(本机 bsch_formcenter,ddl-auto=update)由 Hibernate
|
||||
-- 自动追加,本脚本同时是"实表应当长什么样"的评审权威(沿 t2/t3 先例)。
|
||||
-- 5.7 复核要点:①无 CTE/WITH、无函数索引、无生成列、无 CHECK 约束;②utf8mb4 显式写 CHARSET/COLLATE;
|
||||
-- ③InnoDB、无物理外键(方案 §7.7 逻辑外键约定:user_id→UserBase、form_uuid→form.uuid 都不建 FK);
|
||||
-- ④可空列一律写 DEFAULT NULL,TEXT 类不出现(本脚本无大字段)。
|
||||
-- P5/P15 裁决:实体继承 BaseEntity → 实表=方案 §4 草案 + create_by/update_by 两审计列;
|
||||
-- 审计列在基类未标 nullable=false,故按建表实态写 DEFAULT NULL(FormCenterAuditListener 恒写 now())。
|
||||
-- 重跑口径:MySQL 5.7 无 ADD COLUMN IF NOT EXISTS,本脚本【不是幂等的】——执行前先用
|
||||
-- `SHOW COLUMNS FROM answer LIKE 'submitter_sch_id'` 确认列不存在;两表若已建则只跑第三条 ALTER。
|
||||
-- 存量:生产零存量(H2 尚未执行、160 在线仍是 T5 旧版),无需回填;本地/perf 库的测试数据不强推
|
||||
-- (NULL 行天然不匹配 SCHOOL 谓词=fail-closed,方案 §4 存量条款)。
|
||||
-- 部署说明已同步补"加列"一笔(《表单中心160部署Runbook》§0)。
|
||||
-- ============================================================
|
||||
|
||||
-- ① 校级表单管理员:数据范围扩展载体,取代已退役的 UserBase 侧 customId 权限锚点行(方案 §4①/§7)
|
||||
CREATE TABLE `school_admin` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`sch_id` BIGINT NOT NULL COMMENT '租户键(=会话校;超管代查时=显式目标校)',
|
||||
`user_id` INT NOT NULL COMMENT 'UserBase 用户主键(BoaUser.id),逻辑外键不建 FK',
|
||||
`user_name` VARCHAR(64) NOT NULL COMMENT '姓名快照(列表展示免回查,权威在 UserBase)',
|
||||
`create_by` VARCHAR(255) DEFAULT NULL,
|
||||
`create_time` DATETIME DEFAULT NULL,
|
||||
`update_by` VARCHAR(255) DEFAULT NULL,
|
||||
`update_time` DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_school_admin` (`sch_id`, `user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
||||
COMMENT='校级表单管理员(方案 §5.1:本校表单范围=全部,基础表单范围=本校提交)';
|
||||
|
||||
-- ② 单表单管理员:指定表单的数据查看+导出(D3 裁决:不含编辑权)
|
||||
CREATE TABLE `form_admin` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`form_uuid` VARCHAR(32) NOT NULL COMMENT '授权表单 uuid(跨版本不变,契约 §1)',
|
||||
`sch_id` BIGINT NOT NULL COMMENT '冗余表单租户域(form.sch_id,基础表单=0),落库域复核用',
|
||||
`user_id` INT NOT NULL,
|
||||
`user_name` VARCHAR(64) NOT NULL COMMENT '姓名快照(列表展示免回查,权威在 UserBase)',
|
||||
`create_by` VARCHAR(255) DEFAULT NULL,
|
||||
`create_time` DATETIME DEFAULT NULL,
|
||||
`update_by` VARCHAR(255) DEFAULT NULL,
|
||||
`update_time` DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_form_admin` (`form_uuid`, `user_id`),
|
||||
KEY `idx_form_admin_user` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
||||
COMMENT='单表单管理员(方案 §5.1:指定表单=全部,基础表单上=本校提交)';
|
||||
|
||||
-- ③ 答卷加列:填报人会话学校(D2=B 的落点,SCHOOL 范围的谓词列)
|
||||
-- NULL=未记录(存量行),按"不参与校级范围匹配"处理;updatable=false(落值后不随改)
|
||||
ALTER TABLE `answer`
|
||||
ADD COLUMN `submitter_sch_id` BIGINT NULL DEFAULT NULL
|
||||
COMMENT '填报人会话学校(提交时从会话 currentRole.schId 落值;NULL=未记录,不参与校级范围匹配)'
|
||||
AFTER `submitter_id`;
|
||||
|
||||
ALTER TABLE `answer` ADD KEY `idx_answer_submitter_sch` (`submitter_sch_id`);
|
||||
|
||||
-- 自验(执行后逐条核对,V47):
|
||||
-- SHOW CREATE TABLE answer\G -- 应含 submitter_sch_id bigint NULL + KEY idx_answer_submitter_sch
|
||||
-- EXPLAIN SELECT id FROM answer WHERE sch_id=3260 AND app_code='form-center' AND code='x'
|
||||
-- AND is_deleted=0 AND submitter_sch_id=3260; -- SCHOOL 谓词应能走 key 列(V47 探针口径)
|
||||
-- SELECT COUNT(*) FROM school_admin; -- 期望 0(新库)
|
||||
-- SELECT COUNT(*) FROM form_admin; -- 期望 0(新库)
|
||||
Reference in New Issue
Block a user