diff --git a/.gitattributes b/.gitattributes
index 3db3b83d..37e3bee2 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,6 +4,13 @@ backend/migrations/*.sql text eol=lf
# Go 源代码文件
*.go text eol=lf
+# 前端 源代码文件
+*.ts text eol=lf
+*.tsx text eol=lf
+*.js text eol=lf
+*.jsx text eol=lf
+*.vue text eol=lf
+
# Shell 脚本
*.sh text eol=lf
diff --git a/backend/internal/service/account_usage_service.go b/backend/internal/service/account_usage_service.go
index f117abfd..959c1182 100644
--- a/backend/internal/service/account_usage_service.go
+++ b/backend/internal/service/account_usage_service.go
@@ -446,23 +446,17 @@ func (s *AccountUsageService) getOpenAIUsage(ctx context.Context, account *Accou
}
if stats, err := s.usageLogRepo.GetAccountWindowStats(ctx, account.ID, now.Add(-5*time.Hour)); err == nil {
- windowStats := windowStatsFromAccountStats(stats)
- if hasMeaningfulWindowStats(windowStats) {
- if usage.FiveHour == nil {
- usage.FiveHour = &UsageProgress{Utilization: 0}
- }
- usage.FiveHour.WindowStats = windowStats
+ if usage.FiveHour == nil {
+ usage.FiveHour = &UsageProgress{Utilization: 0}
}
+ usage.FiveHour.WindowStats = windowStatsFromAccountStats(stats)
}
if stats, err := s.usageLogRepo.GetAccountWindowStats(ctx, account.ID, now.Add(-7*24*time.Hour)); err == nil {
- windowStats := windowStatsFromAccountStats(stats)
- if hasMeaningfulWindowStats(windowStats) {
- if usage.SevenDay == nil {
- usage.SevenDay = &UsageProgress{Utilization: 0}
- }
- usage.SevenDay.WindowStats = windowStats
+ if usage.SevenDay == nil {
+ usage.SevenDay = &UsageProgress{Utilization: 0}
}
+ usage.SevenDay.WindowStats = windowStatsFromAccountStats(stats)
}
return usage, nil
@@ -992,13 +986,6 @@ func windowStatsFromAccountStats(stats *usagestats.AccountStats) *WindowStats {
}
}
-func hasMeaningfulWindowStats(stats *WindowStats) bool {
- if stats == nil {
- return false
- }
- return stats.Requests > 0 || stats.Tokens > 0 || stats.Cost > 0 || stats.StandardCost > 0 || stats.UserCost > 0
-}
-
func buildCodexUsageProgressFromExtra(extra map[string]any, window string, now time.Time) *UsageProgress {
if len(extra) == 0 {
return nil
diff --git a/backend/internal/service/admin_service.go b/backend/internal/service/admin_service.go
index ea76e171..5eeac183 100644
--- a/backend/internal/service/admin_service.go
+++ b/backend/internal/service/admin_service.go
@@ -1530,7 +1530,9 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U
if len(input.Credentials) > 0 {
account.Credentials = input.Credentials
}
- if len(input.Extra) > 0 {
+ // Extra 使用 map:需要区分“未提供(nil)”与“显式清空({})”。
+ // 关闭配额限制时前端会删除 quota_* 键并提交 extra:{},此时也必须落库。
+ if input.Extra != nil {
// 保留配额用量字段,防止编辑账号时意外重置
for _, key := range []string{"quota_used", "quota_daily_used", "quota_daily_start", "quota_weekly_used", "quota_weekly_start"} {
if v, ok := account.Extra[key]; ok {
diff --git a/backend/internal/service/admin_service_overages_test.go b/backend/internal/service/admin_service_overages_test.go
index 779b08b9..d6380f4d 100644
--- a/backend/internal/service/admin_service_overages_test.go
+++ b/backend/internal/service/admin_service_overages_test.go
@@ -121,3 +121,35 @@ func TestUpdateAccount_EnableOveragesClearsModelRateLimitsBeforePersist(t *testi
_, exists := repo.account.Extra[modelRateLimitsKey]
require.False(t, exists, "开启 overages 时应在持久化前清掉旧模型限流")
}
+
+func TestUpdateAccount_EmptyExtraPayloadCanClearQuotaLimits(t *testing.T) {
+ accountID := int64(103)
+ repo := &updateAccountOveragesRepoStub{
+ account: &Account{
+ ID: accountID,
+ Platform: PlatformAnthropic,
+ Type: AccountTypeAPIKey,
+ Status: StatusActive,
+ Extra: map[string]any{
+ "quota_limit": 100.0,
+ "quota_daily_limit": 10.0,
+ "quota_weekly_limit": 40.0,
+ },
+ },
+ }
+
+ svc := &adminServiceImpl{accountRepo: repo}
+ updated, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{
+ // 显式空对象:语义是“清空 extra 中的可配置键”(例如关闭配额限制)
+ Extra: map[string]any{},
+ })
+
+ require.NoError(t, err)
+ require.NotNil(t, updated)
+ require.Equal(t, 1, repo.updateCalls)
+ require.NotNil(t, repo.account.Extra)
+ require.NotContains(t, repo.account.Extra, "quota_limit")
+ require.NotContains(t, repo.account.Extra, "quota_daily_limit")
+ require.NotContains(t, repo.account.Extra, "quota_weekly_limit")
+ require.Len(t, repo.account.Extra, 0)
+}
diff --git a/frontend/src/components/account/AccountUsageCell.vue b/frontend/src/components/account/AccountUsageCell.vue
index 09236edd..9c145530 100644
--- a/frontend/src/components/account/AccountUsageCell.vue
+++ b/frontend/src/components/account/AccountUsageCell.vue
@@ -75,7 +75,7 @@
-