Commit 23412965 authored by IanShaw027's avatar IanShaw027
Browse files

feat(frontend): 优化弹窗组件架构和用户体验

- 使用 BaseDialog 替代旧版 Modal 组件
- 添加平滑过渡动画和更好的可访问性支持
- 新增 ExportProgressDialog 导出进度弹窗
- 优化所有账号管理和使用记录相关弹窗
- 更新国际化文案,改进用户交互体验
- 精简依赖,减少 package.json 体积
parent c01db6b1
...@@ -219,6 +219,7 @@ ...@@ -219,6 +219,7 @@
</template> </template>
<template #cell-tokens="{ row }"> <template #cell-tokens="{ row }">
<div class="flex items-center gap-1.5">
<div class="space-y-1.5 text-sm"> <div class="space-y-1.5 text-sm">
<!-- Input / Output Tokens --> <!-- Input / Output Tokens -->
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
...@@ -306,6 +307,29 @@ ...@@ -306,6 +307,29 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Token Detail Tooltip -->
<div
class="group relative"
@mouseenter="showTokenTooltip($event, row)"
@mouseleave="hideTokenTooltip"
>
<div
class="flex h-4 w-4 cursor-help items-center justify-center rounded-full bg-gray-100 transition-colors group-hover:bg-blue-100 dark:bg-gray-700 dark:group-hover:bg-blue-900/50"
>
<svg
class="h-3 w-3 text-gray-400 group-hover:text-blue-500 dark:text-gray-500 dark:group-hover:text-blue-400"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
</div>
</template> </template>
<template #cell-cost="{ row }"> <template #cell-cost="{ row }">
...@@ -392,6 +416,54 @@ ...@@ -392,6 +416,54 @@
</TablePageLayout> </TablePageLayout>
</AppLayout> </AppLayout>
<!-- Token Tooltip Portal -->
<Teleport to="body">
<div
v-if="tokenTooltipVisible"
class="fixed z-[9999] pointer-events-none -translate-y-1/2"
:style="{
left: tokenTooltipPosition.x + 'px',
top: tokenTooltipPosition.y + 'px'
}"
>
<div
class="whitespace-nowrap rounded-lg border border-gray-700 bg-gray-900 px-3 py-2.5 text-xs text-white shadow-xl dark:border-gray-600 dark:bg-gray-800"
>
<div class="space-y-1.5">
<!-- Token Breakdown -->
<div class="mb-2 border-b border-gray-700 pb-1.5">
<div class="text-xs font-semibold text-gray-300 mb-1">Token 明细</div>
<div v-if="tokenTooltipData && tokenTooltipData.input_tokens > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.inputTokens') }}</span>
<span class="font-medium text-white">{{ tokenTooltipData.input_tokens.toLocaleString() }}</span>
</div>
<div v-if="tokenTooltipData && tokenTooltipData.output_tokens > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.outputTokens') }}</span>
<span class="font-medium text-white">{{ tokenTooltipData.output_tokens.toLocaleString() }}</span>
</div>
<div v-if="tokenTooltipData && tokenTooltipData.cache_creation_tokens > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.cacheCreationTokens') }}</span>
<span class="font-medium text-white">{{ tokenTooltipData.cache_creation_tokens.toLocaleString() }}</span>
</div>
<div v-if="tokenTooltipData && tokenTooltipData.cache_read_tokens > 0" class="flex items-center justify-between gap-4">
<span class="text-gray-400">{{ t('admin.usage.cacheReadTokens') }}</span>
<span class="font-medium text-white">{{ tokenTooltipData.cache_read_tokens.toLocaleString() }}</span>
</div>
</div>
<!-- Total -->
<div class="flex items-center justify-between gap-6 border-t border-gray-700 pt-1.5">
<span class="text-gray-400">{{ t('usage.totalTokens') }}</span>
<span class="font-semibold text-blue-400">{{ ((tokenTooltipData?.input_tokens || 0) + (tokenTooltipData?.output_tokens || 0) + (tokenTooltipData?.cache_creation_tokens || 0) + (tokenTooltipData?.cache_read_tokens || 0)).toLocaleString() }}</span>
</div>
</div>
<!-- Tooltip Arrow (left side) -->
<div
class="absolute right-full top-1/2 h-0 w-0 -translate-y-1/2 border-b-[6px] border-r-[6px] border-t-[6px] border-b-transparent border-r-gray-900 border-t-transparent dark:border-r-gray-800"
></div>
</div>
</div>
</Teleport>
<!-- Tooltip Portal --> <!-- Tooltip Portal -->
<Teleport to="body"> <Teleport to="body">
<div <div
...@@ -458,6 +530,11 @@ const tooltipVisible = ref(false) ...@@ -458,6 +530,11 @@ const tooltipVisible = ref(false)
const tooltipPosition = ref({ x: 0, y: 0 }) const tooltipPosition = ref({ x: 0, y: 0 })
const tooltipData = ref<UsageLog | null>(null) const tooltipData = ref<UsageLog | null>(null)
// Token tooltip state
const tokenTooltipVisible = ref(false)
const tokenTooltipPosition = ref({ x: 0, y: 0 })
const tokenTooltipData = ref<UsageLog | null>(null)
// Usage stats from API // Usage stats from API
const usageStats = ref<UsageStatsResponse | null>(null) const usageStats = ref<UsageStatsResponse | null>(null)
...@@ -778,6 +855,22 @@ const hideTooltip = () => { ...@@ -778,6 +855,22 @@ const hideTooltip = () => {
tooltipData.value = null tooltipData.value = null
} }
// Token tooltip functions
const showTokenTooltip = (event: MouseEvent, row: UsageLog) => {
const target = event.currentTarget as HTMLElement
const rect = target.getBoundingClientRect()
tokenTooltipData.value = row
tokenTooltipPosition.value.x = rect.right + 8
tokenTooltipPosition.value.y = rect.top + rect.height / 2
tokenTooltipVisible.value = true
}
const hideTokenTooltip = () => {
tokenTooltipVisible.value = false
tokenTooltipData.value = null
}
onMounted(() => { onMounted(() => {
loadApiKeys() loadApiKeys()
loadUsageLogs() loadUsageLogs()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment