feat: 代理池均衡分发&批量添加代理节点

This commit is contained in:
wzw
2026-05-23 10:40:25 +08:00
parent c7641dad0a
commit bf456450d7
10 changed files with 1335 additions and 17 deletions
@@ -0,0 +1,77 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const { getSystemConfigMock } = vi.hoisted(() => ({
getSystemConfigMock: vi.fn(),
}))
vi.mock('@/api/admin', () => ({
adminApi: {
getSystemConfig: getSystemConfigMock,
updateSystemConfig: vi.fn(),
getSystemVersion: vi.fn(),
},
}))
vi.mock('@/composables/useToast', () => ({
useToast: () => ({
success: vi.fn(),
error: vi.fn(),
}),
}))
vi.mock('@/composables/useSiteInfo', () => ({
useSiteInfo: () => ({
refreshSiteInfo: vi.fn(),
}),
}))
vi.mock('@/utils/logger', () => ({
log: {
error: vi.fn(),
},
}))
import { useSystemConfig } from '../composables/useSystemConfig'
interface DeferredConfigResponse {
resolve: (value: { key: string, value: unknown, is_set?: boolean }) => void
}
describe('useSystemConfig', () => {
beforeEach(() => {
getSystemConfigMock.mockReset()
})
it('loads config keys in parallel and keeps change detection disabled until the baseline is ready', async () => {
const pending = new Map<string, DeferredConfigResponse>()
getSystemConfigMock.mockImplementation((key: string) => new Promise((resolve) => {
pending.set(key, { resolve })
}))
const state = useSystemConfig()
const loadPromise = state.loadSystemConfig()
expect(getSystemConfigMock.mock.calls.map(([key]) => key)).toContain('request_record_level')
expect(getSystemConfigMock.mock.calls.map(([key]) => key)).toContain('proxy_node_metrics_cleanup_batch_size')
state.systemConfig.value.request_record_level = 'headers'
expect(state.systemConfigLoading.value).toBe(true)
expect(state.hasLogConfigChanges.value).toBe(false)
for (const [key, deferred] of pending) {
deferred.resolve({
key,
value: key === 'request_record_level' ? 'basic' : undefined,
is_set: false,
})
}
await loadPromise
expect(state.systemConfigLoading.value).toBe(false)
expect(state.systemConfig.value.request_record_level).toBe('basic')
expect(state.hasLogConfigChanges.value).toBe(false)
state.systemConfig.value.request_record_level = 'full'
expect(state.hasLogConfigChanges.value).toBe(true)
})
})
@@ -177,6 +177,7 @@ export function useSystemConfig() {
const systemConfig = ref<SystemConfig>(createDefaultConfig())
const originalConfig = ref<SystemConfig | null>(null)
const systemVersion = ref<string>('')
const systemConfigLoading = ref(true)
// 各模块 loading 状态
const siteInfoLoading = ref(false)
@@ -187,6 +188,7 @@ export function useSystemConfig() {
// 变动检测
const hasSiteInfoChanges = computed(() => {
if (systemConfigLoading.value) return false
if (!originalConfig.value) return false
return (
systemConfig.value.site_name !== originalConfig.value.site_name ||
@@ -195,11 +197,13 @@ export function useSystemConfig() {
})
const hasProxyConfigChanges = computed(() => {
if (systemConfigLoading.value) return false
if (!originalConfig.value) return false
return systemConfig.value.system_proxy_node_id !== originalConfig.value.system_proxy_node_id
})
const hasBasicConfigChanges = computed(() => {
if (systemConfigLoading.value) return false
if (!originalConfig.value) return false
return (
systemConfig.value.default_user_initial_gift_usd !== originalConfig.value.default_user_initial_gift_usd ||
@@ -231,6 +235,7 @@ export function useSystemConfig() {
})
const hasLogConfigChanges = computed(() => {
if (systemConfigLoading.value) return false
if (!originalConfig.value) return false
return (
systemConfig.value.request_record_level !== originalConfig.value.request_record_level ||
@@ -242,6 +247,7 @@ export function useSystemConfig() {
})
const hasCleanupConfigChanges = computed(() => {
if (systemConfigLoading.value) return false
if (!originalConfig.value) return false
return (
systemConfig.value.detail_log_retention_days !==
@@ -304,26 +310,47 @@ export function useSystemConfig() {
// 加载配置
async function loadSystemConfig() {
systemConfigLoading.value = true
try {
for (const key of CONFIG_KEYS) {
const results = await Promise.all(
CONFIG_KEYS.map(async (key) => {
try {
return {
key,
response: await adminApi.getSystemConfig(key),
}
} catch {
return null
}
})
)
const nextConfig = createDefaultConfig()
for (const result of results) {
if (!result) {
continue
}
const { key, response } = result
try {
const response = await adminApi.getSystemConfig(key)
if (key === 'turnstile_secret_key') {
systemConfig.value.turnstile_secret_key = ''
systemConfig.value.turnstile_secret_key_is_set = !!response.is_set
nextConfig.turnstile_secret_key = ''
nextConfig.turnstile_secret_key_is_set = !!response.is_set
continue
}
if (response.value !== null && response.value !== undefined) {
; (systemConfig.value as Record<string, unknown>)[key] = response.value
; (nextConfig as Record<string, unknown>)[key] = response.value
}
} catch {
// 单个配置项加载失败时忽略,使用默认值
}
}
originalConfig.value = JSON.parse(JSON.stringify(systemConfig.value))
systemConfig.value = nextConfig
originalConfig.value = JSON.parse(JSON.stringify(nextConfig))
} catch (err) {
error('加载系统配置失败')
log.error('加载系统配置失败:', err)
} finally {
systemConfigLoading.value = false
}
}
@@ -734,6 +761,7 @@ export function useSystemConfig() {
systemConfig,
originalConfig,
systemVersion,
systemConfigLoading,
// loading 状态
siteInfoLoading,
proxyConfigLoading,