first commit

This commit is contained in:
liu
2026-07-13 15:23:29 +08:00
commit 50885a98c8
473 changed files with 33772 additions and 0 deletions
@@ -0,0 +1,152 @@
import React, {useCallback, useMemo} from 'react';
import {
Form,
Button,
Space, Row, Col,
} from 'antd';
import { useTranslation } from 'react-i18next';
import type { SearchFormProps, SubmitterButton } from './typings';
import type { FormItemProps } from 'antd';
import type { FormColumn } from "@/components/XinFormField/FieldRender";
import FieldRender from '@/components/XinFormField/FieldRender';
import { pick } from 'lodash';
/**
* SearchForm - JSON 配置动态搜索表单组件
*/
function SearchForm<T extends Record<string, any> = any>(props: SearchFormProps<T>) {
const {
columns,
handleSearch,
submitter,
form: formRef,
grid = true,
rowProps = {
gutter: [20, 20],
wrap: true
},
colProps = {
xs: 24,
sm: 12,
md: 12,
lg: 8,
xl: 6,
xxl: 4
},
...formProps
} = props;
const { t } = useTranslation();
const [form] = Form.useForm<T>(formRef);
// 渲染表单项
const renderFormItem = useCallback((column: FormColumn<T>, index: number): React.ReactNode => {
const {
dataIndex,
valueType,
title = '',
fieldProps = {},
fieldRender
} = column;
// Form.Item 允许的属性列表
const formItemPropKeys = [
'colon', 'extra', 'getValueFromEvent', 'help', 'htmlFor',
'initialValue', 'labelAlign', 'labelCol', 'name', 'normalize',
'noStyle', 'tooltip', 'wrapperCol', 'layout'
];
const formItemProps = pick(column, formItemPropKeys);
const key = String(dataIndex) || `form-item-${index}`;
const defaultFieldRender = (
<FieldRender
valueType={valueType}
placeholder={title}
{...fieldProps}
/>
);
const formItemContent = (
<Form.Item
style={{marginBottom: 0}}
key={key}
name={key}
label={column.title}
{...formItemProps as FormItemProps}
required={false}
>
{fieldRender ? fieldRender(form) : defaultFieldRender}
</Form.Item>
);
return grid ? <Col {...colProps} {...column.colProps} key={key}>{formItemContent}</Col> : formItemContent;
}, [form, grid, colProps]);
// 渲染提交按钮
const renderSubmitter = useMemo(() => {
if (submitter?.render === false) return null;
const submitButton = (
<Button
type="primary"
onClick={() => form.submit()}
{...submitter?.submitButtonProps}
>
{submitter?.submitText || t('xin.table.search.search')}
</Button>
);
const resetButton = (
<Button
onClick={() => form.resetFields()}
{...submitter?.resetButtonProps}
>
{submitter?.resetText || t('xin.table.search.reset')}
</Button>
);
const buttons: SubmitterButton = {
search: submitButton,
reset: resetButton
};
if (typeof submitter?.render === 'function') {
return submitter.render(buttons);
}
return (
<Form.Item style={{marginBottom: 0}}>
<Space size={16}>
{buttons.reset}
{buttons.search}
</Space>
</Form.Item>
);
}, [form, submitter, t]);
// 表单内容
return (
<Form
{...formProps}
form={form}
onFinish={handleSearch}
style={{ width: '100%' }}
>
{grid ? (
<Row {...rowProps}>
{columns.map((column, index) => renderFormItem(column, index))}
<Col {...colProps}>{renderSubmitter}</Col>
</Row>
) : (
<>
{columns.map((column, index) => renderFormItem(column, index))}
{renderSubmitter}
</>
)}
</Form>
)
}
export default SearchForm;
export type { SearchFormProps };
@@ -0,0 +1,53 @@
import type { ButtonProps, ColProps, FormInstance, FormProps, RowProps } from "antd";
import type { ReactNode } from "react";
import type { FormColumn } from "@/components/XinFormField/FieldRender";
/**
* 操作栏按钮
*/
export type SubmitterButton = {
/** 查询按钮 */
search: ReactNode;
/** 重置按钮 */
reset: ReactNode;
/** 折叠按钮 */
collapse?: ReactNode;
}
/**
* 表单操作栏属性
*/
export interface SubmitterProps {
/** 操作栏渲染 */
render?: false | ((dom: SubmitterButton) => ReactNode);
/** 提交按钮文本 */
submitText?: string | ReactNode;
/** 重置按钮文本 */
resetText?: string | ReactNode;
/** 提交按钮属性 */
submitButtonProps?: Omit<ButtonProps, 'loading' | 'onClick'>;
/** 重置按钮属性 */
resetButtonProps?: Omit<ButtonProps, 'loading' | 'onClick'>;
/** 折叠按钮渲染 */
collapseRender?: (collapse: boolean) => ReactNode;
}
/**
* XinSearch 组件属性
*/
export type SearchFormProps<T = any> = Omit<FormProps<T>, 'onFinish' | 'form'> & {
/** 表单列配置 */
columns: FormColumn<T>[];
/** 表单实例引用 */
form?: FormInstance<T>;
/** 表单提交 */
handleSearch?: (values: T) => Promise<boolean | void>;
/** 渲染表单操作栏 */
submitter?: SubmitterProps;
/** 是否使用 Grid 布局 */
grid?: boolean;
/** 开启 grid 模式时传递给 Row */
rowProps?: RowProps;
/** 传递给表单项的 Col */
colProps?: ColProps;
}