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() {