feat(tenant): 实现多租户功能支持
This commit is contained in:
186
sql/mysql/tenant_add.sql
Normal file
186
sql/mysql/tenant_add.sql
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
-- ============================================
|
||||||
|
-- 多租户支持 SQL 脚本(为现有系统添加多租户功能)
|
||||||
|
-- ============================================
|
||||||
|
-- 说明:此脚本用于为现有表添加 tenant_id 字段,启用多租户功能
|
||||||
|
-- 适用场景:已有系统需要升级支持多租户
|
||||||
|
-- 执行前请确保已备份数据库!
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
USE youlai_admin;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 1. 创建租户表(如果不存在)
|
||||||
|
-- ============================================
|
||||||
|
DROP TABLE IF EXISTS `sys_tenant`;
|
||||||
|
CREATE TABLE `sys_tenant` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '租户ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '租户名称',
|
||||||
|
`code` varchar(50) NOT NULL COMMENT '租户编码(唯一)',
|
||||||
|
`contact_name` varchar(50) DEFAULT NULL COMMENT '联系人姓名',
|
||||||
|
`contact_phone` varchar(20) DEFAULT NULL COMMENT '联系人电话',
|
||||||
|
`contact_email` varchar(100) DEFAULT NULL COMMENT '联系人邮箱',
|
||||||
|
`domain` varchar(100) DEFAULT NULL COMMENT '租户域名(用于域名识别)',
|
||||||
|
`logo` varchar(255) DEFAULT NULL COMMENT '租户Logo',
|
||||||
|
`status` tinyint DEFAULT '1' COMMENT '状态(1-正常 0-禁用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`expire_time` datetime DEFAULT NULL COMMENT '过期时间(NULL表示永不过期)',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_code` (`code`),
|
||||||
|
UNIQUE KEY `uk_domain` (`domain`),
|
||||||
|
KEY `idx_status` (`status`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='系统租户表';
|
||||||
|
|
||||||
|
-- 插入默认租户
|
||||||
|
INSERT INTO `sys_tenant` (`id`, `name`, `code`, `status`, `create_time`) VALUES
|
||||||
|
(1, '默认租户', 'DEFAULT', 1, NOW());
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 2. 创建用户租户关联表(支持一个用户属于多个租户)
|
||||||
|
-- ============================================
|
||||||
|
DROP TABLE IF EXISTS `sys_user_tenant`;
|
||||||
|
CREATE TABLE `sys_user_tenant` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
|
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||||
|
`is_default` tinyint DEFAULT '0' COMMENT '是否默认租户(1-是 0-否)',
|
||||||
|
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_user_tenant` (`user_id`, `tenant_id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户租户关联表(多租户模式)';
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 3. 为业务表添加 tenant_id 字段
|
||||||
|
-- ============================================
|
||||||
|
-- 注意:MySQL 5.7 不支持 IF NOT EXISTS,如果字段已存在会报错
|
||||||
|
-- 建议先检查字段是否存在,或使用 MySQL 8.0+
|
||||||
|
|
||||||
|
-- 用户表
|
||||||
|
ALTER TABLE `sys_user`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
-- 更新现有数据的 tenant_id(设置为默认租户)
|
||||||
|
UPDATE `sys_user` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 角色表
|
||||||
|
ALTER TABLE `sys_role`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `sys_role` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 部门表
|
||||||
|
ALTER TABLE `sys_dept`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `sys_dept` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 通知公告表
|
||||||
|
ALTER TABLE `sys_notice`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `sys_notice` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 系统日志表
|
||||||
|
ALTER TABLE `sys_log`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `sys_log` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- AI 命令记录表
|
||||||
|
ALTER TABLE `ai_command_log`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `ai_command_log` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 代码生成配置表(如果存在)
|
||||||
|
-- ALTER TABLE `gen_config`
|
||||||
|
-- ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
-- ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
-- UPDATE `gen_config` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 代码生成字段配置表(如果存在)
|
||||||
|
-- ALTER TABLE `gen_field_config`
|
||||||
|
-- ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
-- ADD INDEX `idx_tenant_id` (`tenant_id`);
|
||||||
|
-- UPDATE `gen_field_config` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 4. 初始化现有用户的租户关联(默认租户)
|
||||||
|
-- ============================================
|
||||||
|
INSERT INTO `sys_user_tenant` (`user_id`, `tenant_id`, `is_default`)
|
||||||
|
SELECT `id`, 1, 1 FROM `sys_user` WHERE `is_deleted` = 0
|
||||||
|
ON DUPLICATE KEY UPDATE `is_default` = 1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 5. 添加租户管理菜单和权限(仅在菜单不存在时添加)
|
||||||
|
-- ============================================
|
||||||
|
-- 租户管理主菜单(放在部门管理之后,字典管理之前,ID=6)
|
||||||
|
INSERT INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `always_show`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`)
|
||||||
|
VALUES (6, 1, '0,1', '租户管理', 1, 'Tenant', 'tenant', 'system/tenant/index', NULL, NULL, NULL, 1, 5, 'el-icon-OfficeBuilding', NULL, NOW(), NOW(), NULL)
|
||||||
|
ON DUPLICATE KEY UPDATE `name` = '租户管理';
|
||||||
|
|
||||||
|
-- 调整字典管理的排序(从6改为7)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 7 WHERE `id` = 7 AND `sort` = 6;
|
||||||
|
|
||||||
|
-- 调整字典项的排序(从7改为8)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 8 WHERE `id` = 8 AND `sort` = 7;
|
||||||
|
|
||||||
|
-- 调整系统日志的排序(从8改为9)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 9 WHERE `id` = 9 AND `sort` = 8;
|
||||||
|
|
||||||
|
-- 调整系统配置的排序(从9改为10)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 10 WHERE `id` = 10 AND `sort` = 9;
|
||||||
|
|
||||||
|
-- 调整通知公告的排序(从10改为11)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 11 WHERE `id` = 11 AND `sort` = 10;
|
||||||
|
|
||||||
|
-- 租户管理权限按钮(ID: 141-145)
|
||||||
|
INSERT INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `always_show`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`)
|
||||||
|
VALUES
|
||||||
|
(141, 6, '0,1,6', '租户查询', 4, NULL, '', NULL, 'sys:tenant:query', NULL, NULL, 1, 1, '', NULL, NOW(), NOW(), NULL),
|
||||||
|
(142, 6, '0,1,6', '租户新增', 4, NULL, '', NULL, 'sys:tenant:add', NULL, NULL, 1, 2, '', NULL, NOW(), NOW(), NULL),
|
||||||
|
(143, 6, '0,1,6', '租户编辑', 4, NULL, '', NULL, 'sys:tenant:edit', NULL, NULL, 1, 3, '', NULL, NOW(), NOW(), NULL),
|
||||||
|
(144, 6, '0,1,6', '租户删除', 4, NULL, '', NULL, 'sys:tenant:delete', NULL, NULL, 1, 4, '', NULL, NOW(), NOW(), NULL),
|
||||||
|
(145, 6, '0,1,6', '租户启用/禁用', 4, NULL, '', NULL, 'sys:tenant:status', NULL, NULL, 1, 5, '', NULL, NOW(), NOW(), NULL)
|
||||||
|
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`);
|
||||||
|
|
||||||
|
-- 为系统管理员角色(role_id=2)分配租户管理菜单权限
|
||||||
|
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||||
|
VALUES
|
||||||
|
(2, 6),
|
||||||
|
(2, 141),
|
||||||
|
(2, 142),
|
||||||
|
(2, 143),
|
||||||
|
(2, 144),
|
||||||
|
(2, 145)
|
||||||
|
ON DUPLICATE KEY UPDATE `role_id` = VALUES(`role_id`);
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 脚本执行完成
|
||||||
|
-- ============================================
|
||||||
|
-- 执行完成后,请在 application.yml 中配置:
|
||||||
|
-- youlai:
|
||||||
|
-- tenant:
|
||||||
|
-- enabled: true
|
||||||
|
-- column: tenant_id
|
||||||
|
-- default-tenant-id: 1
|
||||||
|
-- header-name: tenant-id
|
||||||
|
-- ignore-tables:
|
||||||
|
-- - sys_tenant
|
||||||
|
-- - sys_dict
|
||||||
|
-- - sys_dict_item
|
||||||
|
-- - sys_config
|
||||||
|
-- ============================================
|
||||||
111
sql/mysql/tenant_remove.sql
Normal file
111
sql/mysql/tenant_remove.sql
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
-- ============================================
|
||||||
|
-- 多租户移除脚本(移除多租户功能)
|
||||||
|
-- ============================================
|
||||||
|
-- 说明:此脚本用于移除多租户功能,删除 tenant_id 字段和相关表
|
||||||
|
-- 适用场景:不再需要多租户功能,需要回退到单租户模式
|
||||||
|
-- 执行前请确保已备份数据库!
|
||||||
|
-- 警告:此操作不可逆,请谨慎执行!
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
USE youlai_admin;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 1. 删除用户租户关联表
|
||||||
|
-- ============================================
|
||||||
|
DROP TABLE IF EXISTS `sys_user_tenant`;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 2. 删除租户表(可选)
|
||||||
|
-- ============================================
|
||||||
|
-- 注意:如果将来可能再次启用多租户,建议保留此表
|
||||||
|
-- 如需删除,取消下面的注释
|
||||||
|
-- DROP TABLE IF EXISTS `sys_tenant`;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 3. 移除业务表的 tenant_id 字段和索引
|
||||||
|
-- ============================================
|
||||||
|
-- 注意:如果字段不存在会报错,请根据实际情况调整
|
||||||
|
|
||||||
|
-- 用户表
|
||||||
|
ALTER TABLE `sys_user` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `sys_user` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 角色表
|
||||||
|
ALTER TABLE `sys_role` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `sys_role` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 部门表
|
||||||
|
ALTER TABLE `sys_dept` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `sys_dept` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 通知公告表
|
||||||
|
ALTER TABLE `sys_notice` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `sys_notice` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 系统日志表
|
||||||
|
ALTER TABLE `sys_log` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `sys_log` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- AI 命令记录表
|
||||||
|
ALTER TABLE `ai_command_log` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
ALTER TABLE `ai_command_log` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 代码生成配置表(如果存在)
|
||||||
|
-- ALTER TABLE `gen_config` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
-- ALTER TABLE `gen_config` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 代码生成字段配置表(如果存在)
|
||||||
|
-- ALTER TABLE `gen_field_config` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
-- ALTER TABLE `gen_field_config` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- 菜单表(如果之前添加了)
|
||||||
|
-- ALTER TABLE `sys_menu` DROP INDEX IF EXISTS `idx_tenant_id`;
|
||||||
|
-- ALTER TABLE `sys_menu` DROP COLUMN IF EXISTS `tenant_id`;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 4. 删除租户管理菜单和权限
|
||||||
|
-- ============================================
|
||||||
|
-- 删除角色菜单关联
|
||||||
|
DELETE FROM `sys_role_menu` WHERE `menu_id` IN (6, 141, 142, 143, 144, 145);
|
||||||
|
|
||||||
|
-- 删除租户管理权限按钮
|
||||||
|
DELETE FROM `sys_menu` WHERE `id` IN (141, 142, 143, 144, 145);
|
||||||
|
|
||||||
|
-- 删除租户管理主菜单
|
||||||
|
DELETE FROM `sys_menu` WHERE `id` = 6;
|
||||||
|
|
||||||
|
-- 恢复字典管理的排序(从7改回6)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 6 WHERE `id` = 7 AND `sort` = 7;
|
||||||
|
|
||||||
|
-- 恢复字典项的排序(从8改回7)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 7 WHERE `id` = 8 AND `sort` = 8;
|
||||||
|
|
||||||
|
-- 恢复系统日志的排序(从9改回8)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 8 WHERE `id` = 9 AND `sort` = 9;
|
||||||
|
|
||||||
|
-- 恢复系统配置的排序(从10改回9)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 9 WHERE `id` = 10 AND `sort` = 10;
|
||||||
|
|
||||||
|
-- 恢复通知公告的排序(从11改回10)
|
||||||
|
UPDATE `sys_menu` SET `sort` = 10 WHERE `id` = 11 AND `sort` = 11;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 脚本执行完成
|
||||||
|
-- ============================================
|
||||||
|
-- 执行完成后,请执行以下操作:
|
||||||
|
-- 1. 在 application.yml 中配置:
|
||||||
|
-- youlai:
|
||||||
|
-- tenant:
|
||||||
|
-- enabled: false
|
||||||
|
-- 2. 更新 BaseEntity.java,将 tenantId 字段的 exist 设置为 false
|
||||||
|
-- 或移除 tenantId 字段(如果确定不再使用)
|
||||||
|
-- ============================================
|
||||||
|
-- 注意:
|
||||||
|
-- 1. MySQL 5.7 不支持 IF EXISTS 语法,如果执行报错,请手动检查字段是否存在
|
||||||
|
-- 2. 对于 MySQL 8.0+,可以使用上面的语法
|
||||||
|
-- 3. 如果使用 MySQL 5.7,请先检查字段是否存在,再执行删除操作
|
||||||
|
-- ============================================
|
||||||
648
sql/mysql/youlai_admin.sql
Normal file
648
sql/mysql/youlai_admin.sql
Normal file
@@ -0,0 +1,648 @@
|
|||||||
|
|
||||||
|
# YouLai_Admin 数据库(MySQL 5.7 ~ MySQL 8.x)
|
||||||
|
# Copyright (c) 2021-present, youlai.tech
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 1. 创建数据库
|
||||||
|
-- ----------------------------
|
||||||
|
CREATE DATABASE IF NOT EXISTS youlai_admin CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 2. 创建表 && 数据初始化
|
||||||
|
-- ----------------------------
|
||||||
|
USE youlai_admin;
|
||||||
|
|
||||||
|
SET NAMES utf8mb4; # 设置字符集
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0; # 关闭外键检查,加快导入速度
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_dept
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_dept`;
|
||||||
|
CREATE TABLE `sys_dept` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '部门名称',
|
||||||
|
`code` varchar(100) NOT NULL COMMENT '部门编号',
|
||||||
|
`parent_id` bigint DEFAULT 0 COMMENT '父节点id',
|
||||||
|
`tree_path` varchar(255) NOT NULL COMMENT '父节点id路径',
|
||||||
|
`sort` smallint DEFAULT 0 COMMENT '显示顺序',
|
||||||
|
`status` tinyint DEFAULT 1 COMMENT '状态(1-正常 0-禁用)',
|
||||||
|
`create_by` bigint NULL COMMENT '创建人ID',
|
||||||
|
`create_time` datetime NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint NULL COMMENT '修改人ID',
|
||||||
|
`update_time` datetime NULL COMMENT '更新时间',
|
||||||
|
`is_deleted` tinyint DEFAULT 0 COMMENT '逻辑删除标识(1-已删除 0-未删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uk_code`(`code` ASC) USING BTREE COMMENT '部门编号唯一索引'
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '部门管理表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_dept
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_dept` VALUES (1, '有来技术', 'YOULAI', 0, '0', 1, 1, 1, NULL, 1, now(), 0);
|
||||||
|
INSERT INTO `sys_dept` VALUES (2, '研发部门', 'RD001', 1, '0,1', 1, 1, 2, NULL, 2, now(), 0);
|
||||||
|
INSERT INTO `sys_dept` VALUES (3, '测试部门', 'QA001', 1, '0,1', 1, 1, 2, NULL, 2, now(), 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_dict
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_dict`;
|
||||||
|
CREATE TABLE `sys_dict` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键 ',
|
||||||
|
`dict_code` varchar(50) COMMENT '类型编码',
|
||||||
|
`name` varchar(50) COMMENT '类型名称',
|
||||||
|
`status` tinyint(1) DEFAULT '0' COMMENT '状态(0:正常;1:禁用)',
|
||||||
|
`remark` varchar(255) COMMENT '备注',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`create_by` bigint COMMENT '创建人ID',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`update_by` bigint COMMENT '修改人ID',
|
||||||
|
`is_deleted` tinyint DEFAULT '0' COMMENT '是否删除(1-删除,0-未删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_dict_code` (`dict_code`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据字典类型表';
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_dict
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_dict` VALUES (1, 'gender', '性别', 1, NULL, now() , 1,now(), 1,0);
|
||||||
|
INSERT INTO `sys_dict` VALUES (2, 'notice_type', '通知类型', 1, NULL, now(), 1,now(), 1,0);
|
||||||
|
INSERT INTO `sys_dict` VALUES (3, 'notice_level', '通知级别', 1, NULL, now(), 1,now(), 1,0);
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_dict_item
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_dict_item`;
|
||||||
|
CREATE TABLE `sys_dict_item` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`dict_code` varchar(50) COMMENT '关联字典编码,与sys_dict表中的dict_code对应',
|
||||||
|
`value` varchar(50) COMMENT '字典项值',
|
||||||
|
`label` varchar(100) COMMENT '字典项标签',
|
||||||
|
`tag_type` varchar(50) COMMENT '标签类型,用于前端样式展示(如success、warning等)',
|
||||||
|
`status` tinyint DEFAULT '0' COMMENT '状态(1-正常,0-禁用)',
|
||||||
|
`sort` int DEFAULT '0' COMMENT '排序',
|
||||||
|
`remark` varchar(255) COMMENT '备注',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`create_by` bigint COMMENT '创建人ID',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`update_by` bigint COMMENT '修改人ID',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据字典项表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_dict_item
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (1, 'gender', '1', '男', 'primary', 1, 1, NULL, now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (2, 'gender', '2', '女', 'danger', 1, 2, NULL, now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (3, 'gender', '0', '保密', 'info', 1, 3, NULL, now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (4, 'notice_type', '1', '系统升级', 'success', 1, 1, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (5, 'notice_type', '2', '系统维护', 'primary', 1, 2, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (6, 'notice_type', '3', '安全警告', 'danger', 1, 3, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (7, 'notice_type', '4', '假期通知', 'success', 1, 4, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (8, 'notice_type', '5', '公司新闻', 'primary', 1, 5, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (9, 'notice_type', '99', '其他', 'info', 1, 99, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (10, 'notice_level', 'L', '低', 'info', 1, 1, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (11, 'notice_level', 'M', '中', 'warning', 1, 2, '', now(), 1,now(),1);
|
||||||
|
INSERT INTO `sys_dict_item` VALUES (12, 'notice_level', 'H', '高', 'danger', 1, 3, '', now(), 1,now(),1);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_menu
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_menu`;
|
||||||
|
CREATE TABLE `sys_menu` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||||
|
`parent_id` bigint NOT NULL COMMENT '父菜单ID',
|
||||||
|
`tree_path` varchar(255) COMMENT '父节点ID路径',
|
||||||
|
`name` varchar(64) NOT NULL COMMENT '菜单名称',
|
||||||
|
`type` char(1) NOT NULL COMMENT '菜单类型(C-目录 M-菜单 B-按钮)',
|
||||||
|
`route_name` varchar(255) COMMENT '路由名称(Vue Router 中用于命名路由)',
|
||||||
|
`route_path` varchar(128) COMMENT '路由路径(Vue Router 中定义的 URL 路径)',
|
||||||
|
`component` varchar(128) COMMENT '组件路径(组件页面完整路径,相对于 src/views/,缺省后缀 .vue)',
|
||||||
|
`perm` varchar(128) COMMENT '【按钮】权限标识',
|
||||||
|
`always_show` tinyint DEFAULT 0 COMMENT '【目录】只有一个子路由是否始终显示(1-是 0-否)',
|
||||||
|
`keep_alive` tinyint DEFAULT 0 COMMENT '【菜单】是否开启页面缓存(1-是 0-否)',
|
||||||
|
`visible` tinyint(1) DEFAULT 1 COMMENT '显示状态(1-显示 0-隐藏)',
|
||||||
|
`sort` int DEFAULT 0 COMMENT '排序',
|
||||||
|
`icon` varchar(64) COMMENT '菜单图标',
|
||||||
|
`redirect` varchar(128) COMMENT '跳转路径',
|
||||||
|
`create_time` datetime NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime NULL COMMENT '更新时间',
|
||||||
|
`params` varchar(255) NULL COMMENT '路由参数',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '系统菜单表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_menu
|
||||||
|
-- ----------------------------
|
||||||
|
-- 顶级目录(1-10):平台/系统/代码生成/AI助手/文档/接口文档/组件/演示/多级/路由
|
||||||
|
INSERT INTO `sys_menu` VALUES (1, 0, '0', '平台管理', 'C', '', '/platform', 'Layout', NULL, NULL, NULL, 1, 1, 'platform', '/platform/tenant', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2, 0, '0', '系统管理', 'C', '', '/system', 'Layout', NULL, NULL, NULL, 1, 2, 'system', '/system/user', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (3, 0, '0', '代码生成', 'C', '', '/gen', 'Layout', NULL, NULL, NULL, 1, 3, 'code', '/gen/index', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (4, 0, '0', 'AI助手', 'C', '', '/ai', 'Layout', NULL, NULL, NULL, 1, 4, 'platform', '/ai/command-record', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (5, 0, '0', '平台文档', 'C', '', '/doc', 'Layout', NULL, NULL, NULL, 1, 5, 'document', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (6, 0, '0', '接口文档', 'C', '', '/api', 'Layout', NULL, NULL, NULL, 1, 6, 'api', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (7, 0, '0', '组件封装', 'C', '', '/component', 'Layout', NULL, NULL, NULL, 1, 7, 'menu', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (8, 0, '0', '功能演示', 'C', '', '/function', 'Layout', NULL, NULL, NULL, 1, 8, 'menu', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (9, 0, '0', '多级菜单', 'C', NULL, '/multi-level', 'Layout', NULL, 1, NULL, 1, 9, 'cascader', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (10, 0, '0', '路由参数', 'C', '', '/route-param', 'Layout', NULL, NULL, NULL, 1, 10, 'el-icon-ElementPlus', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 平台管理(平台方)
|
||||||
|
INSERT INTO `sys_menu` VALUES (110, 1, '0,1', '租户管理', 'M', 'Tenant', 'tenant', 'system/tenant/index', NULL, NULL, 1, 1, 1, 'el-icon-OfficeBuilding', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1101, 110, '0,1,110', '租户查询', 'B', NULL, '', NULL, 'sys:tenant:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1102, 110, '0,1,110', '租户新增', 'B', NULL, '', NULL, 'sys:tenant:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1103, 110, '0,1,110', '租户编辑', 'B', NULL, '', NULL, 'sys:tenant:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1104, 110, '0,1,110', '租户删除', 'B', NULL, '', NULL, 'sys:tenant:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (1105, 110, '0,1,110', '租户启用/禁用', 'B', NULL, '', NULL, 'sys:tenant:change-status', NULL, NULL, 1, 5, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 系统管理(租户侧)
|
||||||
|
INSERT INTO `sys_menu` VALUES (210, 2, '0,2', '用户管理', 'M', 'User', 'user', 'system/user/index', NULL, NULL, 1, 1, 1, 'el-icon-User', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2101, 210, '0,2,210', '用户查询', 'B', NULL, '', NULL, 'sys:user:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2102, 210, '0,2,210', '用户新增', 'B', NULL, '', NULL, 'sys:user:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2103, 210, '0,2,210', '用户编辑', 'B', NULL, '', NULL, 'sys:user:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2104, 210, '0,2,210', '用户删除', 'B', NULL, '', NULL, 'sys:user:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2105, 210, '0,2,210', '重置密码', 'B', NULL, '', NULL, 'sys:user:reset-password', NULL, NULL, 1, 5, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2106, 210, '0,2,210', '用户导入', 'B', NULL, '', NULL, 'sys:user:import', NULL, NULL, 1, 6, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2107, 210, '0,2,210', '用户导出', 'B', NULL, '', NULL, 'sys:user:export', NULL, NULL, 1, 7, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (220, 2, '0,2', '角色管理', 'M', 'Role', 'role', 'system/role/index', NULL, NULL, 1, 1, 2, 'role', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2201, 220, '0,2,220', '角色查询', 'B', NULL, '', NULL, 'sys:role:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2202, 220, '0,2,220', '角色新增', 'B', NULL, '', NULL, 'sys:role:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2203, 220, '0,2,220', '角色编辑', 'B', NULL, '', NULL, 'sys:role:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2204, 220, '0,2,220', '角色删除', 'B', NULL, '', NULL, 'sys:role:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (230, 2, '0,2', '菜单管理', 'M', 'SysMenu', 'menu', 'system/menu/index', NULL, NULL, 1, 1, 3, 'menu', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2301, 230, '0,2,230', '菜单查询', 'B', NULL, '', NULL, 'sys:menu:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2302, 230, '0,2,230', '菜单新增', 'B', NULL, '', NULL, 'sys:menu:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2303, 230, '0,2,230', '菜单编辑', 'B', NULL, '', NULL, 'sys:menu:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2304, 230, '0,2,230', '菜单删除', 'B', NULL, '', NULL, 'sys:menu:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (240, 2, '0,2', '部门管理', 'M', 'Dept', 'dept', 'system/dept/index', NULL, NULL, 1, 1, 4, 'tree', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2401, 240, '0,2,240', '部门查询', 'B', NULL, '', NULL, 'sys:dept:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2402, 240, '0,2,240', '部门新增', 'B', NULL, '', NULL, 'sys:dept:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2403, 240, '0,2,240', '部门编辑', 'B', NULL, '', NULL, 'sys:dept:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2404, 240, '0,2,240', '部门删除', 'B', NULL, '', NULL, 'sys:dept:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (250, 2, '0,2', '字典管理', 'M', 'Dict', 'dict', 'system/dict/index', NULL, NULL, 1, 1, 5, 'dict', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2501, 250, '0,2,250', '字典查询', 'B', NULL, '', NULL, 'sys:dict:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2502, 250, '0,2,250', '字典新增', 'B', NULL, '', NULL, 'sys:dict:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2503, 250, '0,2,250', '字典编辑', 'B', NULL, '', NULL, 'sys:dict:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2504, 250, '0,2,250', '字典删除', 'B', NULL, '', NULL, 'sys:dict:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (251, 250, '0,2,250,251', '字典项', 'M', 'DictItem', 'dict-item', 'system/dict/dict-item', NULL, 0, 1, 0, 6, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2511, 251, '0,2,250,251', '字典项查询', 'B', NULL, '', NULL, 'sys:dict-item:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2512, 251, '0,2,250,251', '字典项新增', 'B', NULL, '', NULL, 'sys:dict-item:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2513, 251, '0,2,250,251', '字典项编辑', 'B', NULL, '', NULL, 'sys:dict-item:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2514, 251, '0,2,250,251', '字典项删除', 'B', NULL, '', NULL, 'sys:dict-item:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (260, 2, '0,2', '系统日志', 'M', 'Log', 'log', 'system/log/index', NULL, 0, 1, 1, 7, 'document', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (270, 2, '0,2', '系统配置', 'M', 'Config', 'config', 'system/config/index', NULL, 0, 1, 1, 8, 'setting', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2701, 270, '0,2,270', '系统配置查询', 'B', NULL, '', NULL, 'sys:config:list', 0, 1, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2702, 270, '0,2,270', '系统配置新增', 'B', NULL, '', NULL, 'sys:config:create', 0, 1, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2703, 270, '0,2,270', '系统配置修改', 'B', NULL, '', NULL, 'sys:config:update', 0, 1, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2704, 270, '0,2,270', '系统配置删除', 'B', NULL, '', NULL, 'sys:config:delete', 0, 1, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2705, 270, '0,2,270', '系统配置刷新', 'B', NULL, '', NULL, 'sys:config:refresh', 0, 1, 1, 5, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `sys_menu` VALUES (280, 2, '0,2', '通知公告', 'M', 'Notice', 'notice', 'system/notice/index', NULL, NULL, NULL, 1, 9, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2801, 280, '0,2,280', '通知查询', 'B', NULL, '', NULL, 'sys:notice:list', NULL, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2802, 280, '0,2,280', '通知新增', 'B', NULL, '', NULL, 'sys:notice:create', NULL, NULL, 1, 2, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2803, 280, '0,2,280', '通知编辑', 'B', NULL, '', NULL, 'sys:notice:update', NULL, NULL, 1, 3, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2804, 280, '0,2,280', '通知删除', 'B', NULL, '', NULL, 'sys:notice:delete', NULL, NULL, 1, 4, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2805, 280, '0,2,280', '通知发布', 'B', NULL, '', NULL, 'sys:notice:publish', 0, 1, 1, 5, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (2806, 280, '0,2,280', '通知撤回', 'B', NULL, '', NULL, 'sys:notice:revoke', 0, 1, 1, 6, '', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 代码生成
|
||||||
|
INSERT INTO `sys_menu` VALUES (310, 3, '0,3', '代码生成', 'M', 'Gen', 'gen', 'gen/index', NULL, NULL, 1, 1, 1, 'code', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
-- AI 助手
|
||||||
|
INSERT INTO `sys_menu` VALUES (401, 4, '0,4', 'AI命令记录', 'M', 'AiCommandRecord', 'command-record', 'ai/command-record/index', NULL, NULL, 1, 1, 1, 'document', NULL, now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 平台文档(外链通过 route_path 识别)
|
||||||
|
INSERT INTO `sys_menu` VALUES (501, 5, '0,5', '平台文档(外链)', 'M', NULL, 'https://juejin.cn/post/7228990409909108793', '', NULL, NULL, NULL, 1, 1, 'document', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (502, 5, '0,5', '后端文档', 'M', NULL, 'https://youlai.blog.csdn.net/article/details/145178880', '', NULL, NULL, NULL, 1, 2, 'document', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (503, 5, '0,5', '移动端文档', 'M', NULL, 'https://youlai.blog.csdn.net/article/details/143222890', '', NULL, NULL, NULL, 1, 3, 'document', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (504, 5, '0,5', '内部文档', 'M', NULL, 'internal-doc', 'demo/internal-doc', NULL, NULL, NULL, 1, 4, 'document', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 接口文档
|
||||||
|
INSERT INTO `sys_menu` VALUES (601, 6, '0,6', 'Apifox', 'M', 'Apifox', 'apifox', 'demo/api/apifox', NULL, NULL, 1, 1, 1, 'api', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 组件封装
|
||||||
|
INSERT INTO `sys_menu` VALUES (701, 7, '0,7', '富文本编辑器', 'M', 'WangEditor', 'wang-editor', 'demo/wang-editor', NULL, NULL, 1, 1, 2, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (702, 7, '0,7', '图片上传', 'M', 'Upload', 'upload', 'demo/upload', NULL, NULL, 1, 1, 3, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (703, 7, '0,7', '图标选择器', 'M', 'IconSelect', 'icon-select', 'demo/icon-select', NULL, NULL, 1, 1, 4, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (704, 7, '0,7', '字典组件', 'M', 'DictDemo', 'dict-demo', 'demo/dictionary', NULL, NULL, 1, 1, 4, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (705, 7, '0,7', '增删改查', 'M', 'Curd', 'curd', 'demo/curd/index', NULL, NULL, 1, 1, 0, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (706, 7, '0,7', '列表选择器', 'M', 'TableSelect', 'table-select', 'demo/table-select/index', NULL, NULL, 1, 1, 1, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (707, 7, '0,7', '拖拽组件', 'M', 'Drag', 'drag', 'demo/drag', NULL, NULL, NULL, 1, 5, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (708, 7, '0,7', '滚动文本', 'M', 'TextScroll', 'text-scroll', 'demo/text-scroll', NULL, NULL, NULL, 1, 6, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (709, 7, '0,7', '自适应表格操作列', 'M', 'AutoOperationColumn', 'operation-column', 'demo/auto-operation-column', NULL, NULL, 1, 1, 1, '', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 功能演示
|
||||||
|
INSERT INTO `sys_menu` VALUES (801, 8, '0,8', 'Websocket', 'M', 'WebSocket', '/function/websocket', 'demo/websocket', NULL, NULL, 1, 1, 1, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (802, 8, '0,8', 'Icons', 'M', 'IconDemo', 'icon-demo', 'demo/icons', NULL, NULL, 1, 1, 2, 'el-icon-Notification', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (803, 8, '0,8', '字典实时同步', 'M', 'DictSync', 'dict-sync', 'demo/dict-sync', NULL, NULL, NULL, 1, 3, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (804, 8, '0,8', 'VxeTable', 'M', 'VxeTable', 'vxe-table', 'demo/vxe-table/index', NULL, NULL, 1, 1, 4, 'el-icon-MagicStick', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (805, 8, '0,8', 'CURD单文件', 'M', 'CurdSingle', 'curd-single', 'demo/curd-single', NULL, NULL, 1, 1, 5, 'el-icon-Reading', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 多级菜单示例
|
||||||
|
INSERT INTO `sys_menu` VALUES (910, 9, '0,9', '菜单一级', 'C', NULL, 'multi-level1', 'Layout', NULL, 1, NULL, 1, 1, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (911, 910, '0,9,910', '菜单二级', 'C', NULL, 'multi-level2', 'Layout', NULL, 0, NULL, 1, 1, '', NULL, now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (912, 911, '0,9,910,911', '菜单三级-1', 'M', NULL, 'multi-level3-1', 'demo/multi-level/children/children/level3-1', NULL, 0, 1, 1, 1, '', '', now(), now(), NULL);
|
||||||
|
INSERT INTO `sys_menu` VALUES (913, 911, '0,9,910,911', '菜单三级-2', 'M', NULL, 'multi-level3-2', 'demo/multi-level/children/children/level3-2', NULL, 0, 1, 1, 2, '', '', now(), now(), NULL);
|
||||||
|
|
||||||
|
-- 路由参数
|
||||||
|
INSERT INTO `sys_menu` VALUES (1001, 10, '0,10', '参数(type=1)', 'M', 'RouteParamType1', 'route-param-type1', 'demo/route-param', NULL, 0, 1, 1, 1, 'el-icon-Star', NULL, now(), now(), '{\"type\": \"1\"}');
|
||||||
|
INSERT INTO `sys_menu` VALUES (1002, 10, '0,10', '参数(type=2)', 'M', 'RouteParamType2', 'route-param-type2', 'demo/route-param', NULL, 0, 1, 1, 2, 'el-icon-StarFilled', NULL, now(), now(), '{\"type\": \"2\"}');
|
||||||
|
-- ============================================
|
||||||
|
--- 系统配置权限按钮(ID: 901-905)
|
||||||
|
--- 字典项权限按钮(ID: 701-704)
|
||||||
|
-- ============================================
|
||||||
|
-- 通知公告权限按钮(ID: 1101-1106)
|
||||||
|
-- ============================================
|
||||||
|
-- ============================================
|
||||||
|
-- 字典项权限按钮(ID: 701-704)
|
||||||
|
-- ============================================
|
||||||
|
-- ============================================
|
||||||
|
-- 租户管理权限按钮(ID: 501-505)
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_role
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_role`;
|
||||||
|
CREATE TABLE `sys_role` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(64) NOT NULL COMMENT '角色名称',
|
||||||
|
`code` varchar(32) NOT NULL COMMENT '角色编码',
|
||||||
|
`sort` int NULL COMMENT '显示顺序',
|
||||||
|
`status` tinyint(1) DEFAULT 1 COMMENT '角色状态(1-正常 0-停用)',
|
||||||
|
`data_scope` tinyint NULL COMMENT '数据权限(1-所有数据 2-部门及子部门数据 3-本部门数据 4-本人数据)',
|
||||||
|
`create_by` bigint NULL COMMENT '创建人 ID',
|
||||||
|
`create_time` datetime NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint NULL COMMENT '更新人ID',
|
||||||
|
`update_time` datetime NULL COMMENT '更新时间',
|
||||||
|
`is_deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标识(0-未删除 1-已删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uk_name`(`name` ASC) USING BTREE COMMENT '角色名称唯一索引',
|
||||||
|
UNIQUE INDEX `uk_code`(`code` ASC) USING BTREE COMMENT '角色编码唯一索引'
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '系统角色表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_role
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_role` VALUES (1, '超级管理员', 'ROOT', 1, 1, 1, NULL, now(), NULL, now(), 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (2, '系统管理员', 'ADMIN', 2, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (3, '访问游客', 'GUEST', 3, 1, 3, NULL, now(), NULL, now(), 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (4, '系统管理员1', 'ADMIN1', 4, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (5, '系统管理员2', 'ADMIN2', 5, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (6, '系统管理员3', 'ADMIN3', 6, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (7, '系统管理员4', 'ADMIN4', 7, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (8, '系统管理员5', 'ADMIN5', 8, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (9, '系统管理员6', 'ADMIN6', 9, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (10, '系统管理员7', 'ADMIN7', 10, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (11, '系统管理员8', 'ADMIN8', 11, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
INSERT INTO `sys_role` VALUES (12, '系统管理员9', 'ADMIN9', 12, 1, 1, NULL, now(), NULL, NULL, 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_role_menu
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_role_menu`;
|
||||||
|
CREATE TABLE `sys_role_menu` (
|
||||||
|
`role_id` bigint NOT NULL COMMENT '角色ID',
|
||||||
|
`menu_id` bigint NOT NULL COMMENT '菜单ID',
|
||||||
|
UNIQUE INDEX `uk_roleid_menuid`(`role_id` ASC, `menu_id` ASC) USING BTREE COMMENT '角色菜单唯一索引'
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '角色菜单关联表';
|
||||||
|
|
||||||
|
-- ============================================
|
||||||
|
-- 系统管理员角色菜单权限(role_id=2)
|
||||||
|
-- 顶级目录
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10);
|
||||||
|
-- 平台管理
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 110), (2, 1101), (2, 1102), (2, 1103), (2, 1104), (2, 1105);
|
||||||
|
-- 系统管理
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 210), (2, 2101), (2, 2102), (2, 2103), (2, 2104), (2, 2105), (2, 2106), (2, 2107);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 220), (2, 2201), (2, 2202), (2, 2203), (2, 2204);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 230), (2, 2301), (2, 2302), (2, 2303), (2, 2304);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 240), (2, 2401), (2, 2402), (2, 2403), (2, 2404);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 250), (2, 2501), (2, 2502), (2, 2503), (2, 2504);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 251), (2, 2511), (2, 2512), (2, 2513), (2, 2514);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 260);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 270), (2, 2701), (2, 2702), (2, 2703), (2, 2704), (2, 2705);
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 280), (2, 2801), (2, 2802), (2, 2803), (2, 2804), (2, 2805), (2, 2806);
|
||||||
|
-- 代码生成
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 310);
|
||||||
|
-- AI 助手
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 401);
|
||||||
|
-- 平台文档
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 501), (2, 502), (2, 503), (2, 504);
|
||||||
|
-- 接口文档
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 601);
|
||||||
|
-- 组件封装
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 701), (2, 702), (2, 703), (2, 704), (2, 705), (2, 706), (2, 707), (2, 708), (2, 709);
|
||||||
|
-- 功能演示 / 多级菜单
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 801), (2, 802), (2, 803), (2, 804), (2, 805), (2, 910), (2, 911), (2, 912), (2, 913);
|
||||||
|
-- 路由参数
|
||||||
|
INSERT INTO `sys_role_menu` VALUES (2, 1001), (2, 1002);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_user
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_user`;
|
||||||
|
CREATE TABLE `sys_user` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(64) COMMENT '用户名',
|
||||||
|
`nickname` varchar(64) COMMENT '昵称',
|
||||||
|
`gender` tinyint(1) DEFAULT 1 COMMENT '性别((1-男 2-女 0-保密)',
|
||||||
|
`password` varchar(100) COMMENT '密码',
|
||||||
|
`dept_id` int COMMENT '部门ID',
|
||||||
|
`avatar` varchar(255) COMMENT '用户头像',
|
||||||
|
`mobile` varchar(20) COMMENT '联系方式',
|
||||||
|
`status` tinyint(1) DEFAULT 1 COMMENT '状态(1-正常 0-禁用)',
|
||||||
|
`email` varchar(128) COMMENT '用户邮箱',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`create_by` bigint COMMENT '创建人ID',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`update_by` bigint COMMENT '修改人ID',
|
||||||
|
`is_deleted` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标识(0-未删除 1-已删除)',
|
||||||
|
`openid` char(28) COMMENT '微信 openid',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `login_name` (`username`)
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '系统用户表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_user
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_user` VALUES (1, 'root', '有来技术', 0, '$2a$10$xVWsNOhHrCxh5UbpCE7/HuJ.PAOKcYAqRxD2CO2nVnJS.IAXkr5aq', NULL, 'https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif', '18812345677', 1, 'youlaitech@163.com', now(), NULL, now(), NULL, 0,NULL);
|
||||||
|
INSERT INTO `sys_user` VALUES (2, 'admin', '系统管理员', 1, '$2a$10$xVWsNOhHrCxh5UbpCE7/HuJ.PAOKcYAqRxD2CO2nVnJS.IAXkr5aq', 1, 'https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif', '18812345678', 1, 'youlaitech@163.com', now(), NULL, now(), NULL, 0,NULL);
|
||||||
|
INSERT INTO `sys_user` VALUES (3, 'test', '测试小用户', 1, '$2a$10$xVWsNOhHrCxh5UbpCE7/HuJ.PAOKcYAqRxD2CO2nVnJS.IAXkr5aq', 3, 'https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif', '18812345679', 1, 'youlaitech@163.com', now(), NULL, now(), NULL, 0,NULL);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_user_role
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_user_role`;
|
||||||
|
CREATE TABLE `sys_user_role` (
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
|
`role_id` bigint NOT NULL COMMENT '角色ID',
|
||||||
|
PRIMARY KEY (`user_id`, `role_id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '用户角色关联表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_user_role
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_user_role` VALUES (1, 1);
|
||||||
|
INSERT INTO `sys_user_role` VALUES (2, 2);
|
||||||
|
INSERT INTO `sys_user_role` VALUES (3, 3);
|
||||||
|
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sys_log
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_log`;
|
||||||
|
CREATE TABLE `sys_log` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`module` varchar(50) NOT NULL COMMENT '日志模块',
|
||||||
|
`request_method` varchar(64) NOT NULL COMMENT '请求方式',
|
||||||
|
`request_params` text COMMENT '请求参数(批量请求参数可能会超过text)',
|
||||||
|
`response_content` mediumtext COMMENT '返回参数',
|
||||||
|
`content` varchar(255) NOT NULL COMMENT '日志内容',
|
||||||
|
`request_uri` varchar(255) COMMENT '请求路径',
|
||||||
|
`method` varchar(255) COMMENT '方法名',
|
||||||
|
`ip` varchar(45) COMMENT 'IP地址',
|
||||||
|
`province` varchar(100) COMMENT '省份',
|
||||||
|
`city` varchar(100) COMMENT '城市',
|
||||||
|
`execution_time` bigint COMMENT '执行时间(ms)',
|
||||||
|
`browser` varchar(100) COMMENT '浏览器',
|
||||||
|
`browser_version` varchar(100) COMMENT '浏览器版本',
|
||||||
|
`os` varchar(100) COMMENT '终端系统',
|
||||||
|
`create_by` bigint COMMENT '创建人ID',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`is_deleted` tinyint DEFAULT '0' COMMENT '逻辑删除标识(1-已删除 0-未删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COMMENT='系统操作日志表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for gen_config
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `gen_config`;
|
||||||
|
CREATE TABLE `gen_config` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`table_name` varchar(100) NOT NULL COMMENT '表名',
|
||||||
|
`module_name` varchar(100) COMMENT '模块名',
|
||||||
|
`package_name` varchar(255) NOT NULL COMMENT '包名',
|
||||||
|
`business_name` varchar(100) NOT NULL COMMENT '业务名',
|
||||||
|
`entity_name` varchar(100) NOT NULL COMMENT '实体类名',
|
||||||
|
`author` varchar(50) NOT NULL COMMENT '作者',
|
||||||
|
`parent_menu_id` bigint COMMENT '上级菜单ID,对应sys_menu的id ',
|
||||||
|
`remove_table_prefix` varchar(20) COMMENT '要移除的表前缀,如: sys_',
|
||||||
|
`page_type` varchar(20) COMMENT '页面类型(classic|curd)',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`is_deleted` tinyint(4) DEFAULT 0 COMMENT '是否删除',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_tablename` (`table_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='代码生成配置表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for gen_field_config
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `gen_field_config`;
|
||||||
|
CREATE TABLE `gen_field_config` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`config_id` bigint NOT NULL COMMENT '关联的配置ID',
|
||||||
|
`column_name` varchar(100) ,
|
||||||
|
`column_type` varchar(50) ,
|
||||||
|
`column_length` int ,
|
||||||
|
`field_name` varchar(100) NOT NULL COMMENT '字段名称',
|
||||||
|
`field_type` varchar(100) COMMENT '字段类型',
|
||||||
|
`field_sort` int COMMENT '字段排序',
|
||||||
|
`field_comment` varchar(255) COMMENT '字段描述',
|
||||||
|
`max_length` int ,
|
||||||
|
`is_required` tinyint(1) COMMENT '是否必填',
|
||||||
|
`is_show_in_list` tinyint(1) DEFAULT '0' COMMENT '是否在列表显示',
|
||||||
|
`is_show_in_form` tinyint(1) DEFAULT '0' COMMENT '是否在表单显示',
|
||||||
|
`is_show_in_query` tinyint(1) DEFAULT '0' COMMENT '是否在查询条件显示',
|
||||||
|
`query_type` tinyint COMMENT '查询方式',
|
||||||
|
`form_type` tinyint COMMENT '表单类型',
|
||||||
|
`dict_type` varchar(50) COMMENT '字典类型',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `config_id` (`config_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='代码生成字段配置表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 系统配置表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_config`;
|
||||||
|
CREATE TABLE `sys_config` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`config_name` varchar(50) NOT NULL COMMENT '配置名称',
|
||||||
|
`config_key` varchar(50) NOT NULL COMMENT '配置key',
|
||||||
|
`config_value` varchar(100) NOT NULL COMMENT '配置值',
|
||||||
|
`remark` varchar(255) COMMENT '备注',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`create_by` bigint COMMENT '创建人ID',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`update_by` bigint COMMENT '更新人ID',
|
||||||
|
`is_deleted` tinyint(4) DEFAULT '0' NOT NULL COMMENT '逻辑删除标识(0-未删除 1-已删除)',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB COMMENT='系统配置表';
|
||||||
|
|
||||||
|
INSERT INTO `sys_config` VALUES (1, '系统限流QPS', 'IP_QPS_THRESHOLD_LIMIT', '10', '单个IP请求的最大每秒查询数(QPS)阈值Key', now(), 1, NULL, NULL, 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 通知公告表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_notice`;
|
||||||
|
CREATE TABLE `sys_notice` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||||
|
`title` varchar(50) COMMENT '通知标题',
|
||||||
|
`content` text COMMENT '通知内容',
|
||||||
|
`type` tinyint NOT NULL COMMENT '通知类型(关联字典编码:notice_type)',
|
||||||
|
`level` varchar(5) NOT NULL COMMENT '通知等级(字典code:notice_level)',
|
||||||
|
`target_type` tinyint NOT NULL COMMENT '目标类型(1: 全体, 2: 指定)',
|
||||||
|
`target_user_ids` varchar(255) COMMENT '目标人ID集合(多个使用英文逗号,分割)',
|
||||||
|
`publisher_id` bigint COMMENT '发布人ID',
|
||||||
|
`publish_status` tinyint DEFAULT '0' COMMENT '发布状态(0: 未发布, 1: 已发布, -1: 已撤回)',
|
||||||
|
`publish_time` datetime COMMENT '发布时间',
|
||||||
|
`revoke_time` datetime COMMENT '撤回时间',
|
||||||
|
`create_by` bigint NOT NULL COMMENT '创建人ID',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint COMMENT '更新人ID',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`is_deleted` tinyint(1) DEFAULT '0' COMMENT '是否删除(0: 未删除, 1: 已删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统通知公告表';
|
||||||
|
|
||||||
|
INSERT INTO `sys_notice` VALUES (1, 'v3.0.0 版本发布 - 多租户功能上线', '<p>🎉 新版本发布,主要更新内容:</p><p>1. 新增多租户功能,支持租户隔离和数据管理</p><p>2. 优化系统性能,提升响应速度</p><p>3. 完善权限管理,增强安全性</p><p>4. 修复已知问题,提升系统稳定性</p>', 1, 'H', 1, NULL, 1, 1, '2024-12-15 10:00:00', NULL, 1, '2024-12-15 10:00:00', 1, '2024-12-15 10:00:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (2, '系统维护通知 - 2024年12月20日', '<p>⏰ 系统维护通知</p><p>系统将于 <strong>2024年12月20日(本周五)凌晨 2:00-4:00</strong> 进行例行维护升级。</p><p>维护期间系统将暂停服务,请提前做好数据备份工作。</p><p>给您带来的不便,敬请谅解!</p>', 2, 'H', 1, NULL, 1, 1, '2024-12-18 14:30:00', NULL, 1, '2024-12-18 14:30:00', 1, '2024-12-18 14:30:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (3, '安全提醒 - 防范钓鱼邮件', '<p>⚠️ 安全提醒</p><p>近期发现有不法分子通过钓鱼邮件进行网络攻击,请大家提高警惕:</p><p>1. 不要点击来源不明的邮件链接</p><p>2. 不要下载可疑附件</p><p>3. 遇到可疑邮件请及时联系IT部门</p><p>4. 定期修改密码,使用强密码策略</p>', 3, 'H', 1, NULL, 1, 1, '2024-12-10 09:00:00', NULL, 1, '2024-12-10 09:00:00', 1, '2024-12-10 09:00:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (4, '元旦假期安排通知', '<p>📅 元旦假期安排</p><p>根据国家法定节假日安排,公司元旦假期时间为:</p><p><strong>2024年12月30日(周一)至 2025年1月1日(周三)</strong>,共3天。</p><p>2024年12月29日(周日)正常上班。</p><p>祝大家元旦快乐,假期愉快!</p>', 4, 'M', 1, NULL, 1, 1, '2024-12-25 16:00:00', NULL, 1, '2024-12-25 16:00:00', 1, '2024-12-25 16:00:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (5, '新产品发布会邀请', '<p>🎊 新产品发布会邀请</p><p>公司将于 <strong>2025年1月15日下午14:00</strong> 在总部会议室举办新产品发布会。</p><p>届时将展示最新研发的产品和技术成果,欢迎全体员工参加。</p><p>请各部门提前安排好工作,准时参加。</p>', 5, 'M', 1, NULL, 1, 1, '2024-12-28 11:00:00', NULL, 1, '2024-12-28 11:00:00', 1, '2024-12-28 11:00:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (6, 'v2.16.1 版本更新', '<p>✨ 版本更新</p><p>v2.16.1 版本已发布,主要修复内容:</p><p>1. 修复 WebSocket 重复连接导致的后台线程阻塞问题</p><p>2. 优化通知公告功能,提升用户体验</p><p>3. 修复部分已知bug</p><p>建议尽快更新到最新版本。</p>', 1, 'M', 1, NULL, 1, 1, '2024-12-05 15:30:00', NULL, 1, '2024-12-05 15:30:00', 1, '2024-12-05 15:30:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (7, '年终总结会议通知', '<p>📋 年终总结会议通知</p><p>各部门年终总结会议将于 <strong>2024年12月30日上午9:00</strong> 召开。</p><p>请各部门负责人提前准备好年度工作总结和下年度工作计划。</p><p>会议地点:总部大会议室</p>', 5, 'M', 2, '1,2', 1, 1, '2024-12-22 10:00:00', NULL, 1, '2024-12-22 10:00:00', 1, '2024-12-22 10:00:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (8, '系统功能优化完成', '<p>✅ 系统功能优化</p><p>已完成以下功能优化:</p><p>1. 优化用户管理界面,提升操作体验</p><p>2. 增强数据导出功能,支持更多格式</p><p>3. 优化搜索功能,提升查询效率</p><p>4. 修复部分界面显示问题</p>', 1, 'L', 1, NULL, 1, 1, '2024-12-12 14:20:00', NULL, 1, '2024-12-12 14:20:00', 1, '2024-12-12 14:20:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (9, '员工培训计划', '<p>📚 员工培训计划</p><p>为提升员工专业技能,公司将于 <strong>2025年1月8日-10日</strong> 组织技术培训。</p><p>培训内容:</p><p>1. 新技术框架应用</p><p>2. 代码规范与最佳实践</p><p>3. 系统架构设计</p><p>请各部门合理安排工作,确保培训顺利进行。</p>', 5, 'M', 1, NULL, 1, 1, '2024-12-20 09:30:00', NULL, 1, '2024-12-20 09:30:00', 1, '2024-12-20 09:30:00', 0);
|
||||||
|
INSERT INTO `sys_notice` VALUES (10, '数据备份提醒', '<p>💾 数据备份提醒</p><p>请各部门注意定期备份重要数据,建议每周至少备份一次。</p><p>备份方式:</p><p>1. 使用系统自带备份功能</p><p>2. 手动导出重要数据</p><p>3. 联系IT部门协助备份</p><p>数据安全,人人有责!</p>', 3, 'L', 1, NULL, 1, 1, '2024-12-08 08:00:00', NULL, 1, '2024-12-08 08:00:00', 1, '2024-12-08 08:00:00', 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 用户通知公告表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_user_notice`;
|
||||||
|
CREATE TABLE `sys_user_notice` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||||
|
`notice_id` bigint NOT NULL COMMENT '公共通知id',
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户id',
|
||||||
|
`is_read` bigint DEFAULT '0' COMMENT '读取状态(0: 未读, 1: 已读)',
|
||||||
|
`read_time` datetime COMMENT '阅读时间',
|
||||||
|
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
`is_deleted` tinyint DEFAULT '0' COMMENT '逻辑删除(0: 未删除, 1: 已删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户通知公告关联表';
|
||||||
|
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (1, 1, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (2, 2, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (3, 3, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (4, 4, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (5, 5, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (6, 6, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (7, 7, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (8, 8, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (9, 9, 2, 1, NULL, now(), now(), 0);
|
||||||
|
INSERT INTO `sys_user_notice` VALUES (10, 10, 2, 1, NULL, now(), now(), 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- AI 命令记录表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ai_command_log`;
|
||||||
|
CREATE TABLE `ai_command_log` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` bigint DEFAULT NULL COMMENT '用户ID',
|
||||||
|
`username` varchar(64) DEFAULT NULL COMMENT '用户名',
|
||||||
|
`original_command` text COMMENT '原始命令',
|
||||||
|
`ai_provider` varchar(32) DEFAULT NULL COMMENT 'AI 供应商(qwen/openai/deepseek/gemini等)',
|
||||||
|
`ai_model` varchar(64) DEFAULT NULL COMMENT 'AI 模型名称(qwen-plus/qwen-max/gpt-4-turbo等)',
|
||||||
|
`parse_status` tinyint DEFAULT '0' COMMENT '解析是否成功(0-失败, 1-成功)',
|
||||||
|
`function_calls` text COMMENT '解析出的函数调用列表(JSON)',
|
||||||
|
`explanation` varchar(500) DEFAULT NULL COMMENT 'AI的理解说明',
|
||||||
|
`confidence` decimal(3,2) DEFAULT NULL COMMENT '置信度(0.00-1.00)',
|
||||||
|
`parse_error_message` text COMMENT '解析错误信息',
|
||||||
|
`input_tokens` int DEFAULT NULL COMMENT '输入Token数量',
|
||||||
|
`output_tokens` int DEFAULT NULL COMMENT '输出Token数量',
|
||||||
|
`parse_duration_ms` int DEFAULT NULL COMMENT '解析耗时(毫秒)',
|
||||||
|
`function_name` varchar(255) DEFAULT NULL COMMENT '执行的函数名称',
|
||||||
|
`function_arguments` text COMMENT '函数参数(JSON)',
|
||||||
|
`execute_status` tinyint(1) DEFAULT NULL COMMENT '执行状态(0-待执行, 1-成功, -1-失败)',
|
||||||
|
`execute_error_message` text COMMENT '执行错误信息',
|
||||||
|
`ip_address` varchar(128) DEFAULT NULL COMMENT 'IP地址',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_create_time` (`create_time`),
|
||||||
|
KEY `idx_provider` (`ai_provider`),
|
||||||
|
KEY `idx_model` (`ai_model`),
|
||||||
|
KEY `idx_parse_success` (`parse_status`),
|
||||||
|
KEY `idx_execute_status` (`execute_status`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='AI 命令日志表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 租户表(多租户模式)
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_tenant`;
|
||||||
|
CREATE TABLE `sys_tenant` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '租户ID',
|
||||||
|
`name` varchar(100) NOT NULL COMMENT '租户名称',
|
||||||
|
`code` varchar(50) NOT NULL COMMENT '租户编码(唯一)',
|
||||||
|
`contact_name` varchar(50) DEFAULT NULL COMMENT '联系人姓名',
|
||||||
|
`contact_phone` varchar(20) DEFAULT NULL COMMENT '联系人电话',
|
||||||
|
`contact_email` varchar(100) DEFAULT NULL COMMENT '联系人邮箱',
|
||||||
|
`domain` varchar(100) DEFAULT NULL COMMENT '租户域名(用于域名识别)',
|
||||||
|
`logo` varchar(255) DEFAULT NULL COMMENT '租户Logo',
|
||||||
|
`status` tinyint DEFAULT '1' COMMENT '状态(1-正常 0-禁用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`expire_time` datetime DEFAULT NULL COMMENT '过期时间(NULL表示永不过期)',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
`update_time` datetime COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_code` (`code`),
|
||||||
|
UNIQUE KEY `uk_domain` (`domain`),
|
||||||
|
KEY `idx_status` (`status`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='系统租户表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_tenant
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_tenant` VALUES (1, '默认租户', 'DEFAULT', '系统管理员', '18812345678', 'admin@youlai.tech', NULL, NULL, 1, '系统默认租户', NULL, now(), now());
|
||||||
|
INSERT INTO `sys_tenant` VALUES (2, '演示租户', 'DEMO', '演示用户', '18812345679', 'demo@youlai.tech', 'demo.youlai.tech', NULL, 1, '演示租户', NULL, now(), now());
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 用户租户关联表(多租户模式)
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sys_user_tenant`;
|
||||||
|
CREATE TABLE `sys_user_tenant` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
|
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||||
|
`is_default` tinyint DEFAULT '0' COMMENT '是否默认租户(1-是 0-否)',
|
||||||
|
`create_time` datetime COMMENT '创建时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_user_tenant` (`user_id`, `tenant_id`),
|
||||||
|
KEY `idx_user_id` (`user_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户租户关联表(多租户模式)';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sys_user_tenant
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sys_user_tenant` VALUES (1, 1, 1, 1, now());
|
||||||
|
INSERT INTO `sys_user_tenant` VALUES (2, 2, 1, 1, now());
|
||||||
|
INSERT INTO `sys_user_tenant` VALUES (3, 2, 2, 0, now());
|
||||||
|
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.youlai.boot.common.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略多租户注解
|
||||||
|
* <p>
|
||||||
|
* 标注在方法或类上,表示该方法或类下的所有方法忽略多租户过滤
|
||||||
|
* 适用于系统管理、租户管理等不需要租户隔离的场景
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface IgnoreTenant {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.youlai.boot.common.tenant;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户上下文工具类
|
||||||
|
* <p>
|
||||||
|
* 使用 ThreadLocal 存储当前线程的租户ID,确保线程安全
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class TenantContextHolder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户ID线程本地变量
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> TENANT_ID_HOLDER = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略租户标志(用于某些场景下临时跳过租户过滤)
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Boolean> IGNORE_TENANT_HOLDER = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前租户ID
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
*/
|
||||||
|
public static void setTenantId(Long tenantId) {
|
||||||
|
if (tenantId != null) {
|
||||||
|
TENANT_ID_HOLDER.set(tenantId);
|
||||||
|
log.debug("设置当前租户ID: {}", tenantId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前租户ID
|
||||||
|
*
|
||||||
|
* @return 租户ID,如果未设置则返回 null
|
||||||
|
*/
|
||||||
|
public static Long getTenantId() {
|
||||||
|
return TENANT_ID_HOLDER.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置忽略租户标志
|
||||||
|
*
|
||||||
|
* @param ignore 是否忽略
|
||||||
|
*/
|
||||||
|
public static void setIgnoreTenant(boolean ignore) {
|
||||||
|
IGNORE_TENANT_HOLDER.set(ignore);
|
||||||
|
log.debug("设置忽略租户标志: {}", ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否忽略租户
|
||||||
|
*
|
||||||
|
* @return true-忽略,false-不忽略
|
||||||
|
*/
|
||||||
|
public static boolean isIgnoreTenant() {
|
||||||
|
Boolean ignore = IGNORE_TENANT_HOLDER.get();
|
||||||
|
return ignore != null && ignore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除当前线程的租户上下文
|
||||||
|
* <p>
|
||||||
|
* 必须在请求结束时调用,避免线程池复用导致的数据泄露
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public static void clear() {
|
||||||
|
TENANT_ID_HOLDER.remove();
|
||||||
|
IGNORE_TENANT_HOLDER.remove();
|
||||||
|
log.debug("清除租户上下文");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.youlai.boot.config.property;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户配置属性
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "youlai.tenant")
|
||||||
|
public class TenantProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用多租户功能
|
||||||
|
* 默认:false(不启用)
|
||||||
|
*/
|
||||||
|
private Boolean enabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户字段名
|
||||||
|
* 默认:tenant_id
|
||||||
|
*/
|
||||||
|
private String column = "tenant_id";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认租户ID(用于兼容旧数据,tenant_id 为 NULL 时使用)
|
||||||
|
* 默认:1
|
||||||
|
*/
|
||||||
|
private Long defaultTenantId = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忽略多租户过滤的表名列表
|
||||||
|
* 系统表、租户表等不需要租户隔离的表
|
||||||
|
*/
|
||||||
|
private List<String> ignoreTables = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求头中的租户ID字段名
|
||||||
|
* 默认:tenant-id
|
||||||
|
*/
|
||||||
|
private String headerName = "tenant-id";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化默认忽略的表
|
||||||
|
*/
|
||||||
|
public TenantProperties() {
|
||||||
|
// 系统表默认忽略多租户
|
||||||
|
ignoreTables.add("sys_tenant");
|
||||||
|
ignoreTables.add("sys_dict");
|
||||||
|
ignoreTables.add("sys_dict_item");
|
||||||
|
ignoreTables.add("sys_config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
46
src/main/java/com/youlai/boot/core/aspect/TenantAspect.java
Normal file
46
src/main/java/com/youlai/boot/core/aspect/TenantAspect.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package com.youlai.boot.core.aspect;
|
||||||
|
|
||||||
|
import com.youlai.boot.common.annotation.IgnoreTenant;
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多租户切面
|
||||||
|
* <p>
|
||||||
|
* 处理 @IgnoreTenant 注解,临时跳过租户过滤
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(1)
|
||||||
|
@Slf4j
|
||||||
|
@ConditionalOnProperty(prefix = "youlai.tenant", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
public class TenantAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 环绕通知:处理 @IgnoreTenant 注解
|
||||||
|
*/
|
||||||
|
@Around("@annotation(ignoreTenant) || @within(ignoreTenant)")
|
||||||
|
public Object around(ProceedingJoinPoint joinPoint, IgnoreTenant ignoreTenant) throws Throwable {
|
||||||
|
try {
|
||||||
|
// 设置忽略租户标志
|
||||||
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
|
log.debug("方法 {} 忽略多租户过滤", joinPoint.getSignature().getName());
|
||||||
|
// 执行原方法
|
||||||
|
return joinPoint.proceed();
|
||||||
|
} finally {
|
||||||
|
// 恢复租户过滤
|
||||||
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.youlai.boot.core.filter;
|
||||||
|
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.config.property.TenantProperties;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户上下文过滤器
|
||||||
|
* <p>
|
||||||
|
* 从请求头中获取租户ID,设置到线程上下文
|
||||||
|
* 请求结束时自动清除上下文,避免线程池复用导致的数据泄露
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@Order(1) // 确保在其他过滤器之前执行
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnProperty(prefix = "youlai.tenant", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
public class TenantContextFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
private final TenantProperties tenantProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 从请求头获取租户ID
|
||||||
|
String tenantIdStr = request.getHeader(tenantProperties.getHeaderName());
|
||||||
|
|
||||||
|
if (StringUtils.hasText(tenantIdStr)) {
|
||||||
|
try {
|
||||||
|
Long tenantId = Long.parseLong(tenantIdStr);
|
||||||
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
|
log.debug("从请求头获取租户ID: {}", tenantId);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("租户ID格式错误: {}", tenantIdStr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果未提供租户ID,使用默认租户ID
|
||||||
|
Long defaultTenantId = tenantProperties.getDefaultTenantId();
|
||||||
|
if (defaultTenantId != null) {
|
||||||
|
TenantContextHolder.setTenantId(defaultTenantId);
|
||||||
|
log.debug("使用默认租户ID: {}", defaultTenantId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续执行过滤器链
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 请求结束时清除租户上下文,避免线程池复用导致的数据泄露
|
||||||
|
TenantContextHolder.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.youlai.boot.plugin.mybatis;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.config.property.TenantProperties;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.sf.jsqlparser.expression.Expression;
|
||||||
|
import net.sf.jsqlparser.expression.LongValue;
|
||||||
|
import net.sf.jsqlparser.expression.NullValue;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MyBatis-Plus 多租户处理器
|
||||||
|
* <p>
|
||||||
|
* 实现 TenantLineHandler 接口,自动为 SQL 添加租户过滤条件
|
||||||
|
* 仅在启用多租户时注册(通过 @ConditionalOnProperty 控制)
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnProperty(prefix = "youlai.tenant", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
public class TenantLineHandler implements com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler {
|
||||||
|
|
||||||
|
private final TenantProperties tenantProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取租户ID表达式
|
||||||
|
* <p>
|
||||||
|
* 从 TenantContextHolder 获取当前租户ID
|
||||||
|
* 如果未设置或忽略租户,返回 NULL(不添加租户条件)
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return 租户ID表达式
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Expression getTenantId() {
|
||||||
|
// 如果设置了忽略租户标志,返回 NULL(不添加租户条件)
|
||||||
|
if (TenantContextHolder.isIgnoreTenant()) {
|
||||||
|
return new NullValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前租户ID
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
|
||||||
|
// 如果未设置租户ID,使用默认租户ID
|
||||||
|
if (tenantId == null) {
|
||||||
|
tenantId = tenantProperties.getDefaultTenantId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LongValue(tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取租户字段名
|
||||||
|
*
|
||||||
|
* @return 租户字段名
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getTenantIdColumn() {
|
||||||
|
return tenantProperties.getColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断表是否忽略多租户过滤
|
||||||
|
* <p>
|
||||||
|
* 系统表、租户表等不需要租户隔离的表应返回 true
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param tableName 表名
|
||||||
|
* @return true-忽略,false-不忽略
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean ignoreTable(String tableName) {
|
||||||
|
List<String> ignoreTables = tenantProperties.getIgnoreTables();
|
||||||
|
if (ignoreTables == null || ignoreTables.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 忽略表名匹配(不区分大小写)
|
||||||
|
return ignoreTables.stream()
|
||||||
|
.anyMatch(ignoreTable -> ignoreTable.equalsIgnoreCase(tableName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package com.youlai.boot.system.controller;
|
||||||
|
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.core.web.Result;
|
||||||
|
import com.youlai.boot.security.util.SecurityUtils;
|
||||||
|
import com.youlai.boot.system.model.vo.TenantVO;
|
||||||
|
import com.youlai.boot.system.service.TenantService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户管理控制器
|
||||||
|
* <p>
|
||||||
|
* 提供租户切换、查询等功能
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Tag(name = "租户管理接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/tenant")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@ConditionalOnProperty(prefix = "youlai.tenant", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
public class TenantController {
|
||||||
|
|
||||||
|
private final TenantService tenantService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户的租户列表
|
||||||
|
* <p>
|
||||||
|
* 根据当前登录用户查询其所属的所有租户
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return 租户列表
|
||||||
|
*/
|
||||||
|
@Operation(summary = "获取当前用户的租户列表")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result<List<TenantVO>> getTenantList() {
|
||||||
|
Long userId = SecurityUtils.getUserId();
|
||||||
|
List<TenantVO> tenantList = tenantService.getTenantListByUserId(userId);
|
||||||
|
log.info("获取用户 {} 的租户列表,共 {} 个租户", userId, tenantList.size());
|
||||||
|
return Result.success(tenantList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前租户信息
|
||||||
|
*
|
||||||
|
* @return 当前租户信息
|
||||||
|
*/
|
||||||
|
@Operation(summary = "获取当前租户信息")
|
||||||
|
@GetMapping("/current")
|
||||||
|
public Result<TenantVO> getCurrentTenant() {
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
if (tenantId == null) {
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
TenantVO tenant = tenantService.getTenantById(tenantId);
|
||||||
|
return Result.success(tenant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换租户
|
||||||
|
* <p>
|
||||||
|
* 切换当前用户的租户上下文,需要验证用户是否有权限访问该租户
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param tenantId 目标租户ID
|
||||||
|
* @return 切换结果
|
||||||
|
*/
|
||||||
|
@Operation(summary = "切换租户")
|
||||||
|
@PostMapping("/switch/{tenantId}")
|
||||||
|
public Result<TenantVO> switchTenant(
|
||||||
|
@Parameter(description = "租户ID") @PathVariable Long tenantId
|
||||||
|
) {
|
||||||
|
Long userId = SecurityUtils.getUserId();
|
||||||
|
log.info("用户 {} 请求切换租户到 {}", userId, tenantId);
|
||||||
|
|
||||||
|
// 验证用户是否有权限访问该租户
|
||||||
|
boolean hasPermission = tenantService.hasTenantPermission(userId, tenantId);
|
||||||
|
if (!hasPermission) {
|
||||||
|
log.warn("用户 {} 无权限访问租户 {}", userId, tenantId);
|
||||||
|
return Result.failed("无权限访问该租户");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证租户是否存在且正常
|
||||||
|
TenantVO tenant = tenantService.getTenantById(tenantId);
|
||||||
|
if (tenant == null) {
|
||||||
|
return Result.failed("租户不存在");
|
||||||
|
}
|
||||||
|
if (tenant.getStatus() == null || tenant.getStatus() != 1) {
|
||||||
|
return Result.failed("租户已禁用");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的租户上下文
|
||||||
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
|
log.info("用户 {} 成功切换租户到 {}", userId, tenantId);
|
||||||
|
|
||||||
|
return Result.success(tenant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.youlai.boot.system.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.youlai.boot.system.model.entity.Tenant;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户 Mapper
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface TenantMapper extends BaseMapper<Tenant> {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.youlai.boot.system.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.youlai.boot.system.model.entity.UserTenant;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户租户关联 Mapper
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface UserTenantMapper extends BaseMapper<UserTenant> {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.youlai.boot.system.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.youlai.boot.common.base.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户实体
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("sys_tenant")
|
||||||
|
public class Tenant extends BaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户编码(唯一)
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系人姓名
|
||||||
|
*/
|
||||||
|
private String contactName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系人电话
|
||||||
|
*/
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系人邮箱
|
||||||
|
*/
|
||||||
|
private String contactEmail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户域名(用于域名识别)
|
||||||
|
*/
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户Logo
|
||||||
|
*/
|
||||||
|
private String logo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(1-正常 0-禁用)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间(NULL表示永不过期)
|
||||||
|
*/
|
||||||
|
private LocalDateTime expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.youlai.boot.system.model.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.youlai.boot.common.base.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户租户关联实体
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("sys_user_tenant")
|
||||||
|
public class UserTenant extends BaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户ID
|
||||||
|
*/
|
||||||
|
private Long tenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否默认租户(1-是 0-否)
|
||||||
|
*/
|
||||||
|
private Integer isDefault;
|
||||||
|
}
|
||||||
|
|
||||||
48
src/main/java/com/youlai/boot/system/model/vo/TenantVO.java
Normal file
48
src/main/java/com/youlai/boot/system/model/vo/TenantVO.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package com.youlai.boot.system.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户VO
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "租户信息")
|
||||||
|
public class TenantVO implements Serializable {
|
||||||
|
|
||||||
|
@Schema(description = "租户ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "租户名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "租户编码")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Schema(description = "租户状态(1-正常 0-禁用)")
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "联系人姓名")
|
||||||
|
private String contactName;
|
||||||
|
|
||||||
|
@Schema(description = "联系人电话")
|
||||||
|
private String contactPhone;
|
||||||
|
|
||||||
|
@Schema(description = "联系人邮箱")
|
||||||
|
private String contactEmail;
|
||||||
|
|
||||||
|
@Schema(description = "租户域名")
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
@Schema(description = "租户Logo")
|
||||||
|
private String logo;
|
||||||
|
|
||||||
|
@Schema(description = "是否默认租户")
|
||||||
|
private Boolean isDefault;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.youlai.boot.system.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.youlai.boot.system.model.entity.Tenant;
|
||||||
|
import com.youlai.boot.system.model.vo.TenantVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户服务接口
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
public interface TenantService extends IService<Tenant> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID查询用户所属的租户列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 租户列表
|
||||||
|
*/
|
||||||
|
List<TenantVO> getTenantListByUserId(Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据租户ID查询租户信息
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 租户信息
|
||||||
|
*/
|
||||||
|
TenantVO getTenantById(Long tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据域名查询租户ID
|
||||||
|
*
|
||||||
|
* @param domain 域名
|
||||||
|
* @return 租户ID
|
||||||
|
*/
|
||||||
|
Long getTenantIdByDomain(String domain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证用户是否有权限访问指定租户
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return true-有权限,false-无权限
|
||||||
|
*/
|
||||||
|
boolean hasTenantPermission(Long userId, Long tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package com.youlai.boot.system.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.system.mapper.TenantMapper;
|
||||||
|
import com.youlai.boot.system.mapper.UserTenantMapper;
|
||||||
|
import com.youlai.boot.system.model.entity.Tenant;
|
||||||
|
import com.youlai.boot.system.model.entity.UserTenant;
|
||||||
|
import com.youlai.boot.system.model.vo.TenantVO;
|
||||||
|
import com.youlai.boot.system.service.TenantService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户服务实现类
|
||||||
|
*
|
||||||
|
* @author Ray.Hao
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TenantServiceImpl extends ServiceImpl<TenantMapper, Tenant> implements TenantService {
|
||||||
|
|
||||||
|
private final UserTenantMapper userTenantMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TenantVO> getTenantListByUserId(Long userId) {
|
||||||
|
// 临时忽略租户过滤,查询所有租户
|
||||||
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
|
try {
|
||||||
|
// 查询用户关联的租户ID列表
|
||||||
|
List<UserTenant> userTenants = userTenantMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<UserTenant>()
|
||||||
|
.eq(UserTenant::getUserId, userId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userTenants.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取租户ID列表
|
||||||
|
List<Long> tenantIds = userTenants.stream()
|
||||||
|
.map(UserTenant::getTenantId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 查询租户信息
|
||||||
|
List<Tenant> tenants = this.list(
|
||||||
|
new LambdaQueryWrapper<Tenant>()
|
||||||
|
.in(Tenant::getId, tenantIds)
|
||||||
|
.eq(Tenant::getStatus, 1) // 只查询正常状态的租户
|
||||||
|
.orderByDesc(Tenant::getId)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 转换为VO并标记默认租户
|
||||||
|
return tenants.stream().map(tenant -> {
|
||||||
|
TenantVO vo = new TenantVO();
|
||||||
|
BeanUtils.copyProperties(tenant, vo);
|
||||||
|
// 查找是否为默认租户
|
||||||
|
userTenants.stream()
|
||||||
|
.filter(ut -> ut.getTenantId().equals(tenant.getId()) && ut.getIsDefault() == 1)
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(ut -> vo.setIsDefault(true));
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
} finally {
|
||||||
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TenantVO getTenantById(Long tenantId) {
|
||||||
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
|
try {
|
||||||
|
Tenant tenant = this.getById(tenantId);
|
||||||
|
if (tenant == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TenantVO vo = new TenantVO();
|
||||||
|
BeanUtils.copyProperties(tenant, vo);
|
||||||
|
return vo;
|
||||||
|
} finally {
|
||||||
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getTenantIdByDomain(String domain) {
|
||||||
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
|
try {
|
||||||
|
Tenant tenant = this.getOne(
|
||||||
|
new LambdaQueryWrapper<Tenant>()
|
||||||
|
.eq(Tenant::getDomain, domain)
|
||||||
|
.eq(Tenant::getStatus, 1)
|
||||||
|
.last("LIMIT 1")
|
||||||
|
);
|
||||||
|
return tenant != null ? tenant.getId() : null;
|
||||||
|
} finally {
|
||||||
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasTenantPermission(Long userId, Long tenantId) {
|
||||||
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
|
try {
|
||||||
|
UserTenant userTenant = userTenantMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<UserTenant>()
|
||||||
|
.eq(UserTenant::getUserId, userId)
|
||||||
|
.eq(UserTenant::getTenantId, tenantId)
|
||||||
|
.last("LIMIT 1")
|
||||||
|
);
|
||||||
|
return userTenant != null;
|
||||||
|
} finally {
|
||||||
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user