-- ============================================================= -- 租户套餐 + 用户数配额(平台端「租户套餐」功能) -- -- 业务说明: -- 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 -P -u -p < 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否(新建租户未指定套餐时使用)', `allow_repurchase` tinyint(4) NOT NULL DEFAULT 1 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='租户用户数增购记录表'; -- 4.5) 历史库补列:套餐是否允许重复购买(0=仅可购买一次,适用于体验套餐) SET @tbl := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant_package'); SET @col := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_system_tenant_package' AND COLUMN_NAME = 'allow_repurchase'); SET @ddl := IF(@tbl > 0 AND @col = 0, 'ALTER TABLE `yz_system_tenant_package` ADD COLUMN `allow_repurchase` tinyint(4) NOT NULL DEFAULT 1 COMMENT ''是否允许重复购买:1允许(默认) 0仅可购买一次(体验套餐)'' AFTER `is_default`', 'DO 0'); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; -- 体验套餐(不允许重复购买)不涉及用户数增购:清理历史增购价 UPDATE `yz_system_tenant_package` SET `extra_user_price` = 0 WHERE `allow_repurchase` = 0; -- 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;