From 4251a5a451ab440e37280f4d4e1f44b97fb9f0d8 Mon Sep 17 00:00:00 2001
From: IanShaw027 <131567472+IanShaw027@users.noreply.github.com>
Date: Mon, 5 Jan 2026 20:22:48 +0800
Subject: [PATCH] =?UTF-8?q?refactor(frontend):=20=E5=AE=8C=E6=88=90?=
=?UTF-8?q?=E6=89=80=E6=9C=89=E7=BB=84=E4=BB=B6=E7=9A=84=E5=86=85=E8=81=94?=
=?UTF-8?q?SVG=E7=BB=9F=E4=B8=80=E6=9B=BF=E6=8D=A2=E4=B8=BAIcon=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 扩展 Icon.vue 组件,新增 60+ 图标路径
- 导航类: arrowRight, arrowLeft, arrowUp, arrowDown, chevronUp, externalLink
- 状态类: checkCircle, xCircle, exclamationCircle, exclamationTriangle, infoCircle
- 用户类: user, userCircle, userPlus, users
- 文档类: document, clipboard, copy, inbox
- 操作类: download, upload, filter, sort
- 安全类: key, lock, shield
- UI类: menu, calendar, home, terminal, gift, creditCard, mail
- 数据类: chartBar, trendingUp, database, cube
- 其他: bolt, sparkles, cloud, server, sun, moon, book 等
- 重构 56 个 Vue 组件,用 Icon 组件替换内联 SVG
- 净减少约 2200 行代码
- 提升代码可维护性和一致性
- 统一图标样式和尺寸管理
---
.../components/account/AccountStatsModal.vue | 137 +++--------
.../account/AccountStatusIndicator.vue | 19 +-
.../components/account/AccountTestModal.vue | 55 +----
.../account/BulkEditAccountModal.vue | 24 +-
.../components/account/CreateAccountModal.vue | 179 ++------------
.../components/account/EditAccountModal.vue | 51 +---
.../account/ModelWhitelistSelector.vue | 5 +-
.../account/OAuthAuthorizationFlow.vue | 141 ++---------
.../components/account/ReAuthAccountModal.vue | 43 +---
.../admin/account/AccountStatsModal.vue | 157 ++-----------
.../admin/account/AccountTableActions.vue | 12 +-
.../admin/account/AccountTableFilters.vue | 2 +-
.../admin/account/ReAuthAccountModal.vue | 47 +---
.../admin/usage/UsageStatsCards.vue | 35 ++-
.../src/components/admin/usage/UsageTable.vue | 7 +-
.../components/admin/user/UserCreateModal.vue | 3 +-
.../components/admin/user/UserEditModal.vue | 5 +-
frontend/src/components/common/BaseDialog.vue | 11 +-
frontend/src/components/common/DataTable.vue | 17 +-
.../src/components/common/DateRangePicker.vue | 43 +---
frontend/src/components/common/EmptyState.vue | 12 +-
.../src/components/common/LocaleSwitcher.vue | 26 +-
frontend/src/components/common/Pagination.vue | 17 +-
.../components/common/PlatformTypeBadge.vue | 31 +--
.../src/components/common/ProxySelector.vue | 84 ++-----
.../src/components/common/SearchInput.vue | 15 +-
frontend/src/components/common/Select.vue | 46 ++--
frontend/src/components/common/StatCard.vue | 17 +-
.../common/SubscriptionProgressMini.vue | 15 +-
frontend/src/components/common/Toast.vue | 92 ++------
.../src/components/common/VersionBadge.vue | 113 +++------
frontend/src/components/icons/Icon.vue | 75 +++++-
frontend/src/components/keys/UseKeyModal.vue | 9 +-
frontend/src/components/layout/AppHeader.vue | 57 +----
.../user/UserAttributesConfigModal.vue | 25 +-
.../dashboard/UserDashboardQuickActions.vue | 39 +--
.../dashboard/UserDashboardRecentUsage.vue | 9 +-
.../user/dashboard/UserDashboardStats.vue | 29 +--
.../user/profile/ProfileInfoCard.vue | 29 +--
frontend/src/views/HomeView.vue | 115 +--------
frontend/src/views/NotFoundView.vue | 29 +--
frontend/src/views/admin/DashboardView.vue | 113 +--------
frontend/src/views/admin/GroupsView.vue | 106 ++-------
frontend/src/views/admin/ProxiesView.vue | 137 ++---------
frontend/src/views/admin/RedeemView.vue | 63 +----
frontend/src/views/admin/SettingsView.vue | 45 +---
.../src/views/admin/SubscriptionsView.vue | 93 +-------
frontend/src/views/admin/UsersView.vue | 191 +++------------
frontend/src/views/auth/EmailVerifyView.vue | 72 +-----
frontend/src/views/auth/LoginView.vue | 93 +-------
frontend/src/views/auth/RegisterView.vue | 107 +--------
frontend/src/views/setup/SetupWizardView.vue | 113 ++-------
frontend/src/views/user/KeysView.vue | 222 +++++-------------
frontend/src/views/user/RedeemView.vue | 164 +++----------
frontend/src/views/user/SubscriptionsView.vue | 29 +--
frontend/src/views/user/UsageView.vue | 145 ++----------
56 files changed, 688 insertions(+), 2882 deletions(-)
diff --git a/frontend/src/components/account/AccountStatsModal.vue b/frontend/src/components/account/AccountStatsModal.vue
index 93f38a83..92016699 100644
--- a/frontend/src/components/account/AccountStatsModal.vue
+++ b/frontend/src/components/account/AccountStatsModal.vue
@@ -15,14 +15,7 @@
{{ account.name }}
@@ -97,19 +90,7 @@
t('admin.accounts.stats.totalRequests')
}}
@@ -129,19 +110,12 @@
t('admin.accounts.stats.avgDailyCost')
}}
@@ -245,19 +219,12 @@
{{
t('admin.accounts.stats.highestCostDay')
@@ -295,19 +262,12 @@
{{
t('admin.accounts.stats.highestRequestDay')
@@ -348,19 +308,7 @@
{{
t('admin.accounts.stats.accumulatedTokens')
@@ -390,19 +338,7 @@
{{
t('admin.accounts.stats.performance')
@@ -432,19 +368,12 @@
{{
t('admin.accounts.stats.recentActivity')
@@ -504,14 +433,7 @@
v-else-if="!loading"
class="flex flex-col items-center justify-center py-12 text-gray-500 dark:text-gray-400"
>
-
+
{{ t('admin.accounts.stats.noData') }}
@@ -547,6 +469,7 @@ import { Line } from 'vue-chartjs'
import BaseDialog from '@/components/common/BaseDialog.vue'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
import ModelDistributionChart from '@/components/charts/ModelDistributionChart.vue'
+import Icon from '@/components/icons/Icon.vue'
import { adminAPI } from '@/api/admin'
import type { Account, AccountUsageStatsResponse } from '@/types'
diff --git a/frontend/src/components/account/AccountStatusIndicator.vue b/frontend/src/components/account/AccountStatusIndicator.vue
index 281bf832..7dae33bb 100644
--- a/frontend/src/components/account/AccountStatusIndicator.vue
+++ b/frontend/src/components/account/AccountStatusIndicator.vue
@@ -48,13 +48,7 @@
-
+
429
@@ -73,13 +67,7 @@
-
+
529
@@ -100,6 +88,7 @@ import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import type { Account } from '@/types'
import { formatTime } from '@/utils/format'
+import Icon from '@/components/icons/Icon.vue'
const { t } = useI18n()
@@ -179,4 +168,4 @@ const handleTempUnschedClick = () => {
emit('show-temp-unsched', props.account)
}
-
\ No newline at end of file
+
diff --git a/frontend/src/components/account/AccountTestModal.vue b/frontend/src/components/account/AccountTestModal.vue
index 619a2ba3..42f3c1b9 100644
--- a/frontend/src/components/account/AccountTestModal.vue
+++ b/frontend/src/components/account/AccountTestModal.vue
@@ -15,14 +15,7 @@
{{ account.name }}
@@ -70,14 +63,7 @@
>
-
+
{{ t('admin.accounts.readyToTest') }}
@@ -128,14 +114,7 @@
v-else-if="status === 'error'"
class="mt-3 flex items-center gap-2 border-t border-gray-700 pt-3 text-red-400"
>
-
+
{{ errorMessage }}
@@ -147,14 +126,7 @@
class="absolute right-2 top-2 rounded-lg bg-gray-800/80 p-1.5 text-gray-400 opacity-0 transition-all hover:bg-gray-700 hover:text-white group-hover:opacity-100"
:title="t('admin.accounts.copyOutput')"
>
-
+
@@ -162,26 +134,12 @@
-
+
{{ t('admin.accounts.testModel') }}
-
+
{{ t('admin.accounts.testPrompt') }}
@@ -278,6 +236,7 @@ import { ref, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseDialog from '@/components/common/BaseDialog.vue'
import Select from '@/components/common/Select.vue'
+import Icon from '@/components/icons/Icon.vue'
import { useClipboard } from '@/composables/useClipboard'
import { adminAPI } from '@/api/admin'
import type { Account, ClaudeModel } from '@/types'
diff --git a/frontend/src/components/account/BulkEditAccountModal.vue b/frontend/src/components/account/BulkEditAccountModal.vue
index 60b3d364..6dba60fe 100644
--- a/frontend/src/components/account/BulkEditAccountModal.vue
+++ b/frontend/src/components/account/BulkEditAccountModal.vue
@@ -318,19 +318,7 @@
-
+
{{ t('admin.accounts.customErrorCodesWarning') }}
@@ -391,14 +379,7 @@
class="hover:text-red-900 dark:hover:text-red-300"
@click="removeErrorCode(code)"
>
-
+
@@ -642,6 +623,7 @@ import BaseDialog from '@/components/common/BaseDialog.vue'
import Select from '@/components/common/Select.vue'
import ProxySelector from '@/components/common/ProxySelector.vue'
import GroupSelector from '@/components/common/GroupSelector.vue'
+import Icon from '@/components/icons/Icon.vue'
interface Props {
show: boolean
diff --git a/frontend/src/components/account/CreateAccountModal.vue b/frontend/src/components/account/CreateAccountModal.vue
index 37ef96f0..6671001b 100644
--- a/frontend/src/components/account/CreateAccountModal.vue
+++ b/frontend/src/components/account/CreateAccountModal.vue
@@ -71,19 +71,7 @@
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200'
]"
>
-
+
Anthropic
@@ -186,19 +162,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
{{
@@ -228,19 +192,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
{{
@@ -276,19 +228,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
OAuth
@@ -314,19 +254,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
API Key
@@ -370,19 +298,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -477,9 +393,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -522,9 +436,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -700,19 +612,7 @@
class="flex items-center gap-3 rounded-lg border-2 border-purple-500 bg-purple-50 p-3 dark:bg-purple-900/20"
>
OAuth
@@ -1002,19 +902,7 @@
-
+
{{ t('admin.accounts.customErrorCodesWarning') }}
@@ -1073,14 +961,7 @@
@click="removeErrorCode(code)"
class="hover:text-red-900 dark:hover:text-red-300"
>
-
+
@@ -1148,23 +1029,11 @@
-
-
- {{ t('admin.accounts.tempUnschedulable.notice') }}
-
-
+
+
+ {{ t('admin.accounts.tempUnschedulable.notice') }}
+
+
@@ -1724,6 +1584,7 @@ import { useGeminiOAuth } from '@/composables/useGeminiOAuth'
import { useAntigravityOAuth } from '@/composables/useAntigravityOAuth'
import type { Proxy, Group, AccountPlatform, AccountType } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
+import Icon from '@/components/icons/Icon.vue'
import ProxySelector from '@/components/common/ProxySelector.vue'
import GroupSelector from '@/components/common/GroupSelector.vue'
import ModelWhitelistSelector from '@/components/account/ModelWhitelistSelector.vue'
diff --git a/frontend/src/components/account/EditAccountModal.vue b/frontend/src/components/account/EditAccountModal.vue
index 068148ec..9ac05988 100644
--- a/frontend/src/components/account/EditAccountModal.vue
+++ b/frontend/src/components/account/EditAccountModal.vue
@@ -255,19 +255,7 @@
-
+
{{ t('admin.accounts.customErrorCodesWarning') }}
@@ -326,14 +314,7 @@
@click="removeErrorCode(code)"
class="hover:text-red-900 dark:hover:text-red-300"
>
-
+
@@ -402,19 +383,7 @@
-
+
{{ t('admin.accounts.tempUnschedulable.notice') }}
@@ -448,9 +417,7 @@
@click="moveTempUnschedRule(index, -1)"
class="rounded p-1 text-gray-400 transition-colors hover:text-gray-600 disabled:cursor-not-allowed disabled:opacity-40 dark:hover:text-gray-200"
>
-
+
@@ -692,6 +652,7 @@ import { adminAPI } from '@/api/admin'
import type { Account, Proxy, Group } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
import Select from '@/components/common/Select.vue'
+import Icon from '@/components/icons/Icon.vue'
import ProxySelector from '@/components/common/ProxySelector.vue'
import GroupSelector from '@/components/common/GroupSelector.vue'
import ModelWhitelistSelector from '@/components/account/ModelWhitelistSelector.vue'
diff --git a/frontend/src/components/account/ModelWhitelistSelector.vue b/frontend/src/components/account/ModelWhitelistSelector.vue
index b029d376..c8c1b852 100644
--- a/frontend/src/components/account/ModelWhitelistSelector.vue
+++ b/frontend/src/components/account/ModelWhitelistSelector.vue
@@ -21,9 +21,7 @@
@click.stop="removeModel(model)"
class="shrink-0 rounded-full hover:bg-gray-200 dark:hover:bg-dark-500"
>
-
+
@@ -126,6 +124,7 @@ import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores/app'
import ModelIcon from '@/components/common/ModelIcon.vue'
+import Icon from '@/components/icons/Icon.vue'
import { allModels, getModelsByPlatform } from '@/composables/useModelWhitelist'
const { t } = useI18n()
diff --git a/frontend/src/components/account/OAuthAuthorizationFlow.vue b/frontend/src/components/account/OAuthAuthorizationFlow.vue
index 7ce30b46..194237fa 100644
--- a/frontend/src/components/account/OAuthAuthorizationFlow.vue
+++ b/frontend/src/components/account/OAuthAuthorizationFlow.vue
@@ -2,21 +2,9 @@
-
+
{{ oauthTitle }}
@@ -66,19 +54,7 @@
@@ -427,19 +358,7 @@
>
-
+
{{ oauthAuthCodeHint }}
@@ -471,19 +378,12 @@
class="mt-3 rounded-lg border-2 border-amber-400 bg-amber-50 p-3 dark:border-amber-600 dark:bg-amber-900/30"
>
-
+
{{ $t('admin.accounts.oauth.gemini.stateWarningTitle') }}
{{ $t('admin.accounts.oauth.gemini.stateWarningDesc') }}
@@ -514,6 +414,7 @@
import { ref, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useClipboard } from '@/composables/useClipboard'
+import Icon from '@/components/icons/Icon.vue'
import type { AddMethod, AuthInputMethod } from '@/composables/useAccountOAuth'
interface Props {
diff --git a/frontend/src/components/account/ReAuthAccountModal.vue b/frontend/src/components/account/ReAuthAccountModal.vue
index 26320451..43d1198f 100644
--- a/frontend/src/components/account/ReAuthAccountModal.vue
+++ b/frontend/src/components/account/ReAuthAccountModal.vue
@@ -23,19 +23,7 @@
: 'from-orange-500 to-orange-600'
]"
>
-
+
{{
@@ -135,19 +123,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -179,19 +155,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -295,6 +259,7 @@ import { useGeminiOAuth } from '@/composables/useGeminiOAuth'
import { useAntigravityOAuth } from '@/composables/useAntigravityOAuth'
import type { Account } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
+import Icon from '@/components/icons/Icon.vue'
import OAuthAuthorizationFlow from './OAuthAuthorizationFlow.vue'
// Type for exposed OAuthAuthorizationFlow component
diff --git a/frontend/src/components/admin/account/AccountStatsModal.vue b/frontend/src/components/admin/account/AccountStatsModal.vue
index 93f38a83..138f5811 100644
--- a/frontend/src/components/admin/account/AccountStatsModal.vue
+++ b/frontend/src/components/admin/account/AccountStatsModal.vue
@@ -15,14 +15,7 @@
{{ account.name }}
@@ -60,19 +53,7 @@
t('admin.accounts.stats.totalCost')
}}
@@ -97,19 +78,7 @@
t('admin.accounts.stats.totalRequests')
}}
@@ -129,19 +98,11 @@
t('admin.accounts.stats.avgDailyCost')
}}
@@ -195,19 +156,7 @@
{{
t('admin.accounts.stats.todayOverview')
@@ -245,19 +194,7 @@
{{
t('admin.accounts.stats.highestCostDay')
@@ -295,19 +232,11 @@
{{
t('admin.accounts.stats.highestRequestDay')
@@ -348,19 +277,7 @@
{{
t('admin.accounts.stats.accumulatedTokens')
@@ -390,19 +307,7 @@
{{
t('admin.accounts.stats.performance')
@@ -432,19 +337,11 @@
{{
t('admin.accounts.stats.recentActivity')
@@ -504,14 +401,7 @@
v-else-if="!loading"
class="flex flex-col items-center justify-center py-12 text-gray-500 dark:text-gray-400"
>
-
+
{{ t('admin.accounts.stats.noData') }}
@@ -547,6 +437,7 @@ import { Line } from 'vue-chartjs'
import BaseDialog from '@/components/common/BaseDialog.vue'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
import ModelDistributionChart from '@/components/charts/ModelDistributionChart.vue'
+import Icon from '@/components/icons/Icon.vue'
import { adminAPI } from '@/api/admin'
import type { Account, AccountUsageStatsResponse } from '@/types'
diff --git a/frontend/src/components/admin/account/AccountTableActions.vue b/frontend/src/components/admin/account/AccountTableActions.vue
index ceb7fe9d..96fceaa0 100644
--- a/frontend/src/components/admin/account/AccountTableActions.vue
+++ b/frontend/src/components/admin/account/AccountTableActions.vue
@@ -1,11 +1,19 @@
-
+
diff --git a/frontend/src/components/admin/account/AccountTableFilters.vue b/frontend/src/components/admin/account/AccountTableFilters.vue
index 126a52a2..42043b33 100644
--- a/frontend/src/components/admin/account/AccountTableFilters.vue
+++ b/frontend/src/components/admin/account/AccountTableFilters.vue
@@ -16,7 +16,7 @@
diff --git a/frontend/src/components/admin/account/ReAuthAccountModal.vue b/frontend/src/components/admin/account/ReAuthAccountModal.vue
index 9bfa9530..d9838a2e 100644
--- a/frontend/src/components/admin/account/ReAuthAccountModal.vue
+++ b/frontend/src/components/admin/account/ReAuthAccountModal.vue
@@ -23,19 +23,7 @@
: 'from-orange-500 to-orange-600'
]"
>
-
+
{{
@@ -107,9 +95,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
Google One
@@ -135,19 +121,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -179,19 +153,7 @@
: 'bg-gray-100 text-gray-500 dark:bg-dark-600 dark:text-gray-400'
]"
>
-
+
@@ -295,6 +257,7 @@ import { useGeminiOAuth } from '@/composables/useGeminiOAuth'
import { useAntigravityOAuth } from '@/composables/useAntigravityOAuth'
import type { Account } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
+import Icon from '@/components/icons/Icon.vue'
import OAuthAuthorizationFlow from '@/components/account/OAuthAuthorizationFlow.vue'
// Type for exposed OAuthAuthorizationFlow component
diff --git a/frontend/src/components/admin/usage/UsageStatsCards.vue b/frontend/src/components/admin/usage/UsageStatsCards.vue
index c214fc50..2af25e36 100644
--- a/frontend/src/components/admin/usage/UsageStatsCards.vue
+++ b/frontend/src/components/admin/usage/UsageStatsCards.vue
@@ -1,7 +1,9 @@
-
+
+
+
{{ t('usage.totalRequests') }}
{{ stats?.total_requests?.toLocaleString() || '0' }}
@@ -9,19 +11,36 @@
{{ t('usage.totalTokens') }}
{{ formatTokens(stats?.total_tokens || 0) }}
-
+
+
+
{{ t('usage.totalCost') }}
${{ (stats?.total_actual_cost || 0).toFixed(4) }}
-
+
+
+
{{ t('usage.avgDuration') }}
{{ formatDuration(stats?.average_duration_ms || 0) }}
\ No newline at end of file
+import { useI18n } from 'vue-i18n'
+import type { AdminUsageStatsResponse } from '@/api/admin/usage'
+import Icon from '@/components/icons/Icon.vue'
+
+defineProps<{ stats: AdminUsageStatsResponse | null }>()
+
+const { t } = useI18n()
+
+const formatDuration = (ms: number) =>
+ ms < 1000 ? `${ms.toFixed(0)}ms` : `${(ms / 1000).toFixed(2)}s`
+
+const formatTokens = (value: number) => {
+ if (value >= 1e9) return (value / 1e9).toFixed(2) + 'B'
+ if (value >= 1e6) return (value / 1e6).toFixed(2) + 'M'
+ if (value >= 1e3) return (value / 1e3).toFixed(2) + 'K'
+ return value.toLocaleString()
+}
+
diff --git a/frontend/src/components/admin/usage/UsageTable.vue b/frontend/src/components/admin/usage/UsageTable.vue
index 63694925..87f7aeb7 100644
--- a/frontend/src/components/admin/usage/UsageTable.vue
+++ b/frontend/src/components/admin/usage/UsageTable.vue
@@ -38,11 +38,11 @@
-
+
{{ row.input_tokens?.toLocaleString() || 0 }}
-
+
{{ row.output_tokens?.toLocaleString() || 0 }}
@@ -87,7 +87,7 @@
{{ row.request_id }}
-
@@ -106,6 +106,7 @@ import { formatDateTime } from '@/utils/format'
import { useAppStore } from '@/stores/app'
import DataTable from '@/components/common/DataTable.vue'
import EmptyState from '@/components/common/EmptyState.vue'
+import Icon from '@/components/icons/Icon.vue'
defineProps(['data', 'loading'])
const { t } = useI18n()
diff --git a/frontend/src/components/admin/user/UserCreateModal.vue b/frontend/src/components/admin/user/UserCreateModal.vue
index 2f28bf52..f2ab1e02 100644
--- a/frontend/src/components/admin/user/UserCreateModal.vue
+++ b/frontend/src/components/admin/user/UserCreateModal.vue
@@ -17,7 +17,7 @@
@@ -52,6 +52,7 @@ import { reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'; import { adminAPI } from '@/api/admin'
import { useForm } from '@/composables/useForm'
import BaseDialog from '@/components/common/BaseDialog.vue'
+import Icon from '@/components/icons/Icon.vue'
const props = defineProps<{ show: boolean }>()
const emit = defineEmits(['close', 'success']); const { t } = useI18n()
diff --git a/frontend/src/components/admin/user/UserEditModal.vue b/frontend/src/components/admin/user/UserEditModal.vue
index 43f677d3..2c4b117a 100644
--- a/frontend/src/components/admin/user/UserEditModal.vue
+++ b/frontend/src/components/admin/user/UserEditModal.vue
@@ -21,7 +21,7 @@
@@ -59,6 +59,7 @@ import { adminAPI } from '@/api/admin'
import type { User, UserAttributeValuesMap } from '@/types'
import BaseDialog from '@/components/common/BaseDialog.vue'
import UserAttributeForm from '@/components/user/UserAttributeForm.vue'
+import Icon from '@/components/icons/Icon.vue'
const props = defineProps<{ show: boolean, user: User | null }>()
const emit = defineEmits(['close', 'success'])
@@ -106,4 +107,4 @@ const handleUpdateUser = async () => {
appStore.showError(e.response?.data?.detail || t('admin.users.failedToUpdate'))
} finally { submitting.value = false }
}
-
\ No newline at end of file
+
diff --git a/frontend/src/components/common/BaseDialog.vue b/frontend/src/components/common/BaseDialog.vue
index fab48fe0..3d38b568 100644
--- a/frontend/src/components/common/BaseDialog.vue
+++ b/frontend/src/components/common/BaseDialog.vue
@@ -21,15 +21,7 @@
class="-mr-2 rounded-xl p-2 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 dark:text-dark-500 dark:hover:bg-dark-700 dark:hover:text-dark-300"
aria-label="Close modal"
>
-
+
@@ -50,6 +42,7 @@
\ No newline at end of file
+
diff --git a/frontend/src/components/user/dashboard/UserDashboardRecentUsage.vue b/frontend/src/components/user/dashboard/UserDashboardRecentUsage.vue
index 56f361bb..a0605c76 100644
--- a/frontend/src/components/user/dashboard/UserDashboardRecentUsage.vue
+++ b/frontend/src/components/user/dashboard/UserDashboardRecentUsage.vue
@@ -15,9 +15,7 @@
{{ log.model }}
@@ -35,9 +33,7 @@
{{ t('dashboard.viewAllUsage') }}
-
+
@@ -48,6 +44,7 @@
import { useI18n } from 'vue-i18n'
import LoadingSpinner from '@/components/common/LoadingSpinner.vue'
import EmptyState from '@/components/common/EmptyState.vue'
+import Icon from '@/components/icons/Icon.vue'
import { formatDateTime } from '@/utils/format'
import type { UsageLog } from '@/types'
diff --git a/frontend/src/components/user/dashboard/UserDashboardStats.vue b/frontend/src/components/user/dashboard/UserDashboardStats.vue
index 6cf7e07f..d375ba88 100644
--- a/frontend/src/components/user/dashboard/UserDashboardStats.vue
+++ b/frontend/src/components/user/dashboard/UserDashboardStats.vue
@@ -21,9 +21,7 @@
{{ t('dashboard.apiKeys') }}
@@ -37,9 +35,7 @@
{{ t('dashboard.todayRequests') }}
@@ -53,9 +49,7 @@
{{ t('dashboard.todayCost') }}
@@ -79,9 +73,7 @@
{{ t('dashboard.todayTokens') }}
@@ -95,9 +87,7 @@
{{ t('dashboard.totalTokens') }}
@@ -111,9 +101,7 @@
{{ t('dashboard.performance') }}
@@ -133,9 +121,7 @@
{{ t('dashboard.avgResponse') }}
@@ -149,6 +135,7 @@