refactor(frontend): 统一 routing 数据加载,消除子组件重复请求

将 Model 和 Provider 详情抽屉中的 routing/mapping 数据加载逻辑
从各子组件(RoutingTab、ModelMappingsTab、ModelsTab、ModelMappingTab)
提升到父组件统一管理,通过 props 向下传递数据,避免多个子组件独立发起相同的 API 请求,提升页面加载性能。
This commit is contained in:
AAEE86
2026-02-10 23:47:47 +08:00
parent 347bd3345c
commit cabaa9f1df
6 changed files with 164 additions and 101 deletions
@@ -611,6 +611,9 @@ import { MAX_MODEL_NAME_LENGTH, createLRURegexCache, getCompiledModelMappingRege
const props = defineProps<{
globalModelId: string
routingData?: ModelRoutingPreviewResponse | null
loading?: boolean
error?: string | null
}>()
const emit = defineEmits<{
@@ -624,9 +627,16 @@ const emit = defineEmits<{
const { success: showSuccess, error: showError } = useToast()
const { tick: countdownTick, start: startCountdownTimer } = useCountdownTimer()
const loading = ref(false)
const error = ref<string | null>(null)
const routingData = ref<ModelRoutingPreviewResponse | null>(null)
// 使用外部传入的数据或内部状态
const internalRoutingData = ref<ModelRoutingPreviewResponse | null>(null)
const internalLoading = ref(false)
const internalError = ref<string | null>(null)
// 计算属性:优先使用外部传入的数据
const routingData = computed(() => props.routingData ?? internalRoutingData.value)
const loading = computed(() => props.loading ?? internalLoading.value)
const error = computed(() => props.error ?? internalError.value)
const modelMappingRegexCache = createLRURegexCache(200)
const keyMatchedModelsCache = new Map<string, string[]>()
const compiledGlobalModelMappingRegexes = ref<RegExp[]>([])
@@ -808,16 +818,22 @@ function toggleProviderInFormat(format: string, providerId: string, endpointId?:
}
}
// 加载数据
// 加载数据(仅在没有外部数据时使用)
async function loadRoutingData() {
// 如果有外部传入的数据,通知父组件刷新
if (props.routingData !== undefined) {
emit('refresh')
return
}
if (!props.globalModelId) return
modelMappingRegexCache.clear()
keyMatchedModelsCache.clear()
compiledGlobalModelMappingRegexes.value = []
loading.value = true
error.value = null
internalLoading.value = true
internalError.value = null
try {
const data = await getGlobalModelRoutingPreview(props.globalModelId)
@@ -828,15 +844,30 @@ async function loadRoutingData() {
if (regex) compiled.push(regex)
}
routingData.value = data
internalRoutingData.value = data
compiledGlobalModelMappingRegexes.value = compiled
} catch (err: any) {
error.value = err.response?.data?.detail || '加载失败'
internalError.value = err.response?.data?.detail || '加载失败'
} finally {
loading.value = false
internalLoading.value = false
}
}
// 监听外部 routingData 变化,更新编译后的正则
watch(() => props.routingData, (data) => {
if (data) {
modelMappingRegexCache.clear()
keyMatchedModelsCache.clear()
const compiled: RegExp[] = []
for (const pattern of data.global_model_mappings || []) {
const regex = getCompiledModelMappingRegex(pattern, modelMappingRegexCache)
if (regex) compiled.push(regex)
}
compiledGlobalModelMappingRegexes.value = compiled
}
}, { immediate: true })
// 获取调度模式标签
function getSchedulingModeLabel(mode: string): string {
const labels: Record<string, string> = {
@@ -1086,9 +1117,9 @@ function getKeyProbeCountdown(key: RoutingKeyInfo): string {
async function handleRecoverKey(keyId: string, apiFormat: string) {
try {
const result = await recoverKeyHealth(keyId, apiFormat)
await loadRoutingData()
showSuccess(result.message || 'Key 已恢复')
// 通知父组件刷新数据
emit('refresh')
showSuccess(result.message || 'Key 已恢复')
} catch (err: any) {
showError(err.response?.data?.detail || 'Key 恢复失败', '错误')
}
@@ -1098,11 +1129,17 @@ async function handleRecoverKey(keyId: string, apiFormat: string) {
watch(() => props.globalModelId, () => {
expandedFormats.value.clear()
expandedProvidersInFormat.value.clear()
loadRoutingData()
// 如果没有外部数据,才自己加载
if (props.routingData === undefined) {
loadRoutingData()
}
}, { immediate: false })
onMounted(() => {
loadRoutingData()
// 如果没有外部数据,才自己加载
if (props.routingData === undefined) {
loadRoutingData()
}
startCountdownTimer()
})