增加租户套餐

This commit is contained in:
2026-09-15 17:28:08 +08:00
parent a82b300b1a
commit 71a14c46f9
37 changed files with 3855 additions and 178 deletions
+61 -7
View File
@@ -3,6 +3,8 @@ package controllers
import (
"encoding/json"
"server/models"
"server/pkg/jwtutil"
"server/services"
"strconv"
"strings"
@@ -91,26 +93,74 @@ func (c *BackendMenuController) GetBackendMenu() {
// 否则仅返回角色允许访问的菜单(含其祖先节点,保证树结构完整)。
idStr := c.Ctx.Input.Param(":id")
uid, _ := strconv.ParseUint(idStr, 10, 64)
tid := uint64(0)
if uid > 0 {
var tu models.SystemTenantUser
if e := models.Orm.QueryTable(new(models.SystemTenantUser)).
Filter("id", uid).
Filter("delete_time__isnull", true).
One(&tu); e == nil && tu.GroupID > 0 {
var role models.AdminRole
if re := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", tu.GroupID).
Filter("cid", 2).
One(&role); re == nil {
backendMenus = filterMenusByRights(backendMenus, role.Rights)
One(&tu); e == nil {
tid = tu.Tid
if tu.GroupID > 0 {
var role models.AdminRole
if re := models.Orm.QueryTable(new(models.AdminRole)).
Filter("id", tu.GroupID).
Filter("cid", 2).
One(&role); re == nil {
backendMenus = filterMenusByRights(backendMenus, role.Rights)
}
}
}
}
// 套餐功能开通过滤:仅展示租户套餐已包含的功能模块对应的菜单(未包含的整块菜单不展示)
backendMenus = filterMenusByTenantPackage(c.Ctx.Request.Header.Get("Authorization"), backendMenus, tid)
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": buildMenuTree(backendMenus, 0)}
_ = c.ServeJSON()
}
// backendJWTTenantID 从 Authorization 的 Bearer Token 中解析租户ID;取不到时返回 0。
// 说明:backend 端登录时 token 里写入了租户ID(GenerateToken 的 tenantId),
// 用它做套餐功能过滤比依赖前端传参更可靠。
func backendJWTTenantID(auth string) uint64 {
auth = strings.TrimSpace(auth)
if auth == "" {
return 0
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
return 0
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil || claims == nil || claims.TenantId <= 0 {
return 0
}
return uint64(claims.TenantId)
}
// filterMenusByTenantPackage 按租户套餐包含的功能模块过滤菜单。
// tid 优先取 token 中的租户ID,其次用调用方传入的兜底值;两者都取不到时不处理(保持原行为)。
func filterMenusByTenantPackage(authHeader string, menus []models.SystemMenu, tid uint64) []models.SystemMenu {
if jwtTid := backendJWTTenantID(authHeader); jwtTid > 0 {
tid = jwtTid
}
if tid == 0 {
return menus
}
allModules, err := services.ListEnabledModules()
if err != nil || len(allModules) == 0 {
return menus
}
allowed := services.GetTenantModuleCodes(tid)
// 安全兜底:租户没有绑定套餐或套餐未配置任何功能模块时不做过滤,
// 避免因套餐数据缺失导致租户端菜单整体消失。
if len(allowed) == 0 {
return menus
}
return services.FilterMenusByTenantModules(menus, allModules, allowed)
}
// parseRightsToSet 将角色 rights 解析为菜单 ID 集合(兼容 JSON 数组 / 逗号分隔)
func parseRightsToSet(raw string) map[uint64]bool {
set := map[uint64]bool{}
@@ -267,6 +317,10 @@ func (c *BackendMenuController) GetAssignableMenus() {
menus = filterMenusByView(menus, cid)
}
menus = filterAssignableMenus(menus)
// 租户端:仅可分配当前租户套餐已开通的功能模块下的菜单
if cid == 2 {
menus = filterMenusByTenantPackage(c.Ctx.Request.Header.Get("Authorization"), menus, 0)
}
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": buildMenuTree(menus, 0)}
_ = c.ServeJSON()