mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-03 01:40:21 +08:00
feat(pool,priority): 号池聚合显示、API 格式归一化与优先级管理重构
- 优先级管理对话框按 family 分组显示 API 格式,号池 key 聚合为单条目展示 - 拖拽排序改用 key ID 替代数组索引,号池聚合项禁用拖拽/编辑/开关操作 - 后端 key 分组查询增加 API 格式键归一化,返回 provider_id - 提取 OAuth auth_config 解密逻辑,新增 _derive_oauth_expires_at 从加密配置派生过期时间 - 号池管理移除会话列,调整 OAuth 过期信息与刷新按钮的布局顺序
This commit is contained in:
@@ -294,9 +294,6 @@
|
||||
<TableHead class="w-24 font-semibold whitespace-nowrap">
|
||||
状态
|
||||
</TableHead>
|
||||
<TableHead class="w-20 font-semibold text-center whitespace-nowrap">
|
||||
会话
|
||||
</TableHead>
|
||||
<TableHead class="w-24 font-semibold whitespace-nowrap">
|
||||
最后使用
|
||||
</TableHead>
|
||||
@@ -347,18 +344,6 @@
|
||||
{{ key.auth_type === 'oauth' ? '[OAuth Token]' : (key.auth_type === 'service_account' ? '[Service Account]' : '[Key]') }}
|
||||
</span>
|
||||
<template v-if="key.auth_type === 'oauth'">
|
||||
<span
|
||||
v-if="getKeyOAuthExpires(key)"
|
||||
class="text-[10px]"
|
||||
:class="{
|
||||
'text-destructive': getKeyOAuthExpires(key)?.isInvalid || getKeyOAuthExpires(key)?.isExpired,
|
||||
'text-warning': getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isInvalid,
|
||||
'text-muted-foreground': !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isInvalid
|
||||
}"
|
||||
:title="getOAuthStatusTitle(key)"
|
||||
>
|
||||
{{ getKeyOAuthExpires(key)?.text }}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -372,6 +357,18 @@
|
||||
:class="{ 'animate-spin': refreshingOAuthKeyId === key.key_id }"
|
||||
/>
|
||||
</Button>
|
||||
<span
|
||||
v-if="getKeyOAuthExpires(key)"
|
||||
class="text-[10px]"
|
||||
:class="{
|
||||
'text-destructive': getKeyOAuthExpires(key)?.isInvalid || getKeyOAuthExpires(key)?.isExpired,
|
||||
'text-warning': getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isInvalid,
|
||||
'text-muted-foreground': !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isInvalid
|
||||
}"
|
||||
:title="getOAuthStatusTitle(key)"
|
||||
>
|
||||
{{ getKeyOAuthExpires(key)?.text }}
|
||||
</span>
|
||||
</template>
|
||||
<Badge
|
||||
v-if="key.oauth_plan_type"
|
||||
@@ -529,11 +526,6 @@
|
||||
{{ getSchedulingBadgeLabel(key) }}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell class="py-3 text-center">
|
||||
<span class="text-xs tabular-nums">
|
||||
{{ formatSessionCount(key.sticky_sessions) }}
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell class="py-3">
|
||||
<span class="text-[10px] text-muted-foreground whitespace-nowrap">
|
||||
{{ key.last_used_at ? formatRelativeTime(key.last_used_at) : '-' }}
|
||||
@@ -735,18 +727,6 @@
|
||||
{{ key.auth_type === 'oauth' ? '[OAuth Token]' : (key.auth_type === 'service_account' ? '[Service Account]' : '[Key]') }}
|
||||
</span>
|
||||
<template v-if="key.auth_type === 'oauth'">
|
||||
<span
|
||||
v-if="getKeyOAuthExpires(key)"
|
||||
class="text-[10px]"
|
||||
:class="{
|
||||
'text-destructive': getKeyOAuthExpires(key)?.isInvalid || getKeyOAuthExpires(key)?.isExpired,
|
||||
'text-warning': getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isInvalid,
|
||||
'text-muted-foreground': !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isInvalid
|
||||
}"
|
||||
:title="getOAuthStatusTitle(key)"
|
||||
>
|
||||
{{ getKeyOAuthExpires(key)?.text }}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -760,6 +740,18 @@
|
||||
:class="{ 'animate-spin': refreshingOAuthKeyId === key.key_id }"
|
||||
/>
|
||||
</Button>
|
||||
<span
|
||||
v-if="getKeyOAuthExpires(key)"
|
||||
class="text-[10px]"
|
||||
:class="{
|
||||
'text-destructive': getKeyOAuthExpires(key)?.isInvalid || getKeyOAuthExpires(key)?.isExpired,
|
||||
'text-warning': getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isInvalid,
|
||||
'text-muted-foreground': !getKeyOAuthExpires(key)?.isExpired && !getKeyOAuthExpires(key)?.isExpiringSoon && !getKeyOAuthExpires(key)?.isInvalid
|
||||
}"
|
||||
:title="getOAuthStatusTitle(key)"
|
||||
>
|
||||
{{ getKeyOAuthExpires(key)?.text }}
|
||||
</span>
|
||||
</template>
|
||||
<Badge
|
||||
v-if="key.oauth_plan_type"
|
||||
@@ -973,16 +965,6 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 bg-muted/50 rounded-lg text-xs">
|
||||
<div class="text-muted-foreground mb-0.5">
|
||||
会话
|
||||
</div>
|
||||
<div
|
||||
class="font-medium tabular-nums text-[11px]"
|
||||
>
|
||||
{{ formatSessionCount(key.sticky_sessions) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 bg-muted/50 rounded-lg text-xs">
|
||||
<div class="text-muted-foreground mb-0.5">
|
||||
最后使用
|
||||
@@ -2221,12 +2203,6 @@ function formatStatUsd(value: number | null | undefined): string {
|
||||
return `$${n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
||||
}
|
||||
|
||||
function formatSessionCount(value: number | null | undefined): string {
|
||||
const n = Number(value ?? 0)
|
||||
if (!Number.isFinite(n) || n <= 0) return '0'
|
||||
return Math.round(n).toLocaleString('en-US')
|
||||
}
|
||||
|
||||
function formatRelativeTime(isoStr: string): string {
|
||||
const diff = (Date.now() - new Date(isoStr).getTime()) / 1000
|
||||
if (diff < 60) return '刚刚'
|
||||
|
||||
Reference in New Issue
Block a user