diff --git a/src/pages/home/components/ModelInputForm.tsx b/src/pages/home/components/ModelInputForm.tsx
index 00f442c..4fd46e2 100644
--- a/src/pages/home/components/ModelInputForm.tsx
+++ b/src/pages/home/components/ModelInputForm.tsx
@@ -36,6 +36,20 @@ import { useModelUI, isValueEmpty, type UIFieldConfig } from './useModelUI';
const { Text, Title } = Typography;
+// ---------- 工具 ----------
+
+/**
+ * Form.Item 的 getValueFromEvent,兼容两种 onChange 参数形态:
+ * 1. Upload 组件的 DOM 事件:{ fileList: UploadFile[] } → 提取 fileList
+ * 2. enable_switch 的裸值:undefined / [] / [{...}] → 直接透传
+ */
+function handleFileWidgetValue(e: unknown): unknown {
+ if (e && typeof e === 'object' && 'fileList' in e) {
+ return (e as { fileList: unknown }).fileList;
+ }
+ return e;
+}
+
// ---------- 依赖字段包装组件 ----------
/**
@@ -78,6 +92,7 @@ function DependentFormItem({
);
@@ -329,7 +344,7 @@ export function ModelInputForm() {
}
valuePropName={field.valuePropName}
{...(field.isFileWidget
- ? { getValueFromEvent: (e: { fileList: UploadFile[] }) => e.fileList }
+ ? { getValueFromEvent: handleFileWidgetValue }
: {})}
>
diff --git a/src/pages/home/components/useModelUI.ts b/src/pages/home/components/useModelUI.ts
index 003f192..d5238ca 100644
--- a/src/pages/home/components/useModelUI.ts
+++ b/src/pages/home/components/useModelUI.ts
@@ -169,11 +169,16 @@ export function isFileWidget(widgetName: string): boolean {
// ---------- 值判空工具 ----------
-/** 判断表单值是否为"空"(用于依赖禁用判断) */
+/**
+ * 判断表单值是否为"空"(用于依赖禁用判断)。
+ *
+ * 注意:空数组 [] 不视为空。
+ * 对于 enable_switch 控件:undefined = 开关关闭, [] = 开关开启但未选文件。
+ * 配合 constraints_config.requires:开关开启即解锁依赖字段,无需等待文件上传。
+ */
export function isValueEmpty(value: unknown): boolean {
if (value === undefined || value === null) return true;
if (typeof value === 'string' && value.trim() === '') return true;
- if (Array.isArray(value) && value.length === 0) return true;
if (typeof value === 'boolean' && !value) return true;
return false;
}
diff --git a/src/pages/home/components/useUI/ImageInput.tsx b/src/pages/home/components/useUI/ImageInput.tsx
index 9cf77c5..a5f0c28 100644
--- a/src/pages/home/components/useUI/ImageInput.tsx
+++ b/src/pages/home/components/useUI/ImageInput.tsx
@@ -6,6 +6,11 @@
// 当 API ui.enable_switch === true 时,默认禁用(灰色),
// 需点击 Switch 开关后才能上传——匹配原 Qt 客户端行为。
// 开关关闭时清除已上传文件。
+//
+// 表单值语义(配合 constraints_config.requires 依赖禁用):
+// undefined → 开关关闭 / 未启用 → isValueEmpty = true → 依赖字段禁用
+// [] → 开关开启但未上传文件 → isValueEmpty = false → 依赖字段启用
+// [{...}] → 已上传文件 → isValueEmpty = false → 依赖字段启用
// ============================================================
import { useState, useCallback } from 'react';
@@ -22,6 +27,9 @@ function buildAccept(filters?: string[]): string {
return filters.map((ext) => `image/${ext}`).join(',');
}
+/** 标记"已启用但空"的空数组,避免 react 渲染时引用变化 */
+const ENABLED_EMPTY: UploadFile[] = [];
+
export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
const fileList = (value as UploadFile[]) || [];
const maxSizeMb = (config.maxFileSizeMb as number) || 10;
@@ -35,16 +43,18 @@ export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
(on: boolean) => {
setSwitchOn(on);
if (!on) {
- // 关闭开关 → 清除已上传文件
- onChange?.([] as unknown as UploadFile[]);
+ // 关闭开关 → 表单值置为 undefined(isValueEmpty = true,依赖字段禁用)
+ onChange?.(undefined);
+ } else {
+ // 开启开关 → 空数组 = "已启用但未上传"(isValueEmpty = false,依赖字段启用)
+ onChange?.(ENABLED_EMPTY as unknown as UploadFile[]);
}
},
[onChange],
);
return (
-
+
{hasEnableSwitch && (
onChange?.(newList as unknown as UploadFile[])}
+ onChange={({ fileList: newList }) => {
+ // 仅当开关开启时上报文件变化
+ if (switchOn || !hasEnableSwitch) {
+ onChange?.(newList as unknown as UploadFile[]);
+ }
+ }}
disabled={isUploadDisabled}
beforeUpload={(file) => {
const isImage = file.type.startsWith('image/');