表单设计器
This commit is contained in:
parent
0dabb6aef7
commit
b2efb2ffa7
@ -25,6 +25,7 @@ import {
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
import type { FieldConfig } from '../types';
|
||||
import GridField from './GridField';
|
||||
import '../styles.css';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import { Form, Button, message } from 'antd';
|
||||
import type { FieldConfig, FormConfig } from '../types';
|
||||
import FieldRenderer from './FieldRenderer';
|
||||
import GridFieldPreview from './GridFieldPreview';
|
||||
import '../styles.css';
|
||||
|
||||
interface FormPreviewProps {
|
||||
fields: FieldConfig[];
|
||||
@ -96,11 +97,12 @@ const FormPreview: React.FC<FormPreviewProps> = ({ fields, formConfig }) => {
|
||||
const wrapperColSpan = formConfig.labelAlign === 'left' || formConfig.labelAlign === 'right' ? 18 : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ padding: '24px 40px' }}>
|
||||
<Form
|
||||
form={form}
|
||||
layout={formLayout}
|
||||
size={formConfig.size}
|
||||
colon={true}
|
||||
labelAlign={formConfig.labelAlign === 'top' ? undefined : formConfig.labelAlign}
|
||||
labelCol={labelColSpan ? { span: labelColSpan } : undefined}
|
||||
wrapperCol={wrapperColSpan ? { span: wrapperColSpan } : undefined}
|
||||
@ -111,13 +113,19 @@ const FormPreview: React.FC<FormPreviewProps> = ({ fields, formConfig }) => {
|
||||
|
||||
{renderFields(fields)}
|
||||
|
||||
<Form.Item wrapperCol={wrapperColSpan ? { offset: labelColSpan, span: wrapperColSpan } : undefined}>
|
||||
<Button type="primary" onClick={handleSubmit} style={{ marginRight: 8 }}>
|
||||
提交
|
||||
</Button>
|
||||
<Button onClick={handleReset}>
|
||||
重置
|
||||
</Button>
|
||||
<Form.Item
|
||||
style={{ marginTop: 32, marginBottom: 0 }}
|
||||
labelCol={{ span: 0 }}
|
||||
wrapperCol={{ span: 24 }}
|
||||
>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', gap: 8 }}>
|
||||
<Button type="primary" onClick={handleSubmit}>
|
||||
提交
|
||||
</Button>
|
||||
<Button onClick={handleReset}>
|
||||
重置
|
||||
</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
||||
|
||||
@ -20,8 +20,15 @@ const GridFieldPreview: React.FC<GridFieldPreviewProps> = ({
|
||||
onFieldChange
|
||||
}) => {
|
||||
const columns = field.columns || 2;
|
||||
const colSpan = 24 / columns;
|
||||
const children = field.children || Array(columns).fill([]);
|
||||
|
||||
// 使用自定义列宽度或平均分配
|
||||
const getColSpan = (colIndex: number) => {
|
||||
if (field.columnSpans && field.columnSpans.length > colIndex) {
|
||||
return field.columnSpans[colIndex];
|
||||
}
|
||||
return 24 / columns; // 平均分配
|
||||
};
|
||||
|
||||
const renderFieldItem = (childField: FieldConfig) => {
|
||||
// 布局组件直接渲染,不需要 Form.Item
|
||||
@ -39,6 +46,7 @@ const GridFieldPreview: React.FC<GridFieldPreviewProps> = ({
|
||||
key={childField.id}
|
||||
label={childField.label}
|
||||
name={childField.name}
|
||||
colon={true}
|
||||
rules={[
|
||||
{
|
||||
required: childField.required,
|
||||
@ -59,11 +67,14 @@ const GridFieldPreview: React.FC<GridFieldPreviewProps> = ({
|
||||
return (
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Row gutter={field.gutter || 16}>
|
||||
{children.map((columnFields, colIndex) => (
|
||||
<Col key={colIndex} span={colSpan}>
|
||||
{columnFields.map((childField: FieldConfig) => renderFieldItem(childField))}
|
||||
</Col>
|
||||
))}
|
||||
{children.map((columnFields, colIndex) => {
|
||||
const colSpan = getColSpan(colIndex);
|
||||
return (
|
||||
<Col key={colIndex} span={colSpan}>
|
||||
{columnFields.map((childField: FieldConfig) => renderFieldItem(childField))}
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -133,3 +133,70 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 确保所有表单组件高度一致 */
|
||||
.ant-form-item .ant-input,
|
||||
.ant-form-item .ant-input-number,
|
||||
.ant-form-item .ant-input-number-input-wrap,
|
||||
.ant-form-item .ant-select-selector,
|
||||
.ant-form-item .ant-picker {
|
||||
min-height: 32px !important;
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.ant-form-item .ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||
height: 32px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 11px !important;
|
||||
}
|
||||
|
||||
.ant-form-item .ant-select-selection-search-input {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.ant-form-item .ant-input-number-input {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
/* 中等尺寸 */
|
||||
.ant-form-middle .ant-input,
|
||||
.ant-form-middle .ant-input-number,
|
||||
.ant-form-middle .ant-input-number-input-wrap,
|
||||
.ant-form-middle .ant-select-selector,
|
||||
.ant-form-middle .ant-picker {
|
||||
min-height: 32px !important;
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
.ant-form-middle .ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
/* 大尺寸 */
|
||||
.ant-form-large .ant-input,
|
||||
.ant-form-large .ant-input-number,
|
||||
.ant-form-large .ant-input-number-input-wrap,
|
||||
.ant-form-large .ant-select-selector,
|
||||
.ant-form-large .ant-picker {
|
||||
min-height: 40px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.ant-form-large .ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
/* 小尺寸 */
|
||||
.ant-form-small .ant-input,
|
||||
.ant-form-small .ant-input-number,
|
||||
.ant-form-small .ant-input-number-input-wrap,
|
||||
.ant-form-small .ant-select-selector,
|
||||
.ant-form-small .ant-picker {
|
||||
min-height: 24px !important;
|
||||
height: 24px !important;
|
||||
}
|
||||
|
||||
.ant-form-small .ant-select-single:not(.ant-select-customize-input) .ant-select-selector {
|
||||
height: 24px !important;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user