feat: 实现一键同步网站账号上游模型功能

This commit is contained in:
liumangmang
2026-07-02 15:43:00 +08:00
parent c70b68d814
commit 63cbdf4dca
6 changed files with 548 additions and 0 deletions
+11
View File
@@ -352,6 +352,15 @@ export interface SetConcurrencyItem {
message: string
}
export interface SyncUpstreamModelsItem {
account_id: string
account_name: string | null
model_count: number
models: string[]
status: string
message: string
}
export const websitesApi = {
list: () => api.get<WebsiteData[]>('/api/websites'),
create: (data: WebsiteForm) => api.post<WebsiteData>('/api/websites', data),
@@ -385,6 +394,8 @@ export const websitesApi = {
api.post<{ success: boolean; message: string; items: CleanupInvalidAccountsItem[] }>(`/api/websites/${id}/accounts/cleanup-invalid/execute`),
setConcurrency: (id: number, data: { concurrency: number }) =>
api.post<{ success: boolean; message: string; items: SetConcurrencyItem[] }>(`/api/websites/${id}/accounts/set-concurrency`, data),
syncUpstreamModels: (id: number) =>
api.post<{ success: boolean; message: string; items: SyncUpstreamModelsItem[] }>(`/api/websites/${id}/accounts/sync-upstream-models`),
listBindings: () => api.get<GroupBindingData[]>('/api/group-bindings'),
createBinding: (data: GroupBindingForm) => api.post<GroupBindingData>('/api/group-bindings', data),
updateBinding: (id: number, data: Partial<GroupBindingForm>) => api.put<GroupBindingData>(`/api/group-bindings/${id}`, data),
+105
View File
@@ -142,6 +142,15 @@
>
设置账号并发
</el-button>
<el-button
size="small"
text
:disabled="!selectedWebsite"
@click="triggerSyncUpstreamModels"
title="一键同步当前网站已导入账号的上游支持模型"
>
同步上游模型
</el-button>
<el-button size="small" text :disabled="websites.length === 0" @click="openBindingCreate(selectedWebsite || websites[0])">新增绑定</el-button>
</div>
<div class="binding-list" v-loading="bindingLoading">
@@ -931,6 +940,62 @@
</div>
</template>
</el-dialog>
<!-- 同步上游模型结果弹窗 -->
<el-dialog
v-model="syncModelsDialog"
title="一键同步上游模型结果"
width="850px"
destroy-on-close
>
<div v-loading="syncModelsExecuting">
<div v-if="syncModelsMessage" style="margin-bottom: 15px; font-weight: bold; color: var(--el-color-primary);">
{{ syncModelsMessage }}
</div>
<el-table :data="syncModelsResults" border stripe size="small" style="width: 100%; max-height: 400px; overflow-y: auto;">
<el-table-column prop="account_id" label="账号 ID" width="150" />
<el-table-column prop="account_name" label="账号名" min-width="180" show-overflow-tooltip />
<el-table-column prop="model_count" label="同步模型数" width="110" align="center">
<template #default="{ row }">
<el-tooltip
v-if="row.models && row.models.length > 0"
class="box-item"
effect="dark"
placement="top"
>
<template #content>
<div style="max-width: 300px; word-break: break-all;">
{{ row.models.join(', ') }}
</div>
</template>
<el-tag type="info" size="small" style="cursor: pointer;">
{{ row.model_count }}
</el-tag>
</el-tooltip>
<span v-else class="text-muted">0 </span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag v-if="row.status === 'success'" type="success" size="small">成功</el-tag>
<el-tag v-else-if="row.status === 'skipped'" type="warning" size="small">跳过</el-tag>
<el-tag v-else-if="row.status === 'failed'" type="danger" size="small">失败</el-tag>
<el-tag v-else type="info" size="small">{{ row.status }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="message" label="说明/原因" min-width="200" show-overflow-tooltip />
</el-table>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="syncModelsDialog = false" :disabled="syncModelsExecuting">
关闭
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -957,6 +1022,7 @@ import {
type OrganizeGroupsItem,
type CleanupInvalidAccountsItem,
type SetConcurrencyItem,
type SyncUpstreamModelsItem,
} from '@/api'
const websites = ref<(WebsiteData & { _testing?: boolean })[]>([])
@@ -1119,6 +1185,11 @@ const targetConcurrency = ref(100)
const concurrencyMessage = ref('')
const concurrencyResults = ref<SetConcurrencyItem[]>([])
const syncModelsDialog = ref(false)
const syncModelsExecuting = ref(false)
const syncModelsMessage = ref('')
const syncModelsResults = ref<SyncUpstreamModelsItem[]>([])
const upstreamGroupOptions = computed(() => {
const rows: Array<{ key: string; label: string; rate: string | number; source: BindingSourceGroup }> = []
for (const upstream of upstreams.value) {
@@ -1866,6 +1937,40 @@ async function submitSetConcurrency() {
}
}
async function triggerSyncUpstreamModels() {
if (!selectedWebsite.value) return
try {
await ElMessageBox.confirm(
'确认开始同步上游模型?此操作将仅拉取当前网站中由 SmartUp 导入账号的上游支持模型,并自动更新写入对应的模型白名单/映射配置。',
'确认同步上游模型',
{ type: 'warning' }
)
} catch {
return
}
syncModelsResults.value = []
syncModelsMessage.value = ''
syncModelsExecuting.value = true
syncModelsDialog.value = true
try {
const res = await websitesApi.syncUpstreamModels(selectedWebsite.value.id)
syncModelsMessage.value = res.data.message
syncModelsResults.value = res.data.items
if (res.data.success) {
ElMessage.success('同步完成')
} else {
ElMessage.warning(res.data.message || '部分账号同步模型失败')
}
} catch (e: any) {
ElMessage.error(e.response?.data?.detail || '同步上游模型失败')
syncModelsDialog.value = false
} finally {
syncModelsExecuting.value = false
}
}
async function toggleBinding(row: GroupBindingData) {
try {
await websitesApi.updateBinding(row.id, { enabled: row.enabled })