修复个人中心问题

This commit is contained in:
2026-09-29 18:25:09 +08:00
parent 0dc5c2f075
commit ca4220f92c
44 changed files with 1793 additions and 310 deletions
+74 -1
View File
@@ -5,6 +5,7 @@ import (
"math"
"sort"
"strings"
"sync"
"time"
"server/models"
@@ -151,6 +152,75 @@ func NormalizeModuleCode(code string) string {
return strings.ToLower(strings.TrimSpace(code))
}
// ---------------------------------------------------------------- 模块权益鉴权
// moduleCodesCacheTTL 模块权益缓存时长。
// 模块鉴权中间件会在每个业务请求上判断开通状态,直查数据库代价太高;
// 60 秒延迟对「购买后立即可用」没有实际影响(前端刷新即可)。
const moduleCodesCacheTTL = 60 * time.Second
type tenantModuleCodesItem struct {
codes map[string]bool
expireAt time.Time
}
var (
tenantModuleCodesMu sync.RWMutex
tenantModuleCodesCache = map[uint64]tenantModuleCodesItem{}
)
// GetTenantModuleCodesCached 带进程内缓存的模块权益查询(供请求级鉴权使用)
func GetTenantModuleCodesCached(tid uint64) map[string]bool {
now := time.Now()
tenantModuleCodesMu.RLock()
item, ok := tenantModuleCodesCache[tid]
tenantModuleCodesMu.RUnlock()
if ok && now.Before(item.expireAt) {
return item.codes
}
codes := GetTenantModuleCodes(tid)
tenantModuleCodesMu.Lock()
// 顺带清理过期项,避免长期运行后内存堆积
if len(tenantModuleCodesCache) > 5000 {
for k, v := range tenantModuleCodesCache {
if now.After(v.expireAt) {
delete(tenantModuleCodesCache, k)
}
}
}
tenantModuleCodesCache[tid] = tenantModuleCodesItem{codes: codes, expireAt: now.Add(moduleCodesCacheTTL)}
tenantModuleCodesMu.Unlock()
return codes
}
// InvalidateTenantModuleCodes 清除某租户的模块权益缓存(套餐 / 订单变更后调用)
func InvalidateTenantModuleCodes(tid uint64) {
if tid == 0 {
return
}
tenantModuleCodesMu.Lock()
delete(tenantModuleCodesCache, tid)
tenantModuleCodesMu.Unlock()
}
// IsModuleEnabled 判断租户是否已开通指定功能模块。
//
// 口径与 /backend/modules/getTenantList 保持一致:租户没有任何模块权益时视为「全开」,
// 避免历史租户或未配置套餐的环境被一刀切拦截。
func IsModuleEnabled(tid uint64, moduleCode string) bool {
code := NormalizeModuleCode(moduleCode)
if code == "" || tid == 0 {
return true
}
codes := GetTenantModuleCodesCached(tid)
if len(codes) == 0 {
return true
}
return codes[code]
}
// DayStart 取时间所在自然日的 0 点(有效期按「日」计算,不精确到秒)
func DayStart(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
@@ -277,9 +347,10 @@ func CheckTenantUserQuota(tid, uid uint64) (*TenantQuotaCheck, error) {
result.Quota = quota
if uid > 0 {
// uid 可能来自令牌(identity_id),查老表前先换算
exist, err := models.Orm.QueryTable(new(models.SystemTenantUser)).
Filter("tid", tid).
Filter("uid", uid).
Filter("uid", ResolveTenantUID(tid, uid)).
Filter("delete_time__isnull", true).
Count()
if err == nil && exist > 0 {
@@ -442,6 +513,8 @@ func ApplyPackageToTenant(tid, packageID uint64, syncQuota bool) (int, error) {
Update(update); err != nil {
return 0, err
}
// 套餐变更后清掉模块权益缓存,避免「刚换套餐仍被拦/仍在放行」的延迟
InvalidateTenantModuleCodes(tid)
return newQuota, nil
}