feat(cms): 新增产品置顶字段及完善站点管理权限

- 在 CmsProduct 实体中新增 top 属性标识是否置顶
- 在产品表中添加 top 字段及索引支持置顶排序
- 补充 cms:website 按钮级权限点,解决 about 页面保存返回 403 问题
- 新权限点新增站点管理菜单下,确保权限分配给管理员角色
- 权限脚本支持幂等执行,可多次运行不会重复插入权限数据
This commit is contained in:
2026-07-20 07:46:36 +08:00
parent b79cc1003c
commit e25c385f9d
3 changed files with 131 additions and 1 deletions

View File

@@ -70,6 +70,9 @@ public class CmsProduct implements Serializable {
@JSONField(name = "sortNum")
private Integer sortNumber;
@Schema(description = "是否置顶: 1置顶 0否")
private Integer top;
@Schema(description = "标签, 逗号分隔")
private String tags;

View File

@@ -33,6 +33,7 @@ CREATE TABLE IF NOT EXISTS `cms_product` (
`charge_type` TINYINT DEFAULT 1 COMMENT '计费方式: 1包月 2包年 3一次性 4按量',
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态: 1在售 0下架',
`sort_number` INT NOT NULL DEFAULT 0 COMMENT '排序(数字越小越靠前)',
`top` TINYINT NOT NULL DEFAULT 0 COMMENT '是否置顶: 1置顶 0否',
`tags` VARCHAR(255) DEFAULT NULL COMMENT '标签, 逗号分隔',
`user_id` INT DEFAULT NULL COMMENT '创建人ID',
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是',
@@ -42,7 +43,8 @@ CREATE TABLE IF NOT EXISTS `cms_product` (
PRIMARY KEY (`product_id`),
KEY `idx_tenant_id` (`tenant_id`),
KEY `idx_category_id` (`category_id`),
KEY `idx_status` (`status`)
KEY `idx_status` (`status`),
KEY `idx_top` (`top`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品';
-- ----------------------------

View File

@@ -0,0 +1,125 @@
-- =====================================================================
-- 补齐 cms:website:* 按钮级权限点
-- 用途:解决 /about 公司信息页面保存时返回 403 的问题
-- 背景:
-- CmsWebsiteController 的 save/update/remove 等写操作带
-- @PreAuthorize("hasAuthority('cms:website:save|update|remove')")
-- 但 sys_menu 表里从未 INSERT 过这些权限点,本项目又无超管绕过,
-- 导致任何用户(含超管)点保存都会 403。
-- 幂等:可重复执行,已存在的权限点会跳过。
-- 自适应:不写死 menu_id按 name 查找父菜单。
-- 用法:在能访问 gxwebsoft_core 的 MySQL 连接里执行。
-- =====================================================================
-- ---------------------------------------------------------------------
-- 1. 查找/创建父菜单「站点管理」
-- 约定:父菜单 name = '站点管理'permission = 'cms:website'
-- 若库里没有,就建一个;若有但 permission 为空,补上。
-- ---------------------------------------------------------------------
-- 1.1 若父菜单不存在先创建一个顶级父菜单type=0 菜单,挂在根节点 0 下)
INSERT INTO sys_menu (name, permission, parent_id, icon, path, component, visible,
sort_order, menu_type, keep_alive, embedded, create_by, create_time, del_flag)
SELECT '站点管理', 'cms:website', 0, 'EnvironmentOutlined', '/site', 'Layout',
'0', 100, '0', '0', '0', 'system', NOW(), '0'
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM sys_menu
WHERE name = '站点管理'
AND (permission = 'cms:website' OR permission IS NULL)
AND del_flag = '0'
);
-- 1.2 取父菜单 ID后续子权限点挂在它下面
-- 用变量保存,避免子查询重复执行
SET @parentId = (
SELECT menu_id FROM sys_menu
WHERE name = '站点管理'
AND del_flag = '0'
LIMIT 1
);
-- 1.3 兜底:若「站点管理」仍不存在(极少数情况),挂到根节点 0 下
IF @parentId IS NULL THEN
SET @parentId = 0;
END IF;
-- ---------------------------------------------------------------------
-- 2. 插入 3 个按钮级权限点menu_type=1
-- - cms:website:save 新增
-- - cms:website:update 修改about 页面保存用的就是这个)
-- - cms:website:remove 删除
-- 幂等NOT EXISTS 保证重复执行不重复插入
-- ---------------------------------------------------------------------
INSERT INTO sys_menu (name, permission, parent_id, icon, path, component, visible,
sort_order, menu_type, keep_alive, embedded, create_by, create_time, del_flag)
SELECT '站点-新增', 'cms:website:save', @parentId, NULL, NULL, NULL,
'0', 10, '1', '0', '0', 'system', NOW(), '0'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'cms:website:save' AND del_flag = '0');
INSERT INTO sys_menu (name, permission, parent_id, icon, path, component, visible,
sort_order, menu_type, keep_alive, embedded, create_by, create_time, del_flag)
SELECT '站点-修改', 'cms:website:update', @parentId, NULL, NULL, NULL,
'0', 20, '1', '0', '0', 'system', NOW(), '0'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'cms:website:update' AND del_flag = '0');
INSERT INTO sys_menu (name, permission, parent_id, icon, path, component, visible,
sort_order, menu_type, keep_alive, embedded, create_by, create_time, del_flag)
SELECT '站点-删除', 'cms:website:remove', @parentId, NULL, NULL, NULL,
'0', 30, '1', '0', '0', 'system', NOW(), '0'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE permission = 'cms:website:remove' AND del_flag = '0');
-- ---------------------------------------------------------------------
-- 3. 把新权限点分配给管理员角色
-- 策略:把所有拥有「任意 cms:website:* 权限」的角色(说明该角色在管 CMS
-- 自动补上新权限点。若没有任何角色已有 website 权限(全新环境),
-- 则回退到「把新权限点分配给所有角色」——联调阶段先保证能用。
-- ---------------------------------------------------------------------
-- 3.1 收集需要授权的角色 ID已有任意 cms:website:* 权限的角色)
-- 若结果为空,回退为「所有角色」
-- 用临时表暂存,避免重复扫描
DROP TEMPORARY TABLE IF EXISTS tmp_target_roles;
CREATE TEMPORARY TABLE tmp_target_roles (role_id BIGINT NOT NULL, PRIMARY KEY (role_id));
INSERT IGNORE INTO tmp_target_roles (role_id)
SELECT DISTINCT rm.role_id
FROM sys_role_menu rm
JOIN sys_menu m ON m.menu_id = rm.menu_id
WHERE m.permission LIKE 'cms:website:%'
AND m.del_flag = '0'
AND rm.del_flag = '0';
-- 3.2 回退:若没有任何角色已有 website 权限,则把所有角色作为目标
-- (联调阶段先保证能保存;上线前请按需收紧)
INSERT IGNORE INTO tmp_target_roles (role_id)
SELECT role_id FROM sys_role
WHERE del_flag = '0'
AND NOT EXISTS (SELECT 1 FROM tmp_target_roles WHERE role_id = sys_role.role_id);
-- 3.3 把 3 个新权限点分配给目标角色幂等NOT EXISTS 跳过已分配的)
INSERT INTO sys_role_menu (role_id, menu_id, create_by, create_time, del_flag)
SELECT r.role_id, m.menu_id, 'system', NOW(), '0'
FROM tmp_target_roles r
CROSS JOIN sys_menu m
WHERE m.permission IN ('cms:website:save', 'cms:website:update', 'cms:website:remove')
AND m.del_flag = '0'
AND NOT EXISTS (
SELECT 1 FROM sys_role_menu rm
WHERE rm.role_id = r.role_id AND rm.menu_id = m.menu_id
AND rm.del_flag = '0'
);
DROP TEMPORARY TABLE IF EXISTS tmp_target_roles;
-- ---------------------------------------------------------------------
-- 4. 验证(执行后查看,确认权限点已就位)
-- ---------------------------------------------------------------------
SELECT menu_id, name, permission, parent_id, menu_type, visible, del_flag
FROM sys_menu
WHERE permission LIKE 'cms:website%'
ORDER BY sort_order;