mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
feat: 完成UserUsageStatsModal和ChangeRoleModal组件国际化
- 添加用户使用统计模态框的完整国际化支持 * 时间选择器选项(最近24小时/7天/30天/90天) * 统计卡片(请求数/输入Token/输出Token/总费用) * API Keys表格表头和状态显示 * 使用趋势图表占位符和无数据状态 - 添加角色变更模态框的完整国际化支持 * 角色选择表单和描述文本 * 动态警告消息(授予/移除管理员权限) * 按钮状态和成功提示消息 - 更新三种语言文件(zh-cn/en/zh-tw)添加新的翻译键值 - 集成Vue I18n组合式API支持动态参数替换 - 保持响应式翻译和用户体验的一致性
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<div class="relative top-20 mx-auto w-96 rounded-md border bg-white p-5 shadow-lg">
|
<div class="relative top-20 mx-auto w-96 rounded-md border bg-white p-5 shadow-lg">
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="mb-4 flex items-center justify-between">
|
||||||
<h3 class="text-lg font-medium text-gray-900">Change User Role</h3>
|
<h3 class="text-lg font-medium text-gray-900">{{ $t('user.changeRoleModal.title') }}</h3>
|
||||||
<button class="text-gray-400 hover:text-gray-600" @click="$emit('close')">
|
<button class="text-gray-400 hover:text-gray-600" @click="$emit('close')">
|
||||||
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
: 'bg-blue-100 text-blue-800'
|
: 'bg-blue-100 text-blue-800'
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
Current: {{ user.role }}
|
{{ $t('user.changeRoleModal.currentRole', { role: user.role }) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<!-- Role Selection -->
|
<!-- Role Selection -->
|
||||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||||
<div>
|
<div>
|
||||||
<label class="mb-2 block text-sm font-medium text-gray-700"> New Role </label>
|
<label class="mb-2 block text-sm font-medium text-gray-700"> {{ $t('user.changeRoleModal.newRole') }} </label>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<input
|
<input
|
||||||
@@ -75,8 +75,8 @@
|
|||||||
value="user"
|
value="user"
|
||||||
/>
|
/>
|
||||||
<div class="ml-3">
|
<div class="ml-3">
|
||||||
<div class="text-sm font-medium text-gray-900">User</div>
|
<div class="text-sm font-medium text-gray-900">{{ $t('user.changeRoleModal.roles.user') }}</div>
|
||||||
<div class="text-xs text-gray-500">Regular user with basic permissions</div>
|
<div class="text-xs text-gray-500">{{ $t('user.changeRoleModal.roles.userDesc') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
@@ -88,8 +88,8 @@
|
|||||||
value="admin"
|
value="admin"
|
||||||
/>
|
/>
|
||||||
<div class="ml-3">
|
<div class="ml-3">
|
||||||
<div class="text-sm font-medium text-gray-900">Administrator</div>
|
<div class="text-sm font-medium text-gray-900">{{ $t('user.changeRoleModal.roles.admin') }}</div>
|
||||||
<div class="text-xs text-gray-500">Full access to manage users and system</div>
|
<div class="text-xs text-gray-500">{{ $t('user.changeRoleModal.roles.adminDesc') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -111,15 +111,13 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-3">
|
<div class="ml-3">
|
||||||
<h3 class="text-sm font-medium text-yellow-800">Role Change Warning</h3>
|
<h3 class="text-sm font-medium text-yellow-800">{{ $t('user.changeRoleModal.roleChangeWarning.title') }}</h3>
|
||||||
<div class="mt-2 text-sm text-yellow-700">
|
<div class="mt-2 text-sm text-yellow-700">
|
||||||
<p v-if="selectedRole === 'admin'">
|
<p v-if="selectedRole === 'admin'">
|
||||||
Granting admin privileges will give this user full access to the system,
|
{{ $t('user.changeRoleModal.roleChangeWarning.grantAdmin') }}
|
||||||
including the ability to manage other users and their API keys.
|
|
||||||
</p>
|
</p>
|
||||||
<p v-else>
|
<p v-else>
|
||||||
Removing admin privileges will restrict this user to only managing their own
|
{{ $t('user.changeRoleModal.roleChangeWarning.removeAdmin') }}
|
||||||
API keys and viewing their own usage statistics.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -150,7 +148,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
>
|
>
|
||||||
Cancel
|
{{ $t('user.changeRoleModal.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="rounded-md border border-transparent bg-blue-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
class="rounded-md border border-transparent bg-blue-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
@@ -178,9 +176,9 @@
|
|||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
Updating...
|
{{ $t('user.changeRoleModal.updating') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>Update Role</span>
|
<span v-else>{{ $t('user.changeRoleModal.updateRole') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -194,6 +192,9 @@
|
|||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { apiClient } from '@/config/api'
|
import { apiClient } from '@/config/api'
|
||||||
import { showToast } from '@/utils/toast'
|
import { showToast } from '@/utils/toast'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: {
|
show: {
|
||||||
@@ -226,7 +227,7 @@ const handleSubmit = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
showToast(`User role updated to ${selectedRole.value}`, 'success')
|
showToast(t('user.changeRoleModal.roleUpdated', { role: selectedRole.value }), 'success')
|
||||||
emit('updated')
|
emit('updated')
|
||||||
} else {
|
} else {
|
||||||
error.value = response.message || 'Failed to update user role'
|
error.value = response.message || 'Failed to update user role'
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="mb-6 flex items-center justify-between">
|
<div class="mb-6 flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900">
|
<h3 class="text-lg font-medium text-gray-900">
|
||||||
Usage Statistics - {{ user?.displayName || user?.username }}
|
{{ $t('user.usageStatsModal.titleWithUser', { displayName: user?.displayName || user?.username }) }}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-sm text-gray-500">@{{ user?.username }} • {{ user?.role }}</p>
|
<p class="text-sm text-gray-500">@{{ user?.username }} • {{ user?.role }}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -31,10 +31,10 @@
|
|||||||
class="block w-32 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
|
class="block w-32 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm"
|
||||||
@change="loadUsageStats"
|
@change="loadUsageStats"
|
||||||
>
|
>
|
||||||
<option value="day">Last 24 Hours</option>
|
<option value="day">{{ $t('user.usageStatsModal.periodSelection.day') }}</option>
|
||||||
<option value="week">Last 7 Days</option>
|
<option value="week">{{ $t('user.usageStatsModal.periodSelection.week') }}</option>
|
||||||
<option value="month">Last 30 Days</option>
|
<option value="month">{{ $t('user.usageStatsModal.periodSelection.month') }}</option>
|
||||||
<option value="quarter">Last 90 Days</option>
|
<option value="quarter">{{ $t('user.usageStatsModal.periodSelection.quarter') }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
></path>
|
></path>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="mt-2 text-sm text-gray-500">Loading usage statistics...</p>
|
<p class="mt-2 text-sm text-gray-500">{{ $t('user.usageStatsModal.loadingStats') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Stats Content -->
|
<!-- Stats Content -->
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-5 w-0 flex-1">
|
<div class="ml-5 w-0 flex-1">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="truncate text-sm font-medium text-blue-600">Requests</dt>
|
<dt class="truncate text-sm font-medium text-blue-600">{{ $t('user.usageStatsModal.summaryCards.requests') }}</dt>
|
||||||
<dd class="text-lg font-medium text-blue-900">
|
<dd class="text-lg font-medium text-blue-900">
|
||||||
{{ formatNumber(usageStats?.totalRequests || 0) }}
|
{{ formatNumber(usageStats?.totalRequests || 0) }}
|
||||||
</dd>
|
</dd>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-5 w-0 flex-1">
|
<div class="ml-5 w-0 flex-1">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="truncate text-sm font-medium text-green-600">Input Tokens</dt>
|
<dt class="truncate text-sm font-medium text-green-600">{{ $t('user.usageStatsModal.summaryCards.inputTokens') }}</dt>
|
||||||
<dd class="text-lg font-medium text-green-900">
|
<dd class="text-lg font-medium text-green-900">
|
||||||
{{ formatNumber(usageStats?.totalInputTokens || 0) }}
|
{{ formatNumber(usageStats?.totalInputTokens || 0) }}
|
||||||
</dd>
|
</dd>
|
||||||
@@ -147,7 +147,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-5 w-0 flex-1">
|
<div class="ml-5 w-0 flex-1">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="truncate text-sm font-medium text-purple-600">Output Tokens</dt>
|
<dt class="truncate text-sm font-medium text-purple-600">{{ $t('user.usageStatsModal.summaryCards.outputTokens') }}</dt>
|
||||||
<dd class="text-lg font-medium text-purple-900">
|
<dd class="text-lg font-medium text-purple-900">
|
||||||
{{ formatNumber(usageStats?.totalOutputTokens || 0) }}
|
{{ formatNumber(usageStats?.totalOutputTokens || 0) }}
|
||||||
</dd>
|
</dd>
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ml-5 w-0 flex-1">
|
<div class="ml-5 w-0 flex-1">
|
||||||
<dl>
|
<dl>
|
||||||
<dt class="truncate text-sm font-medium text-yellow-600">Total Cost</dt>
|
<dt class="truncate text-sm font-medium text-yellow-600">{{ $t('user.usageStatsModal.summaryCards.totalCost') }}</dt>
|
||||||
<dd class="text-lg font-medium text-yellow-900">
|
<dd class="text-lg font-medium text-yellow-900">
|
||||||
${{ (usageStats?.totalCost || 0).toFixed(4) }}
|
${{ (usageStats?.totalCost || 0).toFixed(4) }}
|
||||||
</dd>
|
</dd>
|
||||||
@@ -194,7 +194,7 @@
|
|||||||
class="rounded-lg border border-gray-200 bg-white"
|
class="rounded-lg border border-gray-200 bg-white"
|
||||||
>
|
>
|
||||||
<div class="border-b border-gray-200 px-4 py-5 sm:px-6">
|
<div class="border-b border-gray-200 px-4 py-5 sm:px-6">
|
||||||
<h4 class="text-lg font-medium leading-6 text-gray-900">API Keys Usage</h4>
|
<h4 class="text-lg font-medium leading-6 text-gray-900">{{ $t('user.usageStatsModal.apiKeysTable.title') }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden">
|
<div class="overflow-hidden">
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
@@ -204,37 +204,37 @@
|
|||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
API Key
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.apiKey') }}
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Status
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.status') }}
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Requests
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.requests') }}
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Tokens
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.tokens') }}
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Cost
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.cost') }}
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
class="px-6 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-500"
|
||||||
scope="col"
|
scope="col"
|
||||||
>
|
>
|
||||||
Last Used
|
{{ $t('user.usageStatsModal.apiKeysTable.headers.lastUsed') }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -253,21 +253,21 @@
|
|||||||
: 'bg-red-100 text-red-800'
|
: 'bg-red-100 text-red-800'
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{ apiKey.isActive ? 'Active' : 'Disabled' }}
|
{{ apiKey.isActive ? $t('user.usageStatsModal.apiKeysTable.status.active') : $t('user.usageStatsModal.apiKeysTable.status.disabled') }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||||
{{ formatNumber(apiKey.usage?.requests || 0) }}
|
{{ formatNumber(apiKey.usage?.requests || 0) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||||
<div>In: {{ formatNumber(apiKey.usage?.inputTokens || 0) }}</div>
|
<div>{{ $t('user.usageStatsModal.apiKeysTable.tokensFormat.input') }}: {{ formatNumber(apiKey.usage?.inputTokens || 0) }}</div>
|
||||||
<div>Out: {{ formatNumber(apiKey.usage?.outputTokens || 0) }}</div>
|
<div>{{ $t('user.usageStatsModal.apiKeysTable.tokensFormat.output') }}: {{ formatNumber(apiKey.usage?.outputTokens || 0) }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||||
${{ (apiKey.usage?.totalCost || 0).toFixed(4) }}
|
${{ (apiKey.usage?.totalCost || 0).toFixed(4) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-500">
|
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-500">
|
||||||
{{ apiKey.lastUsedAt ? formatDate(apiKey.lastUsedAt) : 'Never' }}
|
{{ apiKey.lastUsedAt ? formatDate(apiKey.lastUsedAt) : $t('user.usageStatsModal.apiKeysTable.never') }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -278,7 +278,7 @@
|
|||||||
<!-- Chart Placeholder -->
|
<!-- Chart Placeholder -->
|
||||||
<div class="rounded-lg border border-gray-200 bg-white">
|
<div class="rounded-lg border border-gray-200 bg-white">
|
||||||
<div class="border-b border-gray-200 px-4 py-5 sm:px-6">
|
<div class="border-b border-gray-200 px-4 py-5 sm:px-6">
|
||||||
<h4 class="text-lg font-medium leading-6 text-gray-900">Usage Trend</h4>
|
<h4 class="text-lg font-medium leading-6 text-gray-900">{{ $t('user.usageStatsModal.usageTrend.title') }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<div
|
<div
|
||||||
@@ -298,12 +298,12 @@
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="mt-2 text-sm font-medium text-gray-900">Usage Chart</h3>
|
<h3 class="mt-2 text-sm font-medium text-gray-900">{{ $t('user.usageStatsModal.usageTrend.chartTitle') }}</h3>
|
||||||
<p class="mt-1 text-sm text-gray-500">
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
Daily usage trends for {{ selectedPeriod }} period
|
{{ $t('user.usageStatsModal.usageTrend.dailyTrends', { period: selectedPeriod }) }}
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2 text-xs text-gray-400">
|
<p class="mt-2 text-xs text-gray-400">
|
||||||
(Chart integration can be added with Chart.js, D3.js, or similar library)
|
{{ $t('user.usageStatsModal.usageTrend.chartNote') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -325,9 +325,9 @@
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="mt-2 text-sm font-medium text-gray-900">No usage data</h3>
|
<h3 class="mt-2 text-sm font-medium text-gray-900">{{ $t('user.usageStatsModal.noData.title') }}</h3>
|
||||||
<p class="mt-1 text-sm text-gray-500">
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
This user hasn't made any API requests in the selected period.
|
{{ $t('user.usageStatsModal.noData.description') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -337,7 +337,7 @@
|
|||||||
class="rounded-md border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
class="rounded-md border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
>
|
>
|
||||||
Close
|
{{ $t('user.usageStatsModal.close') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -349,6 +349,9 @@
|
|||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { apiClient } from '@/config/api'
|
import { apiClient } from '@/config/api'
|
||||||
import { showToast } from '@/utils/toast'
|
import { showToast } from '@/utils/toast'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: {
|
show: {
|
||||||
|
|||||||
@@ -789,6 +789,102 @@ export default {
|
|||||||
loadUsersError: 'Failed to load users',
|
loadUsersError: 'Failed to load users',
|
||||||
toggleStatusError: 'Failed to toggleStatus',
|
toggleStatusError: 'Failed to toggleStatus',
|
||||||
disableKeysError: 'Failed to disableKeys'
|
disableKeysError: 'Failed to disableKeys'
|
||||||
|
},
|
||||||
|
|
||||||
|
// User Usage Stats Modal
|
||||||
|
usageStatsModal: {
|
||||||
|
title: 'Usage Statistics',
|
||||||
|
titleWithUser: 'Usage Statistics - {displayName}',
|
||||||
|
|
||||||
|
// Time period selection
|
||||||
|
periodSelection: {
|
||||||
|
day: 'Last 24 Hours',
|
||||||
|
week: 'Last 7 Days',
|
||||||
|
month: 'Last 30 Days',
|
||||||
|
quarter: 'Last 90 Days'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
loadingStats: 'Loading usage statistics...',
|
||||||
|
|
||||||
|
// Summary cards
|
||||||
|
summaryCards: {
|
||||||
|
requests: 'Requests',
|
||||||
|
inputTokens: 'Input Tokens',
|
||||||
|
outputTokens: 'Output Tokens',
|
||||||
|
totalCost: 'Total Cost'
|
||||||
|
},
|
||||||
|
|
||||||
|
// API Keys table
|
||||||
|
apiKeysTable: {
|
||||||
|
title: 'API Keys Usage',
|
||||||
|
headers: {
|
||||||
|
apiKey: 'API Key',
|
||||||
|
status: 'Status',
|
||||||
|
requests: 'Requests',
|
||||||
|
tokens: 'Tokens',
|
||||||
|
cost: 'Cost',
|
||||||
|
lastUsed: 'Last Used'
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
active: 'Active',
|
||||||
|
disabled: 'Disabled'
|
||||||
|
},
|
||||||
|
tokensFormat: {
|
||||||
|
input: 'In',
|
||||||
|
output: 'Out'
|
||||||
|
},
|
||||||
|
never: 'Never'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Usage trend chart
|
||||||
|
usageTrend: {
|
||||||
|
title: 'Usage Trend',
|
||||||
|
chartTitle: 'Usage Chart',
|
||||||
|
dailyTrends: 'Daily usage trends for {period} period',
|
||||||
|
chartNote: '(Chart integration can be added with Chart.js, D3.js, or similar library)'
|
||||||
|
},
|
||||||
|
|
||||||
|
// No data state
|
||||||
|
noData: {
|
||||||
|
title: 'No usage data',
|
||||||
|
description: 'This user hasn\'t made any API requests in the selected period.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
close: 'Close'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Change Role Modal
|
||||||
|
changeRoleModal: {
|
||||||
|
title: 'Change User Role',
|
||||||
|
|
||||||
|
// User info display
|
||||||
|
currentRole: 'Current: {role}',
|
||||||
|
|
||||||
|
// Role selection form
|
||||||
|
newRole: 'New Role',
|
||||||
|
roles: {
|
||||||
|
user: 'User',
|
||||||
|
userDesc: 'Regular user with basic permissions',
|
||||||
|
admin: 'Administrator',
|
||||||
|
adminDesc: 'Full access to manage users and system'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Warning messages
|
||||||
|
roleChangeWarning: {
|
||||||
|
title: 'Role Change Warning',
|
||||||
|
grantAdmin: 'Granting admin privileges will give this user full access to the system, including the ability to manage other users and their API keys.',
|
||||||
|
removeAdmin: 'Removing admin privileges will restrict this user to only managing their own API keys and viewing their own usage statistics.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
cancel: 'Cancel',
|
||||||
|
updateRole: 'Update Role',
|
||||||
|
updating: 'Updating...',
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
roleUpdated: 'User role updated to {role}'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -789,6 +789,102 @@ export default {
|
|||||||
loadUsersError: 'Failed to load users',
|
loadUsersError: 'Failed to load users',
|
||||||
toggleStatusError: 'Failed to toggleStatus',
|
toggleStatusError: 'Failed to toggleStatus',
|
||||||
disableKeysError: 'Failed to disableKeys'
|
disableKeysError: 'Failed to disableKeys'
|
||||||
|
},
|
||||||
|
|
||||||
|
// User Usage Stats Modal
|
||||||
|
usageStatsModal: {
|
||||||
|
title: '使用统计',
|
||||||
|
titleWithUser: '使用统计 - {displayName}',
|
||||||
|
|
||||||
|
// Time period selection
|
||||||
|
periodSelection: {
|
||||||
|
day: '最近24小时',
|
||||||
|
week: '最近7天',
|
||||||
|
month: '最近30天',
|
||||||
|
quarter: '最近90天'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
loadingStats: '正在加载使用统计...',
|
||||||
|
|
||||||
|
// Summary cards
|
||||||
|
summaryCards: {
|
||||||
|
requests: '请求数',
|
||||||
|
inputTokens: '输入Token',
|
||||||
|
outputTokens: '输出Token',
|
||||||
|
totalCost: '总费用'
|
||||||
|
},
|
||||||
|
|
||||||
|
// API Keys table
|
||||||
|
apiKeysTable: {
|
||||||
|
title: 'API Keys 使用情况',
|
||||||
|
headers: {
|
||||||
|
apiKey: 'API Key',
|
||||||
|
status: '状态',
|
||||||
|
requests: '请求数',
|
||||||
|
tokens: 'Token数',
|
||||||
|
cost: '费用',
|
||||||
|
lastUsed: '最后使用'
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
active: '活跃',
|
||||||
|
disabled: '已禁用'
|
||||||
|
},
|
||||||
|
tokensFormat: {
|
||||||
|
input: '输入',
|
||||||
|
output: '输出'
|
||||||
|
},
|
||||||
|
never: '从未使用'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Usage trend chart
|
||||||
|
usageTrend: {
|
||||||
|
title: '使用趋势',
|
||||||
|
chartTitle: '使用图表',
|
||||||
|
dailyTrends: '最近 {period} 的日使用趋势',
|
||||||
|
chartNote: '(可集成 Chart.js、D3.js 或类似图表库)'
|
||||||
|
},
|
||||||
|
|
||||||
|
// No data state
|
||||||
|
noData: {
|
||||||
|
title: '暂无使用数据',
|
||||||
|
description: '该用户在所选时间段内尚未发起任何API请求。'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
close: '关闭'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Change Role Modal
|
||||||
|
changeRoleModal: {
|
||||||
|
title: '修改用户角色',
|
||||||
|
|
||||||
|
// User info display
|
||||||
|
currentRole: '当前角色:{role}',
|
||||||
|
|
||||||
|
// Role selection form
|
||||||
|
newRole: '新角色',
|
||||||
|
roles: {
|
||||||
|
user: '用户',
|
||||||
|
userDesc: '具有基本权限的普通用户',
|
||||||
|
admin: '管理员',
|
||||||
|
adminDesc: '拥有管理用户和系统的完整权限'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Warning messages
|
||||||
|
roleChangeWarning: {
|
||||||
|
title: '角色变更警告',
|
||||||
|
grantAdmin: '授予管理员权限将使该用户拥有系统的完整访问权限,包括管理其他用户及其API密钥的能力。',
|
||||||
|
removeAdmin: '移除管理员权限将限制该用户只能管理自己的API密钥和查看自己的使用统计。'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
cancel: '取消',
|
||||||
|
updateRole: '更新角色',
|
||||||
|
updating: '更新中...',
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
roleUpdated: '用户角色已更新为 {role}'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -789,6 +789,102 @@ export default {
|
|||||||
loadUsersError: 'Failed to load users',
|
loadUsersError: 'Failed to load users',
|
||||||
toggleStatusError: 'Failed to toggleStatus',
|
toggleStatusError: 'Failed to toggleStatus',
|
||||||
disableKeysError: 'Failed to disableKeys'
|
disableKeysError: 'Failed to disableKeys'
|
||||||
|
},
|
||||||
|
|
||||||
|
// User Usage Stats Modal
|
||||||
|
usageStatsModal: {
|
||||||
|
title: '使用統計',
|
||||||
|
titleWithUser: '使用統計 - {displayName}',
|
||||||
|
|
||||||
|
// Time period selection
|
||||||
|
periodSelection: {
|
||||||
|
day: '最近24小時',
|
||||||
|
week: '最近7天',
|
||||||
|
month: '最近30天',
|
||||||
|
quarter: '最近90天'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Loading state
|
||||||
|
loadingStats: '正在載入使用統計...',
|
||||||
|
|
||||||
|
// Summary cards
|
||||||
|
summaryCards: {
|
||||||
|
requests: '請求數',
|
||||||
|
inputTokens: '輸入Token',
|
||||||
|
outputTokens: '輸出Token',
|
||||||
|
totalCost: '總費用'
|
||||||
|
},
|
||||||
|
|
||||||
|
// API Keys table
|
||||||
|
apiKeysTable: {
|
||||||
|
title: 'API Keys 使用情況',
|
||||||
|
headers: {
|
||||||
|
apiKey: 'API Key',
|
||||||
|
status: '狀態',
|
||||||
|
requests: '請求數',
|
||||||
|
tokens: 'Token數',
|
||||||
|
cost: '費用',
|
||||||
|
lastUsed: '最後使用'
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
active: '活躍',
|
||||||
|
disabled: '已停用'
|
||||||
|
},
|
||||||
|
tokensFormat: {
|
||||||
|
input: '輸入',
|
||||||
|
output: '輸出'
|
||||||
|
},
|
||||||
|
never: '從未使用'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Usage trend chart
|
||||||
|
usageTrend: {
|
||||||
|
title: '使用趨勢',
|
||||||
|
chartTitle: '使用圖表',
|
||||||
|
dailyTrends: '最近 {period} 的日使用趨勢',
|
||||||
|
chartNote: '(可整合 Chart.js、D3.js 或類似圖表庫)'
|
||||||
|
},
|
||||||
|
|
||||||
|
// No data state
|
||||||
|
noData: {
|
||||||
|
title: '暫無使用資料',
|
||||||
|
description: '該使用者在所選時間段內尚未發起任何API請求。'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
close: '關閉'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Change Role Modal
|
||||||
|
changeRoleModal: {
|
||||||
|
title: '修改使用者角色',
|
||||||
|
|
||||||
|
// User info display
|
||||||
|
currentRole: '當前角色:{role}',
|
||||||
|
|
||||||
|
// Role selection form
|
||||||
|
newRole: '新角色',
|
||||||
|
roles: {
|
||||||
|
user: '使用者',
|
||||||
|
userDesc: '具有基本權限的普通使用者',
|
||||||
|
admin: '管理員',
|
||||||
|
adminDesc: '擁有管理使用者和系統的完整權限'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Warning messages
|
||||||
|
roleChangeWarning: {
|
||||||
|
title: '角色變更警告',
|
||||||
|
grantAdmin: '授予管理員權限將使該使用者擁有系統的完整存取權限,包括管理其他使用者及其API密鑰的能力。',
|
||||||
|
removeAdmin: '移除管理員權限將限制該使用者只能管理自己的API密鑰和檢視自己的使用統計。'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
cancel: '取消',
|
||||||
|
updateRole: '更新角色',
|
||||||
|
updating: '更新中...',
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
roleUpdated: '使用者角色已更新為 {role}'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user