diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION
index fa91977d06..a793effa76 100644
--- a/backend/cmd/server/VERSION
+++ b/backend/cmd/server/VERSION
@@ -1 +1 @@
-0.1.93.23
+0.1.93.24
diff --git a/frontend/src/components/account/AccountCapacityCell.vue b/frontend/src/components/account/AccountCapacityCell.vue
index 10374560a1..d3042f98ca 100644
--- a/frontend/src/components/account/AccountCapacityCell.vue
+++ b/frontend/src/components/account/AccountCapacityCell.vue
@@ -30,11 +30,6 @@
-
-
-
-
-
@@ -44,7 +39,6 @@ import { useI18n } from 'vue-i18n'
import type { Account } from '@/types'
import CapacityBadge from '@/components/account/CapacityBadge.vue'
import AffinityBadge from '@/components/account/AffinityBadge.vue'
-import QuotaBadge from '@/components/account/QuotaBadge.vue'
const props = defineProps<{
account: Account
@@ -197,17 +191,6 @@ const affinityBuffer = computed((): number | null => {
return null
})
-// ====== 配额 ======
-const showDailyQuota = computed(() =>
- props.account.type === 'apikey' && props.account.quota_daily_limit != null && props.account.quota_daily_limit > 0
-)
-const showWeeklyQuota = computed(() =>
- props.account.type === 'apikey' && props.account.quota_weekly_limit != null && props.account.quota_weekly_limit > 0
-)
-const showTotalQuota = computed(() =>
- props.account.type === 'apikey' && props.account.quota_limit != null && props.account.quota_limit > 0
-)
-
const formatCost = (value: number | null | undefined) => {
if (value === null || value === undefined) return '0'
return value.toFixed(2)
diff --git a/frontend/src/components/account/AccountUsageCell.vue b/frontend/src/components/account/AccountUsageCell.vue
index cf684b670e..a696383990 100644
--- a/frontend/src/components/account/AccountUsageCell.vue
+++ b/frontend/src/components/account/AccountUsageCell.vue
@@ -334,6 +334,32 @@
@@ -822,6 +848,63 @@ const loadUsage = async () => {
}
}
+// ===== API Key quota progress bars =====
+
+interface QuotaBarInfo {
+ utilization: number
+ displayValue: string
+ resetsAt: string | null
+}
+
+const fmtCost = (v: number) => v.toFixed(2)
+
+const makeQuotaBar = (
+ used: number,
+ limit: number,
+ startKey?: string
+): QuotaBarInfo => {
+ const utilization = limit > 0 ? (used / limit) * 100 : 0
+ const displayValue = `${fmtCost(used)}/${fmtCost(limit)}`
+ let resetsAt: string | null = null
+ if (startKey) {
+ const extra = props.account.extra as Record | undefined
+ const startStr = extra?.[startKey] as string | undefined
+ if (startStr) {
+ const startDate = new Date(startStr)
+ const periodMs = startKey.includes('daily') ? 24 * 60 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000
+ resetsAt = new Date(startDate.getTime() + periodMs).toISOString()
+ }
+ }
+ return { utilization, displayValue, resetsAt }
+}
+
+const hasApiKeyQuota = computed(() => {
+ if (props.account.type !== 'apikey') return false
+ return (
+ (props.account.quota_daily_limit ?? 0) > 0 ||
+ (props.account.quota_weekly_limit ?? 0) > 0 ||
+ (props.account.quota_limit ?? 0) > 0
+ )
+})
+
+const quotaDailyBar = computed((): QuotaBarInfo | null => {
+ const limit = props.account.quota_daily_limit ?? 0
+ if (limit <= 0) return null
+ return makeQuotaBar(props.account.quota_daily_used ?? 0, limit, 'quota_daily_start')
+})
+
+const quotaWeeklyBar = computed((): QuotaBarInfo | null => {
+ const limit = props.account.quota_weekly_limit ?? 0
+ if (limit <= 0) return null
+ return makeQuotaBar(props.account.quota_weekly_used ?? 0, limit, 'quota_weekly_start')
+})
+
+const quotaTotalBar = computed((): QuotaBarInfo | null => {
+ const limit = props.account.quota_limit ?? 0
+ if (limit <= 0) return null
+ return makeQuotaBar(props.account.quota_used ?? 0, limit)
+})
+
onMounted(() => {
loadUsage()
})