diff --git a/web/src/features/dashboard/components/dashboard-search-dialog.tsx b/web/src/features/dashboard/components/dashboard-search-dialog.tsx index f5b6b8336..9737ea616 100644 --- a/web/src/features/dashboard/components/dashboard-search-dialog.tsx +++ b/web/src/features/dashboard/components/dashboard-search-dialog.tsx @@ -4,6 +4,7 @@ import { format } from 'date-fns' import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { CalendarIcon, Search, RotateCcw } from 'lucide-react' +import { useTranslation } from 'react-i18next' import { getStoredUser } from '@/lib/auth' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' @@ -38,19 +39,6 @@ import { } from '@/components/ui/select' import type { DashboardFilters } from '../hooks/use-dashboard-data' -const searchSchema = z - .object({ - startDate: z.date(), - endDate: z.date(), - username: z.string().optional(), - timeGranularity: z.enum(['hour', 'day', 'week']), - modelFilter: z.string().optional(), - }) - .refine((data) => data.endDate >= data.startDate, { - message: 'End date must be after start date', - path: ['endDate'], - }) - interface DashboardSearchDialogProps { open: boolean onOpenChange: (open: boolean) => void @@ -64,10 +52,24 @@ export function DashboardSearchDialog({ onSearch, currentFilters, }: DashboardSearchDialogProps) { + const { t } = useTranslation() const [loading, setLoading] = useState(false) const user = getStoredUser() const isAdmin = user && (user as any).role >= 10 + const searchSchema = z + .object({ + startDate: z.date(), + endDate: z.date(), + username: z.string().optional(), + timeGranularity: z.enum(['hour', 'day', 'week']), + modelFilter: z.string().optional(), + }) + .refine((data) => data.endDate >= data.startDate, { + message: t('dashboard.search.end_date_after_start'), + path: ['endDate'], + }) + const form = useForm>({ resolver: zodResolver(searchSchema), defaultValues: { @@ -123,9 +125,9 @@ export function DashboardSearchDialog({ - Advanced Dashboard Search + {t('dashboard.search.title')} - Search and filter your usage data with advanced criteria + {t('dashboard.search.description')} @@ -142,7 +144,7 @@ export function DashboardSearchDialog({ size='sm' onClick={() => handleQuickTimeRange(1)} > - Last 24h + {t('dashboard.search.last_24h')} @@ -177,7 +179,7 @@ export function DashboardSearchDialog({ name='startDate' render={({ field }) => ( - Start Date + {t('dashboard.search.start_date')} @@ -191,7 +193,7 @@ export function DashboardSearchDialog({ {field.value ? ( format(field.value, 'PPP') ) : ( - Pick a date + {t('dashboard.search.pick_date')} )} @@ -219,7 +221,7 @@ export function DashboardSearchDialog({ name='endDate' render={({ field }) => ( - End Date + {t('dashboard.search.end_date')} @@ -233,7 +235,7 @@ export function DashboardSearchDialog({ {field.value ? ( format(field.value, 'PPP') ) : ( - Pick a date + {t('dashboard.search.pick_date')} )} @@ -263,20 +265,32 @@ export function DashboardSearchDialog({ name='timeGranularity' render={({ field }) => ( - Time Granularity + + {t('dashboard.search.time_granularity')} + @@ -291,10 +305,12 @@ export function DashboardSearchDialog({ name='username' render={({ field }) => ( - Filter by Username (Admin) + + {t('dashboard.search.filter_by_username')} + @@ -310,10 +326,12 @@ export function DashboardSearchDialog({ name='modelFilter' render={({ field }) => ( - Model Filter + {t('dashboard.search.model_filter')} @@ -331,22 +349,14 @@ export function DashboardSearchDialog({ disabled={loading} > - Reset + {t('dashboard.search.reset')} + + -
- - -
diff --git a/web/src/features/dashboard/components/model-monitoring-stats.tsx b/web/src/features/dashboard/components/model-monitoring-stats.tsx index 5ffc86514..704c057e2 100644 --- a/web/src/features/dashboard/components/model-monitoring-stats.tsx +++ b/web/src/features/dashboard/components/model-monitoring-stats.tsx @@ -1,5 +1,6 @@ import type { ModelMonitoringStats } from '@/types/api' import { Activity, BarChart3, CheckCircle, Zap } from 'lucide-react' +import { useTranslation } from 'react-i18next' import { formatNumber } from '@/lib/formatters' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' @@ -15,32 +16,38 @@ export function ModelMonitoringStats({ loading, error, }: ModelMonitoringStatsProps) { + const { t } = useTranslation() const cards = [ { - title: '模型总数', + title: t('dashboard.monitoring.total_models'), value: stats.total_models.toString(), - description: '系统中的模型总数量', + description: t('dashboard.monitoring.total_models_desc'), icon: , trend: null, }, { - title: '活跃模型', + title: t('dashboard.monitoring.active_models'), value: stats.active_models.toString(), - description: `${stats.total_models > 0 ? ((stats.active_models / stats.total_models) * 100).toFixed(1) : 0}% 的模型有调用`, + description: t('dashboard.monitoring.active_models_desc', { + percentage: + stats.total_models > 0 + ? ((stats.active_models / stats.total_models) * 100).toFixed(1) + : 0, + }), icon: , trend: null, }, { - title: '调用总次数', + title: t('dashboard.monitoring.total_requests'), value: formatNumber(stats.total_requests), - description: '所有模型的调用总数', + description: t('dashboard.monitoring.total_requests_desc'), icon: , trend: null, }, { - title: '平均成功率', + title: t('dashboard.monitoring.avg_success_rate'), value: `${stats.avg_success_rate.toFixed(1)}%`, - description: '所有模型的平均成功率', + description: t('dashboard.monitoring.avg_success_rate_desc'), icon: , trend: null, }, @@ -77,7 +84,9 @@ export function ModelMonitoringStats({ {card.icon} -
Error
+
+ {t('common.error')} +

{error}

diff --git a/web/src/features/dashboard/components/model-monitoring-table.tsx b/web/src/features/dashboard/components/model-monitoring-table.tsx index 370584f5e..2c88b0597 100644 --- a/web/src/features/dashboard/components/model-monitoring-table.tsx +++ b/web/src/features/dashboard/components/model-monitoring-table.tsx @@ -9,6 +9,7 @@ import { AlertCircle, CheckCircle, } from 'lucide-react' +import { useTranslation } from 'react-i18next' import { stringToColor } from '@/lib/colors' import { formatQuota, formatNumber, formatTokens } from '@/lib/formatters' import { Badge } from '@/components/ui/badge' @@ -61,6 +62,7 @@ export function ModelMonitoringTable({ onBusinessGroupChange, onRefresh, }: ModelMonitoringTableProps) { + const { t } = useTranslation() const [currentPage, setCurrentPage] = useState(1) // 分页逻辑 @@ -94,7 +96,7 @@ export function ModelMonitoringTable({ return ( - 模型列表 + {t('dashboard.monitoring.model_list')}
@@ -120,16 +122,18 @@ export function ModelMonitoringTable({ return ( - 模型列表 + {t('dashboard.monitoring.model_list')}
-

加载失败

+

+ {t('dashboard.monitoring.load_failed')} +

{error}

@@ -141,12 +145,12 @@ export function ModelMonitoringTable({
- 模型列表 + {t('dashboard.monitoring.model_list')}
onSearchChange(e.target.value)} className='w-64' @@ -154,10 +158,14 @@ export function ModelMonitoringTable({