From f6f8069ce4673ae7027c6ba248daa18c8b602218 Mon Sep 17 00:00:00 2001 From: vin <49336820+Draculabo@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:03:27 +0800 Subject: [PATCH] feat: add cloud reset time UI (#56) * feat: show quota reset time on cloud account card * chore: ignore changelog file in prettier * style: format account card --- .prettierignore | 1 + src/components/AccountCard.tsx | 10 ++-- src/components/CloudAccountCard.tsx | 86 ++++++++++++++++++++++++++--- src/components/CloudAccountList.tsx | 2 +- src/localization/i18n.ts | 18 ++++-- 5 files changed, 98 insertions(+), 19 deletions(-) diff --git a/.prettierignore b/.prettierignore index ecb267b..891bba6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ /coverage /.vite README.md +CHANGELOG.md /src/routeTree.gen.ts .agents/ openspec/ diff --git a/src/components/AccountCard.tsx b/src/components/AccountCard.tsx index 5520717..b87f172 100644 --- a/src/components/AccountCard.tsx +++ b/src/components/AccountCard.tsx @@ -40,11 +40,11 @@ export const AccountCard: React.FC = ({ const initials = account.name ? account.name - .split(' ') - .map((n) => n[0]) - .join('') - .toUpperCase() - .slice(0, 2) + .split(' ') + .map((n) => n[0]) + .join('') + .toUpperCase() + .slice(0, 2) : account.email[0].toUpperCase(); // 处理鼠标移动,计算 3D 旋转角度 diff --git a/src/components/CloudAccountCard.tsx b/src/components/CloudAccountCard.tsx index 665a300..4473e22 100644 --- a/src/components/CloudAccountCard.tsx +++ b/src/components/CloudAccountCard.tsx @@ -19,7 +19,7 @@ import { import { Checkbox } from '@/components/ui/checkbox'; import { MoreVertical, Trash, RefreshCw, Box, Power } from 'lucide-react'; -import { formatDistanceToNow } from 'date-fns'; +import { formatDistanceToNow, differenceInMinutes, differenceInHours, isBefore } from 'date-fns'; import { Badge } from '@/components/ui/badge'; import { useTranslation } from 'react-i18next'; @@ -50,11 +50,64 @@ export function CloudAccountCard({ // Helpers to get quota color const getQuotaColor = (percentage: number) => { - if (percentage > 80) return 'text-green-500'; - if (percentage > 20) return 'text-yellow-500'; + if (percentage > 80) { + return 'text-green-500'; + } + if (percentage > 20) { + return 'text-yellow-500'; + } return 'text-red-500'; }; + const formatTimeRemaining = (dateStr: string) => { + const targetDate = new Date(dateStr); + if (Number.isNaN(targetDate.getTime())) { + return null; + } + + const now = new Date(); + if (isBefore(targetDate, now)) { + return '0h 0m'; + } + + // Calculate difference in hours and minutes + const diffHrs = differenceInHours(targetDate, now); + const diffMins = differenceInMinutes(targetDate, now) - diffHrs * 60; + if (diffHrs >= 24) { + const diffDays = Math.floor(diffHrs / 24); + const remainingHrs = diffHrs % 24; + return `${diffDays}d ${remainingHrs}h`; + } + + return `${diffHrs}h ${diffMins}m`; + }; + + const getResetTimeLabel = (resetTime?: string) => { + if (!resetTime) { + return t('cloud.card.resetUnknown'); + } + + const remaining = formatTimeRemaining(resetTime); + if (!remaining) { + return t('cloud.card.resetUnknown'); + } + + return `${t('cloud.card.resetPrefix')}: ${remaining}`; + }; + + const getResetTimeTitle = (resetTime?: string) => { + if (!resetTime) { + return undefined; + } + + const resetDate = new Date(resetTime); + if (Number.isNaN(resetDate.getTime())) { + return undefined; + } + + return `${t('cloud.card.resetTime')}: ${resetDate.toLocaleString()}`; + }; + const modelQuotas = Object.entries(account.quota?.models || {}); return ( @@ -169,15 +222,30 @@ export function CloudAccountCard({
{modelQuotas.length > 0 ? ( modelQuotas.map(([modelName, info]) => ( -
- +
+ {modelName.replace('models/', '')} -
- - {info.percentage}% +
+ + {getResetTimeLabel(info.resetTime)} - {t('cloud.card.left')} +
+ + {info.percentage}% + + + {t('cloud.card.left')} + +
)) diff --git a/src/components/CloudAccountList.tsx b/src/components/CloudAccountList.tsx index 6673a6e..c9c26c6 100644 --- a/src/components/CloudAccountList.tsx +++ b/src/components/CloudAccountList.tsx @@ -394,7 +394,7 @@ export function CloudAccountList() {
-
+
{accounts?.map((account) => (