From 2e4be9bd77733a79bc678de962552c13b171111e Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Sat, 7 Mar 2026 21:32:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=20WebUI=20=E9=A6=96=E9=A1=B5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard/src/i18n/locales/en.json | 91 +++++++++++++++++ dashboard/src/i18n/locales/ja.json | 91 +++++++++++++++++ dashboard/src/i18n/locales/ko.json | 91 +++++++++++++++++ dashboard/src/i18n/locales/zh.json | 91 +++++++++++++++++ dashboard/src/routes/index.tsx | 150 +++++++++++++++-------------- 5 files changed, 440 insertions(+), 74 deletions(-) diff --git a/dashboard/src/i18n/locales/en.json b/dashboard/src/i18n/locales/en.json index 869b9994..94fd372f 100644 --- a/dashboard/src/i18n/locales/en.json +++ b/dashboard/src/i18n/locales/en.json @@ -473,5 +473,96 @@ "sidebarNav": "Main navigation", "closeMenu": "Close menu", "navigatedTo": "Navigated to {{page}}" + }, + "home": { + "title": "Live Monitor", + "subtitle": "MaiBot runtime status and statistics overview", + "loading": "Loading statistics...", + "loadingHint": "Fetching MaiBot runtime data", + "timeRange": { + "24h": "24 Hours", + "7d": "7 Days", + "30d": "30 Days" + }, + "autoRefresh": "Auto Refresh", + "botStatus": { + "title": "MaiBot Status", + "running": "Running", + "stopped": "Stopped", + "uptime": "Up {{time}}" + }, + "quickActions": { + "title": "Quick Actions", + "restart": "Restart MaiBot", + "restarting": "Restarting...", + "expressionReview": "Expression Review", + "viewLogs": "View Logs", + "pluginManage": "Plugins", + "systemSettings": "Settings" + }, + "survey": { + "title": "Feedback Survey", + "description": "Help us improve the experience", + "webui": "WebUI Feedback", + "maibot": "MaiBot Feedback" + }, + "stats": { + "totalRequests": "Total Requests", + "totalCost": "Total Cost", + "tokenUsage": "Token Usage", + "avgResponse": "Avg Response", + "avgResponseDesc": "Avg API latency", + "onlineTime": "Online Time", + "messageProcessing": "Messages", + "costEfficiency": "Cost Efficiency", + "recentPeriod": "Last {{range}}", + "perHour": "{{value}}/hr", + "noData": "No data", + "replied": "{{num}} replies", + "per100Messages": "Per 100 messages", + "seconds": "sec", + "hours": "hours", + "days": "days" + }, + "charts": { + "tabs": { + "trends": "Trends", + "models": "Models", + "activity": "Activity", + "daily": "Daily" + }, + "requestTrend": "Request Trend", + "requestTrendDesc": "Request volume over the last {{hours}} hours", + "costTrend": "Cost Trend", + "costTrendDesc": "API call cost over time", + "tokenUsage": "Token Usage", + "tokenUsageDesc": "Token consumption over time", + "modelDistribution": "Model Request Distribution", + "modelDistributionDesc": "Usage share per model ({{count}} models)", + "modelDetails": "Model Details", + "modelDetailsDesc": "Requests, cost and performance", + "recentActivity": "Recent Activity", + "recentActivityDesc": "Latest API call records", + "dailyStats": "Daily Statistics", + "dailyStatsDesc": "Data summary for the last 7 days", + "requests": "Requests", + "cost": "Cost (¥)", + "requestCount": "Requests", + "costLabel": "Cost", + "avgTime": "Avg Time", + "timeCost": "Duration", + "status": "Status" + }, + "time": { + "hoursMinutes": "{{hours}}h {{minutes}}m" + }, + "hitokotoFallback": "Life is like a box of chocolates, you never know what you're gonna get.", + "hitokotoFallbackFrom": "Forrest Gump", + "unknownSource": "Unknown", + "ariaLabel": { + "requestTrend": "Hourly request trend chart showing request count changes over recent hours", + "costTrend": "API cost trend chart showing API call cost changes over recent hours", + "tokenUsage": "Token usage trend chart showing token consumption over recent hours" + } } } diff --git a/dashboard/src/i18n/locales/ja.json b/dashboard/src/i18n/locales/ja.json index 924b1385..9dc70330 100644 --- a/dashboard/src/i18n/locales/ja.json +++ b/dashboard/src/i18n/locales/ja.json @@ -473,5 +473,96 @@ "sidebarNav": "メインナビゲーション", "closeMenu": "メニューを閉じる", "navigatedTo": "{{page}} に移動しました" + }, + "home": { + "title": "リアルタイムモニター", + "subtitle": "MaiBotの稼働状況と統計データの一覧", + "loading": "統計データを読み込み中...", + "loadingHint": "MaiBotの稼働データを取得しています", + "timeRange": { + "24h": "24時間", + "7d": "7日間", + "30d": "30日間" + }, + "autoRefresh": "自動更新", + "botStatus": { + "title": "MaiBot ステータス", + "running": "稼働中", + "stopped": "停止中", + "uptime": "稼働 {{time}}" + }, + "quickActions": { + "title": "クイック操作", + "restart": "MaiBotを再起動", + "restarting": "再起動中...", + "expressionReview": "表現レビュー", + "viewLogs": "ログを見る", + "pluginManage": "プラグイン管理", + "systemSettings": "システム設定" + }, + "survey": { + "title": "フィードバック", + "description": "製品体験の改善にご協力ください", + "webui": "WebUI フィードバック", + "maibot": "MaiBot フィードバック" + }, + "stats": { + "totalRequests": "総リクエスト数", + "totalCost": "総コスト", + "tokenUsage": "トークン消費", + "avgResponse": "平均応答", + "avgResponseDesc": "API平均レイテンシ", + "onlineTime": "オンライン時間", + "messageProcessing": "メッセージ処理", + "costEfficiency": "コスト効率", + "recentPeriod": "直近{{range}}", + "perHour": "{{value}}/時", + "noData": "データなし", + "replied": "返信 {{num}} 件", + "per100Messages": "100メッセージあたり", + "seconds": "秒", + "hours": "時間", + "days": "日" + }, + "charts": { + "tabs": { + "trends": "トレンド", + "models": "モデル", + "activity": "アクティビティ", + "daily": "日次統計" + }, + "requestTrend": "リクエストトレンド", + "requestTrendDesc": "直近{{hours}}時間のリクエスト量の変化", + "costTrend": "コストトレンド", + "costTrendDesc": "API呼び出しコストの変化", + "tokenUsage": "トークン消費", + "tokenUsageDesc": "トークン使用量の変化", + "modelDistribution": "モデルリクエスト分布", + "modelDistributionDesc": "各モデルの使用割合({{count}}モデル)", + "modelDetails": "モデル詳細統計", + "modelDetailsDesc": "リクエスト数、コスト、パフォーマンス", + "recentActivity": "最近のアクティビティ", + "recentActivityDesc": "最新のAPI呼び出し記録", + "dailyStats": "日次統計", + "dailyStatsDesc": "直近7日間のデータサマリー", + "requests": "リクエスト数", + "cost": "コスト(¥)", + "requestCount": "リクエスト数", + "costLabel": "コスト", + "avgTime": "平均所要時間", + "timeCost": "所要時間", + "status": "ステータス" + }, + "time": { + "hoursMinutes": "{{hours}}時間{{minutes}}分" + }, + "hitokotoFallback": "人生はチョコレートの箱のようなもの、次に何が出てくるか分からない。", + "hitokotoFallbackFrom": "フォレスト・ガンプ", + "unknownSource": "不明", + "ariaLabel": { + "requestTrend": "時間ごとのリクエスト数トレンドチャート、直近のリクエスト数変化を表示", + "costTrend": "APIコストトレンドチャート、直近のAPI呼び出しコスト変化を表示", + "tokenUsage": "Token消費トレンドチャート、直近のToken使用量変化を表示" + } } } diff --git a/dashboard/src/i18n/locales/ko.json b/dashboard/src/i18n/locales/ko.json index 0233cd57..1b8eb1b7 100644 --- a/dashboard/src/i18n/locales/ko.json +++ b/dashboard/src/i18n/locales/ko.json @@ -473,5 +473,96 @@ "sidebarNav": "메인 내비게이션", "closeMenu": "메뉴 닫기", "navigatedTo": "{{page}}으로 이동했습니다" + }, + "home": { + "title": "실시간 모니터", + "subtitle": "MaiBot 실행 상태 및 통계 데이터 개요", + "loading": "통계 데이터 로딩 중...", + "loadingHint": "MaiBot 실행 데이터를 가져오는 중", + "timeRange": { + "24h": "24시간", + "7d": "7일", + "30d": "30일" + }, + "autoRefresh": "자동 새로고침", + "botStatus": { + "title": "MaiBot 상태", + "running": "실행 중", + "stopped": "중지됨", + "uptime": "가동 {{time}}" + }, + "quickActions": { + "title": "빠른 작업", + "restart": "MaiBot 재시작", + "restarting": "재시작 중...", + "expressionReview": "표현 검토", + "viewLogs": "로그 보기", + "pluginManage": "플러그인 관리", + "systemSettings": "시스템 설정" + }, + "survey": { + "title": "피드백 설문", + "description": "제품 경험 개선에 도움을 주세요", + "webui": "WebUI 피드백", + "maibot": "MaiBot 피드백" + }, + "stats": { + "totalRequests": "총 요청 수", + "totalCost": "총 비용", + "tokenUsage": "토큰 소비", + "avgResponse": "평균 응답", + "avgResponseDesc": "API 평균 지연", + "onlineTime": "온라인 시간", + "messageProcessing": "메시지 처리", + "costEfficiency": "비용 효율", + "recentPeriod": "최근 {{range}}", + "perHour": "{{value}}/시간", + "noData": "데이터 없음", + "replied": "답장 {{num}}건", + "per100Messages": "100건당", + "seconds": "초", + "hours": "시간", + "days": "일" + }, + "charts": { + "tabs": { + "trends": "트렌드", + "models": "모델", + "activity": "활동", + "daily": "일간 통계" + }, + "requestTrend": "요청 트렌드", + "requestTrendDesc": "최근 {{hours}}시간의 요청량 변화", + "costTrend": "비용 트렌드", + "costTrendDesc": "API 호출 비용 변화", + "tokenUsage": "토큰 소비", + "tokenUsageDesc": "토큰 사용량 변화", + "modelDistribution": "모델 요청 분포", + "modelDistributionDesc": "모델별 사용 비율 ({{count}}개 모델)", + "modelDetails": "모델 상세 통계", + "modelDetailsDesc": "요청 수, 비용 및 성능", + "recentActivity": "최근 활동", + "recentActivityDesc": "최신 API 호출 기록", + "dailyStats": "일간 통계", + "dailyStatsDesc": "최근 7일 데이터 요약", + "requests": "요청 수", + "cost": "비용(¥)", + "requestCount": "요청 수", + "costLabel": "비용", + "avgTime": "평균 소요", + "timeCost": "소요 시간", + "status": "상태" + }, + "time": { + "hoursMinutes": "{{hours}}시간 {{minutes}}분" + }, + "hitokotoFallback": "인생은 초콜릿 상자와 같아서, 다음에 무엇이 나올지 모릅니다.", + "hitokotoFallbackFrom": "포레스트 검프", + "unknownSource": "알 수 없음", + "ariaLabel": { + "requestTrend": "시간별 요청 트렌드 차트, 최근 시간대별 요청 수 변화 표시", + "costTrend": "API 비용 트렌드 차트, 최근 시간대별 API 호출 비용 변화 표시", + "tokenUsage": "토큰 소비 트렌드 차트, 최근 시간대별 토큰 사용량 변화 표시" + } } } diff --git a/dashboard/src/i18n/locales/zh.json b/dashboard/src/i18n/locales/zh.json index e21e1ce6..caf8ff28 100644 --- a/dashboard/src/i18n/locales/zh.json +++ b/dashboard/src/i18n/locales/zh.json @@ -473,5 +473,96 @@ "sidebarNav": "主导航", "closeMenu": "关闭菜单", "navigatedTo": "已导航至 {{page}}" + }, + "home": { + "title": "实时监控面板", + "subtitle": "麦麦运行状态和统计数据一览", + "loading": "加载统计数据中...", + "loadingHint": "正在获取麦麦运行数据", + "timeRange": { + "24h": "24小时", + "7d": "7天", + "30d": "30天" + }, + "autoRefresh": "自动刷新", + "botStatus": { + "title": "麦麦状态", + "running": "运行中", + "stopped": "已停止", + "uptime": "运行 {{time}}" + }, + "quickActions": { + "title": "快速操作", + "restart": "重启麦麦", + "restarting": "重启中...", + "expressionReview": "表达审核", + "viewLogs": "查看日志", + "pluginManage": "插件管理", + "systemSettings": "系统设置" + }, + "survey": { + "title": "反馈问卷", + "description": "帮助我们改进产品体验", + "webui": "WebUI 反馈", + "maibot": "麦麦反馈" + }, + "stats": { + "totalRequests": "总请求数", + "totalCost": "总花费", + "tokenUsage": "Token消耗", + "avgResponse": "平均响应", + "avgResponseDesc": "API平均耗时", + "onlineTime": "在线时长", + "messageProcessing": "消息处理", + "costEfficiency": "成本效率", + "recentPeriod": "最近{{range}}", + "perHour": "{{value}}/小时", + "noData": "暂无数据", + "replied": "回复 {{num}} 条", + "per100Messages": "每100条消息", + "seconds": "秒", + "hours": "小时", + "days": "天" + }, + "charts": { + "tabs": { + "trends": "趋势", + "models": "模型", + "activity": "活动", + "daily": "日统计" + }, + "requestTrend": "请求趋势", + "requestTrendDesc": "最近{{hours}}小时的请求量变化", + "costTrend": "花费趋势", + "costTrendDesc": "API调用成本变化", + "tokenUsage": "Token消耗", + "tokenUsageDesc": "Token使用量变化", + "modelDistribution": "模型请求分布", + "modelDistributionDesc": "各模型使用占比 (共 {{count}} 个模型)", + "modelDetails": "模型详细统计", + "modelDetailsDesc": "请求数、花费和性能", + "recentActivity": "最近活动", + "recentActivityDesc": "最新的API调用记录", + "dailyStats": "每日统计", + "dailyStatsDesc": "最近7天的数据汇总", + "requests": "请求数", + "cost": "花费(¥)", + "requestCount": "请求数", + "costLabel": "花费", + "avgTime": "平均耗时", + "timeCost": "耗时", + "status": "状态" + }, + "time": { + "hoursMinutes": "{{hours}}小时{{minutes}}分钟" + }, + "hitokotoFallback": "人生就像一盒巧克力,你永远不知道下一颗是什么味道。", + "hitokotoFallbackFrom": "阿甘正传", + "unknownSource": "未知", + "ariaLabel": { + "requestTrend": "每小时请求量趋势图,显示最近若干小时的请求次数变化", + "costTrend": "API花费趋势图,显示最近若干小时的API调用成本变化", + "tokenUsage": "Token消耗趋势图,显示最近若干小时的Token使用量变化" + } } } diff --git a/dashboard/src/routes/index.tsx b/dashboard/src/routes/index.tsx index 326cfd29..30a88c3d 100644 --- a/dashboard/src/routes/index.tsx +++ b/dashboard/src/routes/index.tsx @@ -1,4 +1,5 @@ import { useEffect, useState, useCallback, useRef } from 'react' +import { useTranslation } from 'react-i18next' import axios from 'axios' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' @@ -129,6 +130,7 @@ const generatePieColors = (count: number): string[] => { // 内部实现组件 function IndexPageContent() { + const { t } = useTranslation() const [dashboardData, setDashboardData] = useState(null) const [loading, setLoading] = useState(true) const [loadingProgress, setLoadingProgress] = useState(0) @@ -179,15 +181,15 @@ function IndexPageContent() { if (isMountedRef.current) { setHitokoto({ hitokoto: response.data.hitokoto, - from: response.data.from || response.data.from_who || '未知' + from: response.data.from || response.data.from_who || t('home.unknownSource') }) } } catch (error) { console.error('获取一言失败:', error) if (isMountedRef.current) { setHitokoto({ - hitokoto: '人生就像一盒巧克力,你永远不知道下一颗是什么味道。', - from: '阿甘正传' + hitokoto: t('home.hitokotoFallback'), + from: t('home.hitokotoFallbackFrom') }) } } finally { @@ -195,7 +197,7 @@ function IndexPageContent() { setHitokotoLoading(false) } } - }, []) + }, [t]) // 获取机器人状态 const fetchBotStatus = useCallback(async () => { @@ -310,8 +312,8 @@ function IndexPageContent() {
-

