feat: 完成API统计组件完整国际化支持

- 完成6个apistats组件的全面国际化改造
  * ModelUsageStats.vue - 模型使用统计
  * AggregatedStatsCard.vue - 聚合统计卡片
  * StatsOverview.vue - 统计概览
  * LimitConfig.vue - 限制配置
  * TokenDistribution.vue - Token使用分布
  * ApiKeyInput.vue - API Key输入组件

- 扩展三语言翻译支持(zh-cn/zh-tw/en)
  * 新增100+专业翻译键涵盖所有UI文字
  * 台湾本地化的繁体中文翻译
  * 技术专业的英文术语翻译
  * 支持参数化翻译处理动态内容

- 技术优化
  * 统一使用Vue 3 Composition API的useI18n()模式
  * 智能日期格式国际化处理
  * 完全消除硬编码中文文字
  * 支持条件性翻译和动态时间段显示

现在整个API统计功能模块支持完整的多语言切换体验
This commit is contained in:
Wangnov
2025-09-08 19:21:41 +08:00
parent c7e1a3429d
commit 4aae4aaec0
9 changed files with 505 additions and 105 deletions

View File

@@ -4,9 +4,9 @@
<div class="wide-card-title mb-6">
<h2 class="mb-2 text-2xl font-bold text-gray-900 dark:text-gray-200">
<i class="fas fa-chart-line mr-3" />
使用统计查询
{{ t('apiStats.usageStatsQuery') }}
</h2>
<p class="text-base text-gray-600 dark:text-gray-400">查询您的 API Key 使用情况和统计数据</p>
<p class="text-base text-gray-600 dark:text-gray-400">{{ t('apiStats.apiKeyDescription') }}</p>
</div>
<!-- 输入区域 -->
@@ -16,7 +16,7 @@
<!-- API Key 标签 -->
<label class="text-sm font-medium text-gray-700 dark:text-gray-300">
<i class="fas fa-key mr-2" />
{{ multiKeyMode ? '输入您的 API Keys每行一个或用逗号分隔' : '输入您的 API Key' }}
{{ multiKeyMode ? t('apiStats.enterApiKeys') : t('apiStats.enterApiKey') }}
</label>
<!-- 模式切换和查询按钮组 -->
@@ -28,20 +28,20 @@
<button
class="mode-switch-btn"
:class="{ active: !multiKeyMode }"
title="单一模式"
:title="t('apiStats.singleModeTitle')"
@click="multiKeyMode = false"
>
<i class="fas fa-key" />
<span class="ml-2 hidden sm:inline">单一</span>
<span class="ml-2 hidden sm:inline">{{ t('apiStats.singleMode') }}</span>
</button>
<button
class="mode-switch-btn"
:class="{ active: multiKeyMode }"
title="聚合模式"
:title="t('apiStats.aggregateModeTitle')"
@click="multiKeyMode = true"
>
<i class="fas fa-layer-group" />
<span class="ml-2 hidden sm:inline">聚合</span>
<span class="ml-2 hidden sm:inline">{{ t('apiStats.aggregateMode') }}</span>
<span
v-if="multiKeyMode && parsedApiKeys.length > 0"
class="ml-1 rounded-full bg-white/20 px-1.5 py-0.5 text-xs font-semibold"
@@ -62,7 +62,7 @@
v-model="apiKey"
class="wide-card-input w-full"
:disabled="loading"
placeholder="请输入您的 API Key (cr_...)"
:placeholder="t('apiStats.apiKeyPlaceholder')"
type="password"
@keyup.enter="queryStats"
/>
@@ -73,14 +73,14 @@
v-model="apiKey"
class="wide-card-input w-full resize-y"
:disabled="loading"
placeholder="请输入您的 API Keys支持以下格式&#10;cr_xxx&#10;cr_yyy&#10;或&#10;cr_xxx, cr_yyy"
:placeholder="t('apiStats.apiKeysPlaceholder')"
rows="4"
@keyup.ctrl.enter="queryStats"
/>
<button
v-if="apiKey && !loading"
class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300"
title="清空输入"
:title="t('apiStats.clearInput')"
@click="clearInput"
>
<i class="fas fa-times-circle" />
@@ -97,7 +97,7 @@
>
<i v-if="loading" class="fas fa-spinner loading-spinner" />
<i v-else class="fas fa-search" />
{{ loading ? '查询中...' : '查询统计' }}
{{ loading ? t('common.loading') : t('apiStats.queryButton') }}
</button>
</div>
</div>
@@ -105,11 +105,7 @@
<!-- 安全提示 -->
<div class="security-notice mt-4">
<i class="fas fa-shield-alt mr-2" />
{{
multiKeyMode
? '您的 API Keys 仅用于查询统计数据,不会被存储。聚合模式下部分个体化信息将不显示。'
: '您的 API Key 仅用于查询自己的统计数据,不会被存储或用于其他用途'
}}
{{ multiKeyMode ? t('apiStats.securityNoticeMulti') : t('apiStats.securityNoticeSingle') }}
</div>
<!-- Key 模式额外提示 -->
@@ -118,7 +114,7 @@
class="mt-2 rounded-lg bg-blue-50 p-3 text-sm text-blue-700 dark:bg-blue-900/20 dark:text-blue-400"
>
<i class="fas fa-lightbulb mr-2" />
<span>提示最多支持同时查询 30 API Keys使用 Ctrl+Enter 快速查询</span>
<span>{{ t('apiStats.multiKeyTip') }}</span>
</div>
</div>
</div>
@@ -127,8 +123,11 @@
<script setup>
import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useI18n } from 'vue-i18n'
import { useApiStatsStore } from '@/stores/apistats'
const { t } = useI18n()
const apiStatsStore = useApiStatsStore()
const { apiKey, loading, multiKeyMode } = storeToRefs(apiStatsStore)
const { queryStats, clearInput } = apiStatsStore