Models.tsx L31 const [lockedCapDefaults, setLockedCapDefaults] = useState(...) 在模块顶层,违反 React Hooks 规则. 移到 Models component 函数体内 (L56). 解决 production 报 React error #321 Invalid hook call.
This commit is contained in:
1 parent
679f23ff93
commit
fa38d2c57a
1 file changed
+11
-4
@@ -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 (
|
||||||
|
|||||||
Reference in new issue
Block a user