#964 修复 React error #321 模块级 useState 调用

Models.tsx L31 const [lockedCapDefaults, setLockedCapDefaults] = useState(...) 在模块顶层,违反 React Hooks 规则. 移到 Models component 函数体内 (L56). 解决 production 报 React error #321 Invalid hook call.
This commit is contained in:
qihu-bot committed 2026-08-11 13:57:51 +08:00
1 parent 679f23ff93
commit fa38d2c57a
1 file changed
+11 -4
+11 -4
View File
@@ -26,9 +26,9 @@ const capabilityLabels: Record<string, string> = {
embedding: '嵌入向量', rerank: '重排序', video: '视频生成', embedding: '嵌入向量', rerank: '重排序', video: '视频生成',
}; };
// 锁定项:文本对话(text) 与 推理思考(thinking) 强制使用平台默认对话模型, // 锁定项:text/thinking 能力动态绑定 is_default=true 模型,不再硬编码 ID。
// 防止被误配到失效模型导致 chat 不可用(见全栈体检修复记录)。 // 后端 defensive guard(chat_service.py)确保普通文字对话不会误走 image/video 模型。
const LOCKED_CAP_DEFAULTS: Record<string, string> = { text: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b', thinking: 'aaae3233-4fd9-4b3e-ab51-cd8a87c82e0b' }; // #964: 修复 React error #321 — useState 必须放在组件函数体内,不能在模块顶层
// Test result type // Test result type
interface TestResult { interface TestResult {
@@ -53,6 +53,8 @@ interface EditingModel {
} }
const Models: React.FC = () => { const Models: React.FC = () => {
const [lockedCapDefaults, setLockedCapDefaults] = useState<Record<string, string>>({});
const [providers, setProviders] = useState<ModelProvider[]>([]); const [providers, setProviders] = useState<ModelProvider[]>([]);
const [models, setModels] = useState<AIModel[]>([]); const [models, setModels] = useState<AIModel[]>([]);
const [protocols, setProtocols] = useState<ProtocolDef[]>([]); const [protocols, setProtocols] = useState<ProtocolDef[]>([]);
@@ -120,6 +122,11 @@ const Models: React.FC = () => {
setCapabilities(cd.capabilities || []); setCapabilities(cd.capabilities || []);
setCapabilityDefaults(cd.defaults || {}); setCapabilityDefaults(cd.defaults || {});
setCapabilityModels(cd.models || []); 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) { } catch (err: any) {
setError('加载数据失败:' + (err.message || err.detail || JSON.stringify(err))); setError('加载数据失败:' + (err.message || err.detail || JSON.stringify(err)));
} finally { } finally {
@@ -531,7 +538,7 @@ const Models: React.FC = () => {
); );
const cur = capabilityDefaults[cap.id] || ''; const cur = capabilityDefaults[cap.id] || '';
const saving = savingCaps.has(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 isLocked = Boolean(lockedModelId);
const dotColor = cap.color || capabilityColors[cap.id] || '#6B7280'; const dotColor = cap.color || capabilityColors[cap.id] || '#6B7280';
return ( return (