From fa38d2c57af16e10cf4033b4aff3bdcc5dd63e11 Mon Sep 17 00:00:00 2001 From: qihu-bot Date: Tue, 11 Aug 2026 13:57:51 +0800 Subject: [PATCH] =?UTF-8?q?#964=20=E4=BF=AE=E5=A4=8D=20React=20error=20#32?= =?UTF-8?q?1=20=E6=A8=A1=E5=9D=97=E7=BA=A7=20useState=20=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Models.tsx L31 const [lockedCapDefaults, setLockedCapDefaults] = useState(...) 在模块顶层,违反 React Hooks 规则. 移到 Models component 函数体内 (L56). 解决 production 报 React error #321 Invalid hook call. --- frontend/src/pages/admin/Models.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/admin/Models.tsx b/frontend/src/pages/admin/Models.tsx index 4692033..1d54870 100644 --- a/frontend/src/pages/admin/Models.tsx +++ b/frontend/src/pages/admin/Models.tsx @@ -26,9 +26,9 @@ const capabilityLabels: Record = { embedding: '嵌入向量', rerank: '重排序', video: '视频生成', }; -// 锁定项:文本对话(text) 与 推理思考(thinking) 强制使用平台默认对话模型, -// 防止被误配到失效模型导致 chat 不可用(见全栈体检修复记录)。 -const LOCKED_CAP_DEFAULTS: Record = { text: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b', thinking: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b' }; +// 锁定项:text/thinking 能力动态绑定 is_default=true 模型,不再硬编码 ID。 +// 后端 defensive guard(chat_service.py)确保普通文字对话不会误走 image/video 模型。 +// #964: 修复 React error #321 — useState 必须放在组件函数体内,不能在模块顶层 // Test result type interface TestResult { @@ -53,6 +53,8 @@ interface EditingModel { } const Models: React.FC = () => { + const [lockedCapDefaults, setLockedCapDefaults] = useState>({}); + const [providers, setProviders] = useState([]); const [models, setModels] = useState([]); const [protocols, setProtocols] = useState([]); @@ -120,6 +122,11 @@ const Models: React.FC = () => { setCapabilities(cd.capabilities || []); setCapabilityDefaults(cd.defaults || {}); setCapabilityModels(cd.models || []); + // 动态锁定:is_default=true 模型绑定 text + thinking + const defaultM = mappedModels.find((m: any) => m.isDefault); + if (defaultM) { + setLockedCapDefaults({ text: defaultM.id, thinking: defaultM.id }); + } } catch (err: any) { setError('加载数据失败:' + (err.message || err.detail || JSON.stringify(err))); } finally { @@ -531,7 +538,7 @@ const Models: React.FC = () => { ); const cur = capabilityDefaults[cap.id] || ''; const saving = savingCaps.has(cap.id); - const lockedModelId = LOCKED_CAP_DEFAULTS[cap.id]; + const lockedModelId = lockedCapDefaults[cap.id]; const isLocked = Boolean(lockedModelId); const dotColor = cap.color || capabilityColors[cap.id] || '#6B7280'; return (