feat: 实现一键同步网站账号上游模型功能
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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 })
|
||||
|
||||
Reference in New Issue
Block a user