mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 09:50:21 +08:00
feat(ui): 新增模型请求链路预览功能
- 添加后端 API 获取 GlobalModel 的请求链路信息 (/api/admin/models/global/{id}/routing)
- 新增 RoutingTab 组件展示模型的请求链路树状结构
- 支持全局 Key 优先和提供商优先两种模式的可视化
- 重构批量模型管理对话框为单列勾选模式
- 修复 errorParser.ts 字符串拼接格式问题
- 若干 Vue 模板格式优化
This commit is contained in:
@@ -107,8 +107,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-medium truncate">{{ model.display_name }}</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">{{ model.name }}</p>
|
||||
<p class="text-sm font-medium truncate">
|
||||
{{ model.display_name }}
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">
|
||||
{{ model.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,8 +163,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-medium truncate">{{ model.id }}</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">{{ model.owned_by || model.id }}</p>
|
||||
<p class="text-sm font-medium truncate">
|
||||
{{ model.id }}
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">
|
||||
{{ model.owned_by || model.id }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -172,7 +180,9 @@
|
||||
class="flex flex-col items-center justify-center py-12 text-muted-foreground"
|
||||
>
|
||||
<Layers class="w-10 h-10 mb-2 opacity-30" />
|
||||
<p class="text-sm">{{ searchQuery ? '无匹配结果' : '暂无可用模型' }}</p>
|
||||
<p class="text-sm">
|
||||
{{ searchQuery ? '无匹配结果' : '暂无可用模型' }}
|
||||
</p>
|
||||
<p
|
||||
v-if="!upstreamModelsLoaded"
|
||||
class="text-xs mt-1"
|
||||
|
||||
@@ -76,7 +76,10 @@
|
||||
</div>
|
||||
|
||||
<!-- 模型列表 -->
|
||||
<div v-else class="space-y-2">
|
||||
<div
|
||||
v-else
|
||||
class="space-y-2"
|
||||
>
|
||||
<!-- 全选/取消 -->
|
||||
<div class="flex items-center justify-between px-1">
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
@@ -131,7 +131,10 @@
|
||||
class="w-4 h-4 border rounded flex items-center justify-center shrink-0"
|
||||
:class="selectedModels.includes(model) ? 'bg-primary border-primary' : ''"
|
||||
>
|
||||
<Check v-if="selectedModels.includes(model)" class="w-3 h-3 text-primary-foreground" />
|
||||
<Check
|
||||
v-if="selectedModels.includes(model)"
|
||||
class="w-3 h-3 text-primary-foreground"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm font-mono truncate">{{ model }}</span>
|
||||
</div>
|
||||
@@ -174,18 +177,28 @@
|
||||
class="w-4 h-4 border rounded flex items-center justify-center shrink-0"
|
||||
:class="selectedModels.includes(model.name) ? 'bg-primary border-primary' : ''"
|
||||
>
|
||||
<Check v-if="selectedModels.includes(model.name)" class="w-3 h-3 text-primary-foreground" />
|
||||
<Check
|
||||
v-if="selectedModels.includes(model.name)"
|
||||
class="w-3 h-3 text-primary-foreground"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm font-medium truncate">{{ model.display_name }}</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">{{ model.name }}</p>
|
||||
<p class="text-sm font-medium truncate">
|
||||
{{ model.display_name }}
|
||||
</p>
|
||||
<p class="text-xs text-muted-foreground truncate font-mono">
|
||||
{{ model.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上游模型组 -->
|
||||
<div v-for="group in filteredUpstreamGroups" :key="group.api_format">
|
||||
<div
|
||||
v-for="group in filteredUpstreamGroups"
|
||||
:key="group.api_format"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between px-3 py-2 bg-muted sticky top-0 z-10 cursor-pointer hover:bg-muted/80 transition-colors"
|
||||
@click="toggleGroupCollapse(group.api_format)"
|
||||
@@ -222,7 +235,10 @@
|
||||
class="w-4 h-4 border rounded flex items-center justify-center shrink-0"
|
||||
:class="selectedModels.includes(model.id) ? 'bg-primary border-primary' : ''"
|
||||
>
|
||||
<Check v-if="selectedModels.includes(model.id)" class="w-3 h-3 text-primary-foreground" />
|
||||
<Check
|
||||
v-if="selectedModels.includes(model.id)"
|
||||
class="w-3 h-3 text-primary-foreground"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-sm font-mono truncate">{{ model.id }}</span>
|
||||
</div>
|
||||
@@ -235,8 +251,15 @@
|
||||
class="flex flex-col items-center justify-center py-12 text-muted-foreground"
|
||||
>
|
||||
<Shield class="w-10 h-10 mb-2 opacity-30" />
|
||||
<p class="text-sm">{{ searchQuery ? '无匹配结果' : '暂无可选模型' }}</p>
|
||||
<p v-if="!upstreamModelsLoaded" class="text-xs mt-1">点击闪电按钮从上游获取模型</p>
|
||||
<p class="text-sm">
|
||||
{{ searchQuery ? '无匹配结果' : '暂无可选模型' }}
|
||||
</p>
|
||||
<p
|
||||
v-if="!upstreamModelsLoaded"
|
||||
class="text-xs mt-1"
|
||||
>
|
||||
点击闪电按钮从上游获取模型
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -250,10 +273,18 @@
|
||||
{{ hasChanges ? '有未保存的更改' : '' }}
|
||||
</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button :disabled="saving || !hasChanges" @click="handleSave">
|
||||
<Button
|
||||
:disabled="saving || !hasChanges"
|
||||
@click="handleSave"
|
||||
>
|
||||
{{ saving ? '保存中...' : '保存' }}
|
||||
</Button>
|
||||
<Button variant="outline" @click="handleCancel">取消</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@click="handleCancel"
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -83,7 +83,10 @@
|
||||
</div>
|
||||
<!-- 端点 API 格式 -->
|
||||
<div class="flex items-center gap-1.5 flex-wrap mt-3">
|
||||
<template v-for="endpoint in endpoints" :key="endpoint.id">
|
||||
<template
|
||||
v-for="endpoint in endpoints"
|
||||
:key="endpoint.id"
|
||||
>
|
||||
<span
|
||||
class="text-xs px-2 py-0.5 rounded-md border border-border bg-background hover:bg-accent hover:border-accent-foreground/20 cursor-pointer transition-colors font-medium"
|
||||
:class="{ 'opacity-40': !endpoint.is_active }"
|
||||
@@ -324,7 +327,10 @@
|
||||
v-for="(format, idx) in getKeyApiFormats(key, endpoint)"
|
||||
:key="format"
|
||||
>
|
||||
<span v-if="idx > 0" class="text-muted-foreground/40">/</span>
|
||||
<span
|
||||
v-if="idx > 0"
|
||||
class="text-muted-foreground/40"
|
||||
>/</span>
|
||||
<span>{{ API_FORMAT_SHORT[format] || format }} {{ getKeyRateMultiplier(key, format) }}x</span>
|
||||
</template>
|
||||
<span v-if="key.rate_limit">| {{ key.rate_limit }}rpm</span>
|
||||
|
||||
@@ -68,9 +68,15 @@
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="monthly_quota">月卡额度</SelectItem>
|
||||
<SelectItem value="pay_as_you_go">按量付费</SelectItem>
|
||||
<SelectItem value="free_tier">免费套餐</SelectItem>
|
||||
<SelectItem value="monthly_quota">
|
||||
月卡额度
|
||||
</SelectItem>
|
||||
<SelectItem value="pay_as_you_go">
|
||||
按量付费
|
||||
</SelectItem>
|
||||
<SelectItem value="free_tier">
|
||||
免费套餐
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user