feat: 统计数据优化 - 支持细粒度时间范围和多维度分析

- 新增 StatsHourly/StatsDaily 预聚合表,支持任意时区的精确统计
- 实现 UTC datetime 范围查询策略,边界数据实时聚合
- 新增统计 API:用户/API Key 维度、成本分析、性能百分位、错误分类
- 新增前端页面:成本分析、性能分析、用户统计
- 新增 TimeRangePicker 组件和统计可视化组件
- 优化 Dashboard 和 Usage 页面支持时间范围筛选

Close #135
This commit is contained in:
fawney19
2026-02-04 02:04:54 +08:00
parent 6f363a7703
commit f3e2f84b38
59 changed files with 6392 additions and 500 deletions
@@ -55,15 +55,17 @@
</div>
</div>
<div class="flex items-center gap-1 shrink-0">
<Button
variant="ghost"
size="icon"
:title="provider.enable_format_conversion ? '已启用格式转换(点击关闭)' : '启用格式转换'"
:class="provider.enable_format_conversion ? 'text-primary' : ''"
@click="toggleFormatConversion"
>
<Shuffle class="w-4 h-4" />
</Button>
<span :title="systemFormatConversionEnabled ? '请先关闭系统级开关' : (provider.enable_format_conversion ? '已启用格式转换(点击关闭)' : '启用格式转换')">
<Button
variant="ghost"
size="icon"
:class="`${provider.enable_format_conversion ? 'text-primary' : ''} ${systemFormatConversionEnabled ? 'opacity-50' : ''}`"
:disabled="systemFormatConversionEnabled"
@click="toggleFormatConversion"
>
<Shuffle class="w-4 h-4" />
</Button>
</span>
<Button
variant="ghost"
size="icon"
@@ -437,6 +439,8 @@
v-model="endpointDialogOpen"
:provider="provider"
:endpoints="endpoints"
:system-format-conversion-enabled="systemFormatConversionEnabled"
:provider-format-conversion-enabled="provider.enable_format_conversion"
@endpoint-created="handleEndpointChanged"
@endpoint-updated="handleEndpointChanged"
/>
@@ -522,6 +526,7 @@ import { useToast } from '@/composables/useToast'
import { useClipboard } from '@/composables/useClipboard'
import { useCountdownTimer, formatCountdown } from '@/composables/useCountdownTimer'
import { getProvider, getProviderEndpoints, updateProvider } from '@/api/endpoints'
import { adminApi } from '@/api/admin'
import {
KeyFormDialog,
KeyAllowedModelsEditDialog,
@@ -575,6 +580,9 @@ const provider = ref<any>(null)
const endpoints = ref<ProviderEndpointWithKeys[]>([])
const providerKeys = ref<EndpointAPIKey[]>([]) // Provider 级别的 keys
// 系统级格式转换配置
const systemFormatConversionEnabled = ref(false)
// 端点相关状态
const endpointDialogOpen = ref(false)
@@ -1256,13 +1264,29 @@ function getFormatProbeCountdown(key: EndpointAPIKey, format: string): string {
return ''
}
// 加载系统级格式转换配置
async function loadSystemFormatConversionConfig() {
try {
const result = await adminApi.getSystemConfig('enable_format_conversion')
systemFormatConversionEnabled.value = result.value === true
} catch {
// 获取失败时默认为关闭
systemFormatConversionEnabled.value = false
}
}
// 加载 Provider 信息
async function loadProvider() {
if (!props.providerId) return
try {
loading.value = true
provider.value = await getProvider(props.providerId)
// 并行加载 Provider 信息和系统级格式转换配置
const [providerData] = await Promise.all([
getProvider(props.providerId),
loadSystemFormatConversionConfig(),
])
provider.value = providerData
if (!provider.value) {
throw new Error('Provider 不存在')