import { InfoCircleOutlined } from "@ant-design/icons"; import { Button, Checkbox, Col, DatePicker, Divider, Form, Input, InputNumber, Radio, Row, Select, Tooltip, } from "antd"; import dayjs from "dayjs"; import { FORM_ITEM_RENDER_ENUM } from "../../enum/formItemRender"; const { TextArea } = Input; const { RangePicker } = DatePicker; /** * 表单项渲染器组件 * @param {object} props - 组件属性 * @param {Array} props.options - 表单配置项数组 * @param {object} props.labelCol - label 栅格配置 * @param {number} props.gutter - 栅格间距 * @param {number} props.span - 默认栅格占据列数 * @param {boolean} props.collapse - 是否折叠(仅显示前3项) * @param {boolean} props.useAutoGenerateRequired - 是否自动生成必填规则 * @param {object} props.initialValues - 初始值 */ const FormItemsRenderer = ({ options, labelCol, gutter = 24, span = 12, collapse = false, useAutoGenerateRequired = true, initialValues, }) => { const form = Form.useFormInstance(); // 获取表单值,优先使用 initialValues const getFormValues = () => { const formValues = form.getFieldsValue(); // 如果表单值为空但有 initialValues,则使用 initialValues if (Object.keys(formValues).length === 0 && initialValues) { return initialValues; } return formValues; }; // 获取传给组件的属性 const getComponentProps = (option) => { return typeof option.componentProps === "function" ? option.componentProps(getFormValues()) : (option.componentProps || {}); }; // 获取 Form.List 独有的属性 const getFormListUniqueProps = (option) => { const defaultProps = { showAddButton: true, showRemoveButton: true, addButtonText: "添加", removeButtonText: "删除", options: [], addDefaultValue: {}, addInsertIndex: undefined, }; if (typeof option.formListUniqueProps === "function") { return { ...defaultProps, ...option.formListUniqueProps(getFormValues()), }; } return { ...defaultProps, ...(option.formListUniqueProps || {}), }; }; // 获取传给formItem的属性 const getFormItemProps = (option) => { const formItemProps = typeof option.formItemProps === "function" ? option.formItemProps(getFormValues()) : (option.formItemProps || {}); // 为日期组件添加特殊处理 if ([ FORM_ITEM_RENDER_ENUM.DATE, FORM_ITEM_RENDER_ENUM.DATE_MONTH, FORM_ITEM_RENDER_ENUM.DATE_YEAR, FORM_ITEM_RENDER_ENUM.DATETIME, ].includes(option.render)) { formItemProps.getValueFromEvent = (_, dateString) => dateString; formItemProps.getValueProps = value => ({ value: value ? dayjs(value) : undefined }); } // 为日期周组件添加特殊处理 if ([ FORM_ITEM_RENDER_ENUM.DATE_WEEK, ].includes(option.render)) { formItemProps.getValueFromEvent = (_, dateString) => dateString; formItemProps.getValueProps = value => ({ value: value ? dayjs(value, "YYYY-wo") : undefined }); } // 为日期范围组件添加特殊处理 if ([ FORM_ITEM_RENDER_ENUM.DATE_RANGE, FORM_ITEM_RENDER_ENUM.DATETIME_RANGE, ].includes(option.render)) { formItemProps.getValueFromEvent = (_, dateString) => dateString; formItemProps.getValueProps = value => ({ value: Array.isArray(value) ? value.map(v => v ? dayjs(v) : undefined) : undefined }); } return formItemProps; }; // 获取items里的value和label字段key const getItemsFieldKey = (option) => { return { valueKey: option?.itemsField?.valueKey || "bianma", labelKey: option?.itemsField?.labelKey || "name", }; }; // 获取 required const getRequired = (required) => { // 支持动态计算 required return typeof required === "function" ? required(getFormValues()) : (required ?? true); }; // 获取验证规则 const getRules = (option) => { if (option.render === FORM_ITEM_RENDER_ENUM.DIVIDER) return []; const rules = []; /** @type {string | Function} */ const render = option.render || FORM_ITEM_RENDER_ENUM.INPUT; switch (render) { case FORM_ITEM_RENDER_ENUM.INPUT: rules.push({ max: 50, message: "最多输入50字符" }); break; case FORM_ITEM_RENDER_ENUM.TEXTAREA: rules.push({ max: 500, message: "最多输入500字符" }); break; case FORM_ITEM_RENDER_ENUM.INPUT_NUMBER: case FORM_ITEM_RENDER_ENUM.NUMBER: rules.push({ pattern: /^(\d+)(\.\d{1,2})?$/, message: "请输入正确的数字,最多保留两位小数" }); rules.push({ validator: (_, value) => { if (value && Math.abs(Number.parseFloat(value)) > 999999999) { return Promise.reject("输入数值超出安全范围"); } return Promise.resolve(); }, }); break; } if (!useAutoGenerateRequired) return option.rules ? (Array.isArray(option.rules) ? [...option.rules, ...rules] : [option.rules, ...rules]) : rules; if (getRequired(option.required)) { const isBlurTrigger = !option.render || [ FORM_ITEM_RENDER_ENUM.INPUT, FORM_ITEM_RENDER_ENUM.TEXTAREA, FORM_ITEM_RENDER_ENUM.INPUT_NUMBER, FORM_ITEM_RENDER_ENUM.NUMBER, ].includes(option.render); rules.push({ required: true, message: `${isBlurTrigger ? "请输入" : "请选择"}${option.label}` }); if (option.rules) { if (Array.isArray(option.rules)) { rules.push(...option.rules); } else { rules.push(option.rules); } } return rules; } return option.rules ? (Array.isArray(option.rules) ? [...option.rules, ...rules] : [option.rules, ...rules]) : rules; }; // 获取key const getKey = (option) => { return option.key || option.name; }; // 使用 style 控制显示/隐藏 const getStyle = (index) => { return collapse && index >= 3 ? { display: "none" } : undefined; }; // 获取 span const getSpan = (span) => { // 支持动态计算 span return typeof span === "function" ? span(getFormValues()) : span; } // 列数 const getCol = (option) => { const itemSpan = option.render === FORM_ITEM_RENDER_ENUM.DIVIDER ? 24 : (getSpan(option.span) ?? span); const itemLabelCol = option.labelCol ?? (itemSpan === 24 ? { span: labelCol.span / 2 } : labelCol); const itemWrapperCol = option.wrapperCol ?? { span: 24 - itemLabelCol.span }; return { span: itemSpan, labelCol: itemLabelCol, wrapperCol: itemWrapperCol }; }; // 获取 hidden const getHidden = (hidden) => { // 支持动态计算 hidden return typeof hidden === "function" ? hidden(getFormValues()) : (hidden ?? false); }; // 获取 listOptions const getListOptions = (listOptions, field, fieldIndex) => { return typeof listOptions === "function" ? listOptions(field, fieldIndex) : (listOptions ?? []); }; // 渲染表单控件 const renderFormControl = (option) => { const componentProps = getComponentProps(option); const itemsFieldKey = getItemsFieldKey(option); /** @type {string | Function} */ const render = option.render || FORM_ITEM_RENDER_ENUM.INPUT; const placeholder = option.placeholder || `请${render === FORM_ITEM_RENDER_ENUM.SELECT || render === FORM_ITEM_RENDER_ENUM.RADIO || render === FORM_ITEM_RENDER_ENUM.CHECKBOX ? "选择" : "输入"}${option.label}`; switch (render) { case FORM_ITEM_RENDER_ENUM.INPUT: return ; case FORM_ITEM_RENDER_ENUM.TEXTAREA: return