diff --git a/backend/internal/service/admin_service.go b/backend/internal/service/admin_service.go index c1233c40..08caed9e 100644 --- a/backend/internal/service/admin_service.go +++ b/backend/internal/service/admin_service.go @@ -1538,6 +1538,13 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U } } account.Extra = input.Extra + if account.Platform == PlatformAntigravity && wasOveragesEnabled && !account.IsOveragesEnabled() { + delete(account.Extra, antigravityCreditsOveragesKey) + } + if account.Platform == PlatformAntigravity && !wasOveragesEnabled && account.IsOveragesEnabled() { + delete(account.Extra, modelRateLimitsKey) + delete(account.Extra, antigravityCreditsOveragesKey) + } // 校验并预计算固定时间重置的下次重置时间 if err := ValidateQuotaResetConfig(account.Extra); err != nil { return nil, err @@ -1623,9 +1630,6 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U if account.Platform == PlatformAntigravity { if !account.IsOveragesEnabled() && wasOveragesEnabled { clearCreditsExhausted(account.ID) - if err := clearAntigravityCreditsOveragesState(ctx, s.accountRepo, account.ID); err != nil { - return nil, err - } } if account.IsOveragesEnabled() && !wasOveragesEnabled { clearCreditsExhausted(account.ID) diff --git a/backend/internal/service/admin_service_overages_test.go b/backend/internal/service/admin_service_overages_test.go new file mode 100644 index 00000000..ea5a4110 --- /dev/null +++ b/backend/internal/service/admin_service_overages_test.go @@ -0,0 +1,111 @@ +//go:build unit + +package service + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +type updateAccountOveragesRepoStub struct { + mockAccountRepoForGemini + account *Account + updateCalls int +} + +func (r *updateAccountOveragesRepoStub) GetByID(ctx context.Context, id int64) (*Account, error) { + return r.account, nil +} + +func (r *updateAccountOveragesRepoStub) Update(ctx context.Context, account *Account) error { + r.updateCalls++ + r.account = account + return nil +} + +func TestUpdateAccount_DisableOveragesClearsRuntimeStateBeforePersist(t *testing.T) { + accountID := int64(101) + repo := &updateAccountOveragesRepoStub{ + account: &Account{ + ID: accountID, + Platform: PlatformAntigravity, + Type: AccountTypeOAuth, + Status: StatusActive, + Extra: map[string]any{ + "allow_overages": true, + "mixed_scheduling": true, + antigravityCreditsOveragesKey: map[string]any{ + "claude-sonnet-4-5": map[string]any{ + "activated_at": "2026-03-15T00:00:00Z", + "active_until": "2099-03-15T00:00:00Z", + }, + }, + }, + }, + } + setCreditsExhausted(accountID, time.Now().Add(time.Minute)) + t.Cleanup(func() { + clearCreditsExhausted(accountID) + }) + + svc := &adminServiceImpl{accountRepo: repo} + updated, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{ + Extra: map[string]any{ + "mixed_scheduling": true, + }, + }) + + require.NoError(t, err) + require.NotNil(t, updated) + require.Equal(t, 1, repo.updateCalls) + require.False(t, updated.IsOveragesEnabled()) + require.False(t, isCreditsExhausted(accountID)) + + _, exists := repo.account.Extra[antigravityCreditsOveragesKey] + require.False(t, exists, "关闭 overages 时应在持久化前移除运行态") +} + +func TestUpdateAccount_EnableOveragesClearsModelRateLimitsBeforePersist(t *testing.T) { + accountID := int64(102) + repo := &updateAccountOveragesRepoStub{ + account: &Account{ + ID: accountID, + Platform: PlatformAntigravity, + Type: AccountTypeOAuth, + Status: StatusActive, + Extra: map[string]any{ + "mixed_scheduling": true, + modelRateLimitsKey: map[string]any{ + "claude-sonnet-4-5": map[string]any{ + "rate_limited_at": "2026-03-15T00:00:00Z", + "rate_limit_reset_at": "2099-03-15T00:00:00Z", + }, + }, + }, + }, + } + setCreditsExhausted(accountID, time.Now().Add(time.Minute)) + t.Cleanup(func() { + clearCreditsExhausted(accountID) + }) + + svc := &adminServiceImpl{accountRepo: repo} + updated, err := svc.UpdateAccount(context.Background(), accountID, &UpdateAccountInput{ + Extra: map[string]any{ + "mixed_scheduling": true, + "allow_overages": true, + }, + }) + + require.NoError(t, err) + require.NotNil(t, updated) + require.Equal(t, 1, repo.updateCalls) + require.True(t, updated.IsOveragesEnabled()) + require.False(t, isCreditsExhausted(accountID)) + + _, exists := repo.account.Extra[modelRateLimitsKey] + require.False(t, exists, "开启 overages 时应在持久化前清掉旧模型限流") +} diff --git a/frontend/src/components/account/AccountUsageCell.vue b/frontend/src/components/account/AccountUsageCell.vue index cdce0997..471ae7a0 100644 --- a/frontend/src/components/account/AccountUsageCell.vue +++ b/frontend/src/components/account/AccountUsageCell.vue @@ -290,30 +290,34 @@ color="amber" /> -