2025-10-22 14:43:42 +08:00
|
|
|
import { DownOutlined, UpOutlined } from "@ant-design/icons";
|
|
|
|
|
import { Button, Col, Form, Row } from "antd";
|
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
|
import FormItemsRenderer from "../FormBuilder/FormItemsRenderer";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 搜索表单组件
|
|
|
|
|
*/
|
|
|
|
|
const Search = (props) => {
|
|
|
|
|
const {
|
2025-10-28 15:39:48 +08:00
|
|
|
labelCol = { span: 6 },
|
2025-10-22 14:43:42 +08:00
|
|
|
options = [],
|
|
|
|
|
values,
|
|
|
|
|
onFinish,
|
|
|
|
|
onSubmit,
|
|
|
|
|
onReset,
|
|
|
|
|
searchText = "搜索",
|
|
|
|
|
resetText = "重置",
|
|
|
|
|
showSearchButton = true,
|
|
|
|
|
showResetButton = true,
|
|
|
|
|
extraButtons,
|
|
|
|
|
form,
|
|
|
|
|
...restProps
|
|
|
|
|
} = props;
|
|
|
|
|
|
|
|
|
|
const [collapse, setCollapse] = useState(true);
|
|
|
|
|
const [span, setSpan] = useState(6);
|
|
|
|
|
const [showCollapseButton, setShowCollapseButton] = useState(false);
|
|
|
|
|
const classNameRef = useRef(`search-${Date.now()}`);
|
|
|
|
|
|
|
|
|
|
// 计算是否需要显示展开/收起按钮
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!options || options.length === 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const calculateLayout = () => {
|
|
|
|
|
const colEl = document.querySelectorAll(
|
|
|
|
|
`.${classNameRef.current}>.${window.process.env.app.antd["ant-prefix"]}-col`,
|
|
|
|
|
);
|
|
|
|
|
const colElLength = colEl.length;
|
|
|
|
|
const excludeLast = colElLength - (extraButtons ? 2 : 1);
|
|
|
|
|
|
|
|
|
|
const spanMap = { 0: 24, 1: 18, 2: 12, 3: 6 };
|
|
|
|
|
setSpan(spanMap[excludeLast % 4] || 6);
|
|
|
|
|
|
|
|
|
|
setShowCollapseButton(excludeLast > 3);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 延迟执行以确保 DOM 已渲染
|
|
|
|
|
setTimeout(calculateLayout, 0);
|
|
|
|
|
}, [options, extraButtons]);
|
|
|
|
|
|
|
|
|
|
// 处理表单提交
|
|
|
|
|
const handleSubmit = () => {
|
|
|
|
|
const values = form.getFieldsValue();
|
|
|
|
|
onFinish?.(values, "submit");
|
|
|
|
|
onSubmit?.(values);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理重置
|
|
|
|
|
const handleReset = () => {
|
|
|
|
|
form.resetFields();
|
|
|
|
|
const values = form.getFieldsValue();
|
|
|
|
|
onFinish?.(values, "reset");
|
|
|
|
|
onReset?.(values);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 切换展开/收起
|
|
|
|
|
const toggleCollapse = () => {
|
|
|
|
|
setCollapse(!collapse);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Form
|
|
|
|
|
form={form}
|
|
|
|
|
labelCol={labelCol}
|
|
|
|
|
initialValues={values}
|
|
|
|
|
{...restProps}
|
|
|
|
|
>
|
|
|
|
|
<Row className={classNameRef.current}>
|
|
|
|
|
<FormItemsRenderer
|
|
|
|
|
options={options}
|
2025-10-28 12:30:57 +08:00
|
|
|
labelCol={labelCol}
|
2025-10-22 14:43:42 +08:00
|
|
|
span={6}
|
|
|
|
|
collapse={collapse}
|
|
|
|
|
useAutoGenerateRequired={false}
|
2025-10-29 09:38:36 +08:00
|
|
|
initialValues={values}
|
2025-10-22 14:43:42 +08:00
|
|
|
/>
|
|
|
|
|
<Col span={showCollapseButton ? (collapse ? 6 : span) : span}>
|
|
|
|
|
<Form.Item label=" " colon={false} style={{ textAlign: "right" }}>
|
|
|
|
|
{showSearchButton && (
|
|
|
|
|
<Button type="primary" onClick={handleSubmit}>
|
|
|
|
|
{searchText}
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
{showResetButton && (
|
|
|
|
|
<Button style={{ marginLeft: 8 }} onClick={handleReset}>
|
|
|
|
|
{resetText}
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
{showCollapseButton && (
|
|
|
|
|
<Button
|
|
|
|
|
type="link"
|
|
|
|
|
icon={collapse ? <DownOutlined /> : <UpOutlined />}
|
|
|
|
|
onClick={toggleCollapse}
|
|
|
|
|
style={{ marginLeft: 8 }}
|
|
|
|
|
>
|
|
|
|
|
{collapse ? "展开" : "收起"}
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
{extraButtons && (
|
|
|
|
|
<Col span={24}>
|
|
|
|
|
<Form.Item label=" " colon={false} labelCol={{ span: 0 }}>
|
|
|
|
|
{extraButtons}
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</Col>
|
|
|
|
|
)}
|
|
|
|
|
</Row>
|
|
|
|
|
</Form>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Search.displayName = "Search";
|
|
|
|
|
|
|
|
|
|
export default Search;
|