新增物联:完成Java 21与IoT融合架构及安全门禁基线归档

This commit is contained in:
wangzhibiao committed 2026-10-13 21:17:39 +08:00
1 parent 9a62ac8536
commit 373921447f
905 files changed
+127387 -95251

No files matched your search

+893
View File
@@ -0,0 +1,893 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 01_system_foundation.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: public)
-- 来源追溯: sql/ry_20250522.sql + sql/quartz.sql
-- 包含内容: RuoYi 基础系统表 (sys_*) 与 Quartz 定时任务调度引擎表 (QRTZ_*)
-- 安全约束: 显式限定 search_path 至 public,无跨库与系统全局权限修改
-- ==============================================================================
SET search_path TO public, pg_catalog;
-- ----------------------------
-- 1、部门表
-- ----------------------------
drop table if exists public.sys_dept;
create table public.sys_dept (
dept_id bigint(20) not null auto_increment comment '部门id',
parent_id bigint(20) default 0 comment '父部门id',
ancestors varchar(50) default '' comment '祖级列表',
dept_name varchar(30) default '' comment '部门名称',
order_num int(4) default 0 comment '显示顺序',
leader varchar(20) default null comment '负责人',
phone varchar(11) default null comment '联系电话',
email varchar(50) default null comment '邮箱',
status char(1) default '0' comment '部门状态(0正常 1停用)',
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
primary key (dept_id)
) engine=innodb auto_increment=200 comment = '部门表';
-- ----------------------------
-- 初始化-部门表数据
-- ----------------------------
insert into public.sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
insert into public.sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
-- ----------------------------
-- 2、用户信息表
-- ----------------------------
drop table if exists public.sys_user;
create table public.sys_user (
user_id bigint(20) not null auto_increment comment '用户ID',
dept_id bigint(20) default null comment '部门ID',
user_name varchar(30) not null comment '用户账号',
nick_name varchar(30) not null comment '用户昵称',
user_type varchar(2) default '00' comment '用户类型(00系统用户)',
email varchar(50) default '' comment '用户邮箱',
phonenumber varchar(11) default '' comment '手机号码',
sex char(1) default '0' comment '用户性别(0男 1女 2未知)',
avatar varchar(100) default '' comment '头像地址',
password varchar(100) default '' comment '密码',
status char(1) default '0' comment '账号状态(0正常 1停用)',
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
login_ip varchar(128) default '' comment '最后登录IP',
login_date datetime comment '最后登录时间',
pwd_update_date datetime comment '密码最后更新时间',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (user_id)
) engine=innodb auto_increment=100 comment = '用户信息表';
-- ----------------------------
-- 初始化-用户信息表数据
-- ----------------------------
insert into public.sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '管理员');
insert into public.sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '测试员');
-- ----------------------------
-- 3、岗位信息表
-- ----------------------------
drop table if exists public.sys_post;
create table public.sys_post
(
post_id bigint(20) not null auto_increment comment '岗位ID',
post_code varchar(64) not null comment '岗位编码',
post_name varchar(50) not null comment '岗位名称',
post_sort int(4) not null comment '显示顺序',
status char(1) not null comment '状态(0正常 1停用)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (post_id)
) engine=innodb comment = '岗位信息表';
-- ----------------------------
-- 初始化-岗位信息表数据
-- ----------------------------
insert into public.sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, '');
insert into public.sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, '');
insert into public.sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, '');
insert into public.sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, '');
-- ----------------------------
-- 4、角色信息表
-- ----------------------------
drop table if exists public.sys_role;
create table public.sys_role (
role_id bigint(20) not null auto_increment comment '角色ID',
role_name varchar(30) not null comment '角色名称',
role_key varchar(100) not null comment '角色权限字符串',
role_sort int(4) not null comment '显示顺序',
data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示',
dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示',
status char(1) not null comment '角色状态(0正常 1停用)',
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (role_id)
) engine=innodb auto_increment=100 comment = '角色信息表';
-- ----------------------------
-- 初始化-角色信息表数据
-- ----------------------------
insert into public.sys_role values('1', '超级管理员', 'admin', 1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员');
insert into public.sys_role values('2', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '普通角色');
-- ----------------------------
-- 5、菜单权限表
-- ----------------------------
drop table if exists public.sys_menu;
create table public.sys_menu (
menu_id bigint(20) not null auto_increment comment '菜单ID',
menu_name varchar(50) not null comment '菜单名称',
parent_id bigint(20) default 0 comment '父菜单ID',
order_num int(4) default 0 comment '显示顺序',
path varchar(200) default '' comment '路由地址',
component varchar(255) default null comment '组件路径',
query varchar(255) default null comment '路由参数',
route_name varchar(50) default '' comment '路由名称',
is_frame int(1) default 1 comment '是否为外链(0是 1否)',
is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)',
menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)',
visible char(1) default 0 comment '菜单状态(0显示 1隐藏)',
status char(1) default 0 comment '菜单状态(0正常 1停用)',
perms varchar(100) default null comment '权限标识',
icon varchar(100) default '#' comment '菜单图标',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (menu_id)
) engine=innodb auto_increment=2000 comment = '菜单权限表';
-- ----------------------------
-- 初始化-菜单信息表数据
-- ----------------------------
-- 一级菜单
insert into public.sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录');
insert into public.sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录');
insert into public.sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录');
insert into public.sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null, '', '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, '若依官网地址');
-- 二级菜单
insert into public.sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单');
insert into public.sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单');
insert into public.sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', sysdate(), '', null, '菜单管理菜单');
insert into public.sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', sysdate(), '', null, '部门管理菜单');
insert into public.sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', sysdate(), '', null, '岗位管理菜单');
insert into public.sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单');
insert into public.sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单');
insert into public.sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单');
insert into public.sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单');
insert into public.sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单');
insert into public.sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', sysdate(), '', null, '定时任务菜单');
insert into public.sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', sysdate(), '', null, '数据监控菜单');
insert into public.sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', sysdate(), '', null, '服务监控菜单');
insert into public.sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单');
insert into public.sys_menu values('114', '缓存列表', '2', '6', 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', sysdate(), '', null, '缓存列表菜单');
insert into public.sys_menu values('115', '表单构建', '3', '1', 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单');
insert into public.sys_menu values('116', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单');
insert into public.sys_menu values('117', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单');
-- 三级菜单
insert into public.sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单');
insert into public.sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单');
-- 用户管理按钮
insert into public.sys_menu values('1000', '用户查询', '100', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1001', '用户新增', '100', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1002', '用户修改', '100', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1003', '用户删除', '100', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1004', '用户导出', '100', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1005', '用户导入', '100', '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1006', '重置密码', '100', '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, '');
-- 角色管理按钮
insert into public.sys_menu values('1007', '角色查询', '101', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1008', '角色新增', '101', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1009', '角色修改', '101', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1010', '角色删除', '101', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1011', '角色导出', '101', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', sysdate(), '', null, '');
-- 菜单管理按钮
insert into public.sys_menu values('1012', '菜单查询', '102', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1013', '菜单新增', '102', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1014', '菜单修改', '102', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1015', '菜单删除', '102', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', sysdate(), '', null, '');
-- 部门管理按钮
insert into public.sys_menu values('1016', '部门查询', '103', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1017', '部门新增', '103', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1018', '部门修改', '103', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1019', '部门删除', '103', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', sysdate(), '', null, '');
-- 岗位管理按钮
insert into public.sys_menu values('1020', '岗位查询', '104', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1021', '岗位新增', '104', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1022', '岗位修改', '104', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1023', '岗位删除', '104', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1024', '岗位导出', '104', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', sysdate(), '', null, '');
-- 字典管理按钮
insert into public.sys_menu values('1025', '字典查询', '105', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1026', '字典新增', '105', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1027', '字典修改', '105', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1028', '字典删除', '105', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1029', '字典导出', '105', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', sysdate(), '', null, '');
-- 参数设置按钮
insert into public.sys_menu values('1030', '参数查询', '106', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1031', '参数新增', '106', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1032', '参数修改', '106', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1033', '参数删除', '106', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1034', '参数导出', '106', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', sysdate(), '', null, '');
-- 通知公告按钮
insert into public.sys_menu values('1035', '公告查询', '107', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1036', '公告新增', '107', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1037', '公告修改', '107', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1038', '公告删除', '107', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', sysdate(), '', null, '');
-- 操作日志按钮
insert into public.sys_menu values('1039', '操作查询', '500', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1040', '操作删除', '500', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1041', '日志导出', '500', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, '');
-- 登录日志按钮
insert into public.sys_menu values('1042', '登录查询', '501', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1043', '登录删除', '501', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1044', '日志导出', '501', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1045', '账户解锁', '501', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, '');
-- 在线用户按钮
insert into public.sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1048', '单条强退', '109', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, '');
-- 定时任务按钮
insert into public.sys_menu values('1049', '任务查询', '110', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1050', '任务新增', '110', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1051', '任务修改', '110', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1052', '任务删除', '110', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1053', '状态修改', '110', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1054', '任务导出', '110', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', sysdate(), '', null, '');
-- 代码生成按钮
insert into public.sys_menu values('1055', '生成查询', '116', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1056', '生成修改', '116', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1057', '生成删除', '116', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1058', '导入代码', '116', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1059', '预览代码', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
insert into public.sys_menu values('1060', '生成代码', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
-- ----------------------------
-- 6、用户和角色关联表 用户N-1角色
-- ----------------------------
drop table if exists public.sys_user_role;
create table public.sys_user_role (
user_id bigint(20) not null comment '用户ID',
role_id bigint(20) not null comment '角色ID',
primary key(user_id, role_id)
) engine=innodb comment = '用户和角色关联表';
-- ----------------------------
-- 初始化-用户和角色关联表数据
-- ----------------------------
insert into public.sys_user_role values ('1', '1');
insert into public.sys_user_role values ('2', '2');
-- ----------------------------
-- 7、角色和菜单关联表 角色1-N菜单
-- ----------------------------
drop table if exists public.sys_role_menu;
create table public.sys_role_menu (
role_id bigint(20) not null comment '角色ID',
menu_id bigint(20) not null comment '菜单ID',
primary key(role_id, menu_id)
) engine=innodb comment = '角色和菜单关联表';
-- ----------------------------
-- 初始化-角色和菜单关联表数据
-- ----------------------------
insert into public.sys_role_menu values ('2', '1');
insert into public.sys_role_menu values ('2', '2');
insert into public.sys_role_menu values ('2', '3');
insert into public.sys_role_menu values ('2', '4');
insert into public.sys_role_menu values ('2', '100');
insert into public.sys_role_menu values ('2', '101');
insert into public.sys_role_menu values ('2', '102');
insert into public.sys_role_menu values ('2', '103');
insert into public.sys_role_menu values ('2', '104');
insert into public.sys_role_menu values ('2', '105');
insert into public.sys_role_menu values ('2', '106');
insert into public.sys_role_menu values ('2', '107');
insert into public.sys_role_menu values ('2', '108');
insert into public.sys_role_menu values ('2', '109');
insert into public.sys_role_menu values ('2', '110');
insert into public.sys_role_menu values ('2', '111');
insert into public.sys_role_menu values ('2', '112');
insert into public.sys_role_menu values ('2', '113');
insert into public.sys_role_menu values ('2', '114');
insert into public.sys_role_menu values ('2', '115');
insert into public.sys_role_menu values ('2', '116');
insert into public.sys_role_menu values ('2', '117');
insert into public.sys_role_menu values ('2', '500');
insert into public.sys_role_menu values ('2', '501');
insert into public.sys_role_menu values ('2', '1000');
insert into public.sys_role_menu values ('2', '1001');
insert into public.sys_role_menu values ('2', '1002');
insert into public.sys_role_menu values ('2', '1003');
insert into public.sys_role_menu values ('2', '1004');
insert into public.sys_role_menu values ('2', '1005');
insert into public.sys_role_menu values ('2', '1006');
insert into public.sys_role_menu values ('2', '1007');
insert into public.sys_role_menu values ('2', '1008');
insert into public.sys_role_menu values ('2', '1009');
insert into public.sys_role_menu values ('2', '1010');
insert into public.sys_role_menu values ('2', '1011');
insert into public.sys_role_menu values ('2', '1012');
insert into public.sys_role_menu values ('2', '1013');
insert into public.sys_role_menu values ('2', '1014');
insert into public.sys_role_menu values ('2', '1015');
insert into public.sys_role_menu values ('2', '1016');
insert into public.sys_role_menu values ('2', '1017');
insert into public.sys_role_menu values ('2', '1018');
insert into public.sys_role_menu values ('2', '1019');
insert into public.sys_role_menu values ('2', '1020');
insert into public.sys_role_menu values ('2', '1021');
insert into public.sys_role_menu values ('2', '1022');
insert into public.sys_role_menu values ('2', '1023');
insert into public.sys_role_menu values ('2', '1024');
insert into public.sys_role_menu values ('2', '1025');
insert into public.sys_role_menu values ('2', '1026');
insert into public.sys_role_menu values ('2', '1027');
insert into public.sys_role_menu values ('2', '1028');
insert into public.sys_role_menu values ('2', '1029');
insert into public.sys_role_menu values ('2', '1030');
insert into public.sys_role_menu values ('2', '1031');
insert into public.sys_role_menu values ('2', '1032');
insert into public.sys_role_menu values ('2', '1033');
insert into public.sys_role_menu values ('2', '1034');
insert into public.sys_role_menu values ('2', '1035');
insert into public.sys_role_menu values ('2', '1036');
insert into public.sys_role_menu values ('2', '1037');
insert into public.sys_role_menu values ('2', '1038');
insert into public.sys_role_menu values ('2', '1039');
insert into public.sys_role_menu values ('2', '1040');
insert into public.sys_role_menu values ('2', '1041');
insert into public.sys_role_menu values ('2', '1042');
insert into public.sys_role_menu values ('2', '1043');
insert into public.sys_role_menu values ('2', '1044');
insert into public.sys_role_menu values ('2', '1045');
insert into public.sys_role_menu values ('2', '1046');
insert into public.sys_role_menu values ('2', '1047');
insert into public.sys_role_menu values ('2', '1048');
insert into public.sys_role_menu values ('2', '1049');
insert into public.sys_role_menu values ('2', '1050');
insert into public.sys_role_menu values ('2', '1051');
insert into public.sys_role_menu values ('2', '1052');
insert into public.sys_role_menu values ('2', '1053');
insert into public.sys_role_menu values ('2', '1054');
insert into public.sys_role_menu values ('2', '1055');
insert into public.sys_role_menu values ('2', '1056');
insert into public.sys_role_menu values ('2', '1057');
insert into public.sys_role_menu values ('2', '1058');
insert into public.sys_role_menu values ('2', '1059');
insert into public.sys_role_menu values ('2', '1060');
-- ----------------------------
-- 8、角色和部门关联表 角色1-N部门
-- ----------------------------
drop table if exists public.sys_role_dept;
create table public.sys_role_dept (
role_id bigint(20) not null comment '角色ID',
dept_id bigint(20) not null comment '部门ID',
primary key(role_id, dept_id)
) engine=innodb comment = '角色和部门关联表';
-- ----------------------------
-- 初始化-角色和部门关联表数据
-- ----------------------------
insert into public.sys_role_dept values ('2', '100');
insert into public.sys_role_dept values ('2', '101');
insert into public.sys_role_dept values ('2', '105');
-- ----------------------------
-- 9、用户与岗位关联表 用户1-N岗位
-- ----------------------------
drop table if exists public.sys_user_post;
create table public.sys_user_post
(
user_id bigint(20) not null comment '用户ID',
post_id bigint(20) not null comment '岗位ID',
primary key (user_id, post_id)
) engine=innodb comment = '用户与岗位关联表';
-- ----------------------------
-- 初始化-用户与岗位关联表数据
-- ----------------------------
insert into public.sys_user_post values ('1', '1');
insert into public.sys_user_post values ('2', '2');
-- ----------------------------
-- 10、操作日志记录
-- ----------------------------
drop table if exists public.sys_oper_log;
create table public.sys_oper_log (
oper_id bigint(20) not null auto_increment comment '日志主键',
title varchar(50) default '' comment '模块标题',
business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)',
method varchar(200) default '' comment '方法名称',
request_method varchar(10) default '' comment '请求方式',
operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)',
oper_name varchar(50) default '' comment '操作人员',
dept_name varchar(50) default '' comment '部门名称',
oper_url varchar(255) default '' comment '请求URL',
oper_ip varchar(128) default '' comment '主机地址',
oper_location varchar(255) default '' comment '操作地点',
oper_param varchar(2000) default '' comment '请求参数',
json_result varchar(2000) default '' comment '返回参数',
status int(1) default 0 comment '操作状态(0正常 1异常)',
error_msg varchar(2000) default '' comment '错误消息',
oper_time datetime comment '操作时间',
cost_time bigint(20) default 0 comment '消耗时间',
primary key (oper_id),
key idx_sys_oper_log_bt (business_type),
key idx_sys_oper_log_s (status),
key idx_sys_oper_log_ot (oper_time)
) engine=innodb auto_increment=100 comment = '操作日志记录';
-- ----------------------------
-- 11、字典类型表
-- ----------------------------
drop table if exists public.sys_dict_type;
create table public.sys_dict_type
(
dict_id bigint(20) not null auto_increment comment '字典主键',
dict_name varchar(100) default '' comment '字典名称',
dict_type varchar(100) default '' comment '字典类型',
status char(1) default '0' comment '状态(0正常 1停用)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (dict_id),
unique (dict_type)
) engine=innodb auto_increment=100 comment = '字典类型表';
insert into public.sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表');
insert into public.sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表');
insert into public.sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表');
insert into public.sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', sysdate(), '', null, '任务状态列表');
insert into public.sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', sysdate(), '', null, '任务分组列表');
insert into public.sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表');
insert into public.sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表');
insert into public.sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表');
insert into public.sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表');
insert into public.sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表');
-- ----------------------------
-- 12、字典数据表
-- ----------------------------
drop table if exists public.sys_dict_data;
create table public.sys_dict_data
(
dict_code bigint(20) not null auto_increment comment '字典编码',
dict_sort int(4) default 0 comment '字典排序',
dict_label varchar(100) default '' comment '字典标签',
dict_value varchar(100) default '' comment '字典键值',
dict_type varchar(100) default '' comment '字典类型',
css_class varchar(100) default null comment '样式属性(其他样式扩展)',
list_class varchar(100) default null comment '表格回显样式',
is_default char(1) default 'N' comment '是否默认(Y是 N否)',
status char(1) default '0' comment '状态(0正常 1停用)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (dict_code)
) engine=innodb auto_increment=100 comment = '字典数据表';
insert into public.sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男');
insert into public.sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女');
insert into public.sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知');
insert into public.sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单');
insert into public.sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单');
insert into public.sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
insert into public.sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
insert into public.sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
insert into public.sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
insert into public.sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', sysdate(), '', null, '默认分组');
insert into public.sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', sysdate(), '', null, '系统分组');
insert into public.sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是');
insert into public.sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否');
insert into public.sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知');
insert into public.sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告');
insert into public.sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
insert into public.sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态');
insert into public.sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作');
insert into public.sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作');
insert into public.sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作');
insert into public.sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作');
insert into public.sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作');
insert into public.sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作');
insert into public.sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作');
insert into public.sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作');
insert into public.sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作');
insert into public.sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作');
insert into public.sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态');
insert into public.sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
-- ----------------------------
-- 13、参数配置表
-- ----------------------------
drop table if exists public.sys_config;
create table public.sys_config (
config_id int(5) not null auto_increment comment '参数主键',
config_name varchar(100) default '' comment '参数名称',
config_key varchar(100) default '' comment '参数键名',
config_value varchar(500) default '' comment '参数键值',
config_type char(1) default 'N' comment '系统内置(Y是 N否)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (config_id)
) engine=innodb auto_increment=100 comment = '参数配置表';
insert into public.sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
insert into public.sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
insert into public.sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' );
insert into public.sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
insert into public.sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
insert into public.sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
insert into public.sys_config values(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
insert into public.sys_config values(8, '用户管理-账号密码更新周期', 'sys.account.passwordValidateDays', '0', 'Y', 'admin', sysdate(), '', null, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框');
-- ----------------------------
-- 14、系统访问记录
-- ----------------------------
drop table if exists public.sys_logininfor;
create table public.sys_logininfor (
info_id bigint(20) not null auto_increment comment '访问ID',
user_name varchar(50) default '' comment '用户账号',
ipaddr varchar(128) default '' comment '登录IP地址',
login_location varchar(255) default '' comment '登录地点',
browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统',
status char(1) default '0' comment '登录状态(0成功 1失败)',
msg varchar(255) default '' comment '提示消息',
login_time datetime comment '访问时间',
primary key (info_id),
key idx_sys_logininfor_s (status),
key idx_sys_logininfor_lt (login_time)
) engine=innodb auto_increment=100 comment = '系统访问记录';
-- ----------------------------
-- 15、定时任务调度表
-- ----------------------------
drop table if exists public.sys_job;
create table public.sys_job (
job_id bigint(20) not null auto_increment comment '任务ID',
job_name varchar(64) default '' comment '任务名称',
job_group varchar(64) default 'DEFAULT' comment '任务组名',
invoke_target varchar(500) not null comment '调用目标字符串',
cron_expression varchar(255) default '' comment 'cron执行表达式',
misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)',
status char(1) default '0' comment '状态(0正常 1暂停)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default '' comment '备注信息',
primary key (job_id, job_name, job_group)
) engine=innodb auto_increment=100 comment = '定时任务调度表';
insert into public.sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
insert into public.sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(''ry'')', '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
insert into public.sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(''ry'', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
-- ----------------------------
-- 16、定时任务调度日志表
-- ----------------------------
drop table if exists public.sys_job_log;
create table public.sys_job_log (
job_log_id bigint(20) not null auto_increment comment '任务日志ID',
job_name varchar(64) not null comment '任务名称',
job_group varchar(64) not null comment '任务组名',
invoke_target varchar(500) not null comment '调用目标字符串',
job_message varchar(500) comment '日志信息',
status char(1) default '0' comment '执行状态(0正常 1失败)',
exception_info varchar(2000) default '' comment '异常信息',
create_time datetime comment '创建时间',
primary key (job_log_id)
) engine=innodb comment = '定时任务调度日志表';
-- ----------------------------
-- 17、通知公告表
-- ----------------------------
drop table if exists public.sys_notice;
create table public.sys_notice (
notice_id int(4) not null auto_increment comment '公告ID',
notice_title varchar(50) not null comment '公告标题',
notice_type char(1) not null comment '公告类型(1通知 2公告)',
notice_content longblob default null comment '公告内容',
status char(1) default '0' comment '公告状态(0正常 1关闭)',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(255) default null comment '备注',
primary key (notice_id)
) engine=innodb auto_increment=10 comment = '通知公告表';
-- ----------------------------
-- 初始化-公告信息表数据
-- ----------------------------
insert into public.sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');
insert into public.sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员');
-- ----------------------------
-- 18、代码生成业务表
-- ----------------------------
drop table if exists public.gen_table;
create table public.gen_table (
table_id bigint(20) not null auto_increment comment '编号',
table_name varchar(200) default '' comment '表名称',
table_comment varchar(500) default '' comment '表描述',
sub_table_name varchar(64) default null comment '关联子表的表名',
sub_table_fk_name varchar(64) default null comment '子表关联的外键名',
class_name varchar(100) default '' comment '实体类名称',
tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)',
tpl_web_type varchar(30) default '' comment '前端模板类型(element-ui模版 element-plus模版)',
package_name varchar(100) comment '生成包路径',
module_name varchar(30) comment '生成模块名',
business_name varchar(30) comment '生成业务名',
function_name varchar(50) comment '生成功能名',
function_author varchar(50) comment '生成功能作者',
gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)',
gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)',
options varchar(1000) comment '其它生成选项',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (table_id)
) engine=innodb auto_increment=1 comment = '代码生成业务表';
-- ----------------------------
-- 19、代码生成业务表字段
-- ----------------------------
drop table if exists public.gen_table_column;
create table public.gen_table_column (
column_id bigint(20) not null auto_increment comment '编号',
table_id bigint(20) comment '归属表编号',
column_name varchar(200) comment '列名称',
column_comment varchar(500) comment '列描述',
column_type varchar(100) comment '列类型',
java_type varchar(500) comment 'JAVA类型',
java_field varchar(200) comment 'JAVA字段名',
is_pk char(1) comment '是否主键(1是)',
is_increment char(1) comment '是否自增(1是)',
is_required char(1) comment '是否必填(1是)',
is_insert char(1) comment '是否为插入字段(1是)',
is_edit char(1) comment '是否编辑字段(1是)',
is_list char(1) comment '是否列表字段(1是)',
is_query char(1) comment '是否查询字段(1是)',
query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)',
html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
dict_type varchar(200) default '' comment '字典类型',
sort int comment '排序',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
primary key (column_id)
) engine=innodb auto_increment=1 comment = '代码生成业务表字段';
-- ==============================================================================
-- Quartz 定时任务调度表
-- ==============================================================================
drop table if exists public.QRTZ_FIRED_TRIGGERS;
drop table if exists public.QRTZ_PAUSED_TRIGGER_GRPS;
drop table if exists public.QRTZ_SCHEDULER_STATE;
drop table if exists public.QRTZ_LOCKS;
drop table if exists public.QRTZ_SIMPLE_TRIGGERS;
drop table if exists public.QRTZ_SIMPROP_TRIGGERS;
drop table if exists public.QRTZ_CRON_TRIGGERS;
drop table if exists public.QRTZ_BLOB_TRIGGERS;
drop table if exists public.QRTZ_TRIGGERS;
drop table if exists public.QRTZ_JOB_DETAILS;
drop table if exists public.QRTZ_CALENDARS;
-- ----------------------------
-- 1、存储每一个已配置的 jobDetail 的详细信息
-- ----------------------------
create table public.QRTZ_JOB_DETAILS (
sched_name varchar(120) not null comment '调度名称',
job_name varchar(200) not null comment '任务名称',
job_group varchar(200) not null comment '任务组名',
description varchar(250) null comment '相关介绍',
job_class_name varchar(250) not null comment '执行任务类名称',
is_durable varchar(1) not null comment '是否持久化',
is_nonconcurrent varchar(1) not null comment '是否并发',
is_update_data varchar(1) not null comment '是否更新数据',
requests_recovery varchar(1) not null comment '是否接受恢复执行',
job_data blob null comment '存放持久化job对象',
primary key (sched_name, job_name, job_group)
) engine=innodb comment = '任务详细信息表';
-- ----------------------------
-- 2、 存储已配置的 Trigger 的信息
-- ----------------------------
create table public.QRTZ_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
trigger_name varchar(200) not null comment '触发器的名字',
trigger_group varchar(200) not null comment '触发器所属组的名字',
job_name varchar(200) not null comment 'qrtz_job_details表job_name的外键',
job_group varchar(200) not null comment 'qrtz_job_details表job_group的外键',
description varchar(250) null comment '相关介绍',
next_fire_time bigint(13) null comment '上一次触发时间(毫秒)',
prev_fire_time bigint(13) null comment '下一次触发时间(默认为-1表示不触发)',
priority integer null comment '优先级',
trigger_state varchar(16) not null comment '触发器状态',
trigger_type varchar(8) not null comment '触发器的类型',
start_time bigint(13) not null comment '开始时间',
end_time bigint(13) null comment '结束时间',
calendar_name varchar(200) null comment '日程表名称',
misfire_instr smallint(2) null comment '补偿执行的策略',
job_data blob null comment '存放持久化job对象',
primary key (sched_name, trigger_name, trigger_group),
foreign key (sched_name, job_name, job_group) references public.QRTZ_JOB_DETAILS(sched_name, job_name, job_group)
) engine=innodb comment = '触发器详细信息表';
-- ----------------------------
-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
-- ----------------------------
create table public.QRTZ_SIMPLE_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
repeat_count bigint(7) not null comment '重复的次数统计',
repeat_interval bigint(12) not null comment '重复的间隔时间',
times_triggered bigint(10) not null comment '已经触发的次数',
primary key (sched_name, trigger_name, trigger_group),
foreign key (sched_name, trigger_name, trigger_group) references public.QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = '简单触发器的信息表';
-- ----------------------------
-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
-- ----------------------------
create table public.QRTZ_CRON_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
cron_expression varchar(200) not null comment 'cron表达式',
time_zone_id varchar(80) comment '时区',
primary key (sched_name, trigger_name, trigger_group),
foreign key (sched_name, trigger_name, trigger_group) references public.QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = 'Cron类型的触发器表';
-- ----------------------------
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
-- ----------------------------
create table public.QRTZ_BLOB_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
blob_data blob null comment '存放持久化Trigger对象',
primary key (sched_name, trigger_name, trigger_group),
foreign key (sched_name, trigger_name, trigger_group) references public.QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = 'Blob类型的触发器表';
-- ----------------------------
-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
-- ----------------------------
create table public.QRTZ_CALENDARS (
sched_name varchar(120) not null comment '调度名称',
calendar_name varchar(200) not null comment '日历名称',
calendar blob not null comment '存放持久化calendar对象',
primary key (sched_name, calendar_name)
) engine=innodb comment = '日历信息表';
-- ----------------------------
-- 7、 存储已暂停的 Trigger 组的信息
-- ----------------------------
create table public.QRTZ_PAUSED_TRIGGER_GRPS (
sched_name varchar(120) not null comment '调度名称',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
primary key (sched_name, trigger_group)
) engine=innodb comment = '暂停的触发器表';
-- ----------------------------
-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
-- ----------------------------
create table public.QRTZ_FIRED_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
entry_id varchar(95) not null comment '调度器实例id',
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
instance_name varchar(200) not null comment '调度器实例名',
fired_time bigint(13) not null comment '触发的时间',
sched_time bigint(13) not null comment '定时器制定的时间',
priority integer not null comment '优先级',
state varchar(16) not null comment '状态',
job_name varchar(200) null comment '任务名称',
job_group varchar(200) null comment '任务组名',
is_nonconcurrent varchar(1) null comment '是否并发',
requests_recovery varchar(1) null comment '是否接受恢复执行',
primary key (sched_name, entry_id)
) engine=innodb comment = '已触发的触发器表';
-- ----------------------------
-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
-- ----------------------------
create table public.QRTZ_SCHEDULER_STATE (
sched_name varchar(120) not null comment '调度名称',
instance_name varchar(200) not null comment '实例名称',
last_checkin_time bigint(13) not null comment '上次检查时间',
checkin_interval bigint(13) not null comment '检查间隔时间',
primary key (sched_name, instance_name)
) engine=innodb comment = '调度器状态表';
-- ----------------------------
-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
-- ----------------------------
create table public.QRTZ_LOCKS (
sched_name varchar(120) not null comment '调度名称',
lock_name varchar(40) not null comment '悲观锁名称',
primary key (sched_name, lock_name)
) engine=innodb comment = '存储的悲观锁信息表';
-- ----------------------------
-- 11、 Quartz集群实现同步机制的行锁表
-- ----------------------------
create table public.QRTZ_SIMPROP_TRIGGERS (
sched_name varchar(120) not null comment '调度名称',
trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键',
trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键',
str_prop_1 varchar(512) null comment 'String类型的trigger的第一个参数',
str_prop_2 varchar(512) null comment 'String类型的trigger的第二个参数',
str_prop_3 varchar(512) null comment 'String类型的trigger的第三个参数',
int_prop_1 int null comment 'int类型的trigger的第一个参数',
int_prop_2 int null comment 'int类型的trigger的第二个参数',
long_prop_1 bigint null comment 'long类型的trigger的第一个参数',
long_prop_2 bigint null comment 'long类型的trigger的第二个参数',
dec_prop_1 numeric(13,4) null comment 'decimal类型的trigger的第一个参数',
dec_prop_2 numeric(13,4) null comment 'decimal类型的trigger的第二个参数',
bool_prop_1 varchar(1) null comment 'Boolean类型的trigger的第一个参数',
bool_prop_2 varchar(1) null comment 'Boolean类型的trigger的第二个参数',
primary key (sched_name, trigger_name, trigger_group),
foreign key (sched_name, trigger_name, trigger_group) references public.QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
) engine=innodb comment = '同步机制的行锁表';
commit;
+619
View File
@@ -0,0 +1,619 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 02_training_v2_schema.sql (权威最终修复版)
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: public)
-- 依据来源:
-- 1. 融合工程最新真实 Java 实体类 (TrainAccommodation, TrainEnrollment, TrainResource, etc.)
-- 2. 最新 MyBatis Mapper XML (TrainAccommodationMapper, TrainClassroomInfoMapper, etc.)
-- 3. 权威迁移与结构基线:
-- - sql/train/v2/rollback/000_phase05_exact_schema.sql
-- - sql/train/v2/002_create_new_tables.sql
-- - sql/train/v2/003_alter_master_tables.sql
-- - sql/train/v2/004_rebuild_business_tables.sql
-- - sql/train/v2/005_constraints.sql
-- 覆盖范围: 全部 23 张培训业务表、完整列定义、主外键、唯一约束与业务索引
-- 安全设计:
-- 1. 纯净 DDL: 杜绝 DROP TABLE / TRUNCATE / CTAS,采用 CREATE TABLE IF NOT EXISTS
-- 2. 外键统一使用 ON DELETE NO ACTION (杜绝 CASCADE)
-- 3. 修复 train_accommodation(enrollment_id) 全局唯一冲突,采用部分唯一索引支持退宿与重新入住
-- 4. 字段名严格对齐 Mapper SQL (如 accommodation_id, class_room_id, resource_id, student_id, weight, door_auth_id)
-- 5. 显式限定 search_path 至 public
-- ==============================================================================
BEGIN;
SET search_path TO public, pg_catalog, sys_catalog;
-- ==============================================================================
-- 第一部分: 培训主数据表 (8 张)
-- ==============================================================================
-- 1. 教师主档表 (包含 person_no 门禁人员编号)
CREATE TABLE IF NOT EXISTS public.train_teacher (
t_id VARCHAR(32) NOT NULL,
t_name VARCHAR(50) NOT NULL,
person_no VARCHAR(32),
t_gender CHAR(1),
t_birth DATE,
t_department VARCHAR(50),
org_name VARCHAR(100),
job_title VARCHAR(50),
t_title VARCHAR(30),
t_phone VARCHAR(20),
t_email VARCHAR(100),
user_id BIGINT,
avatar VARCHAR(255),
major VARCHAR(100),
courses VARCHAR(255),
start_teaching DATE,
status SMALLINT DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_teacher PRIMARY KEY (t_id)
);
COMMENT ON TABLE public.train_teacher IS '教师主档表';
COMMENT ON COLUMN public.train_teacher.person_no IS '教师门禁/人脸人员编号 (对接 IoT 门禁系统)';
-- 2. 学员主档表 (包含 person_no, id_card_ciphertext, face_ref)
CREATE TABLE IF NOT EXISTS public.train_student (
s_id VARCHAR(32) NOT NULL,
s_name VARCHAR(50) NOT NULL,
person_no VARCHAR(32),
s_gender CHAR(1),
s_birth DATE,
org_name VARCHAR(100) NOT NULL,
s_phone VARCHAR(20),
s_email VARCHAR(100),
id_card_ciphertext TEXT,
id_card_hash VARCHAR(128),
id_card_last4 CHAR(4),
face_ref VARCHAR(255),
source_type SMALLINT NOT NULL DEFAULT 1,
user_id BIGINT,
avatar VARCHAR(255),
duty_level VARCHAR(64),
status SMALLINT NOT NULL DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_student PRIMARY KEY (s_id)
);
COMMENT ON TABLE public.train_student IS '学员主档表';
COMMENT ON COLUMN public.train_student.person_no IS '学员门禁/人脸人员编号 (对接 IoT 门禁系统,如 AA000001)';
COMMENT ON COLUMN public.train_student.id_card_ciphertext IS '身份证号加密密文';
COMMENT ON COLUMN public.train_student.face_ref IS '人脸特征或图片引用路径';
-- 3. 课程主表 (包含 resource_id 关联教学资源)
CREATE TABLE IF NOT EXISTS public.train_course (
c_id VARCHAR(32) NOT NULL,
c_name VARCHAR(100) NOT NULL,
c_code VARCHAR(50),
c_type SMALLINT,
c_duration INTEGER,
teaching_objective TEXT,
course_content TEXT,
resource_id VARCHAR(32),
status SMALLINT NOT NULL DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_course PRIMARY KEY (c_id)
);
COMMENT ON TABLE public.train_course IS '课程标准库主表';
-- 4. 教室信息表 (主键 class_room_id 严格对齐 Mapper 与 Phase 0.5 基线)
CREATE TABLE IF NOT EXISTS public.train_classroom_info (
class_room_id VARCHAR(32) NOT NULL,
room_name VARCHAR(50) NOT NULL,
room_location VARCHAR(100),
capacity INTEGER NOT NULL DEFAULT 30,
seat_arrange VARCHAR(100),
multimedia SMALLINT DEFAULT 0,
projector SMALLINT DEFAULT 0,
room_status SMALLINT NOT NULL DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_classroom_info PRIMARY KEY (class_room_id),
CONSTRAINT ck_classroom_capacity CHECK (capacity > 0)
);
COMMENT ON TABLE public.train_classroom_info IS '教室信息表';
COMMENT ON COLUMN public.train_classroom_info.class_room_id IS '教室唯一ID (对齐 TrainClassroomInfoMapper)';
-- 5. 实训场地信息表
CREATE TABLE IF NOT EXISTS public.train_training_site (
site_id VARCHAR(32) NOT NULL,
site_name VARCHAR(50) NOT NULL,
site_location VARCHAR(100),
capacity INTEGER NOT NULL DEFAULT 20,
site_device VARCHAR(200),
major VARCHAR(100),
seat_arrange VARCHAR(100),
site_status SMALLINT NOT NULL DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_training_site PRIMARY KEY (site_id),
CONSTRAINT ck_site_capacity CHECK (capacity > 0)
);
COMMENT ON TABLE public.train_training_site IS '实训场地信息表';
-- 6. 电子班牌终端表 (包含 api_endpoint)
CREATE TABLE IF NOT EXISTS public.train_electronic_board (
board_id VARCHAR(32) NOT NULL,
board_sn VARCHAR(50) NOT NULL,
board_name VARCHAR(50) NOT NULL,
bind_classroom_id VARCHAR(32),
board_ip VARCHAR(40),
api_endpoint VARCHAR(255),
support_checkin_type VARCHAR(100),
board_status SMALLINT NOT NULL DEFAULT 1,
last_heartbeat TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_electronic_board PRIMARY KEY (board_id)
);
COMMENT ON TABLE public.train_electronic_board IS '电子班牌终端表';
-- 7. 宿舍房间信息表 (包含 lock_device_sn)
CREATE TABLE IF NOT EXISTS public.train_dormitory_info (
dorm_id VARCHAR(32) NOT NULL,
dorm_building VARCHAR(50) NOT NULL,
dorm_floor VARCHAR(20) NOT NULL,
dorm_room VARCHAR(20) NOT NULL,
capacity INTEGER NOT NULL DEFAULT 4,
gender_type SMALLINT NOT NULL DEFAULT 1,
dorm_status SMALLINT NOT NULL DEFAULT 1,
lock_device_sn VARCHAR(64),
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_dormitory_info PRIMARY KEY (dorm_id),
CONSTRAINT ck_dorm_capacity CHECK (capacity > 0),
CONSTRAINT ck_dorm_gender CHECK (gender_type IN (1, 2))
);
COMMENT ON TABLE public.train_dormitory_info IS '宿舍房间信息表';
-- 8. 培训班级计划表 (字段与 TrainClassPlanMapper 严格对齐)
CREATE TABLE IF NOT EXISTS public.train_class_plan (
plan_id VARCHAR(32) NOT NULL,
plan_name VARCHAR(100) NOT NULL,
start_time TIMESTAMP,
end_time TIMESTAMP,
report_deadline TIMESTAMP,
train_address VARCHAR(255),
recruit_num INTEGER DEFAULT 0,
apply_condition TEXT,
plan_status SMALLINT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_class_plan PRIMARY KEY (plan_id)
);
COMMENT ON TABLE public.train_class_plan IS '培训班级计划表';
-- ==============================================================================
-- 第二部分: 教学与参训业务表 (8 张)
-- ==============================================================================
-- 9. 统一教学资源主表 (主键 resource_id 严格对齐 TrainResourceMapper)
CREATE TABLE IF NOT EXISTS public.train_resource (
resource_id VARCHAR(32) NOT NULL,
resource_name VARCHAR(150) NOT NULL,
resource_type SMALLINT NOT NULL,
resource_url TEXT NOT NULL,
description TEXT,
status SMALLINT NOT NULL DEFAULT 1,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
del_flag CHAR(1) NOT NULL DEFAULT '0',
CONSTRAINT pk_train_resource PRIMARY KEY (resource_id)
);
COMMENT ON TABLE public.train_resource IS '统一教学资源主表';
-- 10. 课程与教学资源关联表 (外键 resource_id 对齐 TrainCourseResourceMapper)
CREATE TABLE IF NOT EXISTS public.train_course_resource (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
c_id VARCHAR(32) NOT NULL,
resource_id VARCHAR(32) NOT NULL,
sort_no INTEGER DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT pk_train_course_resource PRIMARY KEY (id)
);
COMMENT ON TABLE public.train_course_resource IS '课程与教学资源关联表';
-- 11. 培训班与课程关联表 (主键 plan_course_id)
CREATE TABLE IF NOT EXISTS public.train_plan_course (
plan_course_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
plan_id VARCHAR(32) NOT NULL,
c_id VARCHAR(32) NOT NULL,
sort_no INTEGER DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_plan_course PRIMARY KEY (plan_course_id)
);
COMMENT ON TABLE public.train_plan_course IS '培训班与课程关联表';
-- 12. 学员参训报名表 (外键 student_id 对齐 TrainEnrollmentMapper)
CREATE TABLE IF NOT EXISTS public.train_enrollment (
enrollment_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
plan_id VARCHAR(32) NOT NULL,
student_id VARCHAR(32) NOT NULL,
source_type SMALLINT NOT NULL DEFAULT 1,
enrollment_status SMALLINT NOT NULL DEFAULT 0,
accommodation_required SMALLINT NOT NULL DEFAULT 0,
join_time TIMESTAMP,
complete_time TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_enrollment PRIMARY KEY (enrollment_id)
);
COMMENT ON TABLE public.train_enrollment IS '学员参训报名档案表';
COMMENT ON COLUMN public.train_enrollment.student_id IS '学员ID (关联 train_student.s_id)';
-- 13. 宿舍住宿安排表 (主键 accommodation_id, accommodation_status, assigned_time)
-- 依据 sql/train/v2/002_create_new_tables.sql 行 136-156 与 TrainAccommodationMapper
CREATE TABLE IF NOT EXISTS public.train_accommodation (
accommodation_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
dorm_id VARCHAR(32) NOT NULL,
bed_no VARCHAR(20),
assigned_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
accommodation_status SMALLINT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_accommodation PRIMARY KEY (accommodation_id)
);
COMMENT ON TABLE public.train_accommodation IS '宿舍住宿安排记录表';
COMMENT ON COLUMN public.train_accommodation.accommodation_id IS '住宿安排ID (自增主键)';
COMMENT ON COLUMN public.train_accommodation.accommodation_status IS '住宿状态 (0:预分配, 1:已入住, 2:已退宿)';
-- 14. 培训课表排课记录表 (外键关联 plan_course_id, class_room_id)
CREATE TABLE IF NOT EXISTS public.train_lesson (
lesson_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
plan_course_id BIGINT NOT NULL,
t_id VARCHAR(32) NOT NULL,
start_time TIMESTAMP NOT NULL,
end_time TIMESTAMP NOT NULL,
venue_type SMALLINT NOT NULL,
class_room_id VARCHAR(32),
site_id VARCHAR(32),
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_lesson PRIMARY KEY (lesson_id),
CONSTRAINT ck_lesson_time CHECK (end_time > start_time),
CONSTRAINT ck_lesson_venue CHECK (
(venue_type = 1 AND class_room_id IS NOT NULL AND site_id IS NULL) OR
(venue_type = 2 AND site_id IS NOT NULL AND class_room_id IS NULL)
)
);
COMMENT ON TABLE public.train_lesson IS '培训课表排课记录表';
-- 15. 课程考核分项配置表 (列名 weight, score_item_id 对齐 002 及 TrainScoreInfoMapper)
CREATE TABLE IF NOT EXISTS public.train_score_item (
score_item_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
plan_id VARCHAR(32) NOT NULL,
plan_course_id BIGINT,
item_name VARCHAR(100) NOT NULL,
item_type SMALLINT NOT NULL DEFAULT 1,
weight NUMERIC(5,2) NOT NULL DEFAULT 0.00,
full_score NUMERIC(5,2) NOT NULL DEFAULT 100.00,
sort_no INTEGER DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_score_item PRIMARY KEY (score_item_id),
CONSTRAINT ck_score_item_weight CHECK (weight >= 0.00 AND weight <= 100.00)
);
COMMENT ON TABLE public.train_score_item IS '课程考核分项配置表';
COMMENT ON COLUMN public.train_score_item.weight IS '所占综合权重百分比 (对齐 002_create_new_tables)';
-- 16. 学员考核成绩明细表 (关联 score_item_id, enrollment_id)
CREATE TABLE IF NOT EXISTS public.train_student_score (
score_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
score_item_id BIGINT NOT NULL,
score NUMERIC(7,2) NOT NULL,
source_type SMALLINT NOT NULL DEFAULT 1,
source_system VARCHAR(100),
source_event_id VARCHAR(100),
import_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_student_score PRIMARY KEY (score_id),
CONSTRAINT ck_student_score_val CHECK (score >= 0.00)
);
COMMENT ON TABLE public.train_student_score IS '学员考核成绩明细表';
-- ==============================================================================
-- 第三部分: 业务过程扩展表 (5 张)
-- ==============================================================================
-- 17. 门禁授权同步过程表 (包含完整 DMS/物联桥接状态列)
CREATE TABLE IF NOT EXISTS public.train_dorm_auth (
auth_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
accommodation_id BIGINT NOT NULL,
auth_status VARCHAR(32) DEFAULT 'PENDING',
credential_type VARCHAR(32) DEFAULT 'FACE',
latest_operation_id BIGINT,
operation_version BIGINT DEFAULT 0,
auth_start TIMESTAMP,
auth_end TIMESTAMP,
face_sync_status SMALLINT NOT NULL DEFAULT 0,
retry_count INTEGER NOT NULL DEFAULT 0,
last_error VARCHAR(500),
external_auth_id VARCHAR(100),
last_sync_time TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_dorm_auth PRIMARY KEY (auth_id)
);
COMMENT ON TABLE public.train_dorm_auth IS '宿舍门禁授权同步过程表';
-- 18. 班级报到记录表
CREATE TABLE IF NOT EXISTS public.train_class_report (
report_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
report_way SMALLINT NOT NULL DEFAULT 1,
report_device_sn VARCHAR(64),
report_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
verify_result SMALLINT NOT NULL DEFAULT 1,
verify_note VARCHAR(500),
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_class_report PRIMARY KEY (report_id)
);
COMMENT ON TABLE public.train_class_report IS '班级报到记录表';
-- 19. 学员课次考勤打卡表
CREATE TABLE IF NOT EXISTS public.train_student_checkin (
checkin_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
lesson_id BIGINT NOT NULL,
board_id VARCHAR(32),
checkin_way SMALLINT NOT NULL DEFAULT 1,
sign_in_time TIMESTAMP,
sign_out_time TIMESTAMP,
attendance_status SMALLINT NOT NULL DEFAULT 0,
manual_flag SMALLINT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_student_checkin PRIMARY KEY (checkin_id)
);
COMMENT ON TABLE public.train_student_checkin IS '学员课次考勤打卡记录表';
-- 20. 实际学习学时记录表 (主键 dur_id)
CREATE TABLE IF NOT EXISTS public.train_study_duration (
dur_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
plan_course_id BIGINT,
resource_id VARCHAR(32),
learning_content VARCHAR(200),
source_system VARCHAR(100),
source_event_id VARCHAR(100),
start_time TIMESTAMP,
end_time TIMESTAMP,
study_seconds INTEGER NOT NULL DEFAULT 0,
sync_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_study_duration PRIMARY KEY (dur_id),
CONSTRAINT ck_study_seconds CHECK (study_seconds >= 0)
);
COMMENT ON TABLE public.train_study_duration IS '实际学习学时记录表';
-- 21. 学员培训画像统计表
CREATE TABLE IF NOT EXISTS public.train_student_portrait (
portrait_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
enrollment_id BIGINT NOT NULL,
attendance_rate NUMERIC(5,2),
theory_score NUMERIC(7,2),
practical_score NUMERIC(7,2),
total_study_hour NUMERIC(8,2),
label_tag TEXT,
portrait_content TEXT,
generated_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_student_portrait PRIMARY KEY (portrait_id)
);
COMMENT ON TABLE public.train_student_portrait IS '学员培训画像综合统计表';
-- ==============================================================================
-- 第四部分: 外部资源对接与操作审计表 (2 张)
-- ==============================================================================
-- 22. 外部资源映射关联表 (DMS 适配支持)
CREATE TABLE IF NOT EXISTS public.train_external_resource_mapping (
mapping_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
dorm_id VARCHAR(32) NOT NULL,
vendor_code VARCHAR(32) NOT NULL,
local_resource_type VARCHAR(32) NOT NULL,
external_resource_type VARCHAR(32) NOT NULL,
external_resource_id VARCHAR(64) NOT NULL,
external_parent_id VARCHAR(64),
external_hardware_id VARCHAR(64),
external_project_id VARCHAR(64),
is_primary SMALLINT NOT NULL DEFAULT 1,
mapping_status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
last_sync_time TIMESTAMP,
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_ext_res_map PRIMARY KEY (mapping_id)
);
COMMENT ON TABLE public.train_external_resource_mapping IS '外部资源映射关联表';
-- 23. 外部对接操作流水与补偿表 (列名 door_auth_id, business_type 严格对齐 Mapper)
CREATE TABLE IF NOT EXISTS public.train_external_operation (
operation_id BIGINT GENERATED BY DEFAULT AS IDENTITY,
door_auth_id BIGINT,
business_type VARCHAR(32) NOT NULL,
vendor_code VARCHAR(32) NOT NULL,
operation_type VARCHAR(32) NOT NULL,
operation_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
idempotency_key VARCHAR(64) NOT NULL,
external_operation_id VARCHAR(64),
external_request_type VARCHAR(64),
external_hardware_id VARCHAR(64),
external_key_id VARCHAR(64),
attempt_count INTEGER NOT NULL DEFAULT 0,
next_poll_time TIMESTAMP,
requested_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
last_error_code VARCHAR(64),
last_error_message VARCHAR(500),
create_by VARCHAR(64),
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP,
remark VARCHAR(500),
CONSTRAINT pk_train_external_operation PRIMARY KEY (operation_id)
);
COMMENT ON TABLE public.train_external_operation IS '外部对接操作流水与补偿表';
COMMENT ON COLUMN public.train_external_operation.door_auth_id IS '门锁授权ID (对齐 TrainExternalOperationMapper)';
COMMENT ON COLUMN public.train_external_operation.business_type IS '业务类型 (对齐 TrainExternalOperationMapper)';
-- ==============================================================================
-- 第五部分: 唯一约束 (UNIQUE)
-- ==============================================================================
ALTER TABLE public.train_student ADD CONSTRAINT uq_student_idcard_hash UNIQUE (id_card_hash);
CREATE UNIQUE INDEX IF NOT EXISTS uq_student_person_no ON public.train_student (person_no) WHERE person_no IS NOT NULL AND del_flag = '0';
CREATE UNIQUE INDEX IF NOT EXISTS uq_teacher_person_no ON public.train_teacher (person_no) WHERE person_no IS NOT NULL AND del_flag = '0';
ALTER TABLE public.train_course ADD CONSTRAINT uq_course_code UNIQUE (c_code);
ALTER TABLE public.train_electronic_board ADD CONSTRAINT uq_board_sn UNIQUE (board_sn);
ALTER TABLE public.train_dormitory_info ADD CONSTRAINT uq_dorm_building_room UNIQUE (dorm_building, dorm_room);
ALTER TABLE public.train_course_resource ADD CONSTRAINT uq_course_resource UNIQUE (c_id, resource_id);
ALTER TABLE public.train_plan_course ADD CONSTRAINT uq_plan_course UNIQUE (plan_id, c_id);
ALTER TABLE public.train_enrollment ADD CONSTRAINT uq_enrollment UNIQUE (plan_id, student_id);
-- 【核心修复】废弃硬性全局 UNIQUE(enrollment_id),使用部分唯一索引保障:同一参训档案至多拥有1条激活中住宿(0预分配或1入住),同时支持历史退宿与重新入住
CREATE UNIQUE INDEX IF NOT EXISTS uq_accommodation_active_enroll
ON public.train_accommodation (enrollment_id)
WHERE accommodation_status IN (0, 1);
ALTER TABLE public.train_dorm_auth ADD CONSTRAINT uq_dorm_auth_accomm UNIQUE (accommodation_id);
ALTER TABLE public.train_class_report ADD CONSTRAINT uq_class_report_enroll UNIQUE (enrollment_id);
ALTER TABLE public.train_student_checkin ADD CONSTRAINT uq_student_checkin_enroll_lesson UNIQUE (enrollment_id, lesson_id);
CREATE UNIQUE INDEX IF NOT EXISTS uq_study_duration_idempotent ON public.train_study_duration (source_system, source_event_id) WHERE source_system IS NOT NULL AND source_event_id IS NOT NULL;
ALTER TABLE public.train_student_portrait ADD CONSTRAINT uq_student_portrait_enroll UNIQUE (enrollment_id);
CREATE UNIQUE INDEX IF NOT EXISTS uq_ext_res_map_vendor_dorm ON public.train_external_resource_mapping (vendor_code, dorm_id);
CREATE UNIQUE INDEX IF NOT EXISTS uq_ext_op_idempotency ON public.train_external_operation (idempotency_key);
-- ==============================================================================
-- 第六部分: 外键约束 (FOREIGN KEY - ON DELETE NO ACTION)
-- ==============================================================================
ALTER TABLE public.train_course_resource ADD CONSTRAINT fk_cr_course FOREIGN KEY (c_id) REFERENCES public.train_course(c_id) ON DELETE NO ACTION;
ALTER TABLE public.train_course_resource ADD CONSTRAINT fk_cr_resource FOREIGN KEY (resource_id) REFERENCES public.train_resource(resource_id) ON DELETE NO ACTION;
ALTER TABLE public.train_plan_course ADD CONSTRAINT fk_pc_plan FOREIGN KEY (plan_id) REFERENCES public.train_class_plan(plan_id) ON DELETE NO ACTION;
ALTER TABLE public.train_plan_course ADD CONSTRAINT fk_pc_course FOREIGN KEY (c_id) REFERENCES public.train_course(c_id) ON DELETE NO ACTION;
ALTER TABLE public.train_enrollment ADD CONSTRAINT fk_enroll_plan FOREIGN KEY (plan_id) REFERENCES public.train_class_plan(plan_id) ON DELETE NO ACTION;
ALTER TABLE public.train_enrollment ADD CONSTRAINT fk_enroll_student FOREIGN KEY (student_id) REFERENCES public.train_student(s_id) ON DELETE NO ACTION;
ALTER TABLE public.train_accommodation ADD CONSTRAINT fk_accomm_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_accommodation ADD CONSTRAINT fk_accomm_dorm FOREIGN KEY (dorm_id) REFERENCES public.train_dormitory_info(dorm_id) ON DELETE NO ACTION;
ALTER TABLE public.train_lesson ADD CONSTRAINT fk_lesson_pc FOREIGN KEY (plan_course_id) REFERENCES public.train_plan_course(plan_course_id) ON DELETE NO ACTION;
ALTER TABLE public.train_lesson ADD CONSTRAINT fk_lesson_teacher FOREIGN KEY (t_id) REFERENCES public.train_teacher(t_id) ON DELETE NO ACTION;
ALTER TABLE public.train_lesson ADD CONSTRAINT fk_lesson_classroom FOREIGN KEY (class_room_id) REFERENCES public.train_classroom_info(class_room_id) ON DELETE NO ACTION;
ALTER TABLE public.train_lesson ADD CONSTRAINT fk_lesson_site FOREIGN KEY (site_id) REFERENCES public.train_training_site(site_id) ON DELETE NO ACTION;
ALTER TABLE public.train_score_item ADD CONSTRAINT fk_si_plan FOREIGN KEY (plan_id) REFERENCES public.train_class_plan(plan_id) ON DELETE NO ACTION;
ALTER TABLE public.train_student_score ADD CONSTRAINT fk_ss_item FOREIGN KEY (score_item_id) REFERENCES public.train_score_item(score_item_id) ON DELETE NO ACTION;
ALTER TABLE public.train_student_score ADD CONSTRAINT fk_ss_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_dorm_auth ADD CONSTRAINT fk_da_accomm FOREIGN KEY (accommodation_id) REFERENCES public.train_accommodation(accommodation_id) ON DELETE NO ACTION;
ALTER TABLE public.train_class_report ADD CONSTRAINT fk_cr_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_student_checkin ADD CONSTRAINT fk_sci_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_student_checkin ADD CONSTRAINT fk_sci_lesson FOREIGN KEY (lesson_id) REFERENCES public.train_lesson(lesson_id) ON DELETE NO ACTION;
ALTER TABLE public.train_study_duration ADD CONSTRAINT fk_sd_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_student_portrait ADD CONSTRAINT fk_sp_enroll FOREIGN KEY (enrollment_id) REFERENCES public.train_enrollment(enrollment_id) ON DELETE NO ACTION;
ALTER TABLE public.train_external_resource_mapping ADD CONSTRAINT fk_erm_dorm FOREIGN KEY (dorm_id) REFERENCES public.train_dormitory_info(dorm_id) ON DELETE NO ACTION;
-- ==============================================================================
-- 第七部分: 业务索引 (INDEXES)
-- ==============================================================================
CREATE INDEX IF NOT EXISTS idx_teacher_user_id ON public.train_teacher (user_id);
CREATE INDEX IF NOT EXISTS idx_teacher_person_no ON public.train_teacher (person_no);
CREATE INDEX IF NOT EXISTS idx_student_user_id ON public.train_student (user_id);
CREATE INDEX IF NOT EXISTS idx_student_person_no ON public.train_student (person_no);
CREATE INDEX IF NOT EXISTS idx_course_status ON public.train_course (status);
CREATE INDEX IF NOT EXISTS idx_dorm_gender ON public.train_dormitory_info (gender_type, dorm_status);
CREATE INDEX IF NOT EXISTS idx_dorm_lock_sn ON public.train_dormitory_info (lock_device_sn);
CREATE INDEX IF NOT EXISTS idx_class_plan_date ON public.train_class_plan (start_time, end_time);
CREATE INDEX IF NOT EXISTS idx_class_plan_status ON public.train_class_plan (plan_status);
CREATE INDEX IF NOT EXISTS idx_enrollment_plan ON public.train_enrollment (plan_id, enrollment_status);
CREATE INDEX IF NOT EXISTS idx_accommodation_dorm ON public.train_accommodation (dorm_id, accommodation_status);
CREATE INDEX IF NOT EXISTS idx_lesson_pc ON public.train_lesson (plan_course_id);
CREATE INDEX IF NOT EXISTS idx_lesson_teacher ON public.train_lesson (t_id);
CREATE INDEX IF NOT EXISTS idx_score_item_plan ON public.train_score_item (plan_id);
CREATE INDEX IF NOT EXISTS idx_student_score_enroll ON public.train_student_score (enrollment_id);
CREATE INDEX IF NOT EXISTS idx_dorm_auth_sync ON public.train_dorm_auth (face_sync_status, auth_status);
COMMIT;
@@ -0,0 +1,762 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 03_system_permissions_and_menus.sql (规范事务版)
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: public)
-- 来源追溯: sql/system/kingbase/ (004, 005, 009, 010, 012, 014, 015)
-- 包含内容: 培训业务三大角色 (train_admin, train_teacher, train_student)、
-- 业务端系统菜单、按钮权限、身份绑定索引与角色菜单关联
-- 事务边界: 严格单一事务 (首尾单次 BEGIN ... COMMIT,无内部嵌套事务)
-- ==============================================================================
BEGIN;
SET search_path TO public, pg_catalog, sys_catalog;
-- >>> 来源模块: sql/system/kingbase/004_rbac_identity_binding.sql >>>
-- =============================================================================
-- RailwaySystem 数据库 RBAC 迁移脚本: 004_rbac_identity_binding.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- 执行目标: 建立 sys_user 与业务主体(教师/学员)物理约束与部分唯一索引
-- 事务边界: 全程在显式事务 BEGIN ... COMMIT 中执行
-- 幂等保证: 仅使用 ADD COLUMN IF NOT EXISTS 与 CREATE INDEX IF NOT EXISTS,严禁 DROP / TRUNCATE
-- 设计依据: docs/development/rbac-r2/01_identity_binding_design.md 及 06_migration_plan.md
-- =============================================================================
-- 步骤 1: 确保 user_id 列存在 (幂等容错,已存在则静默跳过)
ALTER TABLE public.train_teacher ADD COLUMN IF NOT EXISTS user_id BIGINT;
ALTER TABLE public.train_student ADD COLUMN IF NOT EXISTS user_id BIGINT;
-- 步骤 2: 建立教师账号部分唯一索引 (无 DROP,幂等容错,忽略已删除 del_flag='2' 与空值)
CREATE UNIQUE INDEX IF NOT EXISTS uq_train_teacher_user_id
ON public.train_teacher(user_id)
WHERE user_id IS NOT NULL AND del_flag = '0';
-- 步骤 3: 建立学员账号部分唯一索引 (无 DROP,幂等容错,忽略已删除 del_flag='2' 与空值)
CREATE UNIQUE INDEX IF NOT EXISTS uq_train_student_user_id
ON public.train_student(user_id)
WHERE user_id IS NOT NULL AND del_flag = '0';
-- 步骤 4: 更新字段元数据注释
COMMENT ON COLUMN train_teacher.user_id IS '关联sys_user.user_id (唯一绑定教师登录账号)';
COMMENT ON COLUMN train_student.user_id IS '关联sys_user.user_id (唯一绑定学员登录账号)';
-- 步骤 5: 迁移完整性校验
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_indexes
WHERE tablename = 'train_teacher' AND indexname = 'uq_train_teacher_user_id'
) THEN
RAISE EXCEPTION 'uq_train_teacher_user_id partial unique index creation failed';
END IF;
IF NOT EXISTS (
SELECT 1 FROM pg_indexes
WHERE tablename = 'train_student' AND indexname = 'uq_train_student_user_id'
) THEN
RAISE EXCEPTION 'uq_train_student_user_id partial unique index creation failed';
END IF;
END $$;
-- >>> 来源模块: sql/system/kingbase/005_training_roles_permissions.sql >>>
-- =============================================================================
-- RailwaySystem 数据库 RBAC 迁移脚本: 005_training_roles_permissions.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- 执行目标: 预置培训业务三角色、统一班牌权限命名空间、补齐按钮权限与角色关联
-- 事务边界: 全程在显式事务 BEGIN ... COMMIT 中执行
-- 防御保证: 内置 Collision Guard 静态检查,绝不覆盖已有外来资源,冲突即显式 ABORT
-- 设计依据: docs/development/rbac-r2/02_role_permission_matrix.md 及 06_migration_plan.md
-- =============================================================================
-- =============================================================================
-- 步骤 0: ID 碰撞安全守卫 (Migration Collision Guard)
-- =============================================================================
DO $$
DECLARE
rec RECORD;
BEGIN
-- 0.1 检查 role_id 3, 4, 5 的碰撞与业务键一致性
FOR rec IN SELECT role_id, role_key FROM public.sys_role WHERE role_id IN (3, 4, 5)
LOOP
IF rec.role_id = 3 AND rec.role_key <> 'train_admin' THEN
RAISE EXCEPTION 'Collision detected: sys_role.role_id=3 is already occupied by role_key=%', rec.role_key;
ELSIF rec.role_id = 4 AND rec.role_key <> 'train_teacher' THEN
RAISE EXCEPTION 'Collision detected: sys_role.role_id=4 is already occupied by role_key=%', rec.role_key;
ELSIF rec.role_id = 5 AND rec.role_key <> 'train_student' THEN
RAISE EXCEPTION 'Collision detected: sys_role.role_id=5 is already occupied by role_key=%', rec.role_key;
END IF;
END LOOP;
-- 0.2 检查 role_key 存在时是否与预期 role_id 发生错位
FOR rec IN SELECT role_id, role_key FROM public.sys_role WHERE role_key IN ('train_admin', 'train_teacher', 'train_student')
LOOP
IF rec.role_key = 'train_admin' AND rec.role_id <> 3 THEN
RAISE EXCEPTION 'Collision detected: role_key=train_admin exists with mismatched role_id=%', rec.role_id;
ELSIF rec.role_key = 'train_teacher' AND rec.role_id <> 4 THEN
RAISE EXCEPTION 'Collision detected: role_key=train_teacher exists with mismatched role_id=%', rec.role_id;
ELSIF rec.role_key = 'train_student' AND rec.role_id <> 5 THEN
RAISE EXCEPTION 'Collision detected: role_key=train_student exists with mismatched role_id=%', rec.role_id;
END IF;
END LOOP;
-- 0.3 检查 menu_id 2201 ~ 2244 的碰撞:若ID已存在,必须属于预期本系统权限,严禁覆盖外来资源
IF EXISTS (
SELECT 1 FROM public.sys_menu
WHERE menu_id BETWEEN 2201 AND 2244
AND (perms IS NULL OR perms NOT LIKE 'train:%')
) THEN
RAISE EXCEPTION 'Collision detected: sys_menu.menu_id in 2201..2244 is occupied by non-train permissions';
END IF;
END $$;
-- =============================================================================
-- 步骤 1: 预置 3 个核心业务角色 (train_admin, train_teacher, train_student)
-- =============================================================================
INSERT INTO public.sys_role
(role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly,
status, del_flag, create_by, create_time, update_by, update_time, remark)
SELECT 3, '培训管理员', 'train_admin', 3, '1', 1, 1,
'0', '0', 'admin', CURRENT_TIMESTAMP, '', NULL, '一期业务全局管理角色'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role WHERE role_id = 3 OR role_key = 'train_admin');
INSERT INTO public.sys_role
(role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly,
status, del_flag, create_by, create_time, update_by, update_time, remark)
SELECT 4, '培训教师', 'train_teacher', 4, '2', 1, 1,
'0', '0', 'admin', CURRENT_TIMESTAMP, '', NULL, '教师专属教学工作台'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role WHERE role_id = 4 OR role_key = 'train_teacher');
INSERT INTO public.sys_role
(role_id, role_name, role_key, role_sort, data_scope, menu_check_strictly, dept_check_strictly,
status, del_flag, create_by, create_time, update_by, update_time, remark)
SELECT 5, '培训学员', 'train_student', 5, '2', 1, 1,
'0', '0', 'admin', CURRENT_TIMESTAMP, '', NULL, '学员专属个人培训中心'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role WHERE role_id = 5 OR role_key = 'train_student');
-- =============================================================================
-- 步骤 2: 规范统一电子班牌权限命名空间 (system:board:* -> train:board:*)
-- =============================================================================
UPDATE public.sys_menu
SET perms = REPLACE(perms, 'system:board:', 'train:board:'),
update_by = 'admin',
update_time = CURRENT_TIMESTAMP
WHERE perms LIKE 'system:board:%';
-- =============================================================================
-- 步骤 3: 补齐基础培训管理模块按钮级权限 (sys_menu, menu_type='F')
-- =============================================================================
-- 3.1 教师管理 (parent: 2155)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2201, '教师查询', 2155, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:list', '#', 'admin', CURRENT_TIMESTAMP, '教师列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2201 OR perms = 'train:teacher:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2202, '教师详情', 2155, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:query', '#', 'admin', CURRENT_TIMESTAMP, '教师详情查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2202 OR perms = 'train:teacher:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2203, '教师新增', 2155, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:add', '#', 'admin', CURRENT_TIMESTAMP, '教师新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2203 OR perms = 'train:teacher:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2204, '教师修改', 2155, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:edit', '#', 'admin', CURRENT_TIMESTAMP, '教师修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2204 OR perms = 'train:teacher:edit');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2241, '教师账号关联', 2155, 5, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:bindUser', '#', 'admin', CURRENT_TIMESTAMP, '教师系统账号关联'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2241 OR perms = 'train:teacher:bindUser');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2242, '教师账号解绑', 2155, 6, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:unbindUser', '#', 'admin', CURRENT_TIMESTAMP, '教师系统账号解绑'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2242 OR perms = 'train:teacher:unbindUser');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2245, '教师删除', 2155, 7, '#', '', '', 1, 0, 'F', '0', '0', 'train:teacher:remove', '#', 'admin', CURRENT_TIMESTAMP, '教师档案安全删除'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2245 OR perms = 'train:teacher:remove');
-- 3.2 学员管理 (parent: 2156)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2205, '学员查询', 2156, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:list', '#', 'admin', CURRENT_TIMESTAMP, '学员列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2205 OR perms = 'train:student:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2206, '学员详情', 2156, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:query', '#', 'admin', CURRENT_TIMESTAMP, '学员详情查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2206 OR perms = 'train:student:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2207, '学员新增', 2156, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:add', '#', 'admin', CURRENT_TIMESTAMP, '学员新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2207 OR perms = 'train:student:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2243, '学员账号关联', 2156, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:bindUser', '#', 'admin', CURRENT_TIMESTAMP, '学员系统账号关联'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2243 OR perms = 'train:student:bindUser');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2244, '学员账号解绑', 2156, 5, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:unbindUser', '#', 'admin', CURRENT_TIMESTAMP, '学员系统账号解绑'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2244 OR perms = 'train:student:unbindUser');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2246, '学员删除', 2156, 6, '#', '', '', 1, 0, 'F', '0', '0', 'train:student:remove', '#', 'admin', CURRENT_TIMESTAMP, '学员档案安全删除'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2246 OR perms = 'train:student:remove');
-- 3.3 教室管理 (parent: 2157)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2208, '教室查询', 2157, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:classroom:list', '#', 'admin', CURRENT_TIMESTAMP, '教室列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2208 OR perms = 'train:classroom:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2209, '教室修改', 2157, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:classroom:edit', '#', 'admin', CURRENT_TIMESTAMP, '教室修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2209 OR perms = 'train:classroom:edit');
-- 3.4 实训场地 (parent: 2158)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2210, '场地查询', 2158, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:site:list', '#', 'admin', CURRENT_TIMESTAMP, '实训场地列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2210 OR perms = 'train:site:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2211, '场地修改', 2158, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:site:edit', '#', 'admin', CURRENT_TIMESTAMP, '实训场地修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2211 OR perms = 'train:site:edit');
-- 3.5 宿舍管理 (parent: 2161)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2212, '宿舍查询', 2161, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:dormitory:list', '#', 'admin', CURRENT_TIMESTAMP, '宿舍列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2212 OR perms = 'train:dormitory:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2213, '宿舍修改', 2161, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:dormitory:edit', '#', 'admin', CURRENT_TIMESTAMP, '宿舍修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2213 OR perms = 'train:dormitory:edit');
-- 3.6 课程管理 (parent: 2163)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2214, '课程查询', 2163, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:course:list', '#', 'admin', CURRENT_TIMESTAMP, '课程列表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2214 OR perms = 'train:course:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2215, '课程详情', 2163, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:course:query', '#', 'admin', CURRENT_TIMESTAMP, '课程详情查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2215 OR perms = 'train:course:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2216, '课程新增', 2163, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:course:add', '#', 'admin', CURRENT_TIMESTAMP, '课程新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2216 OR perms = 'train:course:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2217, '课程修改', 2163, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:course:edit', '#', 'admin', CURRENT_TIMESTAMP, '课程修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2217 OR perms = 'train:course:edit');
-- 3.7 培训计划 (parent: 2164)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2218, '计划查询', 2164, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:plan:list', '#', 'admin', CURRENT_TIMESTAMP, '培训计划列表'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2218 OR perms = 'train:plan:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2219, '计划详情', 2164, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:plan:query', '#', 'admin', CURRENT_TIMESTAMP, '培训计划详情'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2219 OR perms = 'train:plan:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2220, '计划新增', 2164, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:plan:add', '#', 'admin', CURRENT_TIMESTAMP, '培训计划新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2220 OR perms = 'train:plan:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2221, '计划修改', 2164, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:plan:edit', '#', 'admin', CURRENT_TIMESTAMP, '培训计划修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2221 OR perms = 'train:plan:edit');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2222, '计划结训', 2164, 5, '#', '', '', 1, 0, 'F', '0', '0', 'train:plan:complete', '#', 'admin', CURRENT_TIMESTAMP, '培训计划结束归档'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2222 OR perms = 'train:plan:complete');
-- 3.8 课次与排课 (parent: 2164)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2223, '排课查询', 2164, 6, '#', '', '', 1, 0, 'F', '0', '0', 'train:lesson:query', '#', 'admin', CURRENT_TIMESTAMP, '排课课表查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2223 OR perms = 'train:lesson:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2224, '排课新增', 2164, 7, '#', '', '', 1, 0, 'F', '0', '0', 'train:lesson:add', '#', 'admin', CURRENT_TIMESTAMP, '排课课次新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2224 OR perms = 'train:lesson:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2225, '排课修改', 2164, 8, '#', '', '', 1, 0, 'F', '0', '0', 'train:lesson:edit', '#', 'admin', CURRENT_TIMESTAMP, '排课课次修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2225 OR perms = 'train:lesson:edit');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2226, '排课删除', 2164, 9, '#', '', '', 1, 0, 'F', '0', '0', 'train:lesson:remove', '#', 'admin', CURRENT_TIMESTAMP, '排课课次删除'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2226 OR perms = 'train:lesson:remove');
-- 3.9 参训学员分班 (parent: 2164)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2227, '参训名单查询', 2164, 10, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:list', '#', 'admin', CURRENT_TIMESTAMP, '参训花名册列表'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2227 OR perms = 'train:enrollment:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2228, '参训记录详情', 2164, 11, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:query', '#', 'admin', CURRENT_TIMESTAMP, '参训记录详情'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2228 OR perms = 'train:enrollment:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2229, '参训人员添加', 2164, 12, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:add', '#', 'admin', CURRENT_TIMESTAMP, '参训学员录入'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2229 OR perms = 'train:enrollment:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2230, '参训人员修改', 2164, 13, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:edit', '#', 'admin', CURRENT_TIMESTAMP, '参训学员状态修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2230 OR perms = 'train:enrollment:edit');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2231, '参训人员移除', 2164, 14, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:remove', '#', 'admin', CURRENT_TIMESTAMP, '参训学员移除'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2231 OR perms = 'train:enrollment:remove');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2232, '参训人员导入', 2164, 15, '#', '', '', 1, 0, 'F', '0', '0', 'train:enrollment:import', '#', 'admin', CURRENT_TIMESTAMP, '参训学员批量导入'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2232 OR perms = 'train:enrollment:import');
-- 3.10 电子班牌标准权限 (parent: 2174)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2233, '班牌列表', 2174, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:list', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌列表'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2233 OR perms = 'train:board:list');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2234, '班牌详情', 2174, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:query', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌详情'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2234 OR perms = 'train:board:query');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2235, '班牌新增', 2174, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:add', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌新增'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2235 OR perms = 'train:board:add');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2236, '班牌修改', 2174, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:edit', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌修改'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2236 OR perms = 'train:board:edit');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2237, '班牌删除', 2174, 5, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:remove', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌删除'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2237 OR perms = 'train:board:remove');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2238, '班牌导出', 2174, 6, '#', '', '', 1, 0, 'F', '0', '0', 'train:board:export', '#', 'admin', CURRENT_TIMESTAMP, '电子班牌导出'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2238 OR perms = 'train:board:export');
-- 3.11 自服务专属菜单与页面路由 (挂载于根节点 0,供教师与学员在侧边栏直达工作台)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2239, '教师工作台', 0, 99, 'teacher', 'train/me/teacher/index', '', 1, 0, 'C', '0', '0', 'train:me:teacher', 'education', 'admin', CURRENT_TIMESTAMP, '教师专属工作台页面及自服务权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2239 OR perms = 'train:me:teacher');
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
SELECT 2240, '学员中心', 0, 100, 'student', 'train/me/student/index', '', 1, 0, 'C', '0', '0', 'train:me:student', 'user', 'admin', CURRENT_TIMESTAMP, '学员专属个人培训中心页面及自服务权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2240 OR perms = 'train:me:student');
-- =============================================================================
-- 步骤 4: 为业务角色分配菜单权限映射 (sys_role_menu)
-- =============================================================================
-- 4.1 train_admin (role_id = 3): 授予全部培训模块菜单与按钮
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, m.menu_id
FROM public.sys_menu m
WHERE (m.menu_id BETWEEN 2154 AND 2183 OR m.menu_id BETWEEN 2201 AND 2238 OR m.menu_id BETWEEN 2241 AND 2244)
AND NOT EXISTS (
SELECT 1 FROM public.sys_role_menu rm WHERE rm.role_id = 3 AND rm.menu_id = m.menu_id
);
-- 4.2 train_teacher (role_id = 4): 授予教师专属自服务权限
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 4, 2239
WHERE NOT EXISTS (
SELECT 1 FROM public.sys_role_menu rm WHERE rm.role_id = 4 AND rm.menu_id = 2239
);
-- 4.3 train_student (role_id = 5): 授予学员专属自服务权限
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 5, 2240
WHERE NOT EXISTS (
SELECT 1 FROM public.sys_role_menu rm WHERE rm.role_id = 5 AND rm.menu_id = 2240
);
-- =============================================================================
-- 步骤 5: 迁移验证自检
-- =============================================================================
DO $$
BEGIN
IF (SELECT count(*) FROM public.sys_role WHERE role_key IN ('train_admin', 'train_teacher', 'train_student')) <> 3 THEN
RAISE EXCEPTION 'Training roles count verification failed';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:me:teacher') THEN
RAISE EXCEPTION 'Teacher self-service permission missing';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:me:student') THEN
RAISE EXCEPTION 'Student self-service permission missing';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:teacher:bindUser') THEN
RAISE EXCEPTION 'Teacher binding permission missing';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:student:bindUser') THEN
RAISE EXCEPTION 'Student binding permission missing';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:teacher:remove') THEN
RAISE EXCEPTION 'Teacher safe delete permission missing';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:student:remove') THEN
RAISE EXCEPTION 'Student safe delete permission missing';
END IF;
IF EXISTS (SELECT 1 FROM public.sys_menu WHERE perms LIKE 'system:board:%') THEN
RAISE EXCEPTION 'Legacy system:board:* permission namespace still exists';
END IF;
END $$;
-- >>> 来源模块: sql/system/kingbase/009_dorm_authorization_orchestration.sql >>>
-- ==============================================================================
-- 脚本名称: 009_dorm_authorization_orchestration.sql
-- 业务模块: DMS/外部物联网集成 - 宿舍门禁业务授权编排扩展模型 (R.3B Wave 3A)
-- 适用数据库: KingbaseES V8 / V9 (PostgreSQL 方言兼容)
-- 安全编号: 009 (001-003 基线, 004-005 R.2分支占用, 006 Wave0, 007 保留禁止执行, 008 Wave1)
-- 幂等性设计: 支持重复安全执行,纯增量列结构与索引,不含破坏性语句
-- 安全红线: 严禁引入明文密码列,密码仅在内存短暂留存,严禁落库
-- ==============================================================================
-- 1. 扩展 train_dorm_auth 业务授权字段(增量列添加,防冲突幂等设计)
-- 1.1 凭据类型列 (默认 ONLINE_PASSWORD,未来可扩展 QR, CARD, MOBILE_KEY)
ALTER TABLE public.train_dorm_auth ADD COLUMN IF NOT EXISTS credential_type VARCHAR(32) DEFAULT 'ONLINE_PASSWORD' NOT NULL;
COMMENT ON COLUMN public.train_dorm_auth.credential_type IS '凭据类型 (ONLINE_PASSWORD 在线密码, QR 二维码, CARD 卡片, MOBILE_KEY 手机钥匙)';
-- 1.2 厂商中立业务授权状态列 (从历史 face_sync_status 进化为语义严谨的独立业务状态)
-- 状态枚举:PENDING_GRANT(待下发), GRANTING(下发中), ACTIVE(已生效), PENDING_REVOKE(待注销), REVOKING(注销中), REVOKED(已注销), ERROR(下发或注销失败)
ALTER TABLE public.train_dorm_auth ADD COLUMN IF NOT EXISTS auth_status VARCHAR(32) DEFAULT 'PENDING_GRANT' NOT NULL;
COMMENT ON COLUMN public.train_dorm_auth.auth_status IS '业务授权状态 (PENDING_GRANT, GRANTING, ACTIVE, PENDING_REVOKE, REVOKING, REVOKED, ERROR)';
-- 1.3 关联外部操作流水ID (用于关联并追踪当前最新驱动的 ExternalOperation)
ALTER TABLE public.train_dorm_auth ADD COLUMN IF NOT EXISTS latest_operation_id BIGINT;
COMMENT ON COLUMN public.train_dorm_auth.latest_operation_id IS '最近一次绑定的外部操作流水ID (关联 train_external_operation.operation_id)';
-- 1.4 授权操作世代/版本号 (用于防旧操作晚到结果覆盖更新状态,保证操作时序单调性)
ALTER TABLE public.train_dorm_auth ADD COLUMN IF NOT EXISTS operation_version INTEGER DEFAULT 1 NOT NULL;
COMMENT ON COLUMN public.train_dorm_auth.operation_version IS '授权操作版本号 (乐观并发与迟到操作防覆写防护)';
-- 2. 索引优化 (幂等添加)
CREATE INDEX IF NOT EXISTS idx_dorm_auth_status ON public.train_dorm_auth (auth_status);
CREATE INDEX IF NOT EXISTS idx_dorm_auth_latest_op ON public.train_dorm_auth (latest_operation_id);
-- >>> 来源模块: sql/system/kingbase/010_dms_access_management_permissions.sql >>>
-- =============================================================================
-- 脚本名称: 010_dms_access_management_permissions.sql
-- 业务模块: DMS门禁与外部资源映射管理端权限扩展 (R.3B Wave 3B)
-- 适用数据库: KingbaseES, schema public
-- 范围: 仅限 sys_menu 按钮级权限增量插入,不改动已有角色分配 (sys_role_menu Δ = 0)
-- 幂等性设计: 支持重复执行,WHERE NOT EXISTS 防重,无破坏性语句
-- 安全红线: 严禁引入远程应急开门权限,严禁普通学员/教师授权
-- =============================================================================
-- 1. 门禁与映射查看权限 (train:access:query)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2191, '门禁与资源映射查看', 2060, 1, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:query', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁授权与外部资源映射查看权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:access:query');
-- 2. 门禁资源映射管理权限 (train:access:manage)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2192, '门禁资源映射维护', 2060, 2, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:manage', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁房间与门锁资源绑定解绑维护权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:access:manage');
-- 3. 门禁手动对账权限 (train:access:reconcile)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2193, '门禁手动对账触发', 2060, 3, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:reconcile', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁权限手动对账触发执行权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE perms = 'train:access:reconcile');
-- >>> 来源模块: sql/system/kingbase/012_analytics_v1_permissions.sql >>>
-- =============================================================================
-- Migration: Analytics V1 Permissions & Legacy Menu Deactivation
-- Target: KingbaseES, schema public
-- Scope: Deactivate legacy dropped score menus, add attendance analytics menu & dashboard permissions
-- =============================================================================
-- 1. Deactivate legacy score menus (2166, 2175, 2176)
UPDATE public.sys_menu
SET status = '1', visible = '1', update_by = 'admin', update_time = CURRENT_TIMESTAMP, remark = '已废弃旧表停用(V2架构)'
WHERE menu_id IN (2166, 2175, 2176);
-- 2. Insert attendance analytics menu under '统计分析' (parent_id = 2169)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2251, '考勤分析', 2169, 1, 'attendance', 'train/analysis/attendance/index', '', 1, 0,
'C', '0', '0', 'train:analysis:attendance', 'chart', 'admin', CURRENT_TIMESTAMP, '', NULL, '考勤专题分析页面'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2251);
-- 3. Insert attendance query button permission
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2252, '考勤分析查询', 2251, 1, '#', '', '', 1, 0,
'F', '0', '0', 'train:analysis:attendance:query', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '考勤分析数据查询'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2252);
-- 4. Insert dashboard button permission
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2253, '管理驾驶舱', 2169, 0, '#', '', '', 1, 0,
'F', '0', '0', 'train:analysis:dashboard', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '管理端驾驶舱权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2253);
-- 5. Grant permissions to train_admin role (role_id = 3)
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2251
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2251);
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2252
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2252);
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2253
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2253);
-- 6. Verification
DO $$
BEGIN
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2251 AND perms = 'train:analysis:attendance') <> 1 THEN
RAISE EXCEPTION 'Menu 2251 verification failed';
END IF;
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2252 AND perms = 'train:analysis:attendance:query') <> 1 THEN
RAISE EXCEPTION 'Menu 2252 verification failed';
END IF;
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2253 AND perms = 'train:analysis:dashboard') <> 1 THEN
RAISE EXCEPTION 'Menu 2253 verification failed';
END IF;
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id IN (2251, 2252, 2253)) <> 3 THEN
RAISE EXCEPTION 'Role assignment verification failed';
END IF;
END $$;
-- >>> 来源模块: sql/system/kingbase/014_dms_access_safety_and_accommodation_permissions.sql >>>
-- =============================================================================
-- Migration: 014 DMS Access Safety & Accommodation Permissions
-- Target: KingbaseES, schema public
-- Scope:
-- 1. Register '门禁管理' menu (2060) under '教学设施' (2154)
-- 2. Register '分配住宿' button permission (2264) under '住宿管理' (2261)
-- 3. Ensure minimal operational access permissions (2191, 2192, 2193) exist
-- 4. Grant minimal necessary permissions to train_admin role (role_id = 3):
-- - 2060 (门禁管理页面)
-- - 2191 (train:access:query)
-- - 2192 (train:access:manage)
-- - 2193 (train:access:reconcile)
-- - 2264 (train:accommodation:add)
-- 5. Safety Guard: Explicitly verify train_admin DOES NOT have accommodation:remove or remote unlock
-- 6. Post-migration verification assertion block
-- =============================================================================
-- 1. Register '门禁管理' menu under '教学设施' (parent_id = 2154)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2060, '门禁管理', 2154, 9, 'auth', 'train/auth/index', '', 1, 0,
'C', '0', '0', 'train:access:query', 'lock', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁授权与设备状态管理'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2060);
-- Update menu 2060 in case it existed with different params
UPDATE public.sys_menu
SET parent_id = 2154, path = 'auth', component = 'train/auth/index', perms = 'train:access:query',
status = '0', visible = '0', update_by = 'admin', update_time = CURRENT_TIMESTAMP
WHERE menu_id = 2060;
-- 2. Ensure access permissions (2191, 2192, 2193) exist under parent 2060
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2191, '门禁与资源映射查看', 2060, 1, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:query', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁授权与外部资源映射查看权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2191);
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2192, '门禁资源映射维护', 2060, 2, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:manage', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁凭据下发、注销与映射维护权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2192);
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2193, '门禁手动对账触发', 2060, 3, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:reconcile', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁权限手动对账触发执行权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2193);
-- 3. Register '分配住宿' permission under '住宿管理' (parent_id = 2261)
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2264, '分配住宿', 2261, 3, '#', '', '', 1, 0,
'F', '0', '0', 'train:accommodation:add', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '分配学员住宿安排权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2264);
-- 4. Grant minimal operational permissions to train_admin role (role_id = 3)
-- 门禁管理页面
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2060
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2060);
-- 门禁与资源映射查看
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2191
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2191);
-- 门禁资源维护与下发/注销
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2192
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2192);
-- 门禁手动对账
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2193
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2193);
-- 分配住宿
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2264
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2264);
-- 5. Post-migration Verification Assertions
DO $$
BEGIN
-- Verify 2060 exists and active
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2060 AND perms = 'train:access:query' AND status = '0') <> 1 THEN
RAISE EXCEPTION 'Menu 2060 verification failed';
END IF;
-- Verify 2191, 2192, 2193 exist
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id IN (2191, 2192, 2193)) <> 3 THEN
RAISE EXCEPTION 'Access button permissions (2191, 2192, 2193) verification failed';
END IF;
-- Verify 2264 exists and active
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2264 AND perms = 'train:accommodation:add' AND status = '0') <> 1 THEN
RAISE EXCEPTION 'Menu 2264 verification failed';
END IF;
-- Verify role_id = 3 has 2060, 2191, 2192, 2193, 2264
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id IN (2060, 2191, 2192, 2193, 2264)) <> 5 THEN
RAISE EXCEPTION 'Role assignment for train_admin verification failed';
END IF;
-- Security Guard: Verify train_admin (role_id=3) DOES NOT have any forbidden remove or mutation permissions
IF (SELECT count(*) FROM public.sys_role_menu rm
JOIN public.sys_menu m ON m.menu_id = rm.menu_id
WHERE rm.role_id = 3 AND m.perms IN ('train:course:remove', 'train:teacher:remove', 'train:student:remove', 'train:accommodation:remove')) > 0 THEN
RAISE EXCEPTION 'Security violation: train_admin role must not have remove permissions';
END IF;
END $$;
-- >>> 来源模块: sql/system/kingbase/015_dms_package_a_hardening.sql >>>
-- ============================================================================
-- Migration: 015_dms_package_a_hardening.sql
-- Description: Package A.1 DMS 一致性加固与最小权限拆分
-- 1. 权限最小化拆分:新增 2194 (train:access:credential),从 train_admin 移除 2192 (train:access:manage) 并保证保留 2263 (train:accommodation:edit)
-- 2. 外部操作状态加固:确保 train_external_operation 支持 DISPATCHING 与 AMBIGUOUS
-- 3. 幂等与断言校验
-- ============================================================================
\set ON_ERROR_STOP on
-- 1. 注册 2194 (train:access:credential) 门禁凭据下发与注销专用权限
INSERT INTO public.sys_menu
(menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache,
menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
SELECT 2194, '门禁凭据操作', 2060, 4, '#', '', '', 1, 0,
'F', '0', '0', 'train:access:credential', '#', 'admin', CURRENT_TIMESTAMP, '', NULL, '门禁凭据下发与注销权限'
WHERE NOT EXISTS (SELECT 1 FROM public.sys_menu WHERE menu_id = 2194);
-- 2. 超级管理员角色 (role_id = 1) 授予 2194
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 1, 2194
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 1 AND menu_id = 2194);
-- 3. 培训管理员角色 (role_id = 3) 调整权限 (MIN-09):
-- 授予 2194 (train:access:credential)
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2194
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2194);
-- 从 train_admin (role_id = 3) 回收 2192 (train:access:manage,硬件映射与维护权限)
DELETE FROM public.sys_role_menu
WHERE role_id = 3 AND menu_id = 2192;
-- 确保培训管理员 (role_id = 3) 拥有 2263 (train:accommodation:edit,办理入住/退宿/调房)
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, 2263
WHERE NOT EXISTS (SELECT 1 FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2263);
-- 5. 状态机约束兼容性加固 (train_external_operation)
-- 确保 operation_status 允许 DISPATCHING 与 AMBIGUOUS
ALTER TABLE public.train_external_operation DROP CONSTRAINT IF EXISTS chk_external_operation_status;
ALTER TABLE public.train_external_operation ADD CONSTRAINT chk_external_operation_status
CHECK (operation_status IN ('CREATED','DISPATCHING','REQUESTED','ACCEPTED','PENDING','RETRY_WAIT','AMBIGUOUS','SUCCESS','FAILED','TIMEOUT'));
-- 6. 后置断言验证
DO $$
BEGIN
-- 断言 1: 2194 已正确注册
IF (SELECT count(*) FROM public.sys_menu WHERE menu_id = 2194 AND perms = 'train:access:credential' AND status = '0') <> 1 THEN
RAISE EXCEPTION 'Assertion failed: menu 2194 train:access:credential not found or invalid';
END IF;
-- 断言 2: train_admin (role_id = 3) 拥有 2194 (train:access:credential)
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2194) <> 1 THEN
RAISE EXCEPTION 'Assertion failed: role 3 not granted menu 2194';
END IF;
-- 断言 3: train_admin (role_id = 3) 不得拥有 2192 (train:access:manage)
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2192) <> 0 THEN
RAISE EXCEPTION 'Assertion failed: role 3 still has menu 2192 (train:access:manage)';
END IF;
-- 断言 4: train_admin (role_id = 3) 必须拥有 2263 (train:accommodation:edit,办理入住/退宿/调房)
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2263) <> 1 THEN
RAISE EXCEPTION 'Assertion failed: role 3 missing menu 2263 (train:accommodation:edit)';
END IF;
-- 断言 4b: train_admin (role_id = 3) 严禁拥有破坏性删除权限 train:accommodation:remove
IF (SELECT count(*) FROM public.sys_role_menu rm
JOIN public.sys_menu m ON m.menu_id = rm.menu_id
WHERE rm.role_id = 3 AND m.perms = 'train:accommodation:remove') <> 0 THEN
RAISE EXCEPTION 'Security violation: role 3 has forbidden permission train:accommodation:remove';
END IF;
-- 断言 5: train_admin 拥有 2264 (train:accommodation:add)
IF (SELECT count(*) FROM public.sys_role_menu WHERE role_id = 3 AND menu_id = 2264) <> 1 THEN
RAISE EXCEPTION 'Assertion failed: role 3 missing menu 2264 (train:accommodation:add)';
END IF;
-- 断言 6: operation_status CHECK 约束已生效且包含 DISPATCHING 与 AMBIGUOUS
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conrelid = 'train_external_operation'::regclass
AND contype = 'c'
AND pg_get_constraintdef(oid) LIKE '%DISPATCHING%'
AND pg_get_constraintdef(oid) LIKE '%AMBIGUOUS%'
) THEN
RAISE EXCEPTION 'Assertion failed: operation_status constraint invalid or missing DISPATCHING/AMBIGUOUS';
END IF;
END $$;
COMMIT;
+851
View File
@@ -0,0 +1,851 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 04_iotlocks_schema.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: iotlocks + public)
-- 来源追溯: sql/kingbase/lock.sql (修订版)
-- 修订要点:
-- 1. 显式创建 iotlocks schema,9 张核心表严格建于 iotlocks schema 下
-- 2. 将表创建策略从破坏性 DROP TABLE 改为无破坏性 CREATE TABLE IF NOT EXISTS
-- 3. 【核心Bug修复】原脚本中错误引用的 iotlocks.sys_* 全部更正为 public.sys_*
-- (RuoYi 系统字典与系统菜单在 public 模式,杜绝在空库运行时报错)
-- 4. 保留序列号重置 setval 保护
-- ==============================================================================
BEGIN;
CREATE SCHEMA IF NOT EXISTS iotlocks;
SET search_path TO iotlocks, public, pg_catalog, sys_catalog;
-- =========================================================================
-- 公寓人脸门禁系统(智能门锁)业务表 —— KingbaseES 初始化脚本
--
-- 库名:iotlocks 模式:iotlocks
-- 前置:先执行同目录 ry.sql(若依基础表)
-- 版本:v1.0
--
-- 规范(与 ry.sql 完全一致):
-- 1) 所有对象显式限定 iotlocks.<对象名>,不依赖 search_path,避免命中
-- KingbaseES 系统模式 sys_catalog 中的同名内置对象。
-- 2) 主键统一 bigserial;关联列统一 bigint(不建物理外键,由业务层保证)。
-- 3) 状态/标志位统一 char(1) 或 char(2),与若依 del_flag/status 风格一致;
-- 时间统一 timestamp(不带时区),默认值用 CURRENT_TIMESTAMP。
-- 4) 表与列注释统一使用 comment on;索引统一 idx_ / uk_ 前缀。
-- 5) 脚本可重复执行:建表前 drop table if exists,种子数据先 delete 再 insert。
-- 6) 显式指定主键的种子数据,末尾统一 setval 复位序列(沿用 ry.sql 写法)。
--
-- 表清单:
-- 1. lock_group 公寓分组表
-- 2. lock_gateway 门锁网关表
-- 3. lock_device 智能门锁表
-- 4. lock_face 人脸数据表
-- 5. lock_auth 授权数据表
-- 6. lock_access_log 门禁通行日志表
-- 7. lock_command 下行命令记录表
-- 8. lock_mqtt_log MQTT 报文留痕表
-- 9. lock_service_config 服务参数配置表
-- =========================================================================
set search_path to iotlocks, public, pg_catalog, sys_catalog;
create schema if not exists iotlocks;
-- =========================================================================
-- 1、公寓分组表
-- 业务含义:一个公寓对应一个分组;分组是 MQTT 分组级主题
-- (ydlink/{groupCode}/thing/...)的载体,也是批量授权/远程开锁的粒度。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_group;
create table if not exists iotlocks.lock_group (
group_id bigserial not null,
group_code varchar(32) not null,
group_name varchar(64) not null,
dept_id bigint default null,
manager varchar(64) default null,
phone varchar(20) default null,
address varchar(255) default null,
config_id bigint default null,
status char(1) default '0',
order_num int default 0,
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (group_id)
);
comment on table iotlocks.lock_group is '公寓分组表';
comment on column iotlocks.lock_group.group_id is '分组ID';
comment on column iotlocks.lock_group.group_code is '分组编号(MQTT主题第2段,全局唯一,一经占用不再复用)';
comment on column iotlocks.lock_group.group_name is '公寓/分组名称';
comment on column iotlocks.lock_group.dept_id is '所属部门ID(用于数据权限)';
comment on column iotlocks.lock_group.manager is '负责人';
comment on column iotlocks.lock_group.phone is '联系电话';
comment on column iotlocks.lock_group.address is '公寓地址';
comment on column iotlocks.lock_group.config_id is '关联MQTT服务器配置ID(lock_service_config.config_id,空表示用全局默认)';
comment on column iotlocks.lock_group.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_group.order_num is '显示顺序';
comment on column iotlocks.lock_group.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_group.create_by is '创建者';
comment on column iotlocks.lock_group.create_time is '创建时间';
comment on column iotlocks.lock_group.update_by is '更新者';
comment on column iotlocks.lock_group.update_time is '更新时间';
comment on column iotlocks.lock_group.remark is '备注';
create unique index uk_lock_group_code on iotlocks.lock_group (group_code);
create index idx_lock_group_dept on iotlocks.lock_group (dept_id);
create index idx_lock_group_status on iotlocks.lock_group (status);
-- =========================================================================
-- 2、门锁网关表
-- 业务含义:门锁网关是 LoRa 汇聚节点,下挂多台门锁;一个网关属于一个分组。
-- 网关是 MQTT 网关级主题(ydlink/{gatewaySn}/thing/...)的载体。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_gateway;
create table if not exists iotlocks.lock_gateway (
gateway_id bigserial not null,
gateway_sn varchar(32) not null,
gateway_name varchar(64) default null,
group_id bigint default null,
gateway_ip varchar(64) default null,
subnet_mask varchar(64) default null,
default_gateway varchar(64) default null,
gateway_password varchar(128) default null,
config_id bigint default null,
lora_config varchar(1024) default null,
mqtt_config varchar(1024) default null,
config_version int default 0,
sync_status char(1) default '0',
online_status char(1) default '1',
last_online_time timestamp,
last_sync_time timestamp,
device_count int default 0,
firmware_ver varchar(32) default null,
status char(1) default '0',
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (gateway_id)
);
comment on table iotlocks.lock_gateway is '门锁网关表';
comment on column iotlocks.lock_gateway.gateway_id is '网关ID';
comment on column iotlocks.lock_gateway.gateway_sn is '网关SN(MQTT主题第2段,全局唯一)';
comment on column iotlocks.lock_gateway.gateway_name is '网关名称';
comment on column iotlocks.lock_gateway.group_id is '所属分组ID(lock_group.group_id)';
comment on column iotlocks.lock_gateway.gateway_ip is '网关IP';
comment on column iotlocks.lock_gateway.subnet_mask is '子网掩码';
comment on column iotlocks.lock_gateway.default_gateway is '默认网关';
comment on column iotlocks.lock_gateway.gateway_password is '网关密码(密文存储,AES加密)';
comment on column iotlocks.lock_gateway.config_id is '关联MQTT服务器配置ID';
comment on column iotlocks.lock_gateway.lora_config is 'LORA参数配置(JSON)';
comment on column iotlocks.lock_gateway.mqtt_config is '网关侧MQTT参数(JSON)';
comment on column iotlocks.lock_gateway.config_version is '配置版本号(每次下发+1,用于比对网关侧是否已同步)';
comment on column iotlocks.lock_gateway.sync_status is '配置同步状态(0未同步 1已同步 2同步失败)';
comment on column iotlocks.lock_gateway.online_status is '在线状态(0在线 1离线)';
comment on column iotlocks.lock_gateway.last_online_time is '最后在线时间';
comment on column iotlocks.lock_gateway.last_sync_time is '最后配置同步时间';
comment on column iotlocks.lock_gateway.device_count is '下挂门锁数量(冗余统计)';
comment on column iotlocks.lock_gateway.firmware_ver is '网关固件版本';
comment on column iotlocks.lock_gateway.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_gateway.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_gateway.create_by is '创建者';
comment on column iotlocks.lock_gateway.create_time is '创建时间';
comment on column iotlocks.lock_gateway.update_by is '更新者';
comment on column iotlocks.lock_gateway.update_time is '更新时间';
comment on column iotlocks.lock_gateway.remark is '备注';
create unique index uk_lock_gateway_sn on iotlocks.lock_gateway (gateway_sn);
create index idx_lock_gateway_group on iotlocks.lock_gateway (group_id);
create index idx_lock_gateway_online on iotlocks.lock_gateway (online_status);
create index idx_lock_gateway_sync on iotlocks.lock_gateway (sync_status);
-- =========================================================================
-- 3、智能门锁表
-- 业务含义:门锁终端,通过 LoRa 挂在一个网关下;gateway_id 为空表示未绑定网关。
-- 协议字段映射:device_sn -> devId,device_password -> devPsw,
-- dev_type -> devType,dev_ver -> devVer。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_device;
create table if not exists iotlocks.lock_device (
device_id bigserial not null,
device_sn varchar(32) not null,
device_name varchar(64) default null,
gateway_id bigint default null,
group_id bigint default null,
device_password varchar(128) default null,
dev_type varchar(8) default null,
dev_ver varchar(16) default null,
face_algo_version varchar(32) default null,
room_no varchar(64) default null,
bind_time timestamp,
last_sync_time timestamp,
signal_strength varchar(8) default null,
battery_level int default null,
last_status_time timestamp,
online_status char(1) default '1',
last_online_time timestamp,
status char(1) default '0',
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (device_id)
);
comment on table iotlocks.lock_device is '智能门锁表';
comment on column iotlocks.lock_device.device_id is '门锁ID';
comment on column iotlocks.lock_device.device_sn is '门锁SN(对应协议devId,全局唯一)';
comment on column iotlocks.lock_device.device_name is '门锁名称';
comment on column iotlocks.lock_device.gateway_id is '所属网关ID(lock_gateway.gateway_id,为空表示未绑定)';
comment on column iotlocks.lock_device.group_id is '冗余分组ID(便于按分组批量下发,与网关分组保持一致)';
comment on column iotlocks.lock_device.device_password is '门锁密码(密文存储,对应协议devPsw)';
comment on column iotlocks.lock_device.dev_type is '设备类型(对应协议devType)';
comment on column iotlocks.lock_device.dev_ver is '设备固件版本(对应协议devVer)';
comment on column iotlocks.lock_device.face_algo_version is '人脸算法版本(特征提取服务的 algorithm_version 入参,由每把门锁各自维护,如 2.14.5_2.7.1_M3)';
comment on column iotlocks.lock_device.room_no is '分配房间号';
comment on column iotlocks.lock_device.bind_time is '绑定网关时间';
comment on column iotlocks.lock_device.last_sync_time is '最后时间同步时间';
comment on column iotlocks.lock_device.signal_strength is '信号强度RSSI(dBm,op=lockrssi 上报,如 -42)';
comment on column iotlocks.lock_device.battery_level is '剩余电量(百分比,op=lockrssi 上报)';
comment on column iotlocks.lock_device.last_status_time is '最后状态上报时间(信号/电量上报时间)';
comment on column iotlocks.lock_device.online_status is '在线状态(0在线 1离线 2未知)';
comment on column iotlocks.lock_device.last_online_time is '最后在线时间';
comment on column iotlocks.lock_device.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_device.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_device.create_by is '创建者';
comment on column iotlocks.lock_device.create_time is '创建时间';
comment on column iotlocks.lock_device.update_by is '更新者';
comment on column iotlocks.lock_device.update_time is '更新时间';
comment on column iotlocks.lock_device.remark is '备注';
create unique index uk_lock_device_sn on iotlocks.lock_device (device_sn);
create index idx_lock_device_gateway on iotlocks.lock_device (gateway_id);
create index idx_lock_device_group on iotlocks.lock_device (group_id);
create index idx_lock_device_room on iotlocks.lock_device (room_no);
-- =========================================================================
-- 4、人脸数据表
-- 业务含义:以 person_no(人员/人脸编号,协议中的 AA000009 形态)为主键标识的人脸库。
-- 图片与特征分离存储:图片走对象存储/文件服务,特征以 base64 落 text 列。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_face;
create table if not exists iotlocks.lock_face (
face_id bigserial not null,
person_no varchar(32) not null,
person_name varchar(64) default null,
person_type char(1) default '0',
phone varchar(20) default null,
photo_url varchar(512) default null,
photo_md5 varchar(32) default null,
feature_data text,
feature_md5 varchar(32) default null,
feature_algo_version varchar(32) default null,
feature_size int default 0,
extract_status char(1) default '0',
extract_time timestamp,
extract_msg varchar(512) default null,
status char(1) default '0',
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (face_id)
);
comment on table iotlocks.lock_face is '人脸数据表';
comment on column iotlocks.lock_face.face_id is '人脸数据ID';
comment on column iotlocks.lock_face.person_no is '人脸编号/人员编号(业务唯一,协议授权帧中的人员标识)';
comment on column iotlocks.lock_face.person_name is '姓名';
comment on column iotlocks.lock_face.person_type is '人员类型(0住户 1员工 2访客 3其他)';
comment on column iotlocks.lock_face.phone is '联系电话';
comment on column iotlocks.lock_face.photo_url is '人脸图片URL';
comment on column iotlocks.lock_face.photo_md5 is '图片指纹(用于变更检测与去重)';
comment on column iotlocks.lock_face.feature_data is '人脸特征值(base64编码)';
comment on column iotlocks.lock_face.feature_md5 is '特征指纹(变更检测与幂等下发用)';
comment on column iotlocks.lock_face.feature_algo_version is '特征算法版本(提取时实际使用的 algorithm_version)';
comment on column iotlocks.lock_face.feature_size is '特征字节数';
comment on column iotlocks.lock_face.extract_status is '特征提取状态(0未提取 1成功 2失败)';
comment on column iotlocks.lock_face.extract_time is '特征提取时间';
comment on column iotlocks.lock_face.extract_msg is '特征提取失败原因';
comment on column iotlocks.lock_face.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_face.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_face.create_by is '创建者';
comment on column iotlocks.lock_face.create_time is '创建时间';
comment on column iotlocks.lock_face.update_by is '更新者';
comment on column iotlocks.lock_face.update_time is '更新时间';
comment on column iotlocks.lock_face.remark is '备注';
create unique index uk_lock_face_person_no on iotlocks.lock_face (person_no);
create index idx_lock_face_name on iotlocks.lock_face (person_name);
create index idx_lock_face_extract on iotlocks.lock_face (extract_status);
-- =========================================================================
-- 5、授权数据表
-- 业务含义:把某个人员(person_no)在某个门锁(device_id)上的某类凭证
-- (人脸/密码/指纹/IC卡)授权关系落库,并跟踪下发到设备的同步状态。
-- 协议对应:ydlink/{groupCode}/thing/data/batch 的 params 数组(add/delete)。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_auth;
create table if not exists iotlocks.lock_auth (
auth_id bigserial not null,
auth_no varchar(64) not null,
person_no varchar(32) not null,
person_name varchar(64) default null,
device_id bigint not null,
device_sn varchar(32) default null,
gateway_id bigint default null,
group_id bigint default null,
auth_type char(2) not null,
auth_value text,
auth_value_md5 varchar(32) default null,
begin_time timestamp,
end_time timestamp,
auth_time timestamp,
sync_status char(1) default '0',
sync_time timestamp,
sync_msg varchar(512) default null,
retry_count int default 0,
status char(1) default '0',
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (auth_id)
);
comment on table iotlocks.lock_auth is '授权数据表';
comment on column iotlocks.lock_auth.auth_id is '授权ID';
comment on column iotlocks.lock_auth.auth_no is '授权编号(业务唯一,建议规则 AUTH+日期+序号)';
comment on column iotlocks.lock_auth.person_no is '人员编号(lock_face.person_no)';
comment on column iotlocks.lock_auth.person_name is '冗余人员姓名';
comment on column iotlocks.lock_auth.device_id is '授权锁ID(lock_device.device_id)';
comment on column iotlocks.lock_auth.device_sn is '冗余门锁SN(下发组包直接用)';
comment on column iotlocks.lock_auth.gateway_id is '冗余网关ID';
comment on column iotlocks.lock_auth.group_id is '冗余分组ID(决定下发主题)';
comment on column iotlocks.lock_auth.auth_type is '授权类型(01人脸 02密码 03指纹 04IC卡)';
comment on column iotlocks.lock_auth.auth_value is '授权内容(人脸特征base64/密码密文/指纹特征/IC卡号)';
comment on column iotlocks.lock_auth.auth_value_md5 is '授权内容指纹(变更检测与重复下发判断)';
comment on column iotlocks.lock_auth.begin_time is '生效开始时间';
comment on column iotlocks.lock_auth.end_time is '生效结束时间(空表示永久有效)';
comment on column iotlocks.lock_auth.auth_time is '授权操作时间';
comment on column iotlocks.lock_auth.sync_status is '下发同步状态(0待下发 1已下发 2下发成功 3下发失败 4已清除)';
comment on column iotlocks.lock_auth.sync_time is '最后下发/响应时间';
comment on column iotlocks.lock_auth.sync_msg is '下发结果说明';
comment on column iotlocks.lock_auth.retry_count is '下发重试次数';
comment on column iotlocks.lock_auth.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_auth.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_auth.create_by is '创建者';
comment on column iotlocks.lock_auth.create_time is '创建时间';
comment on column iotlocks.lock_auth.update_by is '更新者';
comment on column iotlocks.lock_auth.update_time is '更新时间';
comment on column iotlocks.lock_auth.remark is '备注';
create unique index uk_lock_auth_no on iotlocks.lock_auth (auth_no);
create unique index uk_lock_auth_person_lock on iotlocks.lock_auth (person_no, device_id, auth_type);
create index idx_lock_auth_person on iotlocks.lock_auth (person_no);
create index idx_lock_auth_device on iotlocks.lock_auth (device_id);
create index idx_lock_auth_group on iotlocks.lock_auth (group_id);
create index idx_lock_auth_sync on iotlocks.lock_auth (sync_status);
-- =========================================================================
-- 6、门禁通行日志表
-- 业务含义:设备通过 ydlink/{groupCode}/thing/event/trigger(op=lockrecord)
-- 上报的开门记录。本表为高频只追加表,故不设 del_flag / update_*。
--
-- 【性能提示】单公寓千级住户、日均万级记录时,建议按 open_time 做月度
-- 范围分区(KingbaseES 支持声明式分区),或按 recv_time 定期归档。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_access_log;
create table if not exists iotlocks.lock_access_log (
log_id bigserial not null,
device_id bigint default null,
device_sn varchar(32) not null,
gateway_id bigint default null,
gateway_sn varchar(32) default null,
group_id bigint default null,
person_no varchar(32) default null,
person_name varchar(64) default null,
card_no varchar(32) default null,
-- 以下三项均为设备原样上报的编码:open_type 实测为 "7",open_dir 实测为 "14"/"16",
-- 长度不固定,故统一用 varchar(8),不能用 char(n)
open_type varchar(8) default null,
open_result varchar(8) default null,
open_dir varchar(8) default null,
open_time timestamp,
recv_time timestamp,
seq varchar(32) default null,
raw_params text,
create_time timestamp,
remark varchar(500) default null,
primary key (log_id)
);
comment on table iotlocks.lock_access_log is '门禁通行日志表';
comment on column iotlocks.lock_access_log.log_id is '日志ID';
comment on column iotlocks.lock_access_log.device_id is '门锁ID(解析device_sn得到,未登记时为空)';
comment on column iotlocks.lock_access_log.device_sn is '门锁SN';
comment on column iotlocks.lock_access_log.gateway_id is '上报网关ID';
comment on column iotlocks.lock_access_log.gateway_sn is '上报网关SN';
comment on column iotlocks.lock_access_log.group_id is '所属分组ID';
comment on column iotlocks.lock_access_log.person_no is '人员编号';
comment on column iotlocks.lock_access_log.person_name is '冗余人员姓名';
comment on column iotlocks.lock_access_log.card_no is '卡号/凭证号';
comment on column iotlocks.lock_access_log.open_type is '开门方式(字典 lock_open_type)';
comment on column iotlocks.lock_access_log.open_result is '开门结果(0失败 1成功)';
comment on column iotlocks.lock_access_log.open_dir is '开门方向(0进门 1出门 空未知)';
comment on column iotlocks.lock_access_log.open_time is '开门时间(设备上报时间)';
comment on column iotlocks.lock_access_log.recv_time is '服务端接收时间';
comment on column iotlocks.lock_access_log.seq is '报文序号(用于幂等去重)';
comment on column iotlocks.lock_access_log.raw_params is '原始params数组(JSON,便于协议字段二次解析)';
comment on column iotlocks.lock_access_log.create_time is '创建时间';
comment on column iotlocks.lock_access_log.remark is '备注';
create index idx_lock_access_log_device on iotlocks.lock_access_log (device_sn);
create index idx_lock_access_log_person on iotlocks.lock_access_log (person_no);
create index idx_lock_access_log_time on iotlocks.lock_access_log (open_time);
create index idx_lock_access_log_seq on iotlocks.lock_access_log (device_sn, seq);
create index idx_lock_access_log_group on iotlocks.lock_access_log (group_id);
-- =========================================================================
-- 7、下行命令记录表
-- 业务含义:所有平台→设备的指令统一下发留痕,支撑响应匹配、失败重试、
-- 离线补发与操作审计。覆盖:绑定/解绑门锁、同步时间、远程开关锁、重启网关、
-- 修改网络/LORA/MQTT参数、保存配置、授权下发、清除授权、清除门锁。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_command;
create table if not exists iotlocks.lock_command (
command_id bigserial not null,
command_no varchar(64) not null,
command_type char(4) not null,
target_type char(1) not null,
target_id bigint default null,
target_code varchar(32) default null,
biz_id bigint default null,
topic varchar(255) default null,
payload text,
req_time timestamp,
resp_topic varchar(255) default null,
resp_payload text,
resp_time timestamp,
command_status char(1) default '0',
retry_count int default 0,
max_retry int default 3,
next_retry_time timestamp,
gateway_ack char(1) default '0',
device_ack char(1) default '0',
device_result char(1) default null,
error_msg varchar(512) default null,
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (command_id)
);
comment on table iotlocks.lock_command is '下行命令记录表';
comment on column iotlocks.lock_command.command_id is '命令ID';
comment on column iotlocks.lock_command.command_no is '命令编号(对应协议seq,全局唯一)';
comment on column iotlocks.lock_command.command_type is '命令类型(字典 lock_command_type)';
comment on column iotlocks.lock_command.target_type is '目标类型(1网关 2门锁 3分组)';
comment on column iotlocks.lock_command.target_id is '目标对象ID';
comment on column iotlocks.lock_command.target_code is '目标编号(网关SN/门锁SN/分组编号,用于主题拼装)';
comment on column iotlocks.lock_command.biz_id is '关联业务ID(如授权下发时指向 lock_auth.auth_id)';
comment on column iotlocks.lock_command.topic is '下发主题';
comment on column iotlocks.lock_command.payload is '下发报文内容';
comment on column iotlocks.lock_command.req_time is '下发时间';
comment on column iotlocks.lock_command.resp_topic is '响应主题';
comment on column iotlocks.lock_command.resp_payload is '响应报文内容';
comment on column iotlocks.lock_command.resp_time is '响应时间';
comment on column iotlocks.lock_command.command_status is '命令状态(0待发送 1已发送 2成功 3失败 4超时 5已取消)';
comment on column iotlocks.lock_command.retry_count is '已重试次数';
comment on column iotlocks.lock_command.max_retry is '最大重试次数';
comment on column iotlocks.lock_command.next_retry_time is '下次重试时间(补偿任务扫描用)';
comment on column iotlocks.lock_command.gateway_ack is '是否已收到网关回执(0否 1是)';
comment on column iotlocks.lock_command.device_ack is '是否已收到门锁回执(0否 1是)';
comment on column iotlocks.lock_command.device_result is '门锁回执结果(0失败 1成功),双回执齐备才判定命令成功';
comment on column iotlocks.lock_command.error_msg is '失败原因';
comment on column iotlocks.lock_command.create_by is '创建者';
comment on column iotlocks.lock_command.create_time is '创建时间';
comment on column iotlocks.lock_command.update_by is '更新者';
comment on column iotlocks.lock_command.update_time is '更新时间';
comment on column iotlocks.lock_command.remark is '备注';
create unique index uk_lock_command_no on iotlocks.lock_command (command_no);
create index idx_lock_command_status on iotlocks.lock_command (command_status);
create index idx_lock_command_target on iotlocks.lock_command (target_code);
create index idx_lock_command_time on iotlocks.lock_command (req_time);
create index idx_lock_command_retry on iotlocks.lock_command (command_status, next_retry_time);
-- =========================================================================
-- 8、MQTT 报文留痕表
-- 业务含义:上下行原始报文的落库留痕,用于协议联调、问题回溯与审计。
-- 可通过配置开关(仅记录收发/记录全部)控制写入量。
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_mqtt_log;
create table if not exists iotlocks.lock_mqtt_log (
log_id bigserial not null,
direction char(1) not null,
topic varchar(255) not null,
group_code varchar(32) default null,
gateway_sn varchar(32) default null,
device_sn varchar(32) default null,
op varchar(32) default null,
mode varchar(8) default null,
ac varchar(8) default null,
seq varchar(32) default null,
qos smallint default 1,
retained char(1) default '0',
payload text,
chksum varchar(32) default null,
verify_status char(1) default '0',
handle_status char(1) default '0',
handle_msg varchar(512) default null,
cost_time int default 0,
recv_time timestamp,
create_time timestamp,
primary key (log_id)
);
comment on table iotlocks.lock_mqtt_log is 'MQTT报文留痕表';
comment on column iotlocks.lock_mqtt_log.log_id is '日志ID';
comment on column iotlocks.lock_mqtt_log.direction is '方向(1上行设备→平台 2下行平台→设备)';
comment on column iotlocks.lock_mqtt_log.topic is 'MQTT主题';
comment on column iotlocks.lock_mqtt_log.group_code is '解析出的分组编号';
comment on column iotlocks.lock_mqtt_log.gateway_sn is '解析出的网关SN';
comment on column iotlocks.lock_mqtt_log.device_sn is '解析出的设备SN(协议devId)';
comment on column iotlocks.lock_mqtt_log.op is '操作类型(协议op)';
comment on column iotlocks.lock_mqtt_log.mode is '方向标识(s2d服务端→设备 d2s设备→服务端)';
comment on column iotlocks.lock_mqtt_log.ac is '动作类型(协议ac)';
comment on column iotlocks.lock_mqtt_log.seq is '报文序号(协议seq)';
comment on column iotlocks.lock_mqtt_log.qos is '服务质量';
comment on column iotlocks.lock_mqtt_log.retained is '是否保留消息(0否 1是)';
comment on column iotlocks.lock_mqtt_log.payload is '报文原文';
comment on column iotlocks.lock_mqtt_log.chksum is '报文校验和';
comment on column iotlocks.lock_mqtt_log.verify_status is '校验结果(0未校验 1通过 2失败)';
comment on column iotlocks.lock_mqtt_log.handle_status is '处理状态(0待处理 1成功 2失败 3已忽略)';
comment on column iotlocks.lock_mqtt_log.handle_msg is '处理结果说明';
comment on column iotlocks.lock_mqtt_log.cost_time is '处理耗时(毫秒)';
comment on column iotlocks.lock_mqtt_log.recv_time is '接收/发送时间';
comment on column iotlocks.lock_mqtt_log.create_time is '创建时间';
create index idx_lock_mqtt_log_topic on iotlocks.lock_mqtt_log (topic);
create index idx_lock_mqtt_log_device on iotlocks.lock_mqtt_log (device_sn);
create index idx_lock_mqtt_log_time on iotlocks.lock_mqtt_log (recv_time);
create index idx_lock_mqtt_log_handle on iotlocks.lock_mqtt_log (handle_status);
create index idx_lock_mqtt_log_seq on iotlocks.lock_mqtt_log (seq);
create index idx_lock_mqtt_log_direct on iotlocks.lock_mqtt_log (direction);
-- =========================================================================
-- 9、服务参数配置表
-- 业务含义:承载“系统参数”中的 MQTT 服务器配置、人脸特征提取服务配置
-- 以及其它平台参数。采用 结构化分类字段 + JSON 值 的折中方案:
-- 新增配置项无需改表,前端按 config_type 渲染不同表单。
--
-- config_value JSON 约定:
-- config_type=01(MQTT服务器)
-- {"brokerUrl":"tcp://127.0.0.1:1883","clientId":"","username":"","password":"",
-- "defaultQos":1,"cleanSession":true,"keepAlive":60,"connectionTimeout":30}
-- config_type=02(人脸特征服务)
-- 协议:POST multipart/form-data,表单字段名 file,值为图片文件
-- 返回:{"functionSuccess":true,"resultSuccess":true,"resultData":"特征base64","msg":"处理成功..."}
-- {"endpoint":"http://192.168.1.202:8802/bdws_api/Third/Api/Easen/getFaceFeatureData","timeout":10000}
-- 未配置时使用代码内置默认地址(同上)
-- config_type=03(平台参数)
-- {"accessLogKeepDays":180,"mqttLogLevel":"error","commandTimeout":10,"maxRetry":3}
-- =========================================================================
-- [REV-SAFE] drop table if exists iotlocks.lock_service_config;
create table if not exists iotlocks.lock_service_config (
config_id bigserial not null,
config_name varchar(100) not null,
config_type char(2) not null,
config_value text,
group_id bigint default null,
is_default char(1) default '1',
enabled char(1) default '0',
status char(1) default '0',
del_flag char(1) default '0',
create_by varchar(64) default '',
create_time timestamp,
update_by varchar(64) default '',
update_time timestamp,
remark varchar(500) default null,
primary key (config_id)
);
comment on table iotlocks.lock_service_config is '服务参数配置表';
comment on column iotlocks.lock_service_config.config_id is '配置ID';
comment on column iotlocks.lock_service_config.config_name is '配置名称';
comment on column iotlocks.lock_service_config.config_type is '配置类型(01MQTT服务器 02人脸特征服务 03平台参数,字典 lock_config_type)';
comment on column iotlocks.lock_service_config.config_value is '配置内容(JSON)';
comment on column iotlocks.lock_service_config.group_id is '归属分组ID(为空表示全局默认)';
comment on column iotlocks.lock_service_config.is_default is '是否默认(0是 1否)';
comment on column iotlocks.lock_service_config.enabled is '是否启用(0启用 1停用)';
comment on column iotlocks.lock_service_config.status is '状态(0正常 1停用)';
comment on column iotlocks.lock_service_config.del_flag is '删除标志(0代表存在 2代表删除)';
comment on column iotlocks.lock_service_config.create_by is '创建者';
comment on column iotlocks.lock_service_config.create_time is '创建时间';
comment on column iotlocks.lock_service_config.update_by is '更新者';
comment on column iotlocks.lock_service_config.update_time is '更新时间';
comment on column iotlocks.lock_service_config.remark is '备注';
create unique index uk_lock_service_config_name on iotlocks.lock_service_config (config_name, config_type);
create index idx_lock_service_config_type on iotlocks.lock_service_config (config_type);
-- =========================================================================
-- 10、字典数据初始化
-- 先按 dict_type 清理,保证脚本可重复执行。
-- =========================================================================
delete from public.sys_dict_data where dict_type in
('lock_online_status','lock_open_type','lock_open_result','lock_auth_type',
'lock_command_type','lock_command_status','lock_sync_status','lock_handle_status',
'lock_config_type','lock_extract_status','lock_person_type','lock_target_type');
delete from public.sys_dict_type where dict_type in
('lock_online_status','lock_open_type','lock_open_result','lock_auth_type',
'lock_command_type','lock_command_status','lock_sync_status','lock_handle_status',
'lock_config_type','lock_extract_status','lock_person_type','lock_target_type');
insert into public.sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) values
(100, '门禁设备在线状态', 'lock_online_status', '0', 'admin', CURRENT_TIMESTAMP, '网关/门锁在线状态列表'),
(101, '门禁开门方式', 'lock_open_type', '0', 'admin', CURRENT_TIMESTAMP, '需与设备协议锁定值对齐'),
(102, '门禁开门结果', 'lock_open_result', '0', 'admin', CURRENT_TIMESTAMP, '开门结果列表'),
(103, '门禁授权类型', 'lock_auth_type', '0', 'admin', CURRENT_TIMESTAMP, '人脸/密码/指纹/IC卡'),
(104, '门禁命令类型', 'lock_command_type', '0', 'admin', CURRENT_TIMESTAMP, '下行命令类型列表'),
(105, '门禁命令状态', 'lock_command_status','0', 'admin', CURRENT_TIMESTAMP, '命令下发状态列表'),
(106, '门禁授权同步状态', 'lock_sync_status', '0', 'admin', CURRENT_TIMESTAMP, '授权下发同步状态列表'),
(107, '门禁报文处理状态', 'lock_handle_status', '0', 'admin', CURRENT_TIMESTAMP, 'MQTT报文处理状态列表'),
(108, '门禁服务配置类型', 'lock_config_type', '0', 'admin', CURRENT_TIMESTAMP, '服务参数配置类型列表'),
(109, '人脸特征提取状态', 'lock_extract_status','0', 'admin', CURRENT_TIMESTAMP, '人脸特征提取状态列表'),
(110, '门禁人员类型', 'lock_person_type', '0', 'admin', CURRENT_TIMESTAMP, '人员类型列表'),
(111, '门禁命令目标类型', 'lock_target_type', '0', 'admin', CURRENT_TIMESTAMP, '命令下发目标类型列表');
insert into public.sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) values
-- 在线状态
(100, 1, '在线', '0', 'lock_online_status', '', 'success', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(101, 2, '离线', '1', 'lock_online_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(102, 3, '未知', '2', 'lock_online_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 开门方式(【待确认】以下为拟定编码,须与设备协议 lockrecord 帧字段逐值核对后修订)
(110, 1, '人脸', '01', 'lock_open_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, '待与设备协议对齐'),
(111, 2, '密码', '02', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '待与设备协议对齐'),
(112, 3, '指纹', '03', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '待与设备协议对齐'),
(113, 4, 'IC卡', '04', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '待与设备协议对齐'),
(114, 5, '远程开锁','05','lock_open_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, '平台下发开锁'),
(115, 6, '机械钥匙','06','lock_open_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, '待与设备协议对齐'),
(116, 9, '其他', '99', 'lock_open_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 设备实际上报的开门方式编码(lockrecord params[2]:7 人脸开门、2 密码开锁)
(117, 7, '人脸', '7', 'lock_open_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备实测编码,待完整协议对齐后统一'),
(118, 8, '密码开锁', '2', 'lock_open_type', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, '设备实测编码,密码开锁时人员编号位为开锁密码'),
-- 开门结果
(120, 1, '失败', '0', 'lock_open_result', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(121, 2, '成功', '1', 'lock_open_result', '', 'success', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 授权类型
(130, 1, '人脸', '01', 'lock_auth_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, 'op=facefeature'),
(131, 2, '密码', '02', 'lock_auth_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'op=password'),
(132, 3, '指纹', '03', 'lock_auth_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(133, 4, 'IC卡', '04', 'lock_auth_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'op=iccard'),
-- 命令类型
(140, 1, '绑定门锁', '0001', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(141, 2, '解绑门锁', '0002', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(142, 3, '同步门锁时间', '0003', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(143, 4, '远程开锁', '0004', 'lock_command_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{grpId}/thing/action/execute'),
(144, 5, '远程关锁', '0005', 'lock_command_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{grpId}/thing/action/execute'),
(145, 6, '重启网关', '0006', 'lock_command_type', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(146, 7, '修改网络参数', '0007', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(147, 8, '修改LORA参数', '0008', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(148, 9, '修改MQTT参数', '0009', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(149, 10, '保存配置', '0010', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
(150, 11, '授权下发', '0011', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{grpId}/thing/data/batch'),
(151, 12, '清除授权', '0012', 'lock_command_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{grpId}/thing/data/batch'),
(152, 13, '清除门锁', '0013', 'lock_command_type', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, 'ydlink/{gwId}/thing/property/set'),
-- 命令状态
(160, 1, '待发送', '0', 'lock_command_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(161, 2, '已发送', '1', 'lock_command_status', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(162, 3, '成功', '2', 'lock_command_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(163, 4, '失败', '3', 'lock_command_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(164, 5, '超时', '4', 'lock_command_status', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(165, 6, '已取消', '5', 'lock_command_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 授权同步状态
(170, 1, '待下发', '0', 'lock_sync_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(171, 2, '已下发', '1', 'lock_sync_status', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(172, 3, '下发成功', '2', 'lock_sync_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(173, 4, '下发失败', '3', 'lock_sync_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(174, 5, '已清除', '4', 'lock_sync_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 报文处理状态
(180, 1, '待处理', '0', 'lock_handle_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(181, 2, '成功', '1', 'lock_handle_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(182, 3, '失败', '2', 'lock_handle_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(183, 4, '已忽略', '3', 'lock_handle_status', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 服务配置类型
(190, 1, 'MQTT服务器', '01', 'lock_config_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(191, 2, '人脸特征服务', '02', 'lock_config_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(192, 3, '平台参数', '03', 'lock_config_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 特征提取状态
(200, 1, '未提取', '0', 'lock_extract_status', '', 'info', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(201, 2, '成功', '1', 'lock_extract_status', '', 'success', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(202, 3, '失败', '2', 'lock_extract_status', '', 'danger', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 人员类型
(210, 1, '住户', '0', 'lock_person_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(211, 2, '员工', '1', 'lock_person_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(212, 3, '访客', '2', 'lock_person_type', '', 'warning', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(213, 4, '其他', '3', 'lock_person_type', '', 'info', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
-- 命令目标类型
(220, 1, '网关', '1', 'lock_target_type', '', 'primary', 'Y', '0', 'admin', CURRENT_TIMESTAMP, ''),
(221, 2, '门锁', '2', 'lock_target_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, ''),
(222, 3, '分组', '3', 'lock_target_type', '', 'primary', 'N', '0', 'admin', CURRENT_TIMESTAMP, '');
-- =========================================================================
-- 11、菜单初始化
-- 使用 2000+ 号段(ry.sql 的菜单 setval 下限为 1999,不冲突)。
-- 若依 admin 角色(role_key='admin')默认拥有全部菜单,无需写 sys_role_menu。
-- =========================================================================
delete from public.sys_menu where perms like 'lock:%';
delete from public.sys_menu where menu_name = '门禁管理' and parent_id = 0;
-- 一级目录
insert into public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values
(2000, '门禁管理', 0, 4, 'iot', null, '', '', 1, 0, 'M', '0', '0', '', 'lock', 'admin', CURRENT_TIMESTAMP, '公寓人脸门禁系统目录');
-- 二级菜单:页面
insert into public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values
(2010, '公寓分组', 2000, 1, 'group', 'iot/group/index', '', '', 1, 0, 'C', '0', '0', 'lock:group:list', 'tree', 'admin', CURRENT_TIMESTAMP, '公寓分组菜单'),
(2020, '门锁网关', 2000, 2, 'gateway', 'iot/gateway/index', '', '', 1, 0, 'C', '0', '0', 'lock:gateway:list', 'server', 'admin', CURRENT_TIMESTAMP, '门锁网关菜单'),
(2030, '智能门锁', 2000, 3, 'device', 'iot/device/index', '', '', 1, 0, 'C', '0', '0', 'lock:device:list', 'lock', 'admin', CURRENT_TIMESTAMP, '智能门锁菜单'),
(2040, '人脸数据', 2000, 4, 'face', 'iot/face/index', '', '', 1, 0, 'C', '0', '0', 'lock:face:list', 'peoples', 'admin', CURRENT_TIMESTAMP, '人脸数据菜单'),
(2050, '授权管理', 2000, 5, 'auth', 'iot/auth/index', '', '', 1, 0, 'C', '0', '0', 'lock:auth:list', 'lock', 'admin', CURRENT_TIMESTAMP, '授权管理菜单'),
(2065, '通行记录', 2000, 6, 'accesslog', 'iot/accesslog/index','', '', 1, 0, 'C', '0', '0', 'lock:accesslog:list','list', 'admin', CURRENT_TIMESTAMP, '通行记录菜单'),
(2070, '命令记录', 2000, 7, 'command', 'iot/command/index', '', '', 1, 0, 'C', '0', '0', 'lock:command:list', 'job', 'admin', CURRENT_TIMESTAMP, '命令记录菜单'),
(2080, '报文日志', 2000, 8, 'mqttlog', 'iot/mqttlog/index', '', '', 1, 0, 'C', '0', '0', 'lock:mqttlog:list', 'log', 'admin', CURRENT_TIMESTAMP, '报文日志菜单'),
(2090, '系统参数', 2000, 9, 'config', 'iot/config/index', '', '', 1, 0, 'C', '0', '0', 'lock:config:list', 'edit', 'admin', CURRENT_TIMESTAMP, '系统参数菜单');
-- 三级菜单:按钮权限
insert into public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) values
-- 公寓分组
(2011, '分组查询', 2010, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2012, '分组新增', 2010, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:add', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2013, '分组修改', 2010, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:edit', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2014, '分组删除', 2010, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:remove', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2015, '分组导出', 2010, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:group:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 门锁网关
(2021, '网关查询', 2020, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2022, '网关新增', 2020, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:add', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2023, '网关修改', 2020, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:edit', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2024, '网关删除', 2020, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:remove', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2025, '网关导出', 2020, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2026, '网关配置下发',2020, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:config', '#', 'admin', CURRENT_TIMESTAMP, '修改网络/LORA/MQTT参数与保存配置'),
(2027, '网关重启', 2020, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:reboot', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2028, '网关绑定门锁',2020, 8, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:gateway:bind', '#', 'admin', CURRENT_TIMESTAMP, '绑定/清除门锁'),
-- 智能门锁
(2031, '门锁查询', 2030, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2032, '门锁新增', 2030, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:add', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2033, '门锁修改', 2030, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:edit', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2034, '门锁删除', 2030, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:remove', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2035, '门锁导出', 2030, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2036, '绑定/解绑网关',2030, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:bind', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2037, '时间同步', 2030, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:sync', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2038, '远程开锁', 2030, 8, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:device:open', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 人脸数据
(2041, '人脸查询', 2040, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2042, '人脸新增', 2040, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:add', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2043, '人脸修改', 2040, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:edit', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2044, '人脸删除', 2040, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:remove', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2045, '人脸导出', 2040, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2046, '特征提取', 2040, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:face:extract', '#', 'admin', CURRENT_TIMESTAMP, '调用人脸特征提取服务'),
-- 授权管理
(2051, '授权查询', 2050, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2052, '授权新增', 2050, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:add', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2053, '授权修改', 2050, 3, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:edit', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2054, '授权删除', 2050, 4, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:remove', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2055, '授权导出', 2050, 5, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2056, '授权下发', 2050, 6, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:push', '#', 'admin', CURRENT_TIMESTAMP, '向设备下发授权'),
(2057, '清除授权', 2050, 7, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:auth:clear', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 通行记录
(2066, '记录查询', 2065, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:accesslog:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2067, '记录导出', 2065, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:accesslog:export', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 命令记录
(2071, '命令查询', 2070, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:command:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2072, '命令重发', 2070, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:command:retry', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 报文日志
(2081, '报文查询', 2080, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:mqttlog:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
-- 系统参数
(2091, '参数查询', 2090, 1, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:config:query', '#', 'admin', CURRENT_TIMESTAMP, ''),
(2092, '参数修改', 2090, 2, '', null, '', '', 1, 0, 'F', '0', '0', 'lock:config:edit', '#', 'admin', CURRENT_TIMESTAMP, '');
-- =========================================================================
-- 12、序列复位
-- 本脚本与 ry.sql 均以显式主键插入种子数据,bigserial 序列不会自动推进,
-- 必须复位,否则后续通过页面新增记录会报主键冲突(23505)。
-- =========================================================================
select case when exists (select 1 from iotlocks.lock_group)
then setval(pg_get_serial_sequence('iotlocks.lock_group', 'group_id'), greatest((select max(group_id) from iotlocks.lock_group), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_gateway)
then setval(pg_get_serial_sequence('iotlocks.lock_gateway', 'gateway_id'), greatest((select max(gateway_id) from iotlocks.lock_gateway), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_device)
then setval(pg_get_serial_sequence('iotlocks.lock_device', 'device_id'), greatest((select max(device_id) from iotlocks.lock_device), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_face)
then setval(pg_get_serial_sequence('iotlocks.lock_face', 'face_id'), greatest((select max(face_id) from iotlocks.lock_face), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_auth)
then setval(pg_get_serial_sequence('iotlocks.lock_auth', 'auth_id'), greatest((select max(auth_id) from iotlocks.lock_auth), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_access_log)
then setval(pg_get_serial_sequence('iotlocks.lock_access_log', 'log_id'), greatest((select max(log_id) from iotlocks.lock_access_log), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_command)
then setval(pg_get_serial_sequence('iotlocks.lock_command', 'command_id'), greatest((select max(command_id) from iotlocks.lock_command), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_mqtt_log)
then setval(pg_get_serial_sequence('iotlocks.lock_mqtt_log', 'log_id'), greatest((select max(log_id) from iotlocks.lock_mqtt_log), 0))
else 1 end;
select case when exists (select 1 from iotlocks.lock_service_config)
then setval(pg_get_serial_sequence('iotlocks.lock_service_config', 'config_id'), greatest((select max(config_id) from iotlocks.lock_service_config), 0))
else 1 end;
select case when exists (select 1 from public.sys_menu where menu_id >= 2000)
then setval(pg_get_serial_sequence('public.sys_menu', 'menu_id'), greatest((select max(menu_id) from public.sys_menu), 2999))
else 1 end;
select case when exists (select 1 from public.sys_dict_type)
then setval(pg_get_serial_sequence('public.sys_dict_type', 'dict_id'), greatest((select max(dict_id) from public.sys_dict_type), 199))
else 1 end;
select case when exists (select 1 from public.sys_dict_data)
then setval(pg_get_serial_sequence('public.sys_dict_data', 'dict_code'), greatest((select max(dict_code) from public.sys_dict_data), 299))
else 1 end;
-- =========================================================================
-- 脚本结束
-- =========================================================================
-- 补充:为培训管理员 (role_key = 'train_admin') 动态授权门禁管理菜单 (menu_id=2000 及其子项)
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT r.role_id, m.menu_id
FROM public.sys_role r
CROSS JOIN public.sys_menu m
WHERE r.role_key = 'train_admin'
AND m.menu_id BETWEEN 2000 AND 2092
ON CONFLICT DO NOTHING;
COMMIT;
+616
View File
@@ -0,0 +1,616 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 05_synthetic_demo_data.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: public)
-- 来源追溯: sql/demo/ (001_demo_accounts, 002_demo_master_data, 003_demo_business_data, 004_demo_scenario_data)
-- 数据合规保证:
-- 1. 100% 纯脱敏合成数据,杜绝导入生产或共享库真实备份
-- 2. 学员电话全部为 188000001xx,身份证仅存储 hash 与 last4 (如 1000, 1001)
-- 3. 宿舍与门锁 SN 均使用标准虚拟测试编码 (LOCK-ZY-101, LOCK-BX-101)
-- ==============================================================================
SET search_path TO public, pg_catalog, sys_catalog;
-- >>> 来源: sql/demo/001_demo_accounts.sql >>>
-- ==============================================================================
-- RailwaySystem Clean Demo 资产: 001_demo_accounts.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- 执行目标: 预置演示专属业务角色账号 (培训管理员、培训教师、培训学员)
-- 安全要求: 严禁在脚本注释或交付报告中泄露明文口令,统一采用标准安全口令哈希预置
-- 角色绑定:
-- 1. demo_admin -> role_id = 3 (train_admin) 一期业务全局管理
-- 2. demo_teacher -> role_id = 4 (train_teacher) 教师专属工作台 (绑定教师 T101)
-- 3. demo_teacher2-> role_id = 4 (train_teacher) 教师专属工作台 (绑定教师 T102)
-- 4. demo_student -> role_id = 5 (train_student) 学员专属个人中心 (绑定学员 S101)
-- 5. demo_student2-> role_id = 5 (train_student) 学员专属个人中心 (绑定学员 S102)
-- ==============================================================================
BEGIN;
-- 1. 预置业务演示账号 (sys_user)
-- 密码哈希统一采用系统标准安全初始口令散列
INSERT INTO public.sys_user
(user_id, dept_id, user_name, nick_name, user_type, email, phonenumber, sex, password, status, del_flag, login_ip, login_date, create_by, create_time, remark)
VALUES
(10, 112, 'demo_admin', '演示培训管理员', '00', 'demo_admin@sict.railway.cn', '18800000001', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '演示专用培训管理员账号'),
(11, 112, 'demo_teacher', '崔宏伟(教师)', '00', 'cuihw@sict.railway.cn', '18800000011', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '演示专用主讲教师账号(绑定T101)'),
(12, 116, 'demo_teacher2', '张建国(教师)', '00', 'zhangjg@sict.railway.cn', '18800000012', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '演示专用第二教师账号(绑定T102)'),
(21, 119, 'demo_student', '李强(学员)', '00', 'liqiang@sict.railway.cn', '18800000101', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '演示专用参训学员账号(绑定S101)'),
(22, 120, 'demo_student2', '王芳(学员)', '00', 'wangfang@sict.railway.cn', '18800000102', '1', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '演示专用参训学员账号(绑定S102)')
ON CONFLICT (user_id) DO UPDATE SET
user_name = EXCLUDED.user_name,
nick_name = EXCLUDED.nick_name,
dept_id = EXCLUDED.dept_id,
password = EXCLUDED.password,
status = '0',
del_flag = '0';
-- 2. 绑定用户角色 (sys_user_role)
DELETE FROM public.sys_user_role WHERE user_id IN (10, 11, 12, 21, 22);
INSERT INTO public.sys_user_role (user_id, role_id)
VALUES
(10, 3), -- demo_admin -> 培训管理员 (role_id=3)
(11, 4), -- demo_teacher -> 培训教师 (role_id=4)
(12, 4), -- demo_teacher2-> 培训教师 (role_id=4)
(21, 5), -- demo_student -> 培训学员 (role_id=5)
(22, 5); -- demo_student2-> 培训学员 (role_id=5)
-- 3. 演示环境优化:关闭登录验证码要求 (提升演示流畅度)
UPDATE public.sys_config SET config_value = 'false' WHERE config_key = 'sys.account.captchaEnabled';
COMMIT;
-- >>> 来源: sql/demo/002_demo_master_data.sql >>>
-- ==============================================================================
-- RailwaySystem Clean Demo 资产: 002_demo_master_data.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- ==============================================================================
BEGIN;
-- 1. 教师主档
UPDATE public.train_teacher SET org_name = '沈阳房建公寓段安全培训科', job_title = '首席技师/教授级高工', t_phone = '18800000000', t_email = 'zhaodm@sict.railway.cn', status = 1, del_flag = '0' WHERE t_id = 'T001';
INSERT INTO public.train_teacher (t_id, t_name, t_gender, t_birth, org_name, job_title, t_phone, t_email, status, del_flag, user_id, create_by, create_time, remark)
VALUES
('T101', '崔宏伟', '0', '1982-05-14', '沈阳房建公寓段安全培训科', '高级工程师', '18800000011', 'cuihw@sict.railway.cn', 1, '0', 11, 'admin', CURRENT_TIMESTAMP, '演示主讲教师(绑定账号demo_teacher)'),
('T102', '张建国', '0', '1985-11-20', '沈阳房建公寓段技术科', '副高级工程师', '18800000012', 'zhangjg@sict.railway.cn', 1, '0', 12, 'admin', CURRENT_TIMESTAMP, '技术专家讲师(绑定账号demo_teacher2)'),
('T103', '刘文波', '0', '1979-08-03', '沈阳房建公寓段公寓科', '主任技师', '18800000013', 'liuwb@sict.railway.cn', 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '门禁与后勤管理特聘讲师'),
('T104', '孙亚萍', '1', '1988-03-22', '沈阳房建公寓段安全培训科', '专职讲师', '18800000014', 'sunyp@sict.railway.cn', 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '营业线施工安全专职培训师'),
('T105', '陈广林', '0', '1976-12-09', '大连项目部', '特级技师', '18800000015', 'chengl@sict.railway.cn', 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '防汛抢险实训专家'),
('T106', '马志强', '0', '1990-07-18', '丹东项目部', '工程师', '18800000016', 'mazhq@sict.railway.cn', 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '电气防火与智能化安全监控讲师')
ON CONFLICT (t_id) DO UPDATE SET
t_name = EXCLUDED.t_name, org_name = EXCLUDED.org_name, job_title = EXCLUDED.job_title, user_id = EXCLUDED.user_id, status = EXCLUDED.status, del_flag = '0';
-- 2. 课程标准库
INSERT INTO public.train_course (c_id, c_name, c_code, c_type, c_duration, teaching_objective, course_content, status, del_flag, create_by, create_time, remark)
VALUES
('C001', '高速铁路房建设施检修规范', 'DEMO-CRS-001', 1, 24, '熟练掌握高铁站房、雨棚及站台设施的巡检标准与养护规程', '第一章 高铁站房结构特性;第二章 日常巡检与重点隐患排查;第三章 结构裂缝与屋面防水检修实务', 1, '0', 'admin', CURRENT_TIMESTAMP, '重点理论课程'),
('C002', '铁路营业线施工安全与应急处置', 'DEMO-CRS-002', 1, 16, '强化营业线天窗点内施工安全红线意识,掌握突发险情应急处置规程', '第一章 营业线施工防护等级;第二章 施工要点与天窗管理;第三章 典型事故案例分析与应急预案响应', 1, '0', 'admin', CURRENT_TIMESTAMP, '必修安全红线课程'),
('C003', '铁路公寓智能门禁与物联系统应用', 'DEMO-CRS-003', 2, 16, '掌握公寓智能门禁终端、电子门锁、身份下发及离线对账完整业务链', '第一章 智能门禁拓扑与权限机制;第二章 凭据下发与卡密配置;第三章 离线对账与异常流调实操', 1, '0', 'admin', CURRENT_TIMESTAMP, '理论实作一体化课程'),
('C004', '给排水与暖通设备标准化检修', 'DEMO-CRS-004', 2, 20, '掌握铁路车站及公寓给排水管网、变频泵组与采暖供热设备标准化实操演练', '第一章 供暖锅炉与变频供水设备;第二章 管路试压与漏水排查;第三章 冬季防冻保温与实操演练', 1, '0', 'admin', CURRENT_TIMESTAMP, '核心实训操作课程'),
('C005', '房建设施防汛防台演练', 'DEMO-CRS-005', 2, 16, '掌握极端恶劣天气下地下构筑物防倒灌、泵坑强排及抗台防风应急抢险技能', '第一章 铁路防汛预警机制;第二章 移动防洪挡水板与抽水泵组布设实操;第三章 突发强降雨抢险实操演练', 1, '0', 'admin', CURRENT_TIMESTAMP, '实操抢险演练'),
('C006', '电气防火安全与智能巡检规范', 'DEMO-CRS-006', 1, 12, '掌握铁路配电房、公寓配电间电气火灾隐患红外热成像及阻燃检测技术', '第一章 铁路电气火灾成因与预防;第二章 热成像与绝缘阻抗巡检;第三章 电气火灾报警联动处置', 1, '0', 'admin', CURRENT_TIMESTAMP, '专业理论课程'),
('C007', '特种作业人员安全资质培训', 'DEMO-CRS-007', 1, 16, '高处作业、焊接作业及有限空间作业安全规程与特种作业防护规范', '第一章 高空作业双钩安全带使用规程;第二章 动火作业审批及监护;第三章 有限空间气体检测与通风防护', 1, '0', 'admin', CURRENT_TIMESTAMP, '资质考评必修课程'),
('C008', '智能电子班牌与数字化报到实务', 'DEMO-CRS-008', 2, 8, '掌握智能电子班牌的屏幕互动、无感签到、通知推发与日程核验', '第一章 智能班牌终端交互;第二章 课次无感签到与异常补录;第三章 班级通知与应急插播实演', 1, '0', 'admin', CURRENT_TIMESTAMP, '数字化教学应用课程')
ON CONFLICT (c_id) DO UPDATE SET
c_name = EXCLUDED.c_name, c_code = EXCLUDED.c_code, c_type = EXCLUDED.c_type, c_duration = EXCLUDED.c_duration, status = EXCLUDED.status, del_flag = '0';
-- 3. 教学教室
INSERT INTO public.train_classroom_info (class_room_id, room_name, room_location, capacity, room_status, create_by, create_time, del_flag, remark)
VALUES
('CR01', '教学楼101多功能多媒体教室', '教学楼一楼东侧101室', 60, 1, 'admin', CURRENT_TIMESTAMP, '0', '配备智慧黑板与双屏投影'),
('CR02', '教学楼102信息化研讨教室', '教学楼一楼西侧102室', 40, 1, 'admin', CURRENT_TIMESTAMP, '0', '支持分组讨论与互动教学'),
('CR03', '教学楼201安全实训理论教室', '教学楼二楼东侧201室', 50, 1, 'admin', CURRENT_TIMESTAMP, '0', '安全案例沉浸式视听教室'),
('CR04', '综合楼305智慧学术报告厅', '综合楼三楼报告厅', 100, 1, 'admin', CURRENT_TIMESTAMP, '0', '承办大型培训开班仪式与结训典礼')
ON CONFLICT (class_room_id) DO UPDATE SET
room_name = EXCLUDED.room_name, room_location = EXCLUDED.room_location, capacity = EXCLUDED.capacity, room_status = EXCLUDED.room_status, del_flag = '0';
-- 4. 实训场地
INSERT INTO public.train_training_site (site_id, site_name, site_location, capacity, site_device, site_status, create_by, create_time, del_flag, remark)
VALUES
('SITE01', '沈阳房建综合实训基地', '沈阳段综合实训园区A区', 50, '高仿真站台接缝模型、雨棚防脱索具、钢结构无损探伤仪', 1, 'admin', CURRENT_TIMESTAMP, '0', '高铁房建全构件检修实训场'),
('SITE02', '高铁给排水检修实作工场', '沈阳段综合实训园区B区1号工场', 30, '变频调速供水泵组、管道高压疏通机、法兰热熔焊接设备', 1, 'admin', CURRENT_TIMESTAMP, '0', '暖通给排水专业工场'),
('SITE03', '应急抢险与高空作业演练场', '沈阳段演练拓展场C区', 40, '移动防汛挡水钢板、大流量潜水排污泵、高空悬吊防护训练架', 1, 'admin', CURRENT_TIMESTAMP, '0', '防汛防台与高空实操基地')
ON CONFLICT (site_id) DO UPDATE SET
site_name = EXCLUDED.site_name, site_location = EXCLUDED.site_location, capacity = EXCLUDED.capacity, site_status = EXCLUDED.site_status, del_flag = '0';
-- 5. 电子班牌
INSERT INTO public.train_electronic_board (board_id, board_sn, board_name, bind_classroom_id, board_ip, support_checkin_type, board_status, last_heartbeat, create_by, create_time, del_flag, remark)
VALUES
('BP001', 'BOARD-CR01-01', '教学楼101班牌', 'CR01', '192.168.10.101', 'FACE,CARD,QR', 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '0', '教学楼101门外终端'),
('BP002', 'BOARD-CR02-01', '教学楼102班牌', 'CR02', '192.168.10.102', 'FACE,CARD,QR', 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '0', '教学楼102门外终端')
ON CONFLICT (board_id) DO UPDATE SET
board_sn = EXCLUDED.board_sn, board_name = EXCLUDED.board_name, bind_classroom_id = EXCLUDED.bind_classroom_id, board_status = EXCLUDED.board_status, del_flag = '0';
-- 6. 宿舍房间 (20间)
INSERT INTO public.train_dormitory_info (dorm_id, dorm_building, dorm_floor, dorm_room, capacity, gender_type, dorm_status, lock_device_sn, create_by, create_time, del_flag, remark)
VALUES
('DORM-ZY-101', '致远楼', '1层', '101', 4, 1, 1, 'LOCK-ZY-101', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-102', '致远楼', '1层', '102', 4, 1, 1, 'LOCK-ZY-102', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-103', '致远楼', '1层', '103', 4, 1, 1, 'LOCK-ZY-103', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-104', '致远楼', '1层', '104', 4, 1, 1, 'LOCK-ZY-104', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-105', '致远楼', '1层', '105', 4, 1, 1, 'LOCK-ZY-105', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-201', '致远楼', '2层', '201', 4, 1, 1, 'LOCK-ZY-201', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-202', '致远楼', '2层', '202', 4, 1, 1, 'LOCK-ZY-202', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-203', '致远楼', '2层', '203', 4, 1, 1, 'LOCK-ZY-203', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-204', '致远楼', '2层', '204', 4, 1, 1, 'LOCK-ZY-204', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-ZY-205', '致远楼', '2层', '205', 4, 1, 1, 'LOCK-ZY-205', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍'),
('DORM-BX-101', '博学楼', '1层', '101', 4, 2, 1, 'LOCK-BX-101', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-102', '博学楼', '1层', '102', 4, 2, 1, 'LOCK-BX-102', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-103', '博学楼', '1层', '103', 4, 2, 1, 'LOCK-BX-103', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-104', '博学楼', '1层', '104', 4, 2, 1, 'LOCK-BX-104', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-105', '博学楼', '1层', '105', 4, 2, 1, 'LOCK-BX-105', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-201', '博学楼', '2层', '201', 4, 2, 1, 'LOCK-BX-201', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-202', '博学楼', '2层', '202', 4, 2, 1, 'LOCK-BX-202', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-203', '博学楼', '2层', '203', 4, 2, 1, 'LOCK-BX-203', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-204', '博学楼', '2层', '204', 4, 2, 1, 'LOCK-BX-204', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍'),
('DORM-BX-205', '博学楼', '2层', '205', 4, 2, 1, 'LOCK-BX-205', 'admin', CURRENT_TIMESTAMP, '0', '女生宿舍')
ON CONFLICT (dorm_id) DO UPDATE SET
dorm_building = EXCLUDED.dorm_building, dorm_floor = EXCLUDED.dorm_floor, dorm_room = EXCLUDED.dorm_room, capacity = EXCLUDED.capacity, dorm_status = EXCLUDED.dorm_status, del_flag = '0';
-- 7. 学员主档 (35名)
INSERT INTO public.train_student (s_id, s_name, s_gender, s_birth, org_name, s_phone, s_email, id_card_hash, id_card_last4, source_type, status, del_flag, user_id, create_by, create_time, remark)
VALUES
('S101', '李强', '0', '1990-01-01', '沈阳房建公寓段沈阳车间', '18800000101', 's101@sict.railway.cn', '57ecc1436745329b620ccbfaebbed22cda4ba9b33ec44de468d2e3acd61f63c2', '1000', 1, 1, '0', 21, 'admin', CURRENT_TIMESTAMP, '演示学员样本1'),
('S102', '王芳', '1', '1991-02-02', '沈阳房建公寓段大连车间', '18800000102', 's102@sict.railway.cn', 'f6d29eac73f7ea39158b909683cc36f50a2ea9298be8a453bf8922488e499b29', '1001', 1, 1, '0', 22, 'admin', CURRENT_TIMESTAMP, '演示学员样本2'),
('S103', '张伟', '0', '1992-03-03', '沈阳房建公寓段丹东车间', '18800000103', 's103@sict.railway.cn', 'eb005ec042b0171ab34dc5e7d038c2eec40e4456c4378db6b2578159489fc6b1', '1002', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本3'),
('S104', '赵敏', '0', '1993-04-04', '沈阳房建公寓段安全培训科', '18800000104', 's104@sict.railway.cn', '8dd4b314cf479f0d60d00282548381a52489a0849f6dd499c57d1765fb6ba9b3', '1003', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本4'),
('S105', '陈涛', '0', '1994-05-05', '沈阳房建公寓段技术科', '18800000105', 's105@sict.railway.cn', 'd3b26d75218164246b036037504e03ce9f66052bfbefdf2a247613cfa38c04ad', '1004', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本5'),
('S106', '杨洋', '1', '1995-06-06', '沈阳房建公寓段沈阳车间', '18800000106', 's106@sict.railway.cn', 'c8e5d6133037dda5303504512c11b281413b25a40acfa0a70b65922f8966a97a', '1005', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本6'),
('S107', '周杰', '0', '1996-07-07', '沈阳房建公寓段大连车间', '18800000107', 's107@sict.railway.cn', '6bdcd2c0e867be8cfef52c987e959097099c5188c26f20add1311ac723278ab2', '1006', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本7'),
('S108', '徐静', '0', '1997-08-08', '沈阳房建公寓段丹东车间', '18800000108', 's108@sict.railway.cn', 'ef2d043c2b0f983a77bed02077c12ef30886f7e54d2980f7c64f06407bc7e579', '1007', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本8'),
('S109', '孙磊', '0', '1990-09-09', '沈阳房建公寓段安全培训科', '18800000109', 's109@sict.railway.cn', '1c387866619ee10c7205cf503df503adc694fc3280eef104b32b07803fdb8e95', '1008', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本9'),
('S110', '朱燕', '1', '1991-10-10', '沈阳房建公寓段技术科', '18800000110', 's110@sict.railway.cn', 'f8e31ba15a77222416e139b597c35a9e49f536a1dcbb2d37384c557853c224e0', '1009', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本10'),
('S111', '郭超', '0', '1992-11-11', '沈阳房建公寓段沈阳车间', '18800000111', 's111@sict.railway.cn', '608ba9ded7bc99069a88ce2004c2cf9bc7801c967a5d0f32e8d662b248113e7c', '1010', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本11'),
('S112', '何伟', '0', '1993-12-12', '沈阳房建公寓段大连车间', '18800000112', 's112@sict.railway.cn', 'ce9c847788ad8f0e583faa78e3ef21de612251371e4641f5b52226ee1ae795e0', '1011', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本12'),
('S113', '高健', '0', '1994-01-13', '沈阳房建公寓段丹东车间', '18800000113', 's113@sict.railway.cn', '314ca3c9b0e77d808031970e25bc462c7890647b1d3470b0aa877d8882138314', '1012', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本13'),
('S114', '林峰', '1', '1995-02-14', '沈阳房建公寓段安全培训科', '18800000114', 's114@sict.railway.cn', 'e0f33d968d5b6f053be67e5bb3ae20e6a3301080f9821c452efd6b05d785815f', '1013', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本14'),
('S115', '罗娜', '0', '1996-03-15', '沈阳房建公寓段技术科', '18800000115', 's115@sict.railway.cn', '0f6eb52d873f3a3bc423b973c4ff942e640f1798b584c25292a8e3a6138a1a8f', '1014', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本15'),
('S116', '梁勇', '0', '1997-04-16', '沈阳房建公寓段沈阳车间', '18800000116', 's116@sict.railway.cn', 'd1d72a50041621372868c6622fcc7d941d21c3455b7579aba7c097e3c64a6835', '1015', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本16'),
('S117', '宋佳', '0', '1990-05-17', '沈阳房建公寓段大连车间', '18800000117', 's117@sict.railway.cn', '228dd61eadab8e0f70e14a9a800c2ed80c208cd2c7944f464d8282e4e1d95db8', '1016', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本17'),
('S118', '郑阳', '1', '1991-06-18', '沈阳房建公寓段丹东车间', '18800000118', 's118@sict.railway.cn', '245f22b87575afaff6fbe16fc50e56731da51e2c1d8a9ee1866d5638df3ec31f', '1017', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本18'),
('S119', '谢明', '0', '1992-07-19', '沈阳房建公寓段安全培训科', '18800000119', 's119@sict.railway.cn', '941f0156c2eeb2626f76539d3f62e7fa050799ac1e29a9f42eb00f8dd336760f', '1018', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本19'),
('S120', '韩梅', '0', '1993-08-20', '沈阳房建公寓段技术科', '18800000120', 's120@sict.railway.cn', 'addc31f5380151d90621e63ab40471fc749b47651705fb6e8fbe61b33e8ae51a', '1019', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本20'),
('S121', '唐浩', '0', '1994-09-21', '沈阳房建公寓段沈阳车间', '18800000121', 's121@sict.railway.cn', 'a2f6e5faf5d400013b4d6238f0370d43e5b02744f2898dd8ea6f3fa10dfe04e8', '1020', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本21'),
('S122', '冯霞', '1', '1995-10-22', '沈阳房建公寓段大连车间', '18800000122', 's122@sict.railway.cn', '16d6c76f2bdbd69c504435da2010d436f3c7d597fec78199cc3649f1a6680d91', '1021', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本22'),
('S123', '于洋', '0', '1996-11-23', '沈阳房建公寓段丹东车间', '18800000123', 's123@sict.railway.cn', '57b98c33d6c9ef93e68c7d6bdcf4ac2b98670d0ea998449886b7acefafd6690c', '1022', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本23'),
('S124', '董欣', '0', '1997-12-24', '沈阳房建公寓段安全培训科', '18800000124', 's124@sict.railway.cn', 'c54e399999d52c0a2d33f8dd8e29ae0c00bd293e40750abb59af87dbe453d4d5', '1023', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本24'),
('S125', '萧然', '0', '1990-01-25', '沈阳房建公寓段技术科', '18800000125', 's125@sict.railway.cn', 'e721a7b054a254c3fde7b8ce646c2a9986937b369c61b46e9dee8510cd4ca3f9', '1024', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本25'),
('S126', '程功', '1', '1991-02-26', '沈阳房建公寓段沈阳车间', '18800000126', 's126@sict.railway.cn', '9934af5948c05404c1cfeb75b023d9658273b5f76f2222da1df7c176d6b3c092', '1025', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本26'),
('S127', '曹操', '0', '1992-03-27', '沈阳房建公寓段大连车间', '18800000127', 's127@sict.railway.cn', '6f846b87db0308be283250ecb918511719c4dffaa69dc347bb800ac05b0108ff', '1026', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本27'),
('S128', '袁方', '0', '1993-04-28', '沈阳房建公寓段丹东车间', '18800000128', 's128@sict.railway.cn', '2b21a13ef131923b0966138af218abc111adf31e85320211f86efa178a02b46d', '1027', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本28'),
('S129', '邓超', '0', '1994-05-01', '沈阳房建公寓段安全培训科', '18800000129', 's129@sict.railway.cn', '3cbf1be25fb8561ec9091fc2ad1bdab477465da4aea11b27c9b0642a8a5146a5', '1028', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本29'),
('S130', '许巍', '1', '1995-06-02', '沈阳房建公寓段技术科', '18800000130', 's130@sict.railway.cn', '5d0fca144d4443ecd4bcd85f58f21b369df20a9369b4daccc4b6667b095773fe', '1029', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本30'),
('S131', '沈冰', '0', '1996-07-03', '沈阳房建公寓段沈阳车间', '18800000131', 's131@sict.railway.cn', 'd47b05367012f7166a7a8a6c5d4313a14e234297d6017482493d0f98e383389e', '1030', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本31'),
('S132', '曾诚', '0', '1997-08-04', '沈阳房建公寓段大连车间', '18800000132', 's132@sict.railway.cn', '5dd752b8826ac0258509f27458aa4599ba23c3bced53888d5b001492c468477b', '1031', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本32'),
('S133', '彭飞', '0', '1990-09-05', '沈阳房建公寓段丹东车间', '18800000133', 's133@sict.railway.cn', 'ac7afdf09e2f07d66d3f320d60a11abe0167187455dfd15438229f906ef3e8ef', '1032', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本33'),
('S134', '吕梁', '1', '1991-10-06', '沈阳房建公寓段安全培训科', '18800000134', 's134@sict.railway.cn', '65a78d3839aef33f4059ea214e8faac94125c6c82cfa3001580fa208430b0ad3', '1033', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本34'),
('S135', '卢伟', '0', '1992-11-07', '沈阳房建公寓段技术科', '18800000135', 's135@sict.railway.cn', '2df5ae45334850de9e4ba87333f2388e2b71f5d75ead96fdd7c8734dd73f7147', '1034', 1, 1, '0', NULL, 'admin', CURRENT_TIMESTAMP, '演示学员样本35')
ON CONFLICT (s_id) DO UPDATE SET
s_name = EXCLUDED.s_name, org_name = EXCLUDED.org_name, s_phone = EXCLUDED.s_phone, s_email = EXCLUDED.s_email,
id_card_hash = EXCLUDED.id_card_hash, id_card_last4 = EXCLUDED.id_card_last4, user_id = EXCLUDED.user_id, status = EXCLUDED.status, del_flag = '0';
COMMIT;
-- >>> 来源: sql/demo/003_demo_business_data.sql >>>
-- ==============================================================================
-- RailwaySystem Clean Demo 资产: 003_demo_business_data.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- ==============================================================================
BEGIN;
-- 1. 开班计划
INSERT INTO public.train_class_plan (plan_id, plan_name, start_time, end_time, report_deadline, train_address, recruit_num, apply_condition, plan_status, create_by, create_time, del_flag, remark)
VALUES
('PLAN-2026-01', '2026年秋季高铁房建设施高级研修班', '2026-09-15 08:30:00', '2026-09-30 17:30:00', '2026-09-14 18:00:00', '沈阳房建综合实训园区', 30, '沈阳段各车间从事高铁站房设备检修2年以上技术骨干', 1, 'admin', CURRENT_TIMESTAMP, '0', '核心演示班级(进行中)'),
('PLAN-2026-02', '2026年铁路营业线安全施工与应急处置实训班', '2026-10-10 08:30:00', '2026-10-25 17:30:00', '2026-10-09 18:00:00', '教学楼101多功能多媒体教室', 40, '营业线施工现场防护员及施工负责人', 0, 'admin', CURRENT_TIMESTAMP, '0', '即将开班班级(未开始)'),
('PLAN-2026-03', '2026年夏季铁路给排水设备技术比武集训班', '2026-08-01 08:30:00', '2026-08-15 17:30:00', '2026-07-31 18:00:00', '高铁给排水检修实作工场', 25, '全段给排水与暖通特级技师与高级工选拔参赛人员', 2, 'admin', CURRENT_TIMESTAMP, '0', '历史结训班级(已结束)'),
('PLAN-2026-04', '2026年智能门禁与数字化后勤储备干部培训班', '2026-11-01 08:30:00', '2026-11-15 17:30:00', '2026-10-31 18:00:00', '综合楼305智慧学术报告厅', 30, '公寓管理人员及信息化骨干', 3, 'admin', CURRENT_TIMESTAMP, '0', '计划筹备班级(草稿/未发布)')
ON CONFLICT (plan_id) DO UPDATE SET
plan_name = EXCLUDED.plan_name, start_time = EXCLUDED.start_time, end_time = EXCLUDED.end_time, plan_status = EXCLUDED.plan_status, del_flag = '0';
-- 2. 计划绑定课程
INSERT INTO public.train_plan_course (plan_course_id, plan_id, c_id, sort_no, create_by, create_time)
VALUES
(1, 'PLAN-2026-01', 'C001', 1, 'admin', CURRENT_TIMESTAMP),
(2, 'PLAN-2026-01', 'C003', 2, 'admin', CURRENT_TIMESTAMP),
(3, 'PLAN-2026-01', 'C004', 3, 'admin', CURRENT_TIMESTAMP),
(4, 'PLAN-2026-01', 'C008', 4, 'admin', CURRENT_TIMESTAMP),
(5, 'PLAN-2026-02', 'C002', 1, 'admin', CURRENT_TIMESTAMP),
(6, 'PLAN-2026-02', 'C005', 2, 'admin', CURRENT_TIMESTAMP),
(7, 'PLAN-2026-02', 'C007', 3, 'admin', CURRENT_TIMESTAMP),
(8, 'PLAN-2026-03', 'C004', 1, 'admin', CURRENT_TIMESTAMP),
(9, 'PLAN-2026-03', 'C006', 2, 'admin', CURRENT_TIMESTAMP)
ON CONFLICT (plan_id, c_id) DO UPDATE SET
sort_no = EXCLUDED.sort_no;
-- 3. 参训名单
INSERT INTO public.train_enrollment (enrollment_id, plan_id, student_id, enrollment_status, source_type, accommodation_required, join_time, create_by, create_time)
VALUES
(101, 'PLAN-2026-01', 'S101', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(102, 'PLAN-2026-01', 'S102', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(103, 'PLAN-2026-01', 'S103', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(104, 'PLAN-2026-01', 'S104', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(105, 'PLAN-2026-01', 'S105', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(106, 'PLAN-2026-01', 'S106', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(107, 'PLAN-2026-01', 'S107', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(108, 'PLAN-2026-01', 'S108', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(109, 'PLAN-2026-01', 'S109', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(110, 'PLAN-2026-01', 'S110', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(111, 'PLAN-2026-01', 'S111', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(112, 'PLAN-2026-01', 'S112', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(113, 'PLAN-2026-01', 'S113', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(114, 'PLAN-2026-01', 'S114', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(115, 'PLAN-2026-01', 'S115', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(116, 'PLAN-2026-01', 'S116', 1, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(117, 'PLAN-2026-01', 'S117', 0, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(118, 'PLAN-2026-01', 'S118', 0, 2, 1, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(119, 'PLAN-2026-01', 'S119', 2, 2, 0, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(120, 'PLAN-2026-01', 'S120', 3, 2, 0, '2026-09-10 10:00:00', 'admin', CURRENT_TIMESTAMP),
(201, 'PLAN-2026-02', 'S121', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(202, 'PLAN-2026-02', 'S122', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(203, 'PLAN-2026-02', 'S123', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(204, 'PLAN-2026-02', 'S124', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(205, 'PLAN-2026-02', 'S125', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(206, 'PLAN-2026-02', 'S126', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(207, 'PLAN-2026-02', 'S127', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(208, 'PLAN-2026-02', 'S128', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(209, 'PLAN-2026-02', 'S129', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(210, 'PLAN-2026-02', 'S130', 0, 1, 1, '2026-09-20 09:00:00', 'admin', CURRENT_TIMESTAMP),
(301, 'PLAN-2026-03', 'S101', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(302, 'PLAN-2026-03', 'S102', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(303, 'PLAN-2026-03', 'S103', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(304, 'PLAN-2026-03', 'S104', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(305, 'PLAN-2026-03', 'S105', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(306, 'PLAN-2026-03', 'S106', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(307, 'PLAN-2026-03', 'S107', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(308, 'PLAN-2026-03', 'S108', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(309, 'PLAN-2026-03', 'S109', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(310, 'PLAN-2026-03', 'S110', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(311, 'PLAN-2026-03', 'S111', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(312, 'PLAN-2026-03', 'S112', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(313, 'PLAN-2026-03', 'S113', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(314, 'PLAN-2026-03', 'S114', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP),
(315, 'PLAN-2026-03', 'S115', 4, 3, 1, '2026-07-25 09:00:00', 'admin', CURRENT_TIMESTAMP)
ON CONFLICT (plan_id, student_id) DO UPDATE SET
enrollment_status = EXCLUDED.enrollment_status, accommodation_required = EXCLUDED.accommodation_required;
-- 4. 报到确认流水
INSERT INTO public.train_class_report (report_id, enrollment_id, report_way, report_device_sn, report_time, verify_result, verify_note, create_by, create_time, remark)
VALUES
(101, 101, 1, 'DEV-SN-001', '2026-09-14 09:13:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(102, 102, 3, 'DEV-SN-001', '2026-09-14 10:16:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(103, 103, 2, 'DEV-SN-001', '2026-09-14 11:19:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(104, 104, 1, 'DEV-SN-001', '2026-09-14 08:22:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(105, 105, 3, 'DEV-SN-001', '2026-09-14 09:25:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(106, 106, 2, 'DEV-SN-001', '2026-09-14 10:28:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(107, 107, 1, 'DEV-SN-001', '2026-09-14 11:31:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(108, 108, 3, 'DEV-SN-001', '2026-09-14 08:34:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(109, 109, 2, 'DEV-SN-001', '2026-09-14 09:37:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(110, 110, 1, 'DEV-SN-001', '2026-09-14 10:40:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(111, 111, 3, 'DEV-SN-001', '2026-09-14 11:43:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(112, 112, 2, 'DEV-SN-001', '2026-09-14 08:46:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(113, 113, 1, 'DEV-SN-001', '2026-09-14 09:49:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(114, 114, 3, 'DEV-SN-001', '2026-09-14 10:52:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(115, 115, 2, 'DEV-SN-001', '2026-09-14 11:55:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到'),
(116, 116, 1, 'DEV-SN-001', '2026-09-14 08:58:00', 1, '现场人脸核验通过', 'admin', CURRENT_TIMESTAMP, '按期现场报到')
ON CONFLICT (enrollment_id) DO UPDATE SET
report_time = EXCLUDED.report_time, report_way = EXCLUDED.report_way;
-- 5. 住宿安排 (0:预分配, 1:在住, 2:已退宿)
INSERT INTO public.train_accommodation (accommodation_id, enrollment_id, dorm_id, bed_no, assigned_time, accommodation_status, create_by, create_time, remark)
VALUES
(101, 101, 'DORM-ZY-101', '1号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(102, 102, 'DORM-ZY-101', '2号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(103, 103, 'DORM-ZY-101', '3号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(104, 104, 'DORM-ZY-101', '4号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(105, 105, 'DORM-ZY-102', '1号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(106, 106, 'DORM-ZY-102', '2号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(107, 107, 'DORM-ZY-102', '3号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(108, 108, 'DORM-ZY-102', '4号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(109, 109, 'DORM-ZY-103', '1号床', '2026-09-14 10:00:00', 0, 'admin', CURRENT_TIMESTAMP, '预分配待办理入住(现场演示)'),
(110, 110, 'DORM-ZY-103', '2号床', '2026-09-14 10:00:00', 0, 'admin', CURRENT_TIMESTAMP, '预分配待办理入住(现场演示)'),
(111, 111, 'DORM-ZY-103', '3号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(112, 112, 'DORM-ZY-103', '4号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(113, 113, 'DORM-ZY-104', '1号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(114, 114, 'DORM-ZY-104', '2号床', '2026-09-14 10:00:00', 1, 'admin', CURRENT_TIMESTAMP, '正常在住'),
(115, 115, 'DORM-ZY-104', '3号床', '2026-09-14 10:00:00', 2, 'admin', CURRENT_TIMESTAMP, '因车间抢险提前退宿'),
(116, 116, 'DORM-ZY-104', '4号床', '2026-09-14 10:00:00', 2, 'admin', CURRENT_TIMESTAMP, '因病提前退宿')
ON CONFLICT (accommodation_id) DO UPDATE SET
accommodation_status = EXCLUDED.accommodation_status, dorm_id = EXCLUDED.dorm_id, bed_no = EXCLUDED.bed_no;
-- 门禁凭据与授权
INSERT INTO public.train_dorm_auth (auth_id, accommodation_id, auth_start, auth_end, face_sync_status, credential_type, auth_status, create_by, create_time, remark)
VALUES
(101, 101, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(102, 102, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(103, 103, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(104, 104, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(105, 105, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(106, 106, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(107, 107, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(108, 108, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(109, 109, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(110, 110, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(111, 111, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(112, 112, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(113, 113, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发'),
(114, 114, '2026-09-14 00:00:00', '2026-09-30 23:59:59', 1, 'ONLINE_PASSWORD', 'ACTIVE', 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 智能门禁凭据已下发')
ON CONFLICT (accommodation_id) DO UPDATE SET
auth_status = EXCLUDED.auth_status, face_sync_status = EXCLUDED.face_sync_status;
-- 6. 排课日程 (教室与场地互斥,包含确定性冲突用例)
INSERT INTO public.train_lesson (lesson_id, plan_course_id, t_id, venue_type, class_room_id, site_id, start_time, end_time, create_by, create_time, remark)
VALUES
(101, 1, 'T101', 1, 'CR01', NULL, '2026-09-16 09:00:00', '2026-09-16 11:30:00', 'admin', CURRENT_TIMESTAMP, '已结课:高铁站房巡检理论'),
(102, 1, 'T101', 1, 'CR01', NULL, '2026-09-17 14:00:00', '2026-09-17 16:30:00', 'admin', CURRENT_TIMESTAMP, '已结课:雨棚构件防脱专项理论'),
(103, 3, 'T102', 2, NULL, 'SITE02', '2026-09-18 09:00:00', '2026-09-18 12:00:00', 'admin', CURRENT_TIMESTAMP, '已结课:给排水变频调速泵组实作演练'),
(104, 2, 'T103', 1, 'CR02', NULL, '2026-09-19 14:00:00', '2026-09-19 17:00:00', 'admin', CURRENT_TIMESTAMP, '已结课:智能公寓门禁联动实演'),
(105, 1, 'T101', 1, 'CR01', NULL, '2026-09-24 09:00:00', '2026-09-24 11:30:00', 'admin', CURRENT_TIMESTAMP, '今日核心课次:站台沉降观测技术(预留演示排课四维冲突拦截)'),
(106, 3, 'T102', 2, NULL, 'SITE01', '2026-09-25 09:00:00', '2026-09-25 12:00:00', 'admin', CURRENT_TIMESTAMP, '待上课:实训场结构探伤实作'),
(107, 4, 'T104', 1, 'CR01', NULL, '2026-09-26 14:00:00', '2026-09-26 16:30:00', 'admin', CURRENT_TIMESTAMP, '待上课:电子班牌数字化实务'),
(108, 1, 'T101', 1, 'CR01', NULL, '2026-09-28 09:00:00', '2026-09-28 11:30:00', 'admin', CURRENT_TIMESTAMP, '待上课:研修班综合答辩与结业')
ON CONFLICT (lesson_id) DO UPDATE SET
start_time = EXCLUDED.start_time, end_time = EXCLUDED.end_time, t_id = EXCLUDED.t_id;
-- 7. 考勤签到流水 (包含缺勤0、正常1、迟到2、早退3、请假4)
INSERT INTO public.train_student_checkin (checkin_id, enrollment_id, lesson_id, board_id, checkin_way, sign_in_time, sign_out_time, attendance_status, manual_flag, create_by, create_time, remark)
VALUES
(1, 101, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(2, 102, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(3, 103, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(4, 104, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(5, 105, 101, 'BP001', 1, '2026-09-16 09:12:00', '2026-09-16 11:32:00', 2, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(6, 106, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(7, 107, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(8, 108, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(9, 109, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(10, 110, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(11, 111, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(12, 112, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(13, 113, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(14, 114, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(15, 115, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(16, 116, 101, 'BP001', 1, '2026-09-16 08:52:00', '2026-09-16 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(17, 101, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(18, 102, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(19, 103, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(20, 104, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(21, 105, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(22, 106, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(23, 107, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(24, 108, 102, 'BP001', 1, NULL, NULL, 0, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(25, 109, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(26, 110, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(27, 111, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(28, 112, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(29, 113, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(30, 114, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(31, 115, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(32, 116, 102, 'BP001', 1, '2026-09-17 08:52:00', '2026-09-17 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(33, 101, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(34, 102, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(35, 103, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(36, 104, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(37, 105, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(38, 106, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(39, 107, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(40, 108, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(41, 109, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(42, 110, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(43, 111, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(44, 112, 103, 'BP001', 4, '2026-09-18 09:00:00', '2026-09-18 11:30:00', 4, 1, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(45, 113, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(46, 114, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(47, 115, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(48, 116, 103, 'BP001', 1, '2026-09-18 08:52:00', '2026-09-18 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(49, 101, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(50, 102, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(51, 103, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 16:10:00', 3, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(52, 104, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(53, 105, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(54, 106, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(55, 107, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(56, 108, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(57, 109, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(58, 110, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(59, 111, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(60, 112, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(61, 113, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(62, 114, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(63, 115, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水'),
(64, 116, 104, 'BP001', 1, '2026-09-19 08:52:00', '2026-09-19 11:32:00', 1, 0, 'admin', CURRENT_TIMESTAMP, '课次签到流水')
ON CONFLICT (enrollment_id, lesson_id) DO UPDATE SET
attendance_status = EXCLUDED.attendance_status, sign_in_time = EXCLUDED.sign_in_time, sign_out_time = EXCLUDED.sign_out_time;
-- 8. Score V2 成绩
INSERT INTO public.train_score_item (score_item_id, plan_id, plan_course_id, item_name, item_type, weight, full_score, sort_no, create_by, create_time, remark)
VALUES
(1, 'PLAN-2026-01', 1, '高铁房建检修规范-期末笔试', 1, 40.00, 100.00, 1, 'admin', CURRENT_TIMESTAMP, '闭卷理论测试'),
(2, 'PLAN-2026-01', 3, '给排水设备标准化操作考核', 2, 40.00, 100.00, 2, 'admin', CURRENT_TIMESTAMP, '实操工场考核'),
(3, 'PLAN-2026-01', 1, '课堂考勤与平时研讨成绩', 1, 20.00, 100.00, 3, 'admin', CURRENT_TIMESTAMP, '平时出勤与课堂提问')
ON CONFLICT (score_item_id) DO UPDATE SET
item_name = EXCLUDED.item_name, weight = EXCLUDED.weight, full_score = EXCLUDED.full_score;
INSERT INTO public.train_student_score (score_id, enrollment_id, score_item_id, score, source_type, import_time, create_by, create_time, remark)
VALUES
(1, 101, 1, 92.50, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(2, 101, 2, 95.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(3, 101, 3, 98.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(4, 102, 1, 88.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(5, 102, 2, 86.50, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(6, 102, 3, 92.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(7, 103, 1, 95.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(8, 103, 2, 91.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(9, 103, 3, 96.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(10, 104, 1, 78.50, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(11, 104, 2, 82.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(12, 104, 3, 85.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(13, 105, 1, 84.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(14, 105, 2, 80.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(15, 105, 3, 88.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(16, 106, 1, 68.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(17, 106, 2, 72.50, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(18, 106, 3, 75.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(19, 107, 1, 90.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(20, 107, 2, 94.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(21, 107, 3, 95.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(22, 108, 1, 58.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(23, 108, 2, 65.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(24, 108, 3, 70.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(25, 109, 1, 85.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(26, 109, 2, 88.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(27, 109, 3, 90.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(28, 110, 1, 82.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(29, 110, 2, 84.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(30, 110, 3, 86.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(31, 111, 1, 91.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(32, 111, 2, 93.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(33, 111, 3, 95.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(34, 112, 1, 75.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(35, 112, 2, 78.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(36, 112, 3, 80.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(37, 113, 1, 88.50, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(38, 113, 2, 90.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(39, 113, 3, 92.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(40, 114, 1, 86.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(41, 114, 2, 89.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(42, 114, 3, 91.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(43, 115, 1, 80.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(44, 115, 2, 83.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(45, 115, 3, 85.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(46, 116, 1, 83.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(47, 116, 2, 85.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入'),
(48, 116, 3, 87.00, 1, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '正式考评录入')
ON CONFLICT (score_id) DO UPDATE SET
score = EXCLUDED.score;
COMMIT;
-- >>> 来源: sql/demo/004_demo_scenario_data.sql >>>
-- ==============================================================================
-- RailwaySystem Clean Demo 资产: 004_demo_scenario_data.sql
-- 适用数据库: KingbaseES V009R003C018 (schema: public)
-- ==============================================================================
BEGIN;
-- 1. 教学资源
INSERT INTO public.train_resource (resource_id, resource_name, resource_type, resource_url, description, status, del_flag, create_by, create_time, remark)
VALUES
('RES-001', '高速铁路站房构造与检修工艺图集.pdf', 1, '/profile/upload/train/docs/gt_station_arch_2026.pdf', '站房核心结构权威图册', 1, '0', 'admin', CURRENT_TIMESTAMP, '高清图册'),
('RES-002', '站台雨棚防脱拉索安装与探伤教学视频.mp4', 2, '/profile/upload/train/video/canopy_cable_inspection.mp4', '实操演练视频', 1, '0', 'admin', CURRENT_TIMESTAMP, '实操视频'),
('RES-003', '给排水变频供水泵组交互式3D拆解模型.glb', 3, '/profile/upload/train/models/water_pump_assembly.glb', '3D数字孪生模型', 1, '0', 'admin', CURRENT_TIMESTAMP, '3D模型'),
('RES-004', '营业线施工天窗防护与避车VR交互仿真课件.vr', 4, '/profile/upload/train/vr/rail_safety_window_vr.pkg', '沉浸式VR课件', 1, '0', 'admin', CURRENT_TIMESTAMP, 'VR课件'),
('RES-005', '智能公寓门禁物联通信协议与故障排查指南.pdf', 1, '/profile/upload/train/docs/dms_protocol_guide.pdf', '公寓物联技术指南', 1, '0', 'admin', CURRENT_TIMESTAMP, '协议指南'),
('RES-006', '极端强对流天气防汛防台演练复盘实况.mp4', 2, '/profile/upload/train/video/flood_defense_drill.mp4', '防汛演练纪实视频', 1, '0', 'admin', CURRENT_TIMESTAMP, '演练纪实')
ON CONFLICT (resource_id) DO UPDATE SET
resource_name = EXCLUDED.resource_name, resource_type = EXCLUDED.resource_type, status = EXCLUDED.status, del_flag = '0';
-- 2. 课程资源关联
INSERT INTO public.train_course_resource (id, c_id, resource_id, sort_no, create_by, create_time)
VALUES
(1, 'C001', 'RES-001', 1, 'admin', CURRENT_TIMESTAMP),
(2, 'C001', 'RES-002', 2, 'admin', CURRENT_TIMESTAMP),
(3, 'C004', 'RES-003', 1, 'admin', CURRENT_TIMESTAMP),
(4, 'C002', 'RES-004', 1, 'admin', CURRENT_TIMESTAMP),
(5, 'C003', 'RES-005', 1, 'admin', CURRENT_TIMESTAMP),
(6, 'C005', 'RES-006', 1, 'admin', CURRENT_TIMESTAMP)
ON CONFLICT (c_id, resource_id) DO NOTHING;
-- 3. 自主学习时长
INSERT INTO public.train_study_duration (dur_id, enrollment_id, plan_course_id, resource_id, learning_content, source_system, source_event_id, start_time, end_time, study_seconds, sync_time, create_by, create_time, remark)
VALUES
(1, 101, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0001', '2026-09-18 19:00:00', '2026-09-18 19:53:00', 3180, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(2, 101, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0002', '2026-09-20 19:00:00', '2026-09-20 20:04:00', 3840, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(3, 101, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0003', '2026-09-22 19:00:00', '2026-09-22 20:15:00', 4500, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(4, 102, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0004', '2026-09-18 19:00:00', '2026-09-18 20:00:00', 3600, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(5, 102, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0005', '2026-09-20 19:00:00', '2026-09-20 20:11:00', 4260, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(6, 102, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0006', '2026-09-22 19:00:00', '2026-09-22 20:22:00', 4920, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(7, 103, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0007', '2026-09-18 19:00:00', '2026-09-18 20:07:00', 4020, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(8, 103, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0008', '2026-09-20 19:00:00', '2026-09-20 20:18:00', 4680, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(9, 103, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0009', '2026-09-22 19:00:00', '2026-09-22 19:39:00', 2340, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(10, 104, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0010', '2026-09-18 19:00:00', '2026-09-18 20:14:00', 4440, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(11, 104, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0011', '2026-09-20 19:00:00', '2026-09-20 19:35:00', 2100, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(12, 104, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0012', '2026-09-22 19:00:00', '2026-09-22 19:46:00', 2760, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(13, 105, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0013', '2026-09-18 19:00:00', '2026-09-18 20:21:00', 4860, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(14, 105, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0014', '2026-09-20 19:00:00', '2026-09-20 19:42:00', 2520, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(15, 105, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0015', '2026-09-22 19:00:00', '2026-09-22 19:53:00', 3180, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(16, 106, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0016', '2026-09-18 19:00:00', '2026-09-18 19:38:00', 2280, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(17, 106, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0017', '2026-09-20 19:00:00', '2026-09-20 19:49:00', 2940, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(18, 106, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0018', '2026-09-22 19:00:00', '2026-09-22 20:00:00', 3600, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(19, 107, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0019', '2026-09-18 19:00:00', '2026-09-18 19:45:00', 2700, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(20, 107, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0020', '2026-09-20 19:00:00', '2026-09-20 19:56:00', 3360, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(21, 107, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0021', '2026-09-22 19:00:00', '2026-09-22 20:07:00', 4020, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(22, 108, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0022', '2026-09-18 19:00:00', '2026-09-18 19:52:00', 3120, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(23, 108, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0023', '2026-09-20 19:00:00', '2026-09-20 20:03:00', 3780, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(24, 108, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0024', '2026-09-22 19:00:00', '2026-09-22 20:14:00', 4440, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(25, 109, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0025', '2026-09-18 19:00:00', '2026-09-18 19:59:00', 3540, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(26, 109, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0026', '2026-09-20 19:00:00', '2026-09-20 20:10:00', 4200, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(27, 109, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0027', '2026-09-22 19:00:00', '2026-09-22 20:21:00', 4860, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(28, 110, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0028', '2026-09-18 19:00:00', '2026-09-18 20:06:00', 3960, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(29, 110, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0029', '2026-09-20 19:00:00', '2026-09-20 20:17:00', 4620, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(30, 110, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0030', '2026-09-22 19:00:00', '2026-09-22 19:38:00', 2280, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(31, 111, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0031', '2026-09-18 19:00:00', '2026-09-18 20:13:00', 4380, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(32, 111, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0032', '2026-09-20 19:00:00', '2026-09-20 20:24:00', 5040, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(33, 111, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0033', '2026-09-22 19:00:00', '2026-09-22 19:45:00', 2700, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(34, 112, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0034', '2026-09-18 19:00:00', '2026-09-18 20:20:00', 4800, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(35, 112, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0035', '2026-09-20 19:00:00', '2026-09-20 19:41:00', 2460, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(36, 112, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0036', '2026-09-22 19:00:00', '2026-09-22 19:52:00', 3120, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(37, 113, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0037', '2026-09-18 19:00:00', '2026-09-18 19:37:00', 2220, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(38, 113, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0038', '2026-09-20 19:00:00', '2026-09-20 19:48:00', 2880, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(39, 113, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0039', '2026-09-22 19:00:00', '2026-09-22 19:59:00', 3540, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(40, 114, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0040', '2026-09-18 19:00:00', '2026-09-18 19:44:00', 2640, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(41, 114, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0041', '2026-09-20 19:00:00', '2026-09-20 19:55:00', 3300, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(42, 114, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0042', '2026-09-22 19:00:00', '2026-09-22 20:06:00', 3960, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(43, 115, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0043', '2026-09-18 19:00:00', '2026-09-18 19:51:00', 3060, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(44, 115, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0044', '2026-09-20 19:00:00', '2026-09-20 20:02:00', 3720, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(45, 115, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0045', '2026-09-22 19:00:00', '2026-09-22 20:13:00', 4380, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(46, 116, 1, 'RES-001', '站房结构日常维护规程阅读', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0046', '2026-09-18 19:00:00', '2026-09-18 19:58:00', 3480, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(47, 116, 1, 'RES-002', '雨棚探伤高清教学视频回放', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0047', '2026-09-20 19:00:00', '2026-09-20 20:09:00', 4140, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡'),
(48, 116, 1, 'RES-003', '暖通变频供水泵组3D模拟拆卸', 'RAIL_ELEARNING_V2', 'EVT-STUDY-2026-0048', '2026-09-22 19:00:00', '2026-09-22 20:20:00', 4800, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '移动端自主学习打卡')
ON CONFLICT (dur_id) DO UPDATE SET
study_seconds = EXCLUDED.study_seconds, end_time = EXCLUDED.end_time;
-- 4. 学员360画像
INSERT INTO public.train_student_portrait (portrait_id, enrollment_id, attendance_rate, theory_score, practical_score, total_study_hour, label_tag, portrait_content, generated_time, create_by, create_time, remark)
VALUES
(101, 101, 100.00, 92.50, 95.00, 24.50, '优秀学员,技术骨干,全勤标兵', '{"attendance":100.0,"theory":92.5,"practice":95.0,"studyHour":24.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(102, 102, 100.00, 88.00, 86.50, 18.00, '全勤标兵,实作能手', '{"attendance":100.0,"theory":88.0,"practice":86.5,"studyHour":18.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(103, 103, 100.00, 95.00, 91.00, 26.00, '技术骨干,防汛骨干,理论前沿', '{"attendance":100.0,"theory":95.0,"practice":91.0,"studyHour":26.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(104, 104, 100.00, 78.50, 82.00, 15.50, '勤勉好学,安全卫士', '{"attendance":100.0,"theory":78.5,"practice":82.0,"studyHour":15.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(105, 105, 75.00, 84.00, 80.00, 20.00, '作风优良,综合骨干', '{"attendance":75.0,"theory":84.0,"practice":80.0,"studyHour":20.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(106, 106, 100.00, 68.00, 72.50, 12.00, '稳步提升,出勤良好', '{"attendance":100.0,"theory":68.0,"practice":72.5,"studyHour":12.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(107, 107, 100.00, 90.00, 94.00, 25.00, '拔尖人才,实作标杆', '{"attendance":100.0,"theory":90.0,"practice":94.0,"studyHour":25.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(108, 108, 75.00, 58.00, 65.00, 10.50, '需重点帮扶,理论待补强', '{"attendance":75.0,"theory":58.0,"practice":65.0,"studyHour":10.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(109, 109, 100.00, 85.00, 88.00, 19.50, '全勤学员,技术标兵', '{"attendance":100.0,"theory":85.0,"practice":88.0,"studyHour":19.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(110, 110, 100.00, 82.00, 84.00, 17.00, '勤恳踏实,业务能手', '{"attendance":100.0,"theory":82.0,"practice":84.0,"studyHour":17.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(111, 111, 100.00, 91.00, 93.00, 23.00, '理论扎实,排头兵', '{"attendance":100.0,"theory":91.0,"practice":93.0,"studyHour":23.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(112, 112, 100.00, 75.00, 78.00, 14.50, '作风硬朗,安全先锋', '{"attendance":100.0,"theory":75.0,"practice":78.0,"studyHour":14.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(113, 113, 100.00, 88.50, 90.00, 21.00, '技术能手,优秀学员', '{"attendance":100.0,"theory":88.5,"practice":90.0,"studyHour":21.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(114, 114, 100.00, 86.00, 89.00, 20.50, '全勤标兵,严谨细致', '{"attendance":100.0,"theory":86.0,"practice":89.0,"studyHour":20.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(115, 115, 100.00, 80.00, 83.00, 16.00, '学习积极,出勤达标', '{"attendance":100.0,"theory":80.0,"practice":83.0,"studyHour":16.0,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算'),
(116, 116, 100.00, 83.00, 85.00, 18.50, '业务骨干,善于钻研', '{"attendance":100.0,"theory":83.0,"practice":85.0,"studyHour":18.5,"safetySense":98.0,"discipline":96.0}', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '综合画像智能测算')
ON CONFLICT (enrollment_id) DO UPDATE SET
total_study_hour = EXCLUDED.total_study_hour, theory_score = EXCLUDED.theory_score, practical_score = EXCLUDED.practical_score, attendance_rate = EXCLUDED.attendance_rate, label_tag = EXCLUDED.label_tag, portrait_content = EXCLUDED.portrait_content;
-- 5. 外部系统映射与审计流水
INSERT INTO public.train_external_resource_mapping (mapping_id, dorm_id, vendor_code, local_resource_type, external_resource_type, external_resource_id, is_primary, mapping_status, last_sync_time, create_by, create_time)
VALUES
(1, 'DORM-ZY-101', 'DMS', 'DORM', 'ROOM', 'MOCK-DMS-ROOM-101', 1, 'ACTIVE', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP),
(2, 'DORM-ZY-102', 'DMS', 'DORM', 'ROOM', 'MOCK-DMS-ROOM-102', 1, 'ACTIVE', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP)
ON CONFLICT (mapping_id) DO NOTHING;
INSERT INTO public.train_external_operation (operation_id, door_auth_id, business_type, vendor_code, operation_type, operation_status, idempotency_key, attempt_count, requested_at, completed_at, create_by, create_time, remark)
VALUES
(1, 101, 'DOOR_AUTH', 'DMS', 'ISSUE_CREDENTIAL', 'SUCCESS', 'IDEMP-DMS-CRED-001', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 门禁凭据下发成功'),
(2, 102, 'DOOR_AUTH', 'DMS', 'RECONCILE', 'SUCCESS', 'IDEMP-DMS-RECON-001', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, '[DEMO MOCK] 离线对账完成')
ON CONFLICT (operation_id) DO NOTHING;
COMMIT;
@@ -0,0 +1,189 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 05b_fusion_iot_test_data.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013 (schema: iotlocks + public)
-- 业务场景: 培训住宿与 IoT 智能门锁跨模式业务融合合成测试数据
-- 合规与门禁保证:
-- 1. 100% 虚拟 Mock 合成数据,不包含任何真实学员、人脸图像或生产门锁 SN
-- 2. 不连接真实 MQTT Broker,下发与回执由自动化测试与 Mock 双向驱动
-- 3. 【任务6核心要求】初始测试数据置为未授权/待同步状态 (sync_status=0, status=0),
-- 绝不预置下发成功(sync_status=2)冒充完整链路,确保通过真实业务 API 和 Mock 回执推动
-- 4. 【任务4与5核心要求】外键类型严格对齐 BIGINT,列名与 Mapper 完全一致,
-- 利用部分唯一索引验证退宿 (accommodation_status=2) 与重新入住 (accommodation_status=1) 并存
-- ==============================================================================
BEGIN;
-- ==============================================================================
-- 1. IoT 物联基础设施底座 (schema: iotlocks)
-- ==============================================================================
-- 1.1 分组 (对应公寓楼宇/培训园区)
INSERT INTO iotlocks.lock_group
(group_id, group_code, group_name, dept_id, manager, phone, address, status, order_num, del_flag, create_by, create_time, remark)
VALUES
(1001, 'GRP_FUSION_TEST', '致远楼融合测试公寓', 112, '管理员', '18800000001', '沈阳段实训园区致远楼', '0', 1, '0', 'admin', CURRENT_TIMESTAMP, '融合测试专用设备分组')
ON CONFLICT (group_id) DO UPDATE SET
group_code = EXCLUDED.group_code,
group_name = EXCLUDED.group_name,
del_flag = '0';
-- 1.2 网关设备 (对齐 04 DDL 列名: gateway_ip)
INSERT INTO iotlocks.lock_gateway
(gateway_id, gateway_sn, gateway_name, group_id, gateway_ip, online_status, status, del_flag, create_by, create_time, remark)
VALUES
(1001, 'GW-FUSION-TEST-01', '致远楼1层测试LoRa网关', 1001, '192.168.10.201', '0', '0', '0', 'admin', CURRENT_TIMESTAMP, '融合测试网关')
ON CONFLICT (gateway_id) DO UPDATE SET
gateway_sn = EXCLUDED.gateway_sn,
gateway_name = EXCLUDED.gateway_name,
group_id = EXCLUDED.group_id,
gateway_ip = EXCLUDED.gateway_ip,
del_flag = '0';
-- 1.3 智能门锁设备 (对应宿舍房间 101 与 102)
INSERT INTO iotlocks.lock_device
(device_id, device_sn, device_name, gateway_id, group_id, room_no, dev_type, dev_ver, face_algo_version, online_status, status, del_flag, create_by, create_time, remark)
VALUES
(1001, 'LOCK-ZY-101', '致远楼101智能门锁', 1001, 1001, '101', '01', 'V2.1.0', '2.14.5_2.7.1_M3', '0', '0', '0', 'admin', CURRENT_TIMESTAMP, '宿舍101匹配智能门锁'),
(1002, 'LOCK-ZY-102', '致远楼102智能门锁', 1001, 1001, '102', '01', 'V2.1.0', '2.14.5_2.7.1_M3', '0', '0', '0', 'admin', CURRENT_TIMESTAMP, '宿舍102匹配智能门锁')
ON CONFLICT (device_id) DO UPDATE SET
device_sn = EXCLUDED.device_sn,
device_name = EXCLUDED.device_name,
gateway_id = EXCLUDED.gateway_id,
group_id = EXCLUDED.group_id,
room_no = EXCLUDED.room_no,
del_flag = '0';
-- ==============================================================================
-- 2. 培训业务主档与宿舍房间 (schema: public)
-- ==============================================================================
-- 2.1 宿舍主档 (lock_device_sn 与 iotlocks.lock_device.device_sn 100% 对应)
INSERT INTO public.train_dormitory_info
(dorm_id, dorm_building, dorm_floor, dorm_room, capacity, gender_type, dorm_status, lock_device_sn, create_by, create_time, del_flag, remark)
VALUES
('DORM-ZY-101', '致远楼', '1层', '101', 4, 1, 1, 'LOCK-ZY-101', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍101室(绑定门锁LOCK-ZY-101)'),
('DORM-ZY-102', '致远楼', '1层', '102', 4, 1, 1, 'LOCK-ZY-102', 'admin', CURRENT_TIMESTAMP, '0', '男生宿舍102室(绑定门锁LOCK-ZY-102)')
ON CONFLICT (dorm_id) DO UPDATE SET
lock_device_sn = EXCLUDED.lock_device_sn,
dorm_status = EXCLUDED.dorm_status,
del_flag = '0';
-- 2.2 开班计划
INSERT INTO public.train_class_plan
(plan_id, plan_name, start_time, end_time, report_deadline, train_address, recruit_num, apply_condition, plan_status, create_by, create_time, del_flag, remark)
VALUES
('PLAN-FUSION-01', '2026年公寓智能物联与门禁业务融合实训班', '2026-10-01 08:30:00', '2026-10-30 17:30:00', '2026-09-30 18:00:00', '致远楼实训园区', 20, '参训学员', 1, 'admin', CURRENT_TIMESTAMP, '0', '融合测试专用开班')
ON CONFLICT (plan_id) DO UPDATE SET
plan_name = EXCLUDED.plan_name,
plan_status = EXCLUDED.plan_status,
del_flag = '0';
-- 2.3 融合测试专属学员主档 (稳定唯一的 person_no)
INSERT INTO public.train_student
(s_id, s_name, s_gender, s_birth, org_name, s_phone, s_email, id_card_hash, id_card_last4, person_no, source_type, status, del_flag, create_by, create_time, remark)
VALUES
('S_FUSION_001', '刘强(融合测试)', '0', '1992-05-18', '沈阳房建公寓段沈阳车间', '18800000881', 'liuqiang@sict.railway.cn', 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', '8811', 'AA000001', 1, 1, '0', 'admin', CURRENT_TIMESTAMP, '学员1-用于退宿与重新入住场景'),
('S_FUSION_002', '陈燕(融合测试)', '1', '1994-08-22', '沈阳房建公寓段大连车间', '18800000882', 'chenyan@sict.railway.cn', 'd41d8cd98f00b204e9800998ecf8427e', '8822', 'AA000002', 1, 1, '0', 'admin', CURRENT_TIMESTAMP, '学员2-用于调宿与端到端授权下发场景')
ON CONFLICT (s_id) DO UPDATE SET
s_name = EXCLUDED.s_name,
person_no = EXCLUDED.person_no,
s_phone = EXCLUDED.s_phone,
status = EXCLUDED.status,
del_flag = '0';
-- 2.4 参训记录 (使用正确列名 student_id,enrollment_id 为 BIGINT)
INSERT INTO public.train_enrollment
(enrollment_id, plan_id, student_id, source_type, enrollment_status, accommodation_required, join_time, create_by, create_time)
VALUES
(2001, 'PLAN-FUSION-01', 'S_FUSION_001', 1, 1, 1, '2026-09-30 14:00:00', 'admin', CURRENT_TIMESTAMP),
(2002, 'PLAN-FUSION-01', 'S_FUSION_002', 1, 1, 1, '2026-09-30 14:30:00', 'admin', CURRENT_TIMESTAMP)
ON CONFLICT (enrollment_id) DO UPDATE SET
student_id = EXCLUDED.student_id,
enrollment_status = EXCLUDED.enrollment_status;
-- ==============================================================================
-- 3. 住宿业务记录 (使用正确列名: accommodation_id, enrollment_id, dorm_id, bed_no, assigned_time, accommodation_status)
-- ==============================================================================
-- 学员1 (enrollment_id = 2001, AA000001):
-- - 记录 2001: 历史退宿记录 (accommodation_status = 2)
-- - 记录 2003: 重新入住记录 (accommodation_status = 1)
-- -> 证明部分唯一索引 uq_accommodation_active_enroll 正常放行历史退宿与再次入住
-- 学员2 (enrollment_id = 2002, AA000002):
-- - 记录 2002: 当前在住记录 (accommodation_status = 1)
INSERT INTO public.train_accommodation
(accommodation_id, enrollment_id, dorm_id, bed_no, assigned_time, accommodation_status, create_by, create_time, remark)
VALUES
(2001, 2001, 'DORM-ZY-101', '1号床', '2026-09-01 09:00:00', 2, 'admin', CURRENT_TIMESTAMP, '历史住宿记录-已退宿'),
(2003, 2001, 'DORM-ZY-101', '1号床', '2026-10-01 08:00:00', 1, 'admin', CURRENT_TIMESTAMP, '重新入住记录-当前在住'),
(2002, 2002, 'DORM-ZY-102', '1号床', '2026-10-01 08:30:00', 1, 'admin', CURRENT_TIMESTAMP, '当前分配入住记录')
ON CONFLICT (accommodation_id) DO UPDATE SET
dorm_id = EXCLUDED.dorm_id,
bed_no = EXCLUDED.bed_no,
accommodation_status = EXCLUDED.accommodation_status,
assigned_time = EXCLUDED.assigned_time;
-- ==============================================================================
-- 4. IoT 人脸凭证与门锁授权数据 (schema: iotlocks)
-- 【核心门禁要求】初始态为未授权/待提取/待下发,绝不预置成功状态冒充完整链路
-- ==============================================================================
-- 4.1 Mock 人脸凭证 (对齐 04 DDL 列名: photo_url, feature_data, feature_algo_version)
INSERT INTO iotlocks.lock_face
(face_id, person_no, person_name, person_type, photo_url, feature_data, extract_status, feature_algo_version, create_by, create_time, remark)
VALUES
(1001, 'AA000001', '刘强(融合测试)', '0', 'mock:base64:synthetic_face_image_001', NULL, '0', '2.14.5_2.7.1_M3', 'admin', CURRENT_TIMESTAMP, '初始未提取人脸-待提取特征'),
(1002, 'AA000002', '陈燕(融合测试)', '0', 'mock:base64:synthetic_face_image_002', NULL, '0', '2.14.5_2.7.1_M3', 'admin', CURRENT_TIMESTAMP, '初始未提取人脸-待提取特征')
ON CONFLICT (face_id) DO UPDATE SET
person_no = EXCLUDED.person_no,
person_name = EXCLUDED.person_name,
extract_status = EXCLUDED.extract_status;
-- 4.2 门锁授权记录 (对齐 04 DDL 与 LockAuth 实体: auth_no, device_sn, gateway_id, group_id, auth_type, sync_status, status)
-- 由业务端到端 API 发起下发并经 Mock MQTT 回执推进状态至成功
INSERT INTO iotlocks.lock_auth
(auth_id, auth_no, person_no, person_name, device_id, device_sn, gateway_id, group_id, auth_type, sync_status, status, begin_time, end_time, retry_count, del_flag, create_by, create_time, remark)
VALUES
(1001, 'AUTH202610130001', 'AA000001', '刘强(融合测试)', 1001, 'LOCK-ZY-101', 1001, 1001, '01', '0', '0', '2026-10-01 08:00:00', '2026-10-30 23:59:59', 0, '0', 'admin', CURRENT_TIMESTAMP, '学员1门锁101-初始待下发授权'),
(1002, 'AUTH202610130002', 'AA000002', '陈燕(融合测试)', 1002, 'LOCK-ZY-102', 1001, 1001, '01', '0', '0', '2026-10-01 08:00:00', '2026-10-30 23:59:59', 0, '0', 'admin', CURRENT_TIMESTAMP, '学员2门锁102-初始待下发授权')
ON CONFLICT (auth_id) DO UPDATE SET
auth_no = EXCLUDED.auth_no,
person_no = EXCLUDED.person_no,
device_id = EXCLUDED.device_id,
device_sn = EXCLUDED.device_sn,
status = EXCLUDED.status,
sync_status = EXCLUDED.sync_status;
-- ==============================================================================
-- 5. 序列号安全复位 (防止后续业务自增冲突)
-- ==============================================================================
DO $$
BEGIN
IF pg_get_serial_sequence('iotlocks.lock_group', 'group_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('iotlocks.lock_group', 'group_id'), greatest((SELECT coalesce(max(group_id), 0) FROM iotlocks.lock_group), 1001));
END IF;
IF pg_get_serial_sequence('iotlocks.lock_gateway', 'gateway_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('iotlocks.lock_gateway', 'gateway_id'), greatest((SELECT coalesce(max(gateway_id), 0) FROM iotlocks.lock_gateway), 1001));
END IF;
IF pg_get_serial_sequence('iotlocks.lock_device', 'device_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('iotlocks.lock_device', 'device_id'), greatest((SELECT coalesce(max(device_id), 0) FROM iotlocks.lock_device), 1002));
END IF;
IF pg_get_serial_sequence('iotlocks.lock_face', 'face_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('iotlocks.lock_face', 'face_id'), greatest((SELECT coalesce(max(face_id), 0) FROM iotlocks.lock_face), 1002));
END IF;
IF pg_get_serial_sequence('iotlocks.lock_auth', 'auth_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('iotlocks.lock_auth', 'auth_id'), greatest((SELECT coalesce(max(auth_id), 0) FROM iotlocks.lock_auth), 1002));
END IF;
IF pg_get_serial_sequence('public.train_enrollment', 'enrollment_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('public.train_enrollment', 'enrollment_id'), greatest((SELECT coalesce(max(enrollment_id), 0) FROM public.train_enrollment), 2002));
END IF;
IF pg_get_serial_sequence('public.train_accommodation', 'accommodation_id') IS NOT NULL THEN
PERFORM setval(pg_get_serial_sequence('public.train_accommodation', 'accommodation_id'), greatest((SELECT coalesce(max(accommodation_id), 0) FROM public.train_accommodation), 2003));
END IF;
END $$;
COMMIT;
@@ -0,0 +1,224 @@
-- ==============================================================================
-- RailwaySystem QA Bootstrap: 06_verify_schema_integrity.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013
-- 目标: 全自动化只读验证 Schema 结构完整性、字段存在性、部分唯一索引与跨模式业务关联
-- 安全性: 100% 只读断言,绝无任何 DDL/DML 写操作
-- ==============================================================================
DO $$
DECLARE
v_dbname VARCHAR;
v_cnt INT;
v_missing_tables TEXT := '';
v_table_name TEXT;
-- 23 张培训业务表全量清单 (严格与源码实体/Mapper及02脚本对齐)
v_train_tables TEXT[] := ARRAY[
'train_teacher', 'train_student', 'train_course',
'train_classroom_info', 'train_training_site', 'train_electronic_board',
'train_dormitory_info', 'train_class_plan', 'train_resource',
'train_course_resource', 'train_plan_course', 'train_enrollment',
'train_accommodation', 'train_lesson', 'train_score_item',
'train_student_score', 'train_dorm_auth', 'train_class_report',
'train_student_checkin', 'train_study_duration', 'train_student_portrait',
'train_external_resource_mapping', 'train_external_operation'
];
-- 9 张 IoT 智能门锁业务表清单
v_iot_tables TEXT[] := ARRAY[
'lock_group', 'lock_gateway', 'lock_device',
'lock_face', 'lock_auth', 'lock_access_log',
'lock_command', 'lock_mqtt_log', 'lock_service_config'
];
BEGIN
-- 1. 白名单断言: 校验当前数据库名称
SELECT current_database() INTO v_dbname;
IF v_dbname <> 'railwaysystem_fusion_qa_20261013' THEN
RAISE EXCEPTION '>>> [FATAL-SECURITY] 当前数据库名为 [%], 绝非授权的目标库 railwaysystem_fusion_qa_20261013! 中止验证!', v_dbname;
END IF;
RAISE NOTICE '>>> [PASS] 数据库白名单校验通过: %', v_dbname;
-- 2. 校验 public 模式下的 23 张培训业务表
FOREACH v_table_name IN ARRAY v_train_tables
LOOP
SELECT count(*) INTO v_cnt FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = v_table_name;
IF v_cnt = 0 THEN
v_missing_tables := v_missing_tables || ' public.' || v_table_name;
END IF;
END LOOP;
IF v_missing_tables <> '' THEN
RAISE EXCEPTION '>>> [FAIL] 缺少以下培训表: %', v_missing_tables;
END IF;
RAISE NOTICE '>>> [PASS] public 模式下的 23 张培训业务表全部物理齐备';
-- 3. 校验 iotlocks 模式下的 9 张物联核心表
v_missing_tables := '';
FOREACH v_table_name IN ARRAY v_iot_tables
LOOP
SELECT count(*) INTO v_cnt FROM information_schema.tables
WHERE table_schema = 'iotlocks' AND table_name = v_table_name;
IF v_cnt = 0 THEN
v_missing_tables := v_missing_tables || ' iotlocks.' || v_table_name;
END IF;
END LOOP;
IF v_missing_tables <> '' THEN
RAISE EXCEPTION '>>> [FAIL] 缺少以下 IoT 表: %', v_missing_tables;
END IF;
RAISE NOTICE '>>> [PASS] iotlocks 模式下的 9 张物联业务表全部物理齐备';
-- 4. 关键业务列与 Mapper 匹配列物理存在性核验 (严格断言)
-- 4.1 public.train_student.person_no
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_student' AND column_name = 'person_no';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_student.person_no 缺失!';
END IF;
-- 4.2 public.train_classroom_info.class_room_id
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_classroom_info' AND column_name = 'class_room_id';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_classroom_info.class_room_id 缺失!';
END IF;
-- 4.3 public.train_resource.resource_id
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_resource' AND column_name = 'resource_id';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_resource.resource_id 缺失!';
END IF;
-- 4.4 public.train_enrollment.student_id
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_enrollment' AND column_name = 'student_id';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_enrollment.student_id 缺失!';
END IF;
-- 4.5 public.train_score_item.weight
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_score_item' AND column_name = 'weight';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_score_item.weight 缺失!';
END IF;
-- 4.6 public.train_accommodation.accommodation_status 与 accommodation_id
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_accommodation' AND column_name = 'accommodation_status';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_accommodation.accommodation_status 缺失!';
END IF;
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_accommodation' AND column_name = 'accommodation_id';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_accommodation.accommodation_id 缺失!';
END IF;
-- 4.7 public.train_external_operation.door_auth_id 与 business_type
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_external_operation' AND column_name = 'door_auth_id';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_external_operation.door_auth_id 缺失!';
END IF;
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'train_external_operation' AND column_name = 'business_type';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 public.train_external_operation.business_type 缺失!';
END IF;
-- 4.8 iotlocks 核心字段
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'iotlocks' AND table_name = 'lock_device' AND column_name = 'device_sn';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 iotlocks.lock_device.device_sn 缺失!';
END IF;
SELECT count(*) INTO v_cnt FROM information_schema.columns
WHERE table_schema = 'iotlocks' AND table_name = 'lock_auth' AND column_name = 'person_no';
IF v_cnt = 0 THEN
RAISE EXCEPTION '>>> [FAIL-P0] 字段 iotlocks.lock_auth.person_no 缺失!';
END IF;
RAISE NOTICE '>>> [PASS] 关键业务对接字段与 Mapper 真实列物理存在性核验全部通过';
-- 5. 跨模式业务关联完整性断言
-- 5.1 门锁 SN 关联一致性: train_dormitory_info 与 lock_device
SELECT count(*) INTO v_cnt
FROM public.train_dormitory_info d
JOIN iotlocks.lock_device ld ON d.lock_device_sn = ld.device_sn
WHERE d.lock_device_sn IN ('LOCK-ZY-101', 'LOCK-ZY-102');
IF v_cnt < 2 THEN
RAISE EXCEPTION '>>> [FAIL] 宿舍 lock_device_sn 与 IoT 门锁 device_sn 跨模式匹配失败: 匹配数 % < 2', v_cnt;
END IF;
RAISE NOTICE '>>> [PASS] 宿舍与智能门锁跨模式设备匹配校验通过 (有效匹配数: %)', v_cnt;
-- 5.2 人员编号关联一致性: train_student.person_no 与 lock_auth.person_no
SELECT count(DISTINCT s.person_no) INTO v_cnt
FROM public.train_student s
JOIN iotlocks.lock_auth la ON s.person_no = la.person_no
WHERE s.person_no IN ('AA000001', 'AA000002');
IF v_cnt < 2 THEN
RAISE EXCEPTION '>>> [FAIL] 学员 person_no 与 IoT 授权 lock_auth.person_no 关联失败: 匹配学员数 % < 2', v_cnt;
END IF;
RAISE NOTICE '>>> [PASS] 学员主档与 IoT 门锁授权跨模式人员匹配校验通过 (关联人员数: %)', v_cnt;
-- 5.3 住宿生命周期覆盖性核验: 入住、退宿、重新入住
-- 当前在住记录 (accommodation_status = 1)
SELECT count(*) INTO v_cnt
FROM public.train_accommodation
WHERE accommodation_status = 1 AND enrollment_id IN (2001, 2002);
IF v_cnt < 2 THEN
RAISE EXCEPTION '>>> [FAIL] 缺少当前在住状态记录, 实际检测到 %', v_cnt;
END IF;
-- 历史退宿记录 (accommodation_status = 2)
SELECT count(*) INTO v_cnt
FROM public.train_accommodation
WHERE accommodation_status = 2 AND enrollment_id = 2001;
IF v_cnt < 1 THEN
RAISE EXCEPTION '>>> [FAIL] 缺少学员 1 历史退宿状态记录, 实际检测到 %', v_cnt;
END IF;
-- 重新入住验证: 学员 1 (enrollment_id = 2001) 同时存在历史退宿(2)与当前在住(1)记录
SELECT count(*) INTO v_cnt
FROM public.train_accommodation
WHERE enrollment_id = 2001;
IF v_cnt < 2 THEN
RAISE EXCEPTION '>>> [FAIL] 学员 1 未能同时存在退宿与在住记录 (重新入住多状态受阻), 实际检测到 %', v_cnt;
END IF;
RAISE NOTICE '>>> [PASS] 住宿生命周期与重新入住结构验证通过 (退宿与在住共存通过部分唯一索引放行)';
-- 5.4 【任务6核心门禁】端到端测试初始未授权状态断言 (确保未预置成功状态冒充完整链路)
SELECT count(*) INTO v_cnt
FROM iotlocks.lock_auth
WHERE sync_status = '0' AND person_no IN ('AA000001', 'AA000002');
IF v_cnt < 2 THEN
RAISE EXCEPTION '>>> [FAIL-SECURITY] 融合测试门锁授权记录未处于初始未授权状态(sync_status=0), 存在伪造成功状态风险: 实际检测到 %', v_cnt;
END IF;
RAISE NOTICE '>>> [PASS] 初始门锁授权数据均为待下发状态 (sync_status=0),完全符合端到端真实下发推导规范';
-- 6. 基础测试数据规模合规性检查
SELECT count(*) INTO v_cnt FROM public.train_student;
IF v_cnt < 35 THEN
RAISE EXCEPTION '>>> [FAIL] 学员合成数据行数异常: 期望 >= 35, 实际检测到 %', v_cnt;
END IF;
SELECT count(*) INTO v_cnt FROM public.train_teacher;
IF v_cnt < 6 THEN
RAISE EXCEPTION '>>> [FAIL] 教师合成数据行数异常: 期望 >= 6, 实际检测到 %', v_cnt;
END IF;
SELECT count(*) INTO v_cnt FROM public.train_dormitory_info;
IF v_cnt < 20 THEN
RAISE EXCEPTION '>>> [FAIL] 宿舍合成数据行数异常: 期望 >= 20, 实际检测到 %', v_cnt;
END IF;
RAISE NOTICE '>>> [PASS] 纯合成基础测试数据行数校验全部达标 (学员 35+, 教师 6+, 宿舍 20+)';
RAISE NOTICE '=========================================================';
RAISE NOTICE '>>> [ALL-PASS] 数据库 Schema、字段断言与跨表业务关联检验全部通过! <<<';
RAISE NOTICE '=========================================================';
END $$;
@@ -0,0 +1,183 @@
-- =============================================================================
-- SYFJGYD学员管理系统 数据库补全脚本: 07_restore_training_menus_and_notice.sql
-- 目标数据库: railwaysystem_fusion_qa_20261013, Schema: public
-- 任务内容:
-- 1. 创建 sys_notice_read 表以解决 relation "sys_notice_read" does not exist
-- 2. 补齐原系统全部一级目录 (人员管理、教学设施、课程管理、自主学习、统计分析、学员画像)
-- 3. 补齐原系统全部二级业务菜单 (教师、学员、教室、实训、宿舍、电子班牌、设备物联、住宿安排、开班计划、课程、签到、时长等)
-- 4. 保留并有序组织 IoT 智能门锁业务菜单 (公寓分组、网关、门锁、人脸、授权、通行、命令、报文等)
-- 5. 隐蔽无关的若依官网外链 (menu_id=4)
-- 6. 全量授予超级管理员 (role_id=1) 和培训管理员 (role_id=3) 菜单与操作权限
-- =============================================================================
BEGIN;
-- 1. 创建 sys_notice_read 表
CREATE TABLE IF NOT EXISTS public.sys_notice_read (
read_id BIGSERIAL PRIMARY KEY,
notice_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
read_time TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uk_notice_user UNIQUE (notice_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_notice_read_user ON public.sys_notice_read (user_id);
GRANT SELECT, INSERT, UPDATE, DELETE ON public.sys_notice_read TO fusion_qa_app;
GRANT USAGE, SELECT ON SEQUENCE public.sys_notice_read_read_id_seq TO fusion_qa_app;
-- 2. 停用并隐藏若依官网菜单 (menu_id = 4)
UPDATE public.sys_menu
SET visible = '1', status = '1', update_by = 'admin', update_time = CURRENT_TIMESTAMP
WHERE menu_id = 4;
-- 3. 补齐原系统顶级目录与业务页面菜单 (幂等插入 / 更新)
-- 3.1 人员管理 (2159)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2159, '人员管理', 0, 1, 'person', NULL, NULL, 1, 0, 'M', '0', '0', '', 'user', 'admin', CURRENT_TIMESTAMP, '人员管理目录')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=1, path='person', visible='0', status='0';
-- 3.1.1 教师信息 (2155)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2155, '教师信息', 2159, 1, 'teacher', 'train/teacher', NULL, 1, 0, 'C', '0', '0', 'train:teacher:list', 'people', 'admin', CURRENT_TIMESTAMP, '教师信息')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2159, order_num=1, path='teacher', component='train/teacher', perms='train:teacher:list', visible='0', status='0';
-- 3.1.2 学员信息 (2156)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2156, '学员信息', 2159, 2, 'student', 'train/student', NULL, 1, 0, 'C', '0', '0', 'train:student:list', 'peoples', 'admin', CURRENT_TIMESTAMP, '学员信息')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2159, order_num=2, path='student', component='train/student', perms='train:student:list', visible='0', status='0';
-- 3.2 教学设施 (2154)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2154, '教学设施', 0, 2, 'equip', NULL, NULL, 1, 0, 'M', '0', '0', '', 'excel', 'admin', CURRENT_TIMESTAMP, '教学设施目录')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=2, path='equip', visible='0', status='0';
-- 3.2.1 教室信息 (2157)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2157, '教室信息', 2154, 1, 'classroom', 'train/classroom', NULL, 1, 0, 'C', '0', '0', '', 'build', 'admin', CURRENT_TIMESTAMP, '教室信息')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=1, path='classroom', component='train/classroom', visible='0', status='0';
-- 3.2.2 实训场地 (2158)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2158, '实训场地', 2154, 2, 'site', 'train/site', NULL, 1, 0, 'C', '0', '0', '', 'row', 'admin', CURRENT_TIMESTAMP, '实训场地')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=2, path='site', component='train/site', visible='0', status='0';
-- 3.2.3 宿舍信息 (2161)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2161, '宿舍信息', 2154, 3, 'dormitory', 'train/dormitory', NULL, 1, 0, 'C', '0', '0', '', 'table', 'admin', CURRENT_TIMESTAMP, '宿舍信息')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=3, path='dormitory', component='train/dormitory', visible='0', status='0';
-- 3.2.4 电子班牌 (2174)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2174, '电子班牌', 2154, 4, 'board', 'train/board', NULL, 1, 0, 'C', '0', '0', '', 'message', 'admin', CURRENT_TIMESTAMP, '电子班牌')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=4, path='board', component='train/board', visible='0', status='0';
-- 3.2.5 设备物联 (2160)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2160, '设备物联', 2154, 5, 'extra', 'train/extra', NULL, 1, 0, 'C', '0', '0', '', 'cascader', 'admin', CURRENT_TIMESTAMP, '设备物联')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=5, path='extra', component='train/extra', visible='0', status='0';
-- 3.2.6 住宿管理 (2261)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2261, '住宿管理', 2154, 6, 'accommodation', 'train/accommodation/index', NULL, 1, 0, 'C', '0', '0', 'train:accommodation:list', 'table', 'admin', CURRENT_TIMESTAMP, '住宿管理')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=6, path='accommodation', component='train/accommodation/index', perms='train:accommodation:list', visible='0', status='0';
-- 3.2.7 门禁管理 (2060)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2060, '门禁管理', 2154, 7, 'auth', 'train/auth/index', NULL, 1, 0, 'C', '0', '0', 'train:access:query', 'lock', 'admin', CURRENT_TIMESTAMP, '门禁管理')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=7, path='auth', component='train/auth/index', perms='train:access:query', visible='0', status='0';
-- 3.2.8 教学资源 (2251)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2251, '教学资源', 2154, 8, 'resource', 'train/resource/index', NULL, 1, 0, 'C', '0', '0', 'train:resource:list', 'documentation', 'admin', CURRENT_TIMESTAMP, '教学资源')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2154, order_num=8, path='resource', component='train/resource/index', perms='train:resource:list', visible='0', status='0';
-- 3.3 课程管理 (2162)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2162, '课程管理', 0, 3, 'coursemgr', NULL, NULL, 1, 0, 'M', '0', '0', '', 'date', 'admin', CURRENT_TIMESTAMP, '课程管理目录')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=3, path='coursemgr', visible='0', status='0';
-- 3.3.1 课程信息 (2163)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2163, '课程信息', 2162, 1, 'course', 'train/course', NULL, 1, 0, 'C', '0', '0', '', 'education', 'admin', CURRENT_TIMESTAMP, '课程信息')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2162, order_num=1, path='course', component='train/course', visible='0', status='0';
-- 3.3.2 开班计划 (2164)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2164, '开班计划', 2162, 2, 'plan', 'train/plan', NULL, 1, 0, 'C', '0', '0', '', 'job', 'admin', CURRENT_TIMESTAMP, '开班计划')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2162, order_num=2, path='plan', component='train/plan', visible='0', status='0';
-- 3.4 自主学习 (2167)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2167, '自主学习', 0, 4, 'self', NULL, NULL, 1, 0, 'M', '0', '0', '', 'skill', 'admin', CURRENT_TIMESTAMP, '自主学习目录')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=4, path='self', visible='0', status='0';
-- 3.4.1 电子设备 (2168)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2168, '电子设备', 2167, 1, 'equipment', 'train/equipment', NULL, 1, 0, 'C', '0', '0', '', 'monitor', 'admin', CURRENT_TIMESTAMP, '电子设备')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2167, order_num=1, path='equipment', component='train/equipment', visible='0', status='0';
-- 3.5 统计分析 (2169)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2169, '统计分析', 0, 5, 'analysis', NULL, NULL, 1, 0, 'M', '0', '0', '', 'chart', 'admin', CURRENT_TIMESTAMP, '统计分析目录')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=5, path='analysis', visible='0', status='0';
-- 3.5.1 开班签到 (2170)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2170, '开班签到', 2169, 1, 'report', 'train/report', NULL, 1, 0, 'C', '0', '0', 'train:report:list', 'list', 'admin', CURRENT_TIMESTAMP, '开班签到')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2169, order_num=1, path='report', component='train/report', perms='train:report:list', visible='0', status='0';
-- 3.5.2 课程签到 (2171)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2171, '课程签到', 2169, 2, 'checkin', 'train/checkin', NULL, 1, 0, 'C', '0', '0', 'train:attendance:list', 'time', 'admin', CURRENT_TIMESTAMP, '课程签到')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2169, order_num=2, path='checkin', component='train/checkin', perms='train:attendance:list', visible='0', status='0';
-- 3.5.3 学习时长 (2172)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2172, '学习时长', 2169, 3, 'duration', 'train/duration', NULL, 1, 0, 'C', '0', '0', 'train:learning:list', 'time-range', 'admin', CURRENT_TIMESTAMP, '学习时长')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=2169, order_num=3, path='duration', component='train/duration', perms='train:learning:list', visible='0', status='0';
-- 3.6 学员画像 (2173)
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2173, '学员画像', 0, 6, 'portrait', 'train/portrait', NULL, 1, 0, 'C', '0', '0', 'train:portrait:query', 'user', 'admin', CURRENT_TIMESTAMP, '学员画像')
ON CONFLICT (menu_id) DO UPDATE SET parent_id=0, order_num=6, path='portrait', component='train/portrait', perms='train:portrait:query', visible='0', status='0';
-- 3.7 门禁管理 / 智能门锁 (2000) 调整排序为 7
UPDATE public.sys_menu
SET menu_name = '智能门锁', parent_id = 0, order_num = 7, path = 'iot', component = NULL,
menu_type = 'M', visible = '0', status = '0', icon = 'lock', update_by = 'admin', update_time = CURRENT_TIMESTAMP
WHERE menu_id = 2000;
-- 3.8 调整系统工具、系统管理、系统监控排序为 8, 9, 10
UPDATE public.sys_menu SET order_num = 8 WHERE menu_id = 3; -- 系统工具
UPDATE public.sys_menu SET order_num = 9 WHERE menu_id = 1; -- 系统管理
UPDATE public.sys_menu SET order_num = 10 WHERE menu_id = 2; -- 系统监控
-- 3.9 确保住宿管理按钮级权限 (2262, 2263, 2264, 2265) 挂载在 2261
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2262, '住宿查询', 2261, 1, '#', '', '', 1, 0, 'F', '0', '0', 'train:accommodation:query', '#', 'admin', CURRENT_TIMESTAMP, '住宿查询')
ON CONFLICT (menu_id) DO NOTHING;
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2263, '住宿办理', 2261, 2, '#', '', '', 1, 0, 'F', '0', '0', 'train:accommodation:edit', '#', 'admin', CURRENT_TIMESTAMP, '住宿办理(入住/调房/退宿)')
ON CONFLICT (menu_id) DO NOTHING;
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2264, '分配住宿', 2261, 3, '#', '', '', 1, 0, 'F', '0', '0', 'train:accommodation:add', '#', 'admin', CURRENT_TIMESTAMP, '分配住宿')
ON CONFLICT (menu_id) DO NOTHING;
INSERT INTO public.sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES (2265, '住宿删除', 2261, 4, '#', '', '', 1, 0, 'F', '0', '0', 'train:accommodation:remove', '#', 'admin', CURRENT_TIMESTAMP, '住宿删除')
ON CONFLICT (menu_id) DO NOTHING;
-- 4. 角色菜单授权:全量授予 role_id = 1 (超级管理员) 所有可用菜单
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 1, menu_id FROM public.sys_menu
ON CONFLICT DO NOTHING;
-- 5. 角色菜单授权:授予 role_id = 3 (培训管理员) 培训业务菜单与智能门锁菜单
INSERT INTO public.sys_role_menu (role_id, menu_id)
SELECT 3, menu_id FROM public.sys_menu
WHERE menu_id BETWEEN 2000 AND 3999
ON CONFLICT DO NOTHING;
COMMIT;