// ============================================================ // ImageInput — imageInput → Upload(单张图片) // 用于垫图、参考图等单图上传场景 // // enable_switch 支持: // 当 API ui.enable_switch === true 时,默认禁用(灰色), // 需点击 Switch 开关后才能上传——匹配原 Qt 客户端行为。 // 开关关闭时清除已上传文件。 // // 表单值语义(配合 constraints_config.requires 依赖禁用): // undefined → 开关关闭 / 未启用 → isValueEmpty = true → 依赖字段禁用 // [] → 开关开启但未上传文件 → isValueEmpty = false → 依赖字段启用 // [{...}] → 已上传文件 → isValueEmpty = false → 依赖字段启用 // ============================================================ import { useState, useCallback } from 'react'; import { Upload, Switch, Space, Typography, message } from 'antd'; import { UploadOutlined } from '@ant-design/icons'; import type { UploadFile, RcFile } from 'antd/es/upload'; import type { WidgetProps } from './types'; import { useFileUpload } from '@/hooks/use-api'; const { Text } = Typography; /** * 创建图片上传前的类型 & 大小校验函数(ImageInput / ImageListInput 共用) * @param maxSizeMb 最大文件大小(MB),默认 10 */ export function createImageBeforeUpload(maxSizeMb: number = 10) { return (file: RcFile) => { 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 true; }; } /** 构建图片 accept 字符串 */ function buildAccept(filters?: string[]): string { if (!filters || filters.length === 0) return 'image/png,image/jpg,image/jpeg,image/webp'; 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; const hasEnableSwitch = (config.enableSwitch as boolean) || false; // 文件上传 Hook(提供 customRequest → antd Upload 集成) const { customRequest } = useFileUpload(); // 有 enable_switch 时默认禁用,需手动开启 const [switchOn, setSwitchOn] = useState(!hasEnableSwitch); const isUploadDisabled = disabled || !switchOn; const handleSwitchChange = useCallback( (on: boolean) => { setSwitchOn(on); if (!on) { // 关闭开关 → 表单值置为 undefined(isValueEmpty = true,依赖字段禁用) onChange?.(undefined); } else { // 开启开关 → 空数组 = "已启用但未上传"(isValueEmpty = false,依赖字段启用) onChange?.(ENABLED_EMPTY as unknown as UploadFile[]); } }, [onChange], ); return ( {hasEnableSwitch && ( {switchOn ? '已启用' : '点击开关启用上传'} )} { // 仅当开关开启时上报文件变化 if (switchOn || !hasEnableSwitch) { onChange?.(newList as unknown as UploadFile[]); } }} disabled={isUploadDisabled} beforeUpload={createImageBeforeUpload(maxSizeMb)} > {fileList.length < 1 && (
上传
)}
); }