From a34d44a824ac5a65d9b629d3f421c72734dd72b9 Mon Sep 17 00:00:00 2001 From: fengsilin Date: Tue, 28 Apr 2026 11:37:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(user):=20=E4=BF=AE=E5=A4=8D=E4=BB=8E?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=E6=98=BE=E7=A4=BA=E4=B8=BA=200=20=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同步用户(synced)的实际余额存储在 synced_quota 字段, 但用户列表/详情接口返回的是 quota 字段(值为 0)。 新增 ApplySyncedQuota 方法,在 API 返回前将 synced_quota 赋值给 quota,使前端能正确显示余额。 同时优化 GetUserModels:map 去重替代 O(n) 线性扫描, 禁用模型查询移至 model 层,新增 StringsSubtract 工具函数。 Co-Authored-By: Claude --- common/str.go | 18 ++++++++++++++++++ controller/user.go | 6 +++++- model/model_meta.go | 10 ++++++++++ model/user.go | 16 ++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/common/str.go b/common/str.go index 71391f7..d61f06b 100644 --- a/common/str.go +++ b/common/str.go @@ -87,6 +87,24 @@ func StringsContains(strs []string, str string) bool { return false } +// StringsSubtract returns elements from source that are not in exclude. +func StringsSubtract(source, exclude []string) []string { + if len(exclude) == 0 { + return source + } + excludeSet := make(map[string]struct{}, len(exclude)) + for _, s := range exclude { + excludeSet[s] = struct{}{} + } + result := make([]string, 0, len(source)) + for _, s := range source { + if _, ok := excludeSet[s]; !ok { + result = append(result, s) + } + } + return result +} + // StringToByteSlice []byte only read, panic on append func StringToByteSlice(s string) []byte { tmp1 := (*[2]uintptr)(unsafe.Pointer(&s)) diff --git a/controller/user.go b/controller/user.go index 8524291..9bfb254 100644 --- a/controller/user.go +++ b/controller/user.go @@ -270,6 +270,7 @@ func GetUser(c *gin.Context) { common.ApiErrorI18n(c, i18n.MsgUserNoPermissionSameLevel) return } + user.ApplySyncedQuota() c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", @@ -523,13 +524,16 @@ func GetUserModels(c *gin.Context) { } groups := service.GetUserUsableGroups(user.Group) var models []string + seen := make(map[string]struct{}) for group := range groups { for _, g := range model.GetGroupEnabledModels(group) { - if !common.StringsContains(models, g) { + if _, ok := seen[g]; !ok { + seen[g] = struct{}{} models = append(models, g) } } } + models = common.StringsSubtract(models, model.GetDisabledModelNames(models)) c.JSON(http.StatusOK, gin.H{ "success": true, "message": "", diff --git a/model/model_meta.go b/model/model_meta.go index f549ec3..ce03391 100644 --- a/model/model_meta.go +++ b/model/model_meta.go @@ -98,6 +98,16 @@ func (mi *Model) Delete() error { return DB.Delete(mi).Error } +// GetDisabledModelNames returns model names that are disabled (status = 0) from the given list. +func GetDisabledModelNames(names []string) []string { + if len(names) == 0 { + return nil + } + var disabled []string + DB.Table("models").Where("model_name IN ? AND status = 0", names).Pluck("model_name", &disabled) + return disabled +} + func GetVendorModelCounts() (map[int64]int64, error) { var stats []struct { VendorID int64 diff --git a/model/user.go b/model/user.go index 89f8c7e..eeec72c 100644 --- a/model/user.go +++ b/model/user.go @@ -214,6 +214,20 @@ func GetMaxUserId() int { return user.Id } +// ApplySyncedQuota 将同步用户的 quota 替换为 synced_quota, +// 使 API 返回的 quota 对所有用户类型都表示实际可用余额。 +func (u *User) ApplySyncedQuota() { + if u.IsSyncedUser() { + u.Quota = u.SyncedQuota + } +} + +func applySyncedUserQuota(users []*User) { + for _, u := range users { + u.ApplySyncedQuota() + } +} + func GetAllUsers(pageInfo *common.PageInfo) (users []*User, total int64, err error) { // Start transaction tx := DB.Begin() @@ -245,6 +259,7 @@ func GetAllUsers(pageInfo *common.PageInfo) (users []*User, total int64, err err return nil, 0, err } + applySyncedUserQuota(users) return users, total, nil } @@ -312,6 +327,7 @@ func SearchUsers(keyword string, group string, startIdx int, num int) ([]*User, return nil, 0, err } + applySyncedUserQuota(users) return users, total, nil }