feat(account): add daily/weekly periodic quota limits for API Key accounts

Extend the existing total quota limit with daily and weekly periodic
dimensions. Each dimension is independently configurable and uses lazy
reset — when the period expires, usage is automatically reset to zero on
the next increment. Any dimension exceeding its limit will pause the
account from scheduling.

Backend:
- Add GetQuotaDailyLimit/Used, GetQuotaWeeklyLimit/Used, HasAnyQuotaLimit
- Rewrite IncrementQuotaUsed with atomic CTE SQL for 3-dimension update
- Rewrite ResetQuotaUsed to clear all dimensions and period timestamps
- Update postUsageBilling to use HasAnyQuotaLimit()
- Preserve daily/weekly used values on account edit

Frontend:
- Refactor QuotaLimitCard from single v-model to 3-dimension props
- Add QuotaBadge component for compact D/W/$ display
- Update AccountCapacityCell with per-dimension badges
- Update Create/Edit modals with daily/weekly quota fields
- Update AccountActionMenu hasQuotaLimit to check all dimensions
- Add i18n strings for daily/weekly/total quota labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
erio
2026-03-07 19:06:59 +08:00
parent bcb6444f89
commit 1ee17383f8
16 changed files with 386 additions and 139 deletions

View File

@@ -125,9 +125,9 @@ func GroupFromServiceAdmin(g *service.Group) *AdminGroup {
Group: groupFromServiceBase(g),
ModelRouting: g.ModelRouting,
ModelRoutingEnabled: g.ModelRoutingEnabled,
MCPXMLInject: g.MCPXMLInject,
DefaultMappedModel: g.DefaultMappedModel,
SupportedModelScopes: g.SupportedModelScopes,
MCPXMLInject: g.MCPXMLInject,
DefaultMappedModel: g.DefaultMappedModel,
SupportedModelScopes: g.SupportedModelScopes,
AccountCount: g.AccountCount,
SortOrder: g.SortOrder,
}
@@ -255,11 +255,19 @@ func AccountFromServiceShallow(a *service.Account) *Account {
if a.Type == service.AccountTypeAPIKey {
if limit := a.GetQuotaLimit(); limit > 0 {
out.QuotaLimit = &limit
}
used := a.GetQuotaUsed()
if out.QuotaLimit != nil {
used := a.GetQuotaUsed()
out.QuotaUsed = &used
}
if limit := a.GetQuotaDailyLimit(); limit > 0 {
out.QuotaDailyLimit = &limit
used := a.GetQuotaDailyUsed()
out.QuotaDailyUsed = &used
}
if limit := a.GetQuotaWeeklyLimit(); limit > 0 {
out.QuotaWeeklyLimit = &limit
used := a.GetQuotaWeeklyUsed()
out.QuotaWeeklyUsed = &used
}
}
return out

View File

@@ -193,8 +193,12 @@ type Account struct {
CacheTTLOverrideTarget *string `json:"cache_ttl_override_target,omitempty"`
// API Key 账号配额限制
QuotaLimit *float64 `json:"quota_limit,omitempty"`
QuotaUsed *float64 `json:"quota_used,omitempty"`
QuotaLimit *float64 `json:"quota_limit,omitempty"`
QuotaUsed *float64 `json:"quota_used,omitempty"`
QuotaDailyLimit *float64 `json:"quota_daily_limit,omitempty"`
QuotaDailyUsed *float64 `json:"quota_daily_used,omitempty"`
QuotaWeeklyLimit *float64 `json:"quota_weekly_limit,omitempty"`
QuotaWeeklyUsed *float64 `json:"quota_weekly_used,omitempty"`
Proxy *Proxy `json:"proxy,omitempty"`
AccountGroups []AccountGroup `json:"account_groups,omitempty"`