feat: add daily model statistics aggregation with stats_daily_model table

This commit is contained in:
fawney19
2025-12-20 02:39:10 +08:00
parent e2e7996a54
commit 4e1aed9976
22 changed files with 561 additions and 202 deletions

View File

@@ -18,7 +18,7 @@
</p>
</div>
<!-- 别名列表 -->
<!-- 映射列表 -->
<div class="space-y-3">
<div class="flex items-center justify-between">
<Label class="text-sm font-medium">名称映射</Label>
@@ -92,7 +92,7 @@
</div>
</div>
<!-- 别名输入框 -->
<!-- 映射输入框 -->
<Input
v-model="alias.name"
placeholder="映射名称,如 Claude-Sonnet-4.5"
@@ -184,9 +184,9 @@ const editingPriorityIndex = ref<number | null>(null)
// 监听 open 变化
watch(() => props.open, (newOpen) => {
if (newOpen && props.model) {
// 加载现有别名配置
if (props.model.provider_model_aliases && Array.isArray(props.model.provider_model_aliases)) {
aliases.value = JSON.parse(JSON.stringify(props.model.provider_model_aliases))
// 加载现有映射配置
if (props.model.provider_model_mappings && Array.isArray(props.model.provider_model_mappings)) {
aliases.value = JSON.parse(JSON.stringify(props.model.provider_model_mappings))
} else {
aliases.value = []
}
@@ -197,16 +197,16 @@ watch(() => props.open, (newOpen) => {
}
})
// 添加别名
// 添加映射
function addAlias() {
// 新别名优先级为当前最大优先级 + 1或者默认为 1
// 新映射优先级为当前最大优先级 + 1或者默认为 1
const maxPriority = aliases.value.length > 0
? Math.max(...aliases.value.map(a => a.priority))
: 0
aliases.value.push({ name: '', priority: maxPriority + 1 })
}
// 移除别名
// 移除映射
function removeAlias(index: number) {
aliases.value.splice(index, 1)
}
@@ -244,7 +244,7 @@ function handleDrop(targetIndex: number) {
const items = [...aliases.value]
const draggedItem = items[dragIndex]
// 记录每个别名的原始优先级(在修改前)
// 记录每个映射的原始优先级(在修改前)
const originalPriorityMap = new Map<number, number>()
items.forEach((alias, idx) => {
originalPriorityMap.set(idx, alias.priority)
@@ -255,7 +255,7 @@ function handleDrop(targetIndex: number) {
items.splice(targetIndex, 0, draggedItem)
// 按新顺序为每个组分配新的优先级
// 同组的别名保持相同的优先级(被拖动的别名单独成组)
// 同组的映射保持相同的优先级(被拖动的映射单独成组)
const groupNewPriority = new Map<number, number>() // 原优先级 -> 新优先级
let currentPriority = 1
@@ -263,12 +263,12 @@ function handleDrop(targetIndex: number) {
const draggedOriginalPriority = originalPriorityMap.get(dragIndex)!
items.forEach((alias, newIdx) => {
// 找到这个别名在原数组中的索引
// 找到这个映射在原数组中的索引
const originalIdx = aliases.value.findIndex(a => a === alias)
const originalPriority = originalIdx >= 0 ? originalPriorityMap.get(originalIdx)! : alias.priority
if (alias === draggedItem) {
// 被拖动的别名是独立的新组,获得当前优先级
// 被拖动的映射是独立的新组,获得当前优先级
alias.priority = currentPriority
currentPriority++
} else {
@@ -318,11 +318,11 @@ async function handleSubmit() {
submitting.value = true
try {
// 过滤掉空的别名
// 过滤掉空的映射
const validAliases = aliases.value.filter(a => a.name.trim())
await updateModel(props.providerId, props.model.id, {
provider_model_aliases: validAliases.length > 0 ? validAliases : null
provider_model_mappings: validAliases.length > 0 ? validAliases : null
})
showSuccess('映射配置已保存')

View File

@@ -419,7 +419,7 @@ const formData = ref<{
aliases: []
})
// 检查是否有有效的别名
// 检查是否有有效的映射
const hasValidAliases = computed(() => {
return formData.value.aliases.some(a => a.name.trim())
})
@@ -538,7 +538,7 @@ function toggleGroupCollapse(apiFormat: string) {
}
}
// 添加别名
// 添加映射
function addAliasItem() {
const maxPriority = formData.value.aliases.length > 0
? Math.max(...formData.value.aliases.map(a => a.priority))
@@ -546,7 +546,7 @@ function addAliasItem() {
formData.value.aliases.push({ name: '', priority: maxPriority + 1, isEditing: true })
}
// 删除别名
// 删除映射
function removeAliasItem(index: number) {
formData.value.aliases.splice(index, 1)
}
@@ -719,7 +719,7 @@ async function handleSubmit() {
return
}
const currentAliases = targetModel.provider_model_aliases || []
const currentAliases = targetModel.provider_model_mappings || []
let newAliases: ProviderModelAlias[]
const buildAlias = (a: FormAlias): ProviderModelAlias => ({
@@ -762,7 +762,7 @@ async function handleSubmit() {
}
await updateModel(props.providerId, targetModel.id, {
provider_model_aliases: newAliases
provider_model_mappings: newAliases
})
showSuccess(props.editingGroup ? '映射组已更新' : '映射已添加')

View File

@@ -101,24 +101,24 @@
</div>
</div>
<!-- 展开的别名列表 -->
<!-- 展开的映射列表 -->
<div
v-show="expandedAliasGroups.has(`${group.model.id}-${group.apiFormatsKey}`)"
class="bg-muted/30 border-t border-border/30"
>
<div class="px-4 py-2 space-y-1">
<div
v-for="alias in group.aliases"
:key="alias.name"
v-for="mapping in group.aliases"
:key="mapping.name"
class="flex items-center gap-2 py-1"
>
<!-- 优先级标签 -->
<span class="inline-flex items-center justify-center w-5 h-5 rounded bg-background border text-xs font-medium shrink-0">
{{ alias.priority }}
{{ mapping.priority }}
</span>
<!-- 别名名称 -->
<!-- 映射名称 -->
<span class="font-mono text-sm truncate">
{{ alias.name }}
{{ mapping.name }}
</span>
</div>
</div>
@@ -222,9 +222,9 @@ const aliasGroups = computed<AliasGroup[]>(() => {
const groupMap = new Map<string, AliasGroup>()
for (const model of models.value) {
if (!model.provider_model_aliases || !Array.isArray(model.provider_model_aliases)) continue
if (!model.provider_model_mappings || !Array.isArray(model.provider_model_mappings)) continue
for (const alias of model.provider_model_aliases) {
for (const alias of model.provider_model_mappings) {
const apiFormatsKey = getApiFormatsKey(alias.api_formats)
const groupKey = `${model.id}|${apiFormatsKey}`
@@ -310,7 +310,7 @@ async function confirmDelete() {
const { model, aliases, apiFormatsKey } = deletingGroup.value
try {
const currentAliases = model.provider_model_aliases || []
const currentAliases = model.provider_model_mappings || []
const aliasNamesToRemove = new Set(aliases.map(a => a.name))
const newAliases = currentAliases.filter((a: ProviderModelAlias) => {
const currentKey = getApiFormatsKey(a.api_formats)
@@ -318,7 +318,7 @@ async function confirmDelete() {
})
await updateModel(props.provider.id, model.id, {
provider_model_aliases: newAliases.length > 0 ? newAliases : null
provider_model_mappings: newAliases.length > 0 ? newAliases : null
})
showSuccess('映射组已删除')