refactor(frontend): 优化管理后台视图

- 改进 AliasManagement, ApiKeys, AuditLogs, CacheMonitoring, ModelManagement, SystemSettings, Users 页面
This commit is contained in:
fawney19
2025-12-12 20:22:15 +08:00
parent 36a84e19b4
commit 15b4f665d1
7 changed files with 33 additions and 71 deletions

View File

@@ -252,6 +252,7 @@ import {
} from '@/api/endpoints/aliases'
import { listGlobalModels, type GlobalModelResponse } from '@/api/global-models'
import { getProvidersSummary } from '@/api/endpoints/providers'
import { log } from '@/utils/logger'
const { success, error: showError } = useToast()
const { confirmDanger } = useConfirm()
@@ -332,7 +333,7 @@ async function loadGlobalModelsList() {
const response = await listGlobalModels()
globalModels.value = response.models || []
} catch (err: any) {
console.error('加载模型失败:', err)
log.error('加载模型失败:', err)
}
}

View File

@@ -689,6 +689,7 @@ import {
import { StandaloneKeyFormDialog, type StandaloneKeyFormData } from '@/features/api-keys'
import { parseNumberInput } from '@/utils/form'
import { log } from '@/utils/logger'
const { success, error } = useToast()
const { confirmDanger } = useConfirm()
@@ -803,7 +804,7 @@ async function loadApiKeys() {
apiKeys.value = response.api_keys
total.value = response.total
} catch (err: any) {
console.error('加载独立Keys失败:', err)
log.error('加载独立Keys失败:', err)
error(err.response?.data?.detail || '加载独立 Keys 失败')
} finally {
loading.value = false
@@ -824,7 +825,7 @@ async function toggleApiKey(apiKey: AdminApiKey) {
}
success(response.message)
} catch (err: any) {
console.error('切换密钥状态失败:', err)
log.error('切换密钥状态失败:', err)
error(err.response?.data?.detail || '操作失败')
}
}
@@ -843,7 +844,7 @@ async function deleteApiKey(apiKey: AdminApiKey) {
total.value = total.value - 1
success(response.message)
} catch (err: any) {
console.error('删除密钥失败:', err)
log.error('删除密钥失败:', err)
error(err.response?.data?.detail || '删除失败')
}
}
@@ -916,7 +917,7 @@ async function handleAddBalance() {
const amount = Math.abs(addBalanceAmount.value).toFixed(2)
success(response.message || `余额${action}成功,${action} $${amount}`)
} catch (err: any) {
console.error('余额调整失败:', err)
log.error('余额调整失败:', err)
error(err.response?.data?.detail || '调整失败')
} finally {
addingBalance.value = false
@@ -931,7 +932,7 @@ async function copyKey() {
try {
await navigator.clipboard.writeText(newKeyValue.value)
success('API Key 已复制到剪贴板')
} catch (err) {
} catch {
error('复制失败,请手动复制')
}
}
@@ -943,7 +944,7 @@ async function copyKeyPrefix(apiKey: AdminApiKey) {
await navigator.clipboard.writeText(response.key)
success('完整密钥已复制到剪贴板')
} catch (err) {
console.error('复制密钥失败:', err)
log.error('复制密钥失败:', err)
error('复制失败,请重试')
}
}
@@ -1077,7 +1078,7 @@ async function handleKeyFormSubmit(data: StandaloneKeyFormData) {
closeKeyFormDialog()
await loadApiKeys()
} catch (err: any) {
console.error('保存独立Key失败:', err)
log.error('保存独立Key失败:', err)
error(err.response?.data?.detail || '保存失败')
} finally {
keyFormDialogRef.value?.setSaving(false)

View File

@@ -460,7 +460,7 @@ async function loadLogs() {
logs.value = data.items || []
totalRecords.value = data.meta?.total ?? logs.value.length
} catch (error) {
console.error('获取审计日志失败:', error)
log.error('获取审计日志失败:', error)
logs.value = []
totalRecords.value = 0
} finally {
@@ -472,19 +472,6 @@ function refreshLogs() {
loadLogs()
}
function clearFilters() {
filters.value = {
userId: '',
eventType: '__all__',
days: 7,
limit: 50
}
filtersDaysString.value = '7'
filtersLimitString.value = '50'
currentPage.value = 1
loadLogs()
}
// 搜索变化处理
function handleSearchChange() {
filters.value.userId = searchQuery.value
@@ -519,12 +506,6 @@ function handleDaysChange(value: string) {
resetAndLoad()
}
function handleLimitChange(value: string) {
filtersLimitString.value = value
filters.value.limit = parseInt(value)
loadLogs()
}
function resetAndLoad() {
currentPage.value = 1
loadLogs()
@@ -578,12 +559,13 @@ async function exportLogs() {
link.download = `audit-logs-${new Date().toISOString().split('T')[0]}.csv`
link.click()
} catch (error) {
console.error('导出失败:', error)
log.error('导出失败:', error)
}
}
// 使用复用的行点击逻辑
import { useRowClick } from '@/composables/useRowClick'
import { log } from '@/utils/logger'
const { handleMouseDown, shouldTriggerRowClick } = useRowClick()
function handleRowClick(event: MouseEvent, log: AuditLog) {

View File

@@ -31,6 +31,7 @@ import {
getFrequencyLabel,
getFrequencyClass
} from '@/composables/useTTLAnalysis'
import { log } from '@/utils/logger'
// ==================== 缓存统计与亲和性列表 ====================
@@ -84,7 +85,7 @@ async function fetchCacheStats() {
stats.value = await cacheApi.getStats()
} catch (error) {
showError('获取缓存统计失败')
console.error(error)
log.error('获取缓存统计失败', error)
} finally {
loading.value = false
}
@@ -94,7 +95,7 @@ async function fetchCacheConfig() {
try {
config.value = await cacheApi.getConfig()
} catch (error) {
console.error(error)
log.error('获取缓存配置失败', error)
}
}
@@ -110,7 +111,7 @@ async function fetchAffinityList(keyword?: string) {
}
} catch (error) {
showError('获取缓存列表失败')
console.error(error)
log.error('获取缓存列表失败', error)
} finally {
listLoading.value = false
}
@@ -159,7 +160,7 @@ async function clearUserCache(identifier: string, displayName?: string) {
await fetchAffinityList(tableKeyword.value.trim() || undefined)
} catch (error) {
showError('清除失败')
console.error(error)
log.error('清除用户缓存失败', error)
} finally {
clearingRowAffinityKey.value = null
}
@@ -189,7 +190,7 @@ async function clearAllCache() {
await fetchAffinityList(tableKeyword.value.trim() || undefined)
} catch (error) {
showError('清除失败')
console.error(error)
log.error('清除所有缓存失败', error)
}
}

View File

@@ -664,6 +664,7 @@ import {
batchAssignToProviders,
type GlobalModelResponse,
} from '@/api/global-models'
import { log } from '@/utils/logger'
import {
getAliases,
createAlias,
@@ -997,7 +998,7 @@ async function loadGlobalModels() {
// API 返回 { models: [...], total: number }
globalModels.value = response.models || []
} catch (err: any) {
console.error('加载模型失败:', err)
log.error('加载模型失败:', err)
showError(err.response?.data?.detail || err.message, '加载模型失败')
} finally {
loading.value = false
@@ -1075,7 +1076,7 @@ async function loadModelProviders(_globalModelId: string) {
selectedModelProviders.value = []
}
} catch (err: any) {
console.error('加载关联提供商失败:', err)
log.error('加载关联提供商失败:', err)
showError(parseApiError(err, '加载关联提供商失败'), '错误')
selectedModelProviders.value = []
} finally {
@@ -1090,7 +1091,7 @@ async function loadModelAliases(globalModelId: string) {
const aliases = await getAliases({ limit: 1000 })
selectedModelAliases.value = aliases.filter(a => a.global_model_id === globalModelId)
} catch (err: any) {
console.error('加载别名失败:', err)
log.error('加载别名失败:', err)
selectedModelAliases.value = []
} finally {
loadingModelAliases.value = false
@@ -1295,12 +1296,6 @@ async function loadAliases() {
}
}
function openCreateAliasDialog() {
editingAliasId.value = null
isTargetModelFixed.value = false // 目标模型需要选择
createAliasDialogOpen.value = true
}
function openEditAliasDialog(alias: ModelAlias) {
editingAliasId.value = alias.id
isTargetModelFixed.value = false
@@ -1409,7 +1404,7 @@ async function loadCapabilities() {
try {
capabilities.value = await getAllCapabilities()
} catch (err) {
console.error('Failed to load capabilities:', err)
log.error('Failed to load capabilities:', err)
}
}

View File

@@ -392,6 +392,7 @@ import SelectItem from '@/components/ui/select-item.vue'
import { PageHeader, PageContainer, CardSection } from '@/components/layout'
import { useToast } from '@/composables/useToast'
import { adminApi } from '@/api/admin'
import { log } from '@/utils/logger'
const { success, error } = useToast()
@@ -508,13 +509,13 @@ async function loadSystemConfig() {
if (response.value !== null && response.value !== undefined) {
(systemConfig.value as any)[key] = response.value
}
} catch (err) {
} catch {
// 配置不存在时使用默认值,无需处理
}
}
} catch (err) {
error('加载系统配置失败')
console.error('加载系统配置失败:', err)
log.error('加载系统配置失败:', err)
}
}
@@ -617,7 +618,7 @@ async function saveSystemConfig() {
success('系统配置已保存')
} catch (err) {
error('保存配置失败')
console.error('保存配置失败:', err)
log.error('保存配置失败:', err)
} finally {
loading.value = false
}

View File

@@ -678,6 +678,7 @@ import {
// 功能组件
import UserFormDialog, { type UserFormData } from '@/features/users/components/UserFormDialog.vue'
import { log } from '@/utils/logger'
const { success, error } = useToast()
const { confirmDanger, confirmWarning } = useConfirm()
@@ -775,7 +776,7 @@ async function loadUserStats() {
return acc
}, {})
} catch (err) {
console.error('加载用户统计失败:', err)
log.error('加载用户统计失败:', err)
} finally {
loadingStats.value = false
}
@@ -900,7 +901,7 @@ async function loadUserApiKeys(userId: string) {
try {
userApiKeys.value = await usersStore.getUserApiKeys(userId)
} catch (err) {
console.error('加载API Keys失败:', err)
log.error('加载API Keys失败:', err)
userApiKeys.value = []
}
}
@@ -932,7 +933,7 @@ async function copyApiKey() {
try {
await navigator.clipboard.writeText(newApiKey.value)
success('API Key已复制到剪贴板')
} catch (err) {
} catch {
error('复制失败,请手动复制')
}
}
@@ -966,7 +967,7 @@ async function copyFullKey(apiKey: any) {
await navigator.clipboard.writeText(response.key)
success('完整密钥已复制到剪贴板')
} catch (err: any) {
console.error('复制密钥失败:', err)
log.error('复制密钥失败:', err)
error(err.response?.data?.detail || '未知错误', '复制密钥失败')
}
}
@@ -1002,24 +1003,4 @@ async function deleteUser(user: any) {
error(err.response?.data?.detail || '未知错误', '删除用户失败')
}
}
function getRelativeTime(dateString: string): string {
const date = new Date(dateString)
const now = new Date()
const diff = now.getTime() - date.getTime()
const seconds = Math.floor(diff / 1000)
const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
const months = Math.floor(days / 30)
const years = Math.floor(days / 365)
if (years > 0) return `${years}年前`
if (months > 0) return `${months}月前`
if (days > 0) return `${days}天前`
if (hours > 0) return `${hours}小时前`
if (minutes > 0) return `${minutes}分钟前`
return '刚刚'
}
</script>