From a66f771cb1626720f4253affc879913144fca3c4 Mon Sep 17 00:00:00 2001 From: benjamin Date: Mon, 18 May 2026 21:09:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E4=BF=AE=E6=AD=A3=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=97=A5=E5=8D=A1=E9=A2=9D=E5=BA=A6=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- frontend/src/views/user/SubscriptionsView.vue | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/frontend/src/views/user/SubscriptionsView.vue b/frontend/src/views/user/SubscriptionsView.vue index 154682b7..31d63d0d 100644 --- a/frontend/src/views/user/SubscriptionsView.vue +++ b/frontend/src/views/user/SubscriptionsView.vue @@ -127,11 +127,7 @@ v-if="subscription.daily_window_start" class="text-xs text-gray-500 dark:text-dark-400" > - {{ - t('userSubscriptions.resetIn', { - time: formatResetTime(subscription.daily_window_start, 24) - }) - }} + {{ formatDailyUsageWindow(subscription) }}

@@ -256,6 +252,7 @@ import AppLayout from '@/components/layout/AppLayout.vue' import Icon from '@/components/icons/Icon.vue' import { formatDateOnly } from '@/utils/format' import { platformBorderClass, platformBadgeClass, platformButtonClass, platformLabel } from '@/utils/platformColors' +import { getRemainingDurationParts, isOneTimeDailyQuota, type RemainingDurationParts } from '@/utils/subscriptionQuota' function platformAccentDotClass(p: string): string { switch (p) { @@ -334,30 +331,38 @@ function getExpirationClass(expiresAt: string): string { return 'text-gray-700 dark:text-gray-300' } +function formatDurationParts(parts: RemainingDurationParts): string { + if (parts.days > 0) { + return `${parts.days}d ${parts.hours}h` + } + + if (parts.hours > 0) { + return `${parts.hours}h ${parts.minutes}m` + } + + return `${parts.minutes}m` +} + +function formatDailyUsageWindow(subscription: UserSubscription): string { + if (isOneTimeDailyQuota(subscription) && subscription.expires_at) { + const parts = getRemainingDurationParts(subscription.expires_at) + if (!parts) return t('userSubscriptions.windowNotActive') + return t('userSubscriptions.quotaEndsIn', { time: formatDurationParts(parts) }) + } + + return t('userSubscriptions.resetIn', { + time: formatResetTime(subscription.daily_window_start, 24) + }) +} + function formatResetTime(windowStart: string | null, windowHours: number): string { if (!windowStart) return t('userSubscriptions.windowNotActive') const start = new Date(windowStart) const end = new Date(start.getTime() + windowHours * 60 * 60 * 1000) - const now = new Date() - const diff = end.getTime() - now.getTime() + const parts = getRemainingDurationParts(end) - if (diff <= 0) return t('userSubscriptions.windowNotActive') - - const hours = Math.floor(diff / (1000 * 60 * 60)) - const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) - - if (hours > 24) { - const days = Math.floor(hours / 24) - const remainingHours = hours % 24 - return `${days}d ${remainingHours}h` - } - - if (hours > 0) { - return `${hours}h ${minutes}m` - } - - return `${minutes}m` + return parts ? formatDurationParts(parts) : t('userSubscriptions.windowNotActive') } onMounted(() => {