mirror of
https://github.com/fawney19/Aether.git
synced 2026-01-02 15:52:26 +08:00
refactor(frontend): optimize feature components (models, providers, usage)
This commit is contained in:
@@ -14,12 +14,12 @@
|
||||
/>
|
||||
|
||||
<!-- 抽屉内容 -->
|
||||
<Card class="relative h-full w-[700px] rounded-none shadow-2xl overflow-y-auto">
|
||||
<div class="sticky top-0 z-10 bg-background border-b p-6">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<Card class="relative h-full w-full sm:w-[700px] sm:max-w-[90vw] rounded-none shadow-2xl overflow-y-auto">
|
||||
<div class="sticky top-0 z-10 bg-background border-b p-4 sm:p-6">
|
||||
<div class="flex items-start justify-between gap-3 sm:gap-4">
|
||||
<div class="space-y-1 flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<h3 class="text-xl font-bold truncate">
|
||||
<h3 class="text-lg sm:text-xl font-bold truncate">
|
||||
{{ model.display_name }}
|
||||
</h3>
|
||||
<Badge
|
||||
@@ -76,12 +76,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6">
|
||||
<div class="p-4 sm:p-6">
|
||||
<!-- 自定义 Tab 切换 -->
|
||||
<div class="flex gap-1 p-1 bg-muted/40 rounded-lg mb-4">
|
||||
<button
|
||||
type="button"
|
||||
class="flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all duration-200"
|
||||
class="flex-1 px-2 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all duration-200"
|
||||
:class="[
|
||||
detailTab === 'basic'
|
||||
? 'bg-primary text-primary-foreground shadow-sm'
|
||||
@@ -93,7 +93,7 @@
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all duration-200"
|
||||
class="flex-1 px-2 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all duration-200"
|
||||
:class="[
|
||||
detailTab === 'providers'
|
||||
? 'bg-primary text-primary-foreground shadow-sm'
|
||||
@@ -101,11 +101,12 @@
|
||||
]"
|
||||
@click="detailTab = 'providers'"
|
||||
>
|
||||
关联提供商
|
||||
<span class="hidden sm:inline">关联提供商</span>
|
||||
<span class="sm:hidden">提供商</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="flex-1 px-4 py-2 text-sm font-medium rounded-md transition-all duration-200"
|
||||
class="flex-1 px-2 sm:px-4 py-2 text-xs sm:text-sm font-medium rounded-md transition-all duration-200"
|
||||
:class="[
|
||||
detailTab === 'aliases'
|
||||
? 'bg-primary text-primary-foreground shadow-sm'
|
||||
@@ -113,7 +114,8 @@
|
||||
]"
|
||||
@click="detailTab = 'aliases'"
|
||||
>
|
||||
别名/映射
|
||||
<span class="hidden sm:inline">别名/映射</span>
|
||||
<span class="sm:hidden">别名</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -142,7 +144,7 @@
|
||||
<h4 class="font-semibold text-sm">
|
||||
模型能力
|
||||
</h4>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div class="flex items-center gap-2 p-3 rounded-lg border">
|
||||
<Zap class="w-5 h-5 text-muted-foreground" />
|
||||
<div class="flex-1">
|
||||
@@ -262,7 +264,7 @@
|
||||
v-if="getTierCount(model.default_tiered_pricing) <= 1"
|
||||
class="space-y-3"
|
||||
>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="grid grid-cols-2 sm:grid-cols-2 gap-3">
|
||||
<!-- 按 Token 计费 -->
|
||||
<div class="p-3 rounded-lg border">
|
||||
<Label class="text-xs text-muted-foreground">输入价格 ($/M)</Label>
|
||||
@@ -463,7 +465,9 @@
|
||||
<Loader2 class="w-6 h-6 animate-spin text-primary" />
|
||||
</div>
|
||||
|
||||
<Table v-else-if="providers.length > 0">
|
||||
<template v-else-if="providers.length > 0">
|
||||
<!-- 桌面端表格 -->
|
||||
<Table class="hidden sm:table">
|
||||
<TableHeader>
|
||||
<TableRow class="border-b border-border/60 hover:bg-transparent">
|
||||
<TableHead class="h-10 font-semibold">
|
||||
@@ -591,11 +595,79 @@
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="sm:hidden divide-y divide-border/40">
|
||||
<div
|
||||
v-for="provider in providers"
|
||||
:key="provider.id"
|
||||
class="p-4 space-y-3"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span
|
||||
class="w-2 h-2 rounded-full shrink-0"
|
||||
:class="provider.is_active ? 'bg-green-500' : 'bg-gray-300'"
|
||||
/>
|
||||
<span class="font-medium truncate">{{ provider.display_name }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('editProvider', provider)"
|
||||
>
|
||||
<Edit class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('toggleProviderStatus', provider)"
|
||||
>
|
||||
<Power class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('deleteProvider', provider)"
|
||||
>
|
||||
<Trash2 class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 text-xs">
|
||||
<div class="flex gap-1">
|
||||
<Zap
|
||||
v-if="provider.supports_streaming"
|
||||
class="w-3.5 h-3.5 text-muted-foreground"
|
||||
/>
|
||||
<Eye
|
||||
v-if="provider.supports_vision"
|
||||
class="w-3.5 h-3.5 text-muted-foreground"
|
||||
/>
|
||||
<Wrench
|
||||
v-if="provider.supports_function_calling"
|
||||
class="w-3.5 h-3.5 text-muted-foreground"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="(provider.input_price_per_1m || 0) > 0 || (provider.output_price_per_1m || 0) > 0"
|
||||
class="text-muted-foreground font-mono"
|
||||
>
|
||||
${{ (provider.input_price_per_1m || 0).toFixed(1) }}/${{ (provider.output_price_per_1m || 0).toFixed(1) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="text-center py-12"
|
||||
>
|
||||
<!-- 空状态 -->
|
||||
<Building2 class="w-12 h-12 mx-auto text-muted-foreground/30 mb-3" />
|
||||
<p class="text-sm text-muted-foreground">
|
||||
暂无关联提供商
|
||||
@@ -658,7 +730,9 @@
|
||||
<Loader2 class="w-6 h-6 animate-spin text-primary" />
|
||||
</div>
|
||||
|
||||
<Table v-else-if="aliases.length > 0">
|
||||
<template v-else-if="aliases.length > 0">
|
||||
<!-- 桌面端表格 -->
|
||||
<Table class="hidden sm:table">
|
||||
<TableHeader>
|
||||
<TableRow class="border-b border-border/60 hover:bg-transparent">
|
||||
<TableHead class="h-10 font-semibold">
|
||||
@@ -751,11 +825,79 @@
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<!-- 移动端卡片列表 -->
|
||||
<div class="sm:hidden divide-y divide-border/40">
|
||||
<div
|
||||
v-for="alias in aliases"
|
||||
:key="alias.id"
|
||||
class="p-4 space-y-2"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex items-center gap-2 min-w-0 flex-1">
|
||||
<span
|
||||
class="w-2 h-2 rounded-full shrink-0"
|
||||
:class="alias.is_active ? 'bg-green-500' : 'bg-gray-300'"
|
||||
/>
|
||||
<code class="text-sm font-medium bg-muted px-1.5 py-0.5 rounded truncate">{{ alias.alias }}</code>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('editAlias', alias)"
|
||||
>
|
||||
<Edit class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('toggleAliasStatus', alias)"
|
||||
>
|
||||
<Power class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="h-7 w-7"
|
||||
@click="$emit('deleteAlias', alias)"
|
||||
>
|
||||
<Trash2 class="w-3.5 h-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
class="text-xs"
|
||||
>
|
||||
{{ alias.mapping_type === 'mapping' ? '映射' : '别名' }}
|
||||
</Badge>
|
||||
<Badge
|
||||
v-if="alias.provider_id"
|
||||
variant="outline"
|
||||
class="text-xs truncate max-w-[120px]"
|
||||
>
|
||||
{{ alias.provider_name || 'Provider' }}
|
||||
</Badge>
|
||||
<Badge
|
||||
v-else
|
||||
variant="default"
|
||||
class="text-xs"
|
||||
>
|
||||
全局
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="text-center py-12"
|
||||
>
|
||||
<!-- 空状态 -->
|
||||
<Tag class="w-12 h-12 mx-auto text-muted-foreground/30 mb-3" />
|
||||
<p class="text-sm text-muted-foreground">
|
||||
暂无别名或映射
|
||||
|
||||
@@ -74,12 +74,12 @@
|
||||
:key="monitor.api_format"
|
||||
class="border border-border/60 rounded-lg p-4 hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<!-- 左右结构布局 -->
|
||||
<div class="flex gap-6 items-center">
|
||||
<!-- 左侧:信息区域 -->
|
||||
<div class="w-44 flex-shrink-0 space-y-1.5">
|
||||
<!-- 响应式布局:窄屏上下两行,宽屏左右结构 -->
|
||||
<div class="flex flex-col sm:flex-row sm:gap-6 sm:items-center">
|
||||
<!-- 第一行/左侧:信息区域 -->
|
||||
<div class="sm:w-44 flex-shrink-0 space-y-1.5 mb-3 sm:mb-0">
|
||||
<!-- API 格式标签和成功率 -->
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<Badge
|
||||
variant="outline"
|
||||
class="font-mono text-xs"
|
||||
@@ -93,20 +93,27 @@
|
||||
>
|
||||
{{ (monitor.success_rate * 100).toFixed(0) }}%
|
||||
</Badge>
|
||||
<!-- 提供商信息(仅管理员可见)- 窄屏时显示在同一行 -->
|
||||
<span
|
||||
v-if="showProviderInfo && 'provider_count' in monitor"
|
||||
class="text-xs text-muted-foreground sm:hidden"
|
||||
>
|
||||
{{ monitor.provider_count }} 个提供商 / {{ monitor.key_count }} 个密钥
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 提供商信息(仅管理员可见) -->
|
||||
<!-- 提供商信息(仅管理员可见)- 宽屏时显示在下方 -->
|
||||
<div
|
||||
v-if="showProviderInfo && 'provider_count' in monitor"
|
||||
class="text-xs text-muted-foreground"
|
||||
class="text-xs text-muted-foreground hidden sm:block"
|
||||
>
|
||||
{{ monitor.provider_count }} 个提供商 / {{ monitor.key_count }} 个密钥
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:时间线区域 -->
|
||||
<div class="flex-1 min-w-0 flex justify-end">
|
||||
<div class="w-full max-w-5xl">
|
||||
<!-- 第二行/右侧:时间线区域 -->
|
||||
<div class="flex-1 min-w-0 sm:flex sm:justify-end">
|
||||
<div class="w-full sm:max-w-5xl">
|
||||
<EndpointHealthTimeline
|
||||
:monitor="monitor"
|
||||
:lookback-hours="parseInt(lookbackHours)"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
/>
|
||||
|
||||
<!-- 抽屉内容 -->
|
||||
<Card class="relative h-full w-[700px] rounded-none shadow-2xl overflow-y-auto">
|
||||
<Card class="relative h-full w-full sm:w-[700px] sm:max-w-[90vw] rounded-none shadow-2xl overflow-y-auto">
|
||||
<!-- 加载状态 -->
|
||||
<div
|
||||
v-if="loading"
|
||||
@@ -25,11 +25,11 @@
|
||||
|
||||
<template v-else-if="provider">
|
||||
<!-- 头部:名称 + 快捷操作 -->
|
||||
<div class="sticky top-0 z-10 bg-background border-b p-6">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="sticky top-0 z-10 bg-background border-b p-4 sm:p-6">
|
||||
<div class="flex items-start justify-between gap-3 sm:gap-4">
|
||||
<div class="space-y-1 flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-xl font-bold truncate">
|
||||
<h2 class="text-lg sm:text-xl font-bold truncate">
|
||||
{{ provider.display_name }}
|
||||
</h2>
|
||||
<Badge
|
||||
@@ -84,7 +84,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6 p-6">
|
||||
<div class="space-y-6 p-4 sm:p-6">
|
||||
<!-- 配额使用情况 -->
|
||||
<Card
|
||||
v-if="provider.billing_type === 'monthly_quota' && provider.monthly_quota_usd"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<Card class="p-4 !overflow-visible">
|
||||
<Card class="p-4 overflow-hidden">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<p class="text-sm font-semibold">
|
||||
{{ title }}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:model-value="selectedPeriod"
|
||||
@update:model-value="$emit('update:selectedPeriod', $event)"
|
||||
>
|
||||
<SelectTrigger class="w-32 h-8 text-xs border-border/60">
|
||||
<SelectTrigger class="w-24 sm:w-32 h-8 text-xs border-border/60">
|
||||
<SelectValue placeholder="选择时间段" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -30,7 +30,7 @@
|
||||
</Select>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-4 w-px bg-border" />
|
||||
<div class="hidden sm:block h-4 w-px bg-border" />
|
||||
|
||||
<!-- 用户筛选(仅管理员可见) -->
|
||||
<Select
|
||||
@@ -39,7 +39,7 @@
|
||||
:model-value="filterUser"
|
||||
@update:model-value="$emit('update:filterUser', $event)"
|
||||
>
|
||||
<SelectTrigger class="w-36 h-8 text-xs border-border/60">
|
||||
<SelectTrigger class="w-24 sm:w-36 h-8 text-xs border-border/60">
|
||||
<SelectValue placeholder="全部用户" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -62,7 +62,7 @@
|
||||
:model-value="filterModel"
|
||||
@update:model-value="$emit('update:filterModel', $event)"
|
||||
>
|
||||
<SelectTrigger class="w-40 h-8 text-xs border-border/60">
|
||||
<SelectTrigger class="w-24 sm:w-40 h-8 text-xs border-border/60">
|
||||
<SelectValue placeholder="全部模型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -85,7 +85,7 @@
|
||||
:model-value="filterProvider"
|
||||
@update:model-value="$emit('update:filterProvider', $event)"
|
||||
>
|
||||
<SelectTrigger class="w-32 h-8 text-xs border-border/60">
|
||||
<SelectTrigger class="w-24 sm:w-32 h-8 text-xs border-border/60">
|
||||
<SelectValue placeholder="全部提供商" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -108,7 +108,7 @@
|
||||
:model-value="filterStatus"
|
||||
@update:model-value="$emit('update:filterStatus', $event)"
|
||||
>
|
||||
<SelectTrigger class="w-28 h-8 text-xs border-border/60">
|
||||
<SelectTrigger class="w-20 sm:w-28 h-8 text-xs border-border/60">
|
||||
<SelectValue placeholder="全部状态" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -134,7 +134,7 @@
|
||||
</Select>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-4 w-px bg-border" />
|
||||
<div class="hidden sm:block h-4 w-px bg-border" />
|
||||
|
||||
<!-- 刷新按钮 -->
|
||||
<RefreshButton
|
||||
|
||||
Reference in New Issue
Block a user