feat(设备搜索): 为设备选择器添加防抖搜索功能
This commit is contained in:
@@ -5,6 +5,18 @@ import axios from 'axios';
|
|||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
|
const debounce = (func, wait) => {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -14,6 +26,30 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
|||||||
const [fetchingDevices, setFetchingDevices] = useState(false);
|
const [fetchingDevices, setFetchingDevices] = useState(false);
|
||||||
const prevVisibleRef = useRef(false);
|
const prevVisibleRef = useRef(false);
|
||||||
|
|
||||||
|
const fetchDevices = useCallback(async (keyword = '') => {
|
||||||
|
try {
|
||||||
|
setFetchingDevices(true);
|
||||||
|
const params = { pageSize: 50 };
|
||||||
|
if (keyword && keyword.trim()) {
|
||||||
|
params.keyword = keyword.trim();
|
||||||
|
}
|
||||||
|
const response = await axios.get('/api/devices', { params });
|
||||||
|
setDevices(response.data.devices || []);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch devices:', error);
|
||||||
|
message.error('获取设备列表失败');
|
||||||
|
} finally {
|
||||||
|
setFetchingDevices(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDeviceSearch = useCallback(
|
||||||
|
debounce(value => {
|
||||||
|
fetchDevices(value);
|
||||||
|
}, 300),
|
||||||
|
[fetchDevices]
|
||||||
|
);
|
||||||
|
|
||||||
// Initialize when visible changes from false to true
|
// Initialize when visible changes from false to true
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible && !prevVisibleRef.current) {
|
if (visible && !prevVisibleRef.current) {
|
||||||
@@ -27,20 +63,7 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
|||||||
fetchDevices();
|
fetchDevices();
|
||||||
}
|
}
|
||||||
prevVisibleRef.current = visible;
|
prevVisibleRef.current = visible;
|
||||||
}, [visible, sourceDevice, form]);
|
}, [visible, sourceDevice, form, fetchDevices]);
|
||||||
|
|
||||||
const fetchDevices = async () => {
|
|
||||||
try {
|
|
||||||
setFetchingDevices(true);
|
|
||||||
const response = await axios.get('/api/devices', { params: { pageSize: 1000 } });
|
|
||||||
setDevices(response.data.devices || []);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to fetch devices:', error);
|
|
||||||
message.error('获取设备列表失败');
|
|
||||||
} finally {
|
|
||||||
setFetchingDevices(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchDevicePorts = async (deviceId, type) => {
|
const fetchDevicePorts = async (deviceId, type) => {
|
||||||
if (!deviceId) {
|
if (!deviceId) {
|
||||||
@@ -136,14 +159,18 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
|||||||
rules={[{ required: true, message: '请选择源设备' }]}
|
rules={[{ required: true, message: '请选择源设备' }]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="选择源设备"
|
placeholder="输入关键词搜索源设备"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) =>
|
filterOption={false}
|
||||||
(option?.children ?? '').toLowerCase().includes(input.toLowerCase())
|
onSearch={handleDeviceSearch}
|
||||||
|
onDropdownVisibleChange={open => {
|
||||||
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
onChange={handleSourceDeviceChange}
|
onChange={handleSourceDeviceChange}
|
||||||
loading={fetchingDevices}
|
loading={fetchingDevices}
|
||||||
disabled={!!sourceDevice} // Lock source device if provided
|
disabled={!!sourceDevice}
|
||||||
>
|
>
|
||||||
{devices.map(d => (
|
{devices.map(d => (
|
||||||
<Option key={d.deviceId} value={d.deviceId}>
|
<Option key={d.deviceId} value={d.deviceId}>
|
||||||
@@ -176,11 +203,15 @@ const CableCreateModal = ({ visible, onClose, onSuccess, sourceDevice }) => {
|
|||||||
rules={[{ required: true, message: '请选择目标设备' }]}
|
rules={[{ required: true, message: '请选择目标设备' }]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="选择目标设备"
|
placeholder="输入关键词搜索目标设备"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) =>
|
filterOption={false}
|
||||||
(option?.children ?? '').toLowerCase().includes(input.toLowerCase())
|
onSearch={handleDeviceSearch}
|
||||||
|
onDropdownVisibleChange={open => {
|
||||||
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
}
|
}
|
||||||
|
}}
|
||||||
onChange={handleTargetDeviceChange}
|
onChange={handleTargetDeviceChange}
|
||||||
loading={fetchingDevices}
|
loading={fetchingDevices}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -57,6 +57,18 @@ const { Panel } = Collapse;
|
|||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
const debounce = (func, wait) => {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// 设计令牌 - 现代化配色方案
|
// 设计令牌 - 现代化配色方案
|
||||||
const designTokens = {
|
const designTokens = {
|
||||||
colors: {
|
colors: {
|
||||||
@@ -171,6 +183,7 @@ const animations = {
|
|||||||
function CableManagement() {
|
function CableManagement() {
|
||||||
const [cables, setCables] = useState([]);
|
const [cables, setCables] = useState([]);
|
||||||
const [devices, setDevices] = useState([]);
|
const [devices, setDevices] = useState([]);
|
||||||
|
const [deviceSearching, setDeviceSearching] = useState(false);
|
||||||
const [switchDevices, setSwitchDevices] = useState([]);
|
const [switchDevices, setSwitchDevices] = useState([]);
|
||||||
const [groupedCables, setGroupedCables] = useState({});
|
const [groupedCables, setGroupedCables] = useState({});
|
||||||
const [devicePorts, setDevicePorts] = useState({});
|
const [devicePorts, setDevicePorts] = useState({});
|
||||||
@@ -262,9 +275,14 @@ function CableManagement() {
|
|||||||
}
|
}
|
||||||
}, [filters, devicePorts]);
|
}, [filters, devicePorts]);
|
||||||
|
|
||||||
const fetchDevices = useCallback(async () => {
|
const fetchDevices = useCallback(async (keyword = '') => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/devices', { params: { pageSize: 100 } });
|
setDeviceSearching(true);
|
||||||
|
const params = { pageSize: 50 };
|
||||||
|
if (keyword && keyword.trim()) {
|
||||||
|
params.keyword = keyword.trim();
|
||||||
|
}
|
||||||
|
const response = await axios.get('/api/devices', { params });
|
||||||
const allDevices = response.data.devices || [];
|
const allDevices = response.data.devices || [];
|
||||||
const switches = allDevices.filter(device => device.type === 'switch');
|
const switches = allDevices.filter(device => device.type === 'switch');
|
||||||
setDevices(allDevices);
|
setDevices(allDevices);
|
||||||
@@ -272,9 +290,18 @@ function CableManagement() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取设备列表失败');
|
message.error('获取设备列表失败');
|
||||||
console.error('获取设备列表失败:', error);
|
console.error('获取设备列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
setDeviceSearching(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleDeviceSearch = useCallback(
|
||||||
|
debounce(value => {
|
||||||
|
fetchDevices(value);
|
||||||
|
}, 300),
|
||||||
|
[fetchDevices]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchDevicePorts = useCallback(async deviceId => {
|
const fetchDevicePorts = useCallback(async deviceId => {
|
||||||
if (!deviceId) {
|
if (!deviceId) {
|
||||||
setDevicePorts(prev => ({ ...prev, [deviceId]: [] }));
|
setDevicePorts(prev => ({ ...prev, [deviceId]: [] }));
|
||||||
@@ -886,17 +913,19 @@ function CableManagement() {
|
|||||||
交换机
|
交换机
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
placeholder="选择交换机"
|
placeholder="输入关键词搜索交换机"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
value={filters.switchDeviceId || undefined}
|
value={filters.switchDeviceId || undefined}
|
||||||
onChange={value => setFilters(prev => ({ ...prev, switchDeviceId: value }))}
|
onChange={value => setFilters(prev => ({ ...prev, switchDeviceId: value }))}
|
||||||
allowClear
|
allowClear
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) => {
|
loading={deviceSearching}
|
||||||
const device = switchDevices.find(d => d.deviceId === option.value);
|
filterOption={false}
|
||||||
if (!device) return false;
|
onSearch={handleDeviceSearch}
|
||||||
const searchText = `${device.name} ${device.deviceId}`.toLowerCase();
|
onDropdownVisibleChange={open => {
|
||||||
return searchText.indexOf(input.toLowerCase()) >= 0;
|
if (open && switchDevices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
suffixIcon={<AppstoreOutlined />}
|
suffixIcon={<AppstoreOutlined />}
|
||||||
>
|
>
|
||||||
@@ -1288,13 +1317,15 @@ function CableManagement() {
|
|||||||
rules={[{ required: true, message: '请选择源设备' }]}
|
rules={[{ required: true, message: '请选择源设备' }]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="请选择源设备"
|
placeholder="输入关键词搜索源设备"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) => {
|
loading={deviceSearching}
|
||||||
const device = switchDevices.find(d => d.deviceId === option.value);
|
filterOption={false}
|
||||||
if (!device) return false;
|
onSearch={handleDeviceSearch}
|
||||||
const searchText = `${device.name} ${device.deviceId}`.toLowerCase();
|
onDropdownVisibleChange={open => {
|
||||||
return searchText.indexOf(input.toLowerCase()) >= 0;
|
if (open && switchDevices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
fetchDevicePorts(value);
|
fetchDevicePorts(value);
|
||||||
@@ -1353,13 +1384,15 @@ function CableManagement() {
|
|||||||
rules={[{ required: true, message: '请选择目标设备' }]}
|
rules={[{ required: true, message: '请选择目标设备' }]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="请选择目标设备"
|
placeholder="输入关键词搜索目标设备"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) => {
|
loading={deviceSearching}
|
||||||
const device = devices.find(d => d.deviceId === option.value);
|
filterOption={false}
|
||||||
if (!device) return false;
|
onSearch={handleDeviceSearch}
|
||||||
const searchText = `${device.name} ${device.deviceId}`.toLowerCase();
|
onDropdownVisibleChange={open => {
|
||||||
return searchText.indexOf(input.toLowerCase()) >= 0;
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
fetchDevicePorts(value);
|
fetchDevicePorts(value);
|
||||||
|
|||||||
@@ -59,6 +59,18 @@ const { Panel } = Collapse;
|
|||||||
const { Text, Title } = Typography;
|
const { Text, Title } = Typography;
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
const debounce = (func, wait) => {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// 设计令牌 - 与接线管理页面保持一致
|
// 设计令牌 - 与接线管理页面保持一致
|
||||||
const designTokens = {
|
const designTokens = {
|
||||||
colors: {
|
colors: {
|
||||||
@@ -149,6 +161,7 @@ const animations = {
|
|||||||
function PortManagement() {
|
function PortManagement() {
|
||||||
const [ports, setPorts] = useState([]);
|
const [ports, setPorts] = useState([]);
|
||||||
const [devices, setDevices] = useState([]);
|
const [devices, setDevices] = useState([]);
|
||||||
|
const [deviceSearching, setDeviceSearching] = useState(false);
|
||||||
const [cables, setCables] = useState([]);
|
const [cables, setCables] = useState([]);
|
||||||
const [groupedPorts, setGroupedPorts] = useState({});
|
const [groupedPorts, setGroupedPorts] = useState({});
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -217,16 +230,30 @@ function PortManagement() {
|
|||||||
}
|
}
|
||||||
}, [filters]);
|
}, [filters]);
|
||||||
|
|
||||||
const fetchDevices = useCallback(async () => {
|
const fetchDevices = useCallback(async (keyword = '') => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/devices', { params: { pageSize: 100 } });
|
setDeviceSearching(true);
|
||||||
|
const params = { pageSize: 50 };
|
||||||
|
if (keyword && keyword.trim()) {
|
||||||
|
params.keyword = keyword.trim();
|
||||||
|
}
|
||||||
|
const response = await axios.get('/api/devices', { params });
|
||||||
setDevices(response.data.devices || response.data || []);
|
setDevices(response.data.devices || response.data || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取设备列表失败');
|
message.error('获取设备列表失败');
|
||||||
console.error('获取设备列表失败:', error);
|
console.error('获取设备列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
setDeviceSearching(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleDeviceSearch = useCallback(
|
||||||
|
debounce(value => {
|
||||||
|
fetchDevices(value);
|
||||||
|
}, 300),
|
||||||
|
[fetchDevices]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchCables = useCallback(async () => {
|
const fetchCables = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/cables');
|
const response = await axios.get('/api/cables');
|
||||||
@@ -772,17 +799,19 @@ function PortManagement() {
|
|||||||
设备
|
设备
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
placeholder="选择设备"
|
placeholder="输入关键词搜索设备"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
value={filters.deviceId || undefined}
|
value={filters.deviceId || undefined}
|
||||||
onChange={value => setFilters(prev => ({ ...prev, deviceId: value }))}
|
onChange={value => setFilters(prev => ({ ...prev, deviceId: value }))}
|
||||||
allowClear
|
allowClear
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) => {
|
loading={deviceSearching}
|
||||||
const device = devices.find(d => d.deviceId === option.value);
|
filterOption={false}
|
||||||
if (!device) return false;
|
onSearch={handleDeviceSearch}
|
||||||
const searchText = `${device.name} ${device.deviceId}`.toLowerCase();
|
onDropdownVisibleChange={open => {
|
||||||
return searchText.indexOf(input.toLowerCase()) >= 0;
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{devices.map(device => (
|
{devices.map(device => (
|
||||||
@@ -1222,13 +1251,15 @@ function PortManagement() {
|
|||||||
rules={[{ required: true, message: '请选择设备' }]}
|
rules={[{ required: true, message: '请选择设备' }]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
placeholder="请选择设备"
|
placeholder="输入关键词搜索设备"
|
||||||
showSearch
|
showSearch
|
||||||
filterOption={(input, option) => {
|
loading={deviceSearching}
|
||||||
const device = devices.find(d => d.deviceId === option.value);
|
filterOption={false}
|
||||||
if (!device) return false;
|
onSearch={handleDeviceSearch}
|
||||||
const searchText = `${device.name} ${device.deviceId}`.toLowerCase();
|
onDropdownVisibleChange={open => {
|
||||||
return searchText.indexOf(input.toLowerCase()) >= 0;
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{devices.map(device => (
|
{devices.map(device => (
|
||||||
|
|||||||
@@ -46,6 +46,18 @@ import axios from 'axios';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
const debounce = (func, wait) => {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// 安全地从 localStorage 获取用户信息
|
// 安全地从 localStorage 获取用户信息
|
||||||
const getUserFromStorage = () => {
|
const getUserFromStorage = () => {
|
||||||
try {
|
try {
|
||||||
@@ -305,15 +317,32 @@ function TicketManagement() {
|
|||||||
[searchFilters]
|
[searchFilters]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fetchDevices = useCallback(async () => {
|
const [deviceSearching, setDeviceSearching] = useState(false);
|
||||||
|
const [deviceSearchValue, setDeviceSearchValue] = useState('');
|
||||||
|
|
||||||
|
const fetchDevices = useCallback(async (keyword = '') => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/devices', { params: { pageSize: 100 } });
|
setDeviceSearching(true);
|
||||||
|
const params = { pageSize: 50 };
|
||||||
|
if (keyword && keyword.trim()) {
|
||||||
|
params.keyword = keyword.trim();
|
||||||
|
}
|
||||||
|
const response = await axios.get('/api/devices', { params });
|
||||||
setDevices(response.data.devices || []);
|
setDevices(response.data.devices || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取设备列表失败:', error);
|
console.error('获取设备列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
setDeviceSearching(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleDeviceSearch = useCallback(
|
||||||
|
debounce(value => {
|
||||||
|
fetchDevices(value);
|
||||||
|
}, 300),
|
||||||
|
[fetchDevices]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchCategories = useCallback(async () => {
|
const fetchCategories = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/ticket-categories');
|
const response = await axios.get('/api/ticket-categories');
|
||||||
@@ -448,10 +477,23 @@ function TicketManagement() {
|
|||||||
break;
|
break;
|
||||||
case 'device':
|
case 'device':
|
||||||
formItem = (
|
formItem = (
|
||||||
<Select placeholder="选择设备" showSearch optionFilterProp="children">
|
<Select
|
||||||
|
placeholder="输入关键词搜索设备(序列号/名称/IP等)"
|
||||||
|
showSearch
|
||||||
|
allowClear
|
||||||
|
loading={deviceSearching}
|
||||||
|
filterOption={false}
|
||||||
|
onSearch={handleDeviceSearch}
|
||||||
|
notFoundContent={deviceSearching ? '搜索中...' : '请输入关键词搜索'}
|
||||||
|
onDropdownVisibleChange={open => {
|
||||||
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
{devices.map(device => (
|
{devices.map(device => (
|
||||||
<Option key={device.deviceId} value={device.deviceId}>
|
<Option key={device.deviceId} value={device.deviceId}>
|
||||||
{device.name} - {device.serialNumber}
|
{device.name} {device.serialNumber ? `- ${device.serialNumber}` : ''}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@@ -467,7 +509,7 @@ function TicketManagement() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[devices]
|
[devices, deviceSearching, handleDeviceSearch, fetchDevices]
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableColumns = useMemo(() => {
|
const tableColumns = useMemo(() => {
|
||||||
@@ -766,10 +808,23 @@ function TicketManagement() {
|
|||||||
if (deviceSource === 'select') {
|
if (deviceSource === 'select') {
|
||||||
return (
|
return (
|
||||||
<Form.Item name="deviceId" label="关联设备" rules={[{ required: false }]}>
|
<Form.Item name="deviceId" label="关联设备" rules={[{ required: false }]}>
|
||||||
<Select placeholder="选择设备" showSearch optionFilterProp="children" allowClear>
|
<Select
|
||||||
|
placeholder="输入关键词搜索设备(序列号/名称/IP等)"
|
||||||
|
showSearch
|
||||||
|
allowClear
|
||||||
|
loading={deviceSearching}
|
||||||
|
filterOption={false}
|
||||||
|
onSearch={handleDeviceSearch}
|
||||||
|
notFoundContent={deviceSearching ? '搜索中...' : '请输入关键词搜索'}
|
||||||
|
onDropdownVisibleChange={open => {
|
||||||
|
if (open && devices.length === 0) {
|
||||||
|
fetchDevices();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
{devices.map(device => (
|
{devices.map(device => (
|
||||||
<Option key={device.deviceId} value={device.deviceId}>
|
<Option key={device.deviceId} value={device.deviceId}>
|
||||||
{device.name} - {device.serialNumber}
|
{device.name} {device.serialNumber ? `- ${device.serialNumber}` : ''}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@@ -794,7 +849,7 @@ function TicketManagement() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, [deviceSource, devices]);
|
}, [deviceSource, devices, deviceSearching, handleDeviceSearch, fetchDevices]);
|
||||||
|
|
||||||
const renderFormItems = useCallback(() => {
|
const renderFormItems = useCallback(() => {
|
||||||
const items = [];
|
const items = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user