From 6bc2189e6f27095a22d72982903ba260d948cd06 Mon Sep 17 00:00:00 2001 From: Zyy Date: Thu, 10 Sep 2026 15:33:43 +0800 Subject: [PATCH] refactor(frontend): streamline quota reset dialog and spacing Show remaining usage limits and an always-visible reset credit list with per-credit reset actions. Use backend-provided credit titles and quota window labels while preserving confirmation and ambiguous-result recovery. Display credit expiration in UTC+8 without a timezone suffix. Balance modal title and reset section spacing, and remove inline baseline whitespace from account quota summary cells without changing row heights or the borderless design. Validation: browser layout and quota popover interaction checks, expiration timezone checks, frontend typecheck, targeted ESLint, and diff whitespace checks passed. Co-authored-by: Codex --- .../src/components/base/BaseModal/index.vue | 2 +- .../AccountQuotaPanel/ResetCredits.vue | 196 +++++++++--------- .../AccountQuotaPanel/UsageLimits.vue | 72 +++++++ .../components/AccountQuotaPanel/index.vue | 2 +- .../AccountQuotaSummaryCell/index.vue | 2 +- 5 files changed, 170 insertions(+), 104 deletions(-) create mode 100644 frontend/src/views/accounts/components/AccountQuotaPanel/UsageLimits.vue diff --git a/frontend/src/components/base/BaseModal/index.vue b/frontend/src/components/base/BaseModal/index.vue index 3491b9435..f90dd44ab 100644 --- a/frontend/src/components/base/BaseModal/index.vue +++ b/frontend/src/components/base/BaseModal/index.vue @@ -239,7 +239,7 @@ onBeforeUnmount(() => {
-

+

{{ title }}

-import type { Account } from '@/api' +import type { Account, AccountResetCredit } from '@/api' import { AlertTriangle, RefreshCw, TicketCheck } from '@lucide/vue' import dayjs from 'dayjs' -import { computed, shallowRef, useId, watch } from 'vue' +import utc from 'dayjs/plugin/utc' +import { computed, shallowRef, watch } from 'vue' import BaseButton from '@/components/base/BaseButton.vue' import BaseEmpty from '@/components/base/BaseEmpty.vue' import BaseIconButton from '@/components/base/BaseIconButton.vue' import BaseModal from '@/components/base/BaseModal/index.vue' -import BaseRadio from '@/components/base/BaseRadio.vue' import { useAccountResetCredits } from '../../composables/useAccountResetCredits' +import UsageLimits from './UsageLimits.vue' const props = defineProps<{ - accountId: string + account: Account }>() const emit = defineEmits<{ accountUpdated: [account: Account] }>() +dayjs.extend(utc) + const { availableCredits, availableCount, - selectedCreditId, consumptionCredit, canRequestConsume, hasSnapshot, @@ -37,18 +39,16 @@ const { cancelConsume, confirmConsume, } = useAccountResetCredits({ - accountId: () => props.accountId, + accountId: () => props.account.id, onAccountUpdated: account => emit('accountUpdated', account), }) const panelOpen = shallowRef(false) -const creditRadioName = `account-reset-credit-${useId()}` const modalTitle = computed(() => { if (!showConfirm.value) - return '主动重置额度' + return '额度重置' return ambiguous.value ? '确认上次重置' : '确认重置额度' }) -const modalDescription = computed(() => (showConfirm.value ? undefined : '选择一张重置卡后继续')) const triggerLabel = computed(() => { if (ambiguous.value) return '查看主动重置卡,有一项操作待确认' @@ -60,7 +60,17 @@ const triggerLabel = computed(() => { return hasSnapshot.value ? `查看主动重置卡,最近查询 ${availableCount.value} 张可用` : '查看主动重置卡' }) const showTriggerCount = computed(() => hasSnapshot.value && availableCount.value > 0) -const confirmCreditTitle = computed(() => consumptionCredit.value?.title || 'Codex 主动重置卡') +const confirmCreditTitle = computed(() => creditTitle(consumptionCredit.value)) +const creditItems = computed(() => availableCredits.value.map(credit => ({ + id: credit.id, + title: creditTitle(credit), + expiry: expiryLabel(credit.expiresAt), +}))) +const countLabel = computed(() => { + if (!hasSnapshot.value) + return loading.value ? '查询中' : '待查询' + return `可用 ${availableCount.value} 次` +}) watch(panelOpen, (isOpen) => { if (isOpen) { @@ -75,25 +85,18 @@ function expiryLabel(value: string | null) { if (!value) return '有效期由上游决定' const expiry = dayjs(value) - return expiry.isValid() ? `${expiry.format('YYYY-MM-DD HH:mm')} 到期` : '到期时间未知' + return expiry.isValid() ? `将于 ${expiry.utcOffset(8).format('YYYY-MM-DD HH:mm')} 到期` : '到期时间未知' } -function creditOptionClasses(creditId: string) { - return [ - 'w-full min-w-0 rounded-cp px-4 py-3 outline-none transition-colors duration-150 motion-reduce:transition-none', - selectedCreditId.value === creditId - ? 'bg-cp-control-item-bg-active' - : 'bg-cp-fill-quaternary hover:bg-cp-bg-text-hover', - ] +function creditTitle(credit: AccountResetCredit | undefined) { + return credit?.title?.trim() || '用量重置' } -function creditOptionLabel(credit: { title: string | null, expiresAt: string | null }) { - return `${credit.title || 'Codex 主动重置卡'},${expiryLabel(credit.expiresAt)}` -} - -async function handleConfirmConsume() { - if (await confirmConsume()) - panelOpen.value = false +function handleRequestConsume(creditId: string) { + if (loading.value || consuming.value || ambiguous.value) + return + selectCredit(creditId) + requestConsume() } @@ -116,9 +119,8 @@ async function handleConfirmConsume() {

@@ -139,43 +141,35 @@ async function handleConfirmConsume() {
+ +
-
+

上次操作结果待确认

- 再确认一次即可。 + 请继续确认上次重置结果。

+ + 继续确认 +
-
- - - -
-

- 可用重置卡 -

-

- 每次操作消费一张 -

-
- - {{ availableCount }} - 张 - -
- -
-
-

- 选择重置卡 +
+
+

+ 使用限额重置

+ + {{ countLabel }} +
-

- {{ loadError }},请刷新重试。 -

- -
- +

- - - {{ credit.title || 'Codex 主动重置卡' }} - - - {{ expiryLabel(credit.expiresAt) }} - - - -

+ {{ loadError }},请刷新重试。 +

+

+ 正在查询可用重置次数… +

+
    +
  • +
    +

    + {{ credit.title }} +

    +

    + {{ credit.expiry }} +

    +
    + + 使用重置 + +
  • +
-

- diff --git a/frontend/src/views/accounts/components/AccountQuotaPanel/UsageLimits.vue b/frontend/src/views/accounts/components/AccountQuotaPanel/UsageLimits.vue new file mode 100644 index 000000000..bbbb4dd85 --- /dev/null +++ b/frontend/src/views/accounts/components/AccountQuotaPanel/UsageLimits.vue @@ -0,0 +1,72 @@ + + + diff --git a/frontend/src/views/accounts/components/AccountQuotaPanel/index.vue b/frontend/src/views/accounts/components/AccountQuotaPanel/index.vue index cb21a1f7a..792b20eef 100644 --- a/frontend/src/views/accounts/components/AccountQuotaPanel/index.vue +++ b/frontend/src/views/accounts/components/AccountQuotaPanel/index.vue @@ -58,7 +58,7 @@ const profileOpen = shallowRef(false) Math.max(summaryEntries.value.length
-
+