加载统计数据中...

-

正在获取麦麦运行数据

+

{t('home.loading')}

+

{t('home.loadingHint')}

@@ -348,7 +350,7 @@ function IndexPageContent() { const formatTime = (seconds: number) => { const hours = Math.floor(seconds / 3600) const minutes = Math.floor((seconds % 3600) / 60) - return `${hours}小时${minutes}分钟` + return t('home.time.hoursMinutes', { hours, minutes }) } // 格式化大数字(自动选择合适单位) @@ -403,11 +405,11 @@ function IndexPageContent() { // 图表配置 const chartConfig = { requests: { - label: '请求数', + label: t('home.charts.requests'), color: 'hsl(var(--color-chart-1))', }, cost: { - label: '花费(¥)', + label: t('home.charts.cost'), color: 'hsl(var(--color-chart-2))', }, tokens: { @@ -422,17 +424,17 @@ function IndexPageContent() { {/* 标题和控制栏 */}
-

实时监控面板

+

{t('home.title')}

- 麦麦运行状态和统计数据一览 + {t('home.subtitle')}

setTimeRange(Number(v))}> - 24小时 - 7天 - 30天 + {t('home.timeRange.24h')} + {t('home.timeRange.7d')} + {t('home.timeRange.30d')}
@@ -573,10 +575,10 @@ function IndexPageContent() { - 反馈问卷 + {t('home.survey.title')} - 帮助我们改进产品体验 + {t('home.survey.description')} @@ -584,13 +586,13 @@ function IndexPageContent() {
@@ -602,7 +604,7 @@ function IndexPageContent() {
- 总请求数 + {t('home.stats.totalRequests')} @@ -613,14 +615,14 @@ function IndexPageContent() { )}

- 最近{timeRange < 48 ? timeRange + '小时' : Math.floor(timeRange / 24) + '天'} + {t('home.stats.recentPeriod', { range: timeRange < 48 ? timeRange + t('home.stats.hours') : Math.floor(timeRange / 24) + t('home.stats.days') })}

- 总花费 + {t('home.stats.totalCost')} @@ -631,14 +633,14 @@ function IndexPageContent() { )}

- {summary.cost_per_hour > 0 ? `¥${summary.cost_per_hour.toFixed(2)}/小时` : '暂无数据'} + {summary.cost_per_hour > 0 ? t('home.stats.perHour', { value: `¥${summary.cost_per_hour.toFixed(2)}` }) : t('home.stats.noData')}

- Token消耗 + {t('home.stats.tokenUsage')} @@ -650,20 +652,20 @@ function IndexPageContent() {

{summary.tokens_per_hour > 0 - ? `${formatNumber(summary.tokens_per_hour).display}/小时` - : '暂无数据'} + ? t('home.stats.perHour', { value: formatNumber(summary.tokens_per_hour).display }) + : t('home.stats.noData')}

- 平均响应 + {t('home.stats.avgResponse')}
{summary.avg_response_time.toFixed(2)}s
-

API平均耗时

+

{t('home.stats.avgResponseDesc')}

@@ -672,20 +674,20 @@ function IndexPageContent() {
- 在线时长 + {t('home.stats.onlineTime')}
{formatTime(summary.online_time)} - ({summary.online_time.toLocaleString()}秒) + ({summary.online_time.toLocaleString()}{t('home.stats.seconds')})
- 消息处理 + {t('home.stats.messageProcessing')} @@ -696,17 +698,17 @@ function IndexPageContent() { )}

- 回复 {formatNumber(summary.total_replies).display} + {t('home.stats.replied', { num: formatNumber(summary.total_replies).display })} {formatNumber(summary.total_replies).needsExact && ( ({formatNumber(summary.total_replies).exact}) - )} 条 + )}

