diff --git a/src/web/pages/Settings.tsx b/src/web/pages/Settings.tsx index 5a2f953..cf89640 100644 --- a/src/web/pages/Settings.tsx +++ b/src/web/pages/Settings.tsx @@ -424,14 +424,6 @@ export default function Settings() { api.getRoutesLite(), api.getRuntimeDatabaseConfig(), ]); - let brandListBrands: string[] = []; - try { - const brandListRes = await api.getBrandList(); - brandListBrands = Array.isArray(brandListRes?.brands) ? brandListRes.brands : []; - } catch { - // best-effort: brand list is non-critical - } - setAllBrandNames(brandListBrands); setMaskedToken(authInfo.masked || '****'); setRuntime({ checkinCron: runtimeInfo.checkinCron || '0 8 * * *', @@ -508,6 +500,10 @@ export default function Settings() { } finally { setLoading(false); } + // Load brand list in background (non-blocking, best-effort) + api.getBrandList() + .then((res: any) => setAllBrandNames(Array.isArray(res?.brands) ? res.brands : [])) + .catch(() => {/* best-effort */}); }; useEffect(() => { @@ -834,10 +830,9 @@ export default function Settings() { setSavingBrandFilter(true); try { const res = await api.updateRuntimeSettings({ globalBlockedBrands: blockedBrands }); - setRuntime((prev) => ({ - ...prev, - globalBlockedBrands: Array.isArray(res?.globalBlockedBrands) ? res.globalBlockedBrands : blockedBrands, - })); + const resolved = Array.isArray(res?.globalBlockedBrands) ? res.globalBlockedBrands : blockedBrands; + setRuntime((prev) => ({ ...prev, globalBlockedBrands: resolved })); + setBlockedBrands(resolved); toast.success('品牌屏蔽设置已保存'); try { await api.rebuildRoutes(false); diff --git a/src/web/pages/Sites.tsx b/src/web/pages/Sites.tsx index 75819fa..debd182 100644 --- a/src/web/pages/Sites.tsx +++ b/src/web/pages/Sites.tsx @@ -953,7 +953,7 @@ export default function Sites() { ) : ( <> {/* Search and brand group controls */} - {availableModels.length > 0 && ( + {brandGroups.length > 0 && (
{ if (e.target.checked) { - setDisabledModels((prev) => [...prev, model]); + setDisabledModels((prev) => Array.from(new Set([...prev, model]))); } else { setDisabledModels((prev) => prev.filter((m) => m !== model)); } diff --git a/src/web/pages/TokenRoutes.tsx b/src/web/pages/TokenRoutes.tsx index 3c0eeef..fa02d4e 100644 --- a/src/web/pages/TokenRoutes.tsx +++ b/src/web/pages/TokenRoutes.tsx @@ -164,6 +164,7 @@ export default function TokenRoutes() { const candidatesLoadedRef = useRef(false); const candidatesPromiseRef = useRef | null>(null); const candidatesVersionRef = useRef(0); + const candidatesSeqRef = useRef(0); const loadRouteDecisions = async ( routeRows: RouteSummaryRow[], @@ -235,10 +236,12 @@ export default function TokenRoutes() { const loadCandidates = (force?: boolean) => { if (candidatesLoadedRef.current && !force) return; if (candidatesPromiseRef.current && !force) return; + const seq = ++candidatesSeqRef.current; candidatesLoadedRef.current = true; const promise = (async () => { try { const candidateRows = await api.getModelTokenCandidates(); + if (candidatesSeqRef.current !== seq) return; // stale startTransition(() => { setModelCandidates((candidateRows?.models || {}) as RouteModelCandidatesByModelName); setMissingTokenModelsByName( @@ -251,7 +254,7 @@ export default function TokenRoutes() { }); candidatesVersionRef.current = Date.now(); } catch { - candidatesLoadedRef.current = false; + if (candidatesSeqRef.current === seq) candidatesLoadedRef.current = false; } finally { if (candidatesPromiseRef.current === promise) { candidatesPromiseRef.current = null; @@ -740,6 +743,7 @@ export default function TokenRoutes() { let enabled = 0; let disabled = 0; for (const route of baseFilteredRoutes) { + if (route.kind === 'zero_channel' || route.readOnly === true || route.isVirtual === true) continue; if (route.enabled) enabled++; else disabled++; } @@ -748,8 +752,10 @@ export default function TokenRoutes() { const filteredRoutes = useMemo(() => { if (enabledFilter === 'all') return baseFilteredRoutes; - if (enabledFilter === 'enabled') return baseFilteredRoutes.filter((route) => route.enabled); - return baseFilteredRoutes.filter((route) => !route.enabled); + return baseFilteredRoutes.filter((route) => { + if (route.kind === 'zero_channel' || route.readOnly === true || route.isVirtual === true) return false; + return enabledFilter === 'enabled' ? route.enabled : !route.enabled; + }); }, [baseFilteredRoutes, enabledFilter]); useEffect(() => { @@ -1451,7 +1457,7 @@ export default function TokenRoutes() {