121 lines
3.0 KiB
React
121 lines
3.0 KiB
React
|
|
import React, { useState, useEffect, useRef } from 'react';
|
|||
|
|
import { Input } from 'antd';
|
|||
|
|
import { Search } from 'lucide-react';
|
|||
|
|
import './ExpandSearchBox.css';
|
|||
|
|
|
|||
|
|
const ExpandSearchBox = ({
|
|||
|
|
searchQuery = '',
|
|||
|
|
onSearchChange = null,
|
|||
|
|
placeholder = '搜索会议名称或发起人...',
|
|||
|
|
collapsedText = '会议搜索',
|
|||
|
|
showIcon = true,
|
|||
|
|
realTimeSearch = false, // 改为默认false,避免频繁刷新
|
|||
|
|
debounceDelay = 500 // 防抖延迟时间(毫秒)
|
|||
|
|
}) => {
|
|||
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|||
|
|
const [inputValue, setInputValue] = useState(searchQuery);
|
|||
|
|
const debounceTimerRef = useRef(null);
|
|||
|
|
|
|||
|
|
// 同步外部 searchQuery 的变化
|
|||
|
|
useEffect(() => {
|
|||
|
|
setInputValue(searchQuery);
|
|||
|
|
}, [searchQuery]);
|
|||
|
|
|
|||
|
|
const handleInputChange = (e) => {
|
|||
|
|
const value = e.target.value;
|
|||
|
|
setInputValue(value);
|
|||
|
|
|
|||
|
|
// 如果启用实时搜索,使用防抖触发回调
|
|||
|
|
if (realTimeSearch && onSearchChange) {
|
|||
|
|
// 清除之前的定时器
|
|||
|
|
if (debounceTimerRef.current) {
|
|||
|
|
clearTimeout(debounceTimerRef.current);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置新的定时器
|
|||
|
|
debounceTimerRef.current = setTimeout(() => {
|
|||
|
|
onSearchChange(value.trim());
|
|||
|
|
}, debounceDelay);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleSearch = () => {
|
|||
|
|
// 立即清除防抖定时器
|
|||
|
|
if (debounceTimerRef.current) {
|
|||
|
|
clearTimeout(debounceTimerRef.current);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (onSearchChange) {
|
|||
|
|
onSearchChange(inputValue.trim());
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleKeyPress = (e) => {
|
|||
|
|
if (e.key === 'Enter') {
|
|||
|
|
handleSearch();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleClear = () => {
|
|||
|
|
// 清除防抖定时器
|
|||
|
|
if (debounceTimerRef.current) {
|
|||
|
|
clearTimeout(debounceTimerRef.current);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setInputValue('');
|
|||
|
|
if (onSearchChange) {
|
|||
|
|
onSearchChange('');
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 组件卸载时清除定时器
|
|||
|
|
useEffect(() => {
|
|||
|
|
return () => {
|
|||
|
|
if (debounceTimerRef.current) {
|
|||
|
|
clearTimeout(debounceTimerRef.current);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
// 如果没有提供搜索回调函数,显示只读标题
|
|||
|
|
if (!onSearchChange) {
|
|||
|
|
return (
|
|||
|
|
<div className="expand-search-readonly">
|
|||
|
|
{showIcon && <Search size={18} />}
|
|||
|
|
<h3>{collapsedText}</h3>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div
|
|||
|
|
className={`expand-search-box ${isExpanded ? 'expanded' : ''}`}
|
|||
|
|
onClick={() => !isExpanded && setIsExpanded(true)}
|
|||
|
|
>
|
|||
|
|
{showIcon && <Search size={18} className="search-icon" />}
|
|||
|
|
{isExpanded ? (
|
|||
|
|
<Input
|
|||
|
|
placeholder={placeholder}
|
|||
|
|
value={inputValue}
|
|||
|
|
onChange={handleInputChange}
|
|||
|
|
onPressEnter={handleSearch}
|
|||
|
|
onKeyPress={handleKeyPress}
|
|||
|
|
onBlur={() => {
|
|||
|
|
if (!inputValue) setIsExpanded(false);
|
|||
|
|
}}
|
|||
|
|
allowClear={{
|
|||
|
|
clearIcon: <span onClick={handleClear}>×</span>
|
|||
|
|
}}
|
|||
|
|
onClear={handleClear}
|
|||
|
|
autoFocus
|
|||
|
|
className="search-input-antd"
|
|||
|
|
/>
|
|||
|
|
) : (
|
|||
|
|
<span className="search-placeholder">{collapsedText}</span>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default ExpandSearchBox;
|