- 成本效率 + {t('home.stats.costEfficiency')} @@ -715,7 +717,7 @@ function IndexPageContent() { ? `¥${((summary.total_cost / summary.total_messages) * 100).toFixed(2)}` : '¥0.00'} -

每100条消息

+

{t('home.stats.per100Messages')}

@@ -723,21 +725,21 @@ function IndexPageContent() { {/* 图表区域 */} - 趋势 - 模型 - 活动 - 日统计 + {t('home.charts.tabs.trends')} + {t('home.charts.tabs.models')} + {t('home.charts.tabs.activity')} + {t('home.charts.tabs.daily')} {/* 趋势图表 */} - 请求趋势 - 最近{timeRange}小时的请求量变化 + {t('home.charts.requestTrend')} + {t('home.charts.requestTrendDesc', { hours: timeRange })} - + @@ -769,11 +771,11 @@ function IndexPageContent() {
- 花费趋势 - API调用成本变化 + {t('home.charts.costTrend')} + {t('home.charts.costTrendDesc')} - + @@ -799,11 +801,11 @@ function IndexPageContent() { - Token消耗 - Token使用量变化 + {t('home.charts.tokenUsage')} + {t('home.charts.tokenUsageDesc')} - + @@ -834,8 +836,8 @@ function IndexPageContent() {
- 模型请求分布 - 各模型使用占比 (共 {model_stats.length} 个模型) + {t('home.charts.modelDistribution')} + {t('home.charts.modelDistributionDesc', { count: model_stats.length })} - 模型详细统计 - 请求数、花费和性能 + {t('home.charts.modelDetails')} + {t('home.charts.modelDetailsDesc')} @@ -902,13 +904,13 @@ function IndexPageContent() {
- 请求数: + {t('home.charts.requestCount')}: {stat.request_count.toLocaleString()}
- 花费: + {t('home.charts.costLabel')}: ¥{stat.total_cost.toFixed(2)}
@@ -918,7 +920,7 @@ function IndexPageContent() {
- 平均耗时: + {t('home.charts.avgTime')}: {stat.avg_response_time.toFixed(2)}s @@ -935,8 +937,8 @@ function IndexPageContent() { - 最近活动 - 最新的API调用记录 + {t('home.charts.recentActivity')} + {t('home.charts.recentActivityDesc')} @@ -963,15 +965,15 @@ function IndexPageContent() { {activity.tokens}
- 花费: + {t('home.charts.costLabel')}: ¥{activity.cost.toFixed(4)}
- 耗时: + {t('home.charts.timeCost')}: {activity.time_cost.toFixed(2)}s
- 状态: + {t('home.charts.status')}: @@ -991,18 +993,18 @@ function IndexPageContent() { - 每日统计 - 最近7天的数据汇总 + {t('home.charts.dailyStats')} + {t('home.charts.dailyStatsDesc')}