From 0c7b33aac16d34541fad7b51b00b4db524514caa Mon Sep 17 00:00:00 2001 From: YoungestSongMo <2130460579@qq.com> Date: Tue, 9 Jun 2026 17:36:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20constraints=5Fconfig.requires=20?= =?UTF-8?q?=E8=81=94=E5=8A=A8=E6=8E=A7=E5=88=B6=20=E2=80=94=20enable=5Fswi?= =?UTF-8?q?tch=20=E5=BC=80=E5=85=B3=E5=90=8C=E6=AD=A5=E5=90=AF=E7=94=A8/?= =?UTF-8?q?=E7=A6=81=E7=94=A8=E4=BE=9D=E8=B5=96=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DependentFormItem: 透传 disabled 为顶层 prop(之前藏在 config.disabled 中,widget 组件读取不到) - ImageInput: 值语义分层 — undefined(开关关) / [](开关开但空) / [{...}](已上传) - isValueEmpty: 空数组[] 不再视为空,配合 enable_switch 语义 - handleFileWidgetValue: 兼容 Upload DOM事件 和 enable_switch 裸值两种 onChange 形态 Co-Authored-By: Claude Opus 4.8 --- src/pages/home/components/ModelInputForm.tsx | 17 ++++++++++++- src/pages/home/components/useModelUI.ts | 9 +++++-- .../home/components/useUI/ImageInput.tsx | 25 +++++++++++++++---- 3 files changed, 43 insertions(+), 8 deletions(-) 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/');