feat: provider api_formats 可空继承、OpenAI 图片 edit/variation 与用量配额多项补强

- 鉴权: provider_api_keys.api_formats 改为可空,OAuth 托管 key 自动继承 provider endpoints 激活格式,相关 handler/测试同步更新
- 图片 planner: OpenAI 图片路由新增 edit/variation 操作并完善参数校验、响应合并与流式处理
- 用量: user me usage 返回区分 client_requested_stream/upstream_is_stream,前端 usage 列表筛选与展示增强
- 统计: stats_daily_model 新增 cache_creation_ephemeral_5m/1h tokens 字段与回填链路
- 配额/observability: quota repository 新增内存与 SQL 扩展,admin observability usage 字段扩充
- 其它: OAuth 导入/轮询收敛、provider 汇总与 pool admin 读写链路小修、新增 system_config 缓存与 provider template handler

Closes #318

Co-authored-by: Entropy.Xu <[email protected]>
This commit is contained in:
fawney19
2026-04-23 14:42:51 +08:00
co-authored by Entropy.Xu
parent f55f22d2e8
commit fa328e18a1
128 changed files with 5583 additions and 690 deletions
@@ -58,7 +58,7 @@
variant="outline"
class="text-xs"
>
{{ detail.is_stream ? '流式' : '标准' }}
{{ detail ? formatUsageStreamLabel(detail) : '标准' }}
</Badge>
</div>
<div class="flex items-center gap-1 shrink-0">
@@ -695,6 +695,7 @@ import { formatApiFormat } from '@/api/endpoints/types/api-format'
import { formatShortRequestId } from '@/utils/format'
import { log } from '@/utils/logger'
import { getEffectiveInputTokens } from '../token-normalization'
import { formatUsageStreamLabel } from '../utils/status'
// 子组件
import RequestHeadersContent from './RequestDetailDrawer/RequestHeadersContent.vue'
@@ -232,19 +232,14 @@
>
取消
</Badge>
<Badge
v-else-if="record.is_stream"
variant="secondary"
class="whitespace-nowrap text-[10px] px-1.5 h-4 leading-4 inline-flex items-center"
>
流式
</Badge>
<Badge
v-else
variant="outline"
class="whitespace-nowrap border-border/60 text-muted-foreground text-[10px] px-1.5 h-4 leading-4 inline-flex items-center"
:variant="getUpstreamStream(record) ? 'secondary' : 'outline'"
:class="getUpstreamStream(record)
? 'whitespace-nowrap text-[10px] px-1.5 h-4 leading-4 inline-flex items-center'
: 'whitespace-nowrap border-border/60 text-muted-foreground text-[10px] px-1.5 h-4 leading-4 inline-flex items-center'"
>
标准
{{ getStreamModeLabel(record) }}
</Badge>
<span class="text-muted-foreground/50">|</span>
<span>{{ formatDateTime(record.created_at) }}</span>
@@ -310,7 +305,7 @@
<TableHead class="h-12 font-semibold w-[120px]">
API格式
</TableHead>
<TableHead class="h-12 font-semibold w-[70px] text-center">
<TableHead class="h-12 font-semibold w-[110px] text-center">
类型
</TableHead>
<TableHead class="h-12 font-semibold w-[140px] text-right">
@@ -534,19 +529,14 @@
>
已取消
</Badge>
<Badge
v-else-if="record.is_stream"
variant="secondary"
class="whitespace-nowrap"
>
流式
</Badge>
<Badge
v-else
variant="outline"
class="whitespace-nowrap border-border/60 text-muted-foreground"
:variant="getUpstreamStream(record) ? 'secondary' : 'outline'"
:class="getUpstreamStream(record)
? 'whitespace-nowrap'
: 'whitespace-nowrap border-border/60 text-muted-foreground'"
>
标准
{{ getStreamModeLabel(record) }}
</Badge>
</TableCell>
<TableCell class="text-right py-4 w-[140px]">
@@ -678,7 +668,12 @@ import { RefreshCcw, Search } from 'lucide-vue-next'
import { formatTokens, formatCurrency } from '@/utils/format'
import { formatDateTime } from '../composables'
import { getCacheCreationTokens, getEffectiveInputTokens } from '../token-normalization'
import { isUsageRecordFailed, resolveDisplayRequestStatus } from '../utils/status'
import {
formatUsageStreamLabel,
isUsageRecordFailed,
isUsageUpstreamStream,
resolveDisplayRequestStatus
} from '../utils/status'
import { useRowClick } from '@/composables/useRowClick'
import { formatApiFormat } from '@/api/endpoints/types/api-format'
import type { DateRangeParams, UsageRecord } from '../types'
@@ -764,6 +759,14 @@ function getDisplayStatus(record: UsageRecord) {
return resolveDisplayRequestStatus(record)
}
function getStreamModeLabel(record: UsageRecord): string {
return formatUsageStreamLabel(record)
}
function getUpstreamStream(record: UsageRecord): boolean {
return isUsageUpstreamStream(record)
}
watch(() => props.filterSearch, (value) => {
if (value !== localSearch.value) {
localSearch.value = value