fastbee/sql/sys_user_setting.sql
2026-10-05 18:26:40 +08:00

117 lines
8.3 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================
-- 用户系统设置(用户维度)+ 设备侧全局开关入库
-- 维度判据:读的时候拿不拿得到 userId
-- · 拿得到(HTTP 请求,有 SecurityContext)→ sys_user_setting,per-user
-- · 拿不到(设备上电 @Async 线程)→ sys_config,全局
-- 配套代码:SysUserSetting* / PowerOnTriggerTaskExecutor:93
-- 版本: 1.0 2026-10-05
-- =============================================
-- ------------------------------------------------------------
-- 一、用户维度设置表
-- 一行一用户;所有设置列 NOT NULL + DEFAULT,不设「未配置过」这种 NULL 态
-- 业务默认值由 Java 常量兜底(UserSettingConstants),不依赖 DB 兜底
--
-- pinned_tags:任务栏「固定标签到任务栏」的 JSON 数组,按固定顺序存 route path。
-- * 原实现存浏览器 localStorage(key: pinned-tags),换浏览器/换电脑就丢,
-- 现改为落库,同一账号在任何设备登录都能恢复固定区。
-- * 只存用户右键固定的 pinned 集合;路由自身声明的 affix(首页,router/index.js:80)
-- 由 constantRoutes 天然重建,不入此列。
-- * **写入语义:单条增量**。接口是 POST/DELETE 一个 path,服务端在事务里
-- 「SELECT ... FOR UPDATE → 读数组 → 改 → UPDATE 整列」。
-- 刻意**不提供提交整份列表的覆盖写接口**:前端手里那份列表可能已被
-- 另一个标签页/另一台设备改过,整份提交会把对方的改动静默抹掉,
-- 这正是固定标签「用着用着就少了」的成因。
-- * 增删都在 Java 侧按列表处理,**未使用任何 MySQL JSON 函数**。
-- * DEFAULT ('[]') 是 MySQL 8.0.13+ 的表达式默认值。TEXT 列不能带字面量 DEFAULT,
-- 不给默认值时 STRICT_TRANS_TABLES 下会直接报错,故必须显式写空数组。
-- 低版本数据库请改为 VARCHAR(2000) NOT NULL DEFAULT '[]'。
--
-- 已建过表的库用下面的 ALTER 补列(可重复执行前请先确认列不存在):
-- ALTER TABLE `sys_user_setting`
-- ADD COLUMN `pinned_tags` text NOT NULL DEFAULT ('[]')
-- COMMENT '任务栏固定标签JSON数组,按序存 path;空数组表示未固定'
-- AFTER `login_redirect`;
-- ALTER TABLE `sys_user_setting`
-- ADD COLUMN `query_gateway_child` tinyint(1) NOT NULL DEFAULT 0
-- COMMENT '按编号查询时是否查网关子设备(0否1是)'
-- AFTER `pinned_tags`;
-- ALTER TABLE `sys_user_setting`
-- ADD COLUMN `show_child` tinyint(1) NOT NULL DEFAULT 0
-- COMMENT '设备管理列表是否包含下级机构数据(0否1是)'
-- AFTER `query_gateway_child`;
--
-- query_gateway_child:开启后 /iot/device/shortList **按设备编号查询时**(serialNumber 非空):
-- ① 命中的若是网关子设备编号,返回其所属的网关设备(子设备 gw_dev_code 存的就是网关 serial_number,
-- 取 ifnull(gw_dev_code, serial_number) 换算);
-- ② 放开产品类型为「网关子设备(4)」的过滤 —— 这类设备 gw_dev_code 为空、实为独立设备,
-- 只是产品被标成 4,默认在列表中被隐藏(否则设备管理页会多出一大批),仅在按编号精确定位时可见。
-- 该开关**不改变列表范围** —— gw_dev_code is null 恒生效,不带编号时 device_type != 4 依然过滤,
-- 所以短列表始终只出顶层设备(网关 + 直连),既不出现挂在网关下的真子设备,
-- 默认列表也不会多出 device_type=4 的设备。
-- 默认 0。读该值的入口是 DeviceController#shortList,有 SecurityContext,故为 per-user 设置。
--
-- show_child:设备管理列表是否包含下级机构数据(原为设备管理页勾选框,值存在浏览器
-- localStorage 的 device-showChild,换浏览器/换电脑就丢,现改为落库)。
-- 生效条件同 Device.showChild:仅在 deptId 非空(机构用户)时参与 SQL,语义见
-- DeviceMapper.xml#selectDeviceShortListJoinWhere —— 开启时 tenant_id 落在「本机构
-- 及全部下级机构用户」集合内,关闭时仅本机构。
-- 该值现在由「系统管理 → 系统设置」页维护,设备管理页只读不写(页面内的勾选框已移除)。
-- 设备管理页进入时读一次该设置并作为查询参数下发,故本列是「前端读取、后端不感知」的偏好,
-- DeviceController 在未收到 showChild 时依然按 false 处理。
-- 默认 0 = 与引入本开关前完全一致。
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `sys_user_setting` (
`setting_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '设置主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID(sys_user.user_id)',
`login_redirect` varchar(128) NOT NULL DEFAULT '/bigscreen' COMMENT '登录后跳转路由path',
`pinned_tags` text NOT NULL DEFAULT ('[]') COMMENT '任务栏固定标签JSON数组,按序存 path;空数组表示未固定',
`query_gateway_child` tinyint(1) NOT NULL DEFAULT 0 COMMENT '按编号查询时是否查网关子设备(0否1是)',
`show_child` tinyint(1) NOT NULL DEFAULT 0 COMMENT '设备管理列表是否包含下级机构数据(0否1是)',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`setting_id`) USING BTREE,
UNIQUE KEY `uk_sys_user_setting_user` (`user_id`) USING BTREE COMMENT '每用户仅一行'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
ROW_FORMAT=DYNAMIC COMMENT='用户系统设置表';
-- ------------------------------------------------------------
-- 二、设备侧全局开关 → 复用已有 sys_config 表
-- 原实现:PowerOnTriggerTaskExecutor 直读运维手动写入的裸 Redis key
-- "get_imei_iccid"(经 BackendController /set 写入)
-- 新实现:改读 sys_config,运维改用已有的 PUT /system/config
-- config_type='Y' = 系统内置,deleteConfigByIds 会拒删
-- ------------------------------------------------------------
INSERT INTO `sys_config`
(`config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `remark`)
SELECT '是否下发读取设备IMEI/ICCID指令', 'iot.power_on.read_imei_iccid', 'true', 'Y', 'system', NOW(),
'设备上电后是否下发 AT+IMEI/AT+ICCID/AT+LBS 指令读取;读该值的线程无登录上下文,故为全局配置'
WHERE NOT EXISTS (
SELECT 1 FROM `sys_config` WHERE `config_key` = 'iot.power_on.read_imei_iccid'
);
-- ------------------------------------------------------------
-- 三、菜单:系统管理 → 个人设置
-- 不设 system:setting:list 权限点的原因:
-- 接口读写的是「当前登录用户自己的」设置,无需菜单级授权;
-- 若填了权限点,非管理员账号将看不到也用不了自己的设置页。
-- menu_type='C' 菜单,component 指向新建的 views/system/setting/index.vue
-- ------------------------------------------------------------
INSERT INTO `sys_menu`
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`)
SELECT '系统设置', 1, 13, 'setting', 'system/setting/index', 1, 0, 'C', '0', '0', '', 'setting', 'system', NOW()
WHERE NOT EXISTS (
SELECT 1 FROM `sys_menu` WHERE `parent_id` = 1 AND `path` = 'setting'
);
-- ------------------------------------------------------------
-- 四、清理历史遗留的裸 Redis key
-- 原开关 key 无前缀、不在任何 key 生成器中,与 RedisKeyBuilder 规范不符。
-- 确认线上设备已完成一轮上电、开关已由 sys_config 接管后再执行:
-- redis-cli DEL get_imei_iccid
-- 切勿在切换完成前执行,否则 IMEI/ICCID 指令会立即停止下发。
-- ------------------------------------------------------------