Files
yunzerwebsiteallinone/go/docs/sql/create_tenant_package.sql
T
2026-09-15 17:28:08 +08:00

219 lines
16 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.
-- =============================================================
-- 租户套餐 + 用户数配额(平台端「租户套餐」功能)
--
-- 业务说明:
-- 1. 套餐(yz_system_tenant_package)决定租户能开通哪些功能模块
-- (模块取自 yz_system_modules,如 erp / oa / crm / cms),
-- 租户绑定套餐后,租户端菜单按套餐包含的模块过滤(未包含的整块菜单不展示)。
-- 2. 所有租户都有用户数上限(yz_system_tenant.user_quota,默认 20),
-- 租户用户数达到上限后不允许再新增账号,需要先增购用户数:
-- · 单个增购:按套餐的 extra_user_price(如 200 元/人)
-- · 套餐增购:按 yz_system_tenant_user_quota_package 配置的规格(如 5人/500元)
-- 每次增购写入 yz_system_tenant_quota_order 记录,并累加到租户的 user_quota。
--
-- 本脚本可重复执行:建表用 IF NOT EXISTS,补列/预置数据均做存在性判断。
-- 运行:mysql --default-character-set=utf8mb4 -h<host> -P<port> -u<user> -p <db> < create_tenant_package.sql
-- =============================================================
-- 1) 租户套餐表
CREATE TABLE IF NOT EXISTS `yz_system_tenant_package` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '套餐名称,如:ERP套餐',
`code` varchar(64) NOT NULL DEFAULT '' COMMENT '套餐编码(唯一,程序识别用)',
`description` varchar(500) NOT NULL DEFAULT '' COMMENT '套餐说明',
`price` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '套餐售价(元)',
`user_quota` int(11) NOT NULL DEFAULT 20 COMMENT '套餐包含的用户数(新租户绑定套餐后初始化的用户数上限)',
`extra_user_price` decimal(10,2) NOT NULL DEFAULT 200.00 COMMENT '单个用户增购价格(元/人)',
`is_default` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否默认套餐:1是 0否(新建租户未指定套餐时使用)',
`sort` int(11) NOT NULL DEFAULT 0 COMMENT '排序号,越小越靠前',
`status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间(软删除)',
PRIMARY KEY (`id`),
KEY `idx_code` (`code`, `delete_time`),
KEY `idx_delete_time` (`delete_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户套餐表(功能模块 + 用户数配额)';
-- 2) 套餐-功能模块关联表(一个套餐勾选多个模块,模块取自 yz_system_modules.code)
CREATE TABLE IF NOT EXISTS `yz_system_tenant_package_module` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`package_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '套餐ID 关联 yz_system_tenant_package(id)',
`module_code` varchar(64) NOT NULL DEFAULT '' COMMENT '功能模块编码 关联 yz_system_modules(code),如 erp/oa/crm/cms',
`module_name` varchar(64) NOT NULL DEFAULT '' COMMENT '功能模块名称(冗余,便于展示)',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_package_id` (`package_id`),
KEY `idx_module_code` (`module_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户套餐-功能模块关联表';
-- 3) 用户数加购套餐表(平台可维护的「人/元」规格,如 5人 500元)
CREATE TABLE IF NOT EXISTS `yz_system_tenant_user_quota_package` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`name` varchar(64) NOT NULL DEFAULT '' COMMENT '规格名称,如:5人套餐',
`user_count` int(11) NOT NULL DEFAULT 0 COMMENT '包含用户数',
`price` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '售价(元)',
`sort` int(11) NOT NULL DEFAULT 0 COMMENT '排序号,越小越靠前',
`status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
`delete_time` datetime DEFAULT NULL COMMENT '删除时间(软删除)',
PRIMARY KEY (`id`),
KEY `idx_delete_time` (`delete_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户用户数加购套餐表';
-- 4) 租户用户数增购记录表
CREATE TABLE IF NOT EXISTS `yz_system_tenant_quota_order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
`tid` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户ID 关联 yz_system_tenant(id)',
`type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '增购方式:1单个增购 2套餐增购',
`quota_package_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '加购套餐ID(type=2 时有效)',
`package_name` varchar(64) NOT NULL DEFAULT '' COMMENT '加购规格名称(冗余)',
`user_count` int(11) NOT NULL DEFAULT 0 COMMENT '本次增购用户数',
`unit_price` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '单价(元/人,type=1 时使用)',
`amount` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '本次金额(元)',
`quota_before` int(11) NOT NULL DEFAULT 0 COMMENT '增购前用户数上限',
`quota_after` int(11) NOT NULL DEFAULT 0 COMMENT '增购后用户数上限',
`operator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人(平台账号)',
`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_tid` (`tid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户用户数增购记录表';
-- 5) 租户表补列:套餐ID + 用户数上限
SET @tbl := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant');
SET @col := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant' AND COLUMN_NAME = 'package_id');
SET @ddl := IF(@tbl > 0 AND @col = 0, 'ALTER TABLE `yz_system_tenant` ADD COLUMN `package_id` bigint(20) NOT NULL DEFAULT 0 COMMENT ''套餐ID 关联 yz_system_tenant_package(id),0-未绑定''', 'DO 0');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @tbl := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant');
SET @col := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant' AND COLUMN_NAME = 'user_quota');
SET @ddl := IF(@tbl > 0 AND @col = 0, 'ALTER TABLE `yz_system_tenant` ADD COLUMN `user_quota` int(11) NOT NULL DEFAULT 20 COMMENT ''用户数上限(默认20,增购后累加)''', 'DO 0');
PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 存量租户兜底:用户数上限为 0 的按默认 20 初始化
UPDATE `yz_system_tenant` SET `user_quota` = 20 WHERE `user_quota` <= 0;
-- 存量租户兜底:用户数上限小于已开用户数时,按已开用户数抬高(避免历史租户立刻被锁死)
UPDATE `yz_system_tenant` t
SET t.`user_quota` = (
SELECT cnt FROM (SELECT COUNT(*) AS cnt FROM `yz_system_tenant_user` u WHERE u.`tid` = t.`id` AND u.`delete_time` IS NULL) c
)
WHERE t.`user_quota` < (
SELECT cnt FROM (SELECT COUNT(*) AS cnt FROM `yz_system_tenant_user` u WHERE u.`tid` = t.`id` AND u.`delete_time` IS NULL) c2
);
-- 6) 预置套餐(幂等:按 code 判断,不存在才插入)
INSERT INTO `yz_system_tenant_package` (`name`, `code`, `description`, `price`, `user_quota`, `extra_user_price`, `is_default`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT '基础版', 'basic', '基础功能:系统管理、基础设置、便捷工具', 0.00, 20, 200.00, 1, 1, 1, '默认套餐,新建租户自动绑定', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'basic' AND `delete_time` IS NULL) t);
INSERT INTO `yz_system_tenant_package` (`name`, `code`, `description`, `price`, `user_quota`, `extra_user_price`, `is_default`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT 'ERP套餐', 'erp', '基础功能 + 进销存(ERP)', 0.00, 20, 200.00, 0, 2, 1, '', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'erp' AND `delete_time` IS NULL) t);
INSERT INTO `yz_system_tenant_package` (`name`, `code`, `description`, `price`, `user_quota`, `extra_user_price`, `is_default`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT 'CRM套餐', 'crm', '基础功能 + 客户关系管理(CRM)', 0.00, 20, 200.00, 0, 3, 1, '', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'crm' AND `delete_time` IS NULL) t);
INSERT INTO `yz_system_tenant_package` (`name`, `code`, `description`, `price`, `user_quota`, `extra_user_price`, `is_default`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT '企业全功能版', 'all', '基础功能 + 进销存 + OA + CRM + 网站管理', 0.00, 20, 200.00, 0, 9, 1, '', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'all' AND `delete_time` IS NULL) t);
-- 7) 预置套餐功能模块(按套餐 code + 模块 code 幂等插入)
-- 注意:MySQL 的派生表不能引用外层字段,因此这里把「已存在的关联」整表materialize 成 ex,
-- 再在 WHERE 中与外层套餐/模块做关联,既避免了「不能 SELECT 目标表」,也保证可重复执行。
-- 基础模块:基础设置(basicSettings)、系统管理(systemManager)、便捷工具(bianjiegongju)
INSERT INTO `yz_system_tenant_package_module` (`package_id`, `module_code`, `module_name`, `create_time`)
SELECT p.`id`, m.`code`, m.`name`, NOW()
FROM `yz_system_tenant_package` p
JOIN `yz_system_modules` m ON m.`delete_time` IS NULL AND m.`code` IN ('basicSettings', 'systemManager', 'bianjiegongju')
WHERE p.`code` IN ('basic', 'erp', 'crm', 'all') AND p.`delete_time` IS NULL
AND NOT EXISTS (
SELECT 1 FROM (SELECT `package_id`, `module_code` FROM `yz_system_tenant_package_module`) ex
WHERE ex.`package_id` = p.`id` AND ex.`module_code` = m.`code`
);
-- ERP套餐:附加 erp 模块
INSERT INTO `yz_system_tenant_package_module` (`package_id`, `module_code`, `module_name`, `create_time`)
SELECT p.`id`, m.`code`, m.`name`, NOW()
FROM `yz_system_tenant_package` p
JOIN `yz_system_modules` m ON m.`delete_time` IS NULL AND m.`code` = 'erp'
WHERE p.`code` = 'erp' AND p.`delete_time` IS NULL
AND NOT EXISTS (
SELECT 1 FROM (SELECT `package_id`, `module_code` FROM `yz_system_tenant_package_module`) ex
WHERE ex.`package_id` = p.`id` AND ex.`module_code` = m.`code`
);
-- CRM套餐:附加 crm 模块
INSERT INTO `yz_system_tenant_package_module` (`package_id`, `module_code`, `module_name`, `create_time`)
SELECT p.`id`, m.`code`, m.`name`, NOW()
FROM `yz_system_tenant_package` p
JOIN `yz_system_modules` m ON m.`delete_time` IS NULL AND m.`code` = 'crm'
WHERE p.`code` = 'crm' AND p.`delete_time` IS NULL
AND NOT EXISTS (
SELECT 1 FROM (SELECT `package_id`, `module_code` FROM `yz_system_tenant_package_module`) ex
WHERE ex.`package_id` = p.`id` AND ex.`module_code` = m.`code`
);
-- 企业全功能版:附加 erp / oa / crm / cms
INSERT INTO `yz_system_tenant_package_module` (`package_id`, `module_code`, `module_name`, `create_time`)
SELECT p.`id`, m.`code`, m.`name`, NOW()
FROM `yz_system_tenant_package` p
JOIN `yz_system_modules` m ON m.`delete_time` IS NULL AND m.`code` IN ('erp', 'oa', 'crm', 'cms')
WHERE p.`code` = 'all' AND p.`delete_time` IS NULL
AND NOT EXISTS (
SELECT 1 FROM (SELECT `package_id`, `module_code` FROM `yz_system_tenant_package_module`) ex
WHERE ex.`package_id` = p.`id` AND ex.`module_code` = m.`code`
);
-- 8) 预置用户数加购套餐(5人 500元;可按需在平台端维护更多规格)
INSERT INTO `yz_system_tenant_user_quota_package` (`name`, `user_count`, `price`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT '5人套餐', 5, 500.00, 1, 1, '一次性增购 5 个用户数', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_user_quota_package` WHERE `name` = '5人套餐' AND `delete_time` IS NULL) t);
INSERT INTO `yz_system_tenant_user_quota_package` (`name`, `user_count`, `price`, `sort`, `status`, `remark`, `create_time`, `update_time`)
SELECT '10人套餐', 10, 900.00, 2, 1, '一次性增购 10 个用户数', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_user_quota_package` WHERE `name` = '10人套餐' AND `delete_time` IS NULL) t);
-- 9) 存量租户兜底:未绑定套餐的存量租户绑定「企业全功能版」,
-- 避免上线后老租户因套餐未配置而看不到原有功能菜单;
-- 之后可在「租户管理 → 编辑 / 套餐与用户数」中按实际购买情况改为 ERP/CRM 等套餐。
-- (若没有 all 套餐,则退回绑定默认套餐)
UPDATE `yz_system_tenant` t
SET t.`package_id` = (SELECT p.`id` FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'all' AND `delete_time` IS NULL ORDER BY `sort`, `id` LIMIT 1) p)
WHERE (t.`package_id` IS NULL OR t.`package_id` = 0)
AND EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'all' AND `delete_time` IS NULL) p2);
UPDATE `yz_system_tenant` t
SET t.`package_id` = (SELECT p.`id` FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `is_default` = 1 AND `delete_time` IS NULL ORDER BY `sort`, `id` LIMIT 1) p)
WHERE (t.`package_id` IS NULL OR t.`package_id` = 0)
AND EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `is_default` = 1 AND `delete_time` IS NULL) p2);
-- 10) 平台端菜单:基础设置 → 租户套餐(仅平台端可见)
-- pid=17 为「基础设置」菜单;若环境中 17 不是基础设置,请在平台端「菜单管理」里手工挂载本页面:
-- 组件路径 /basicSettings/tenantpackage/index.vue,路径 /basicSettings/tenantpackage
INSERT INTO `yz_system_menu` (`pid`, `title`, `path`, `component_path`, `icon`, `sort`, `status`, `is_visible`, `views`, `type`, `permission`, `creater`, `remark`, `create_time`, `update_time`)
SELECT 17, '租户套餐', '/basicSettings/tenantpackage', '/basicSettings/tenantpackage/index.vue', 'Box', 4, 1, 1, '[1]', 2, '', 'system', '租户功能套餐与用户数加购规格', NOW(), NOW()
WHERE NOT EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_menu` WHERE `path` = '/basicSettings/tenantpackage' AND `delete_time` IS NULL) t)
AND EXISTS (SELECT 1 FROM (SELECT `id` FROM `yz_system_menu` WHERE `id` = 17 AND `delete_time` IS NULL) t2);
-- 11) 【按需执行】存量租户套餐调整
-- 本脚本第 9 步只处理「package_id 为空/0」的租户;若存量租户已被绑定为「基础版」,
-- 上线菜单按套餐过滤后,这些租户将看不到 进销存/OA/CRM/网站管理 等菜单。
-- 如需要让老租户保留原有全部功能,按下面的语句把它们改为「企业全功能版」
-- (或改成各自实际购买的套餐;也可直接在平台端「租户管理 → 编辑」里选择套餐)。
--
-- UPDATE `yz_system_tenant`
-- SET `package_id` = (SELECT p.`id` FROM (SELECT `id` FROM `yz_system_tenant_package` WHERE `code` = 'all' AND `delete_time` IS NULL ORDER BY `sort`, `id` LIMIT 1) p)
-- WHERE `id` IN (1, 2); -- ← 改成你的租户ID,或去掉 WHERE 批量处理
-- 校验:套餐与模块
-- SELECT p.id, p.name, p.code, p.user_quota, p.extra_user_price, GROUP_CONCAT(pm.module_code) AS modules
-- FROM yz_system_tenant_package p LEFT JOIN yz_system_tenant_package_module pm ON pm.package_id = p.id
-- WHERE p.delete_time IS NULL GROUP BY p.id;
-- SELECT id, tenant_name, package_id, user_quota FROM yz_system_tenant;