fix: 修复模型默认值不加载 + DependentFormItem prop 透传断裂

- DependentFormItem 透传 Form.Item 注入的 value/onChange/disabled prop
- 稳定化 constraintsConfig 空对象引用(EMPTY_OBJ),避免 useMemo 失效导致无限重渲染
- useLayoutEffect 手动 setFieldsValue(initialValues)替代 antd 被忽略的 initialValues prop
- handleReset 使用 resetFields + setFieldsValue 组合确保默认值归位

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 17:00:44 +08:00
parent d5ba7e63cd
commit 4261915679
5 changed files with 287 additions and 131 deletions

View File

@@ -1,13 +1,21 @@
// ============================================================
// ImageInput — imageInput → Upload单张图片
// 用于垫图、参考图等单图上传场景
//
// enable_switch 支持:
// 当 API ui.enable_switch === true 时,默认禁用(灰色),
// 需点击 Switch 开关后才能上传——匹配原 Qt 客户端行为。
// 开关关闭时清除已上传文件。
// ============================================================
import { Upload, message } from 'antd';
import { useState, useCallback } from 'react';
import { Upload, Switch, Space, Typography, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload';
import type { WidgetProps } from './types';
const { Text } = Typography;
/** 构建图片 accept 字符串 */
function buildAccept(filters?: string[]): string {
if (!filters || filters.length === 0) return 'image/png,image/jpg,image/jpeg,image/webp';
@@ -17,34 +25,67 @@ function buildAccept(filters?: string[]): string {
export function ImageInput({ value, onChange, disabled, config }: WidgetProps) {
const fileList = (value as UploadFile[]) || [];
const maxSizeMb = (config.maxFileSizeMb as number) || 10;
const hasEnableSwitch = (config.enableSwitch as boolean) || false;
// 有 enable_switch 时默认禁用,需手动开启
const [switchOn, setSwitchOn] = useState(!hasEnableSwitch);
const isUploadDisabled = disabled || !switchOn;
const handleSwitchChange = useCallback(
(on: boolean) => {
setSwitchOn(on);
if (!on) {
// 关闭开关 → 清除已上传文件
onChange?.([] as unknown as UploadFile[]);
}
},
[onChange],
);
return (
<Upload
listType="picture-card"
maxCount={1}
accept={buildAccept(config.fileFilter as string[] | undefined)}
fileList={fileList}
onChange={({ fileList: newList }) => onChange?.(newList)}
disabled={disabled}
beforeUpload={(file) => {
const isImage = file.type.startsWith('image/');
if (!isImage) {
message.error('只能上传图片文件');
return Upload.LIST_IGNORE;
}
if (file.size / 1024 / 1024 >= maxSizeMb) {
message.error(`图片大小不能超过 ${maxSizeMb}MB`);
return Upload.LIST_IGNORE;
}
return false;
}}
>
{fileList.length < 1 && (
<div>
<UploadOutlined />
<div style={{ marginTop: 4, fontSize: 12 }}></div>
</div>
<Space orientation={"vertical"}
style={{ width: '100%' }} size={8}>
{hasEnableSwitch && (
<Space size={8}>
<Switch
size="small"
checked={switchOn}
onChange={handleSwitchChange}
disabled={disabled}
/>
<Text type={switchOn ? 'success' : 'secondary'} style={{ fontSize: 12 }}>
{switchOn ? '已启用' : '点击开关启用上传'}
</Text>
</Space>
)}
</Upload>
<Upload
listType="picture-card"
maxCount={1}
accept={buildAccept(config.fileFilter as string[] | undefined)}
fileList={fileList}
onChange={({ fileList: newList }) => onChange?.(newList as unknown as UploadFile[])}
disabled={isUploadDisabled}
beforeUpload={(file) => {
const isImage = file.type.startsWith('image/');
if (!isImage) {
message.error('只能上传图片文件');
return Upload.LIST_IGNORE;
}
if (file.size / 1024 / 1024 >= maxSizeMb) {
message.error(`图片大小不能超过 ${maxSizeMb}MB`);
return Upload.LIST_IGNORE;
}
return false;
}}
>
{fileList.length < 1 && (
<div style={{ opacity: isUploadDisabled ? 0.4 : 1 }}>
<UploadOutlined />
<div style={{ marginTop: 4, fontSize: 12 }}></div>
</div>
)}
</Upload>
</Space>
);
}