From d278b41be2c9868f951714bc36574e3bbff5ee81 Mon Sep 17 00:00:00 2001 From: Hureru <3507039083@qq.com> Date: Sun, 22 Mar 2026 20:44:55 +0800 Subject: [PATCH] fix: address review issues in brand filter sync, model guard, route counts, and candidate loading - Sync blockedBrands local state after save to prevent stale chips - Defer getBrandList from blocking Settings bootstrap - Guard model management UI on brandGroups instead of availableModels - Deduplicate single-model add in disabled models - Skip read-only/zero-channel routes in enabledCounts and filter - Add sequence counter to loadCandidates to prevent force race condition - Use stableAddChannel for mobile add-channel button --- src/web/pages/Settings.tsx | 19 +++++++------------ src/web/pages/Sites.tsx | 4 ++-- src/web/pages/TokenRoutes.tsx | 14 ++++++++++---- 3 files changed, 19 insertions(+), 18 deletions(-) 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 && (