feat: 配置导入导出支持 ProxyNode,号池 key 可用性检查延迟到排序后分页执行

配置导入导出:
- 导出/导入新增 ProxyNode(代理节点)数据
- 导入时自动建立 old_id -> new_id 映射,重映射 Provider/Endpoint/Key 中的 node_id
- 前端预览和结果展示新增代理节点统计

号池调度优化:
- CandidateBuilder 不再逐 key 调用 _check_key_availability,直接收集全部 active key
- 将可用性检查参数打包到 PoolCandidate._deferred_check_params
- PoolManager.select_pool_keys 排序后分页调用 availability_checker,找到足够可用 key 即停止
- 减少大号池场景下不必要的可用性检查开销
This commit is contained in:
fawney19
2026-03-09 13:26:54 +08:00
parent 0046123e22
commit d84c9d4b71
7 changed files with 291 additions and 55 deletions

View File

@@ -47,11 +47,28 @@ export interface ConfigExportData {
exported_at: string
global_models: GlobalModelExport[]
providers: ProviderExport[]
proxy_nodes?: ProxyNodeExport[]
ldap_config?: LDAPConfigExport | null
oauth_providers?: OAuthProviderExport[]
system_configs?: SystemConfigExport[]
}
export interface ProxyNodeExport {
id: string
name: string
ip: string
port: number
region?: string | null
is_manual: boolean
proxy_url?: string | null
proxy_username?: string | null
proxy_password?: string | null
tunnel_mode: boolean
heartbeat_interval: number
remote_config?: Record<string, unknown> | null
config_version: number
}
// 用户导出数据结构
export interface UsersExportData {
version: string
@@ -308,6 +325,7 @@ export interface ConfigImportResponse {
message: string
stats: {
global_models: { created: number; updated: number; skipped: number }
proxy_nodes?: { created: number; updated: number; skipped: number }
providers: { created: number; updated: number; skipped: number }
endpoints: { created: number; updated: number; skipped: number }
keys: { created: number; updated: number; skipped: number }

View File

@@ -23,6 +23,9 @@
<li>
API Keys: {{ importPreview.providers?.reduce((sum: number, p: { api_keys?: unknown[] }) => sum + (p.api_keys?.length || 0), 0) }}
</li>
<li v-if="importPreview.proxy_nodes?.length">
代理节点: {{ importPreview.proxy_nodes.length }}
</li>
<li v-if="importPreview.ldap_config">
LDAP 配置: 1
</li>
@@ -169,6 +172,16 @@
跳过: {{ importResult.stats.oauth.skipped }}
</p>
</div>
<div v-if="importResult.stats.proxy_nodes">
<p class="font-medium">
代理节点
</p>
<p class="text-muted-foreground">
创建: {{ importResult.stats.proxy_nodes.created }},
更新: {{ importResult.stats.proxy_nodes.updated }},
跳过: {{ importResult.stats.proxy_nodes.skipped }}
</p>
</div>
</div>
<div