diff --git a/web/src/admin/pages/Agents/AgentDetail.tsx b/web/src/admin/pages/Agents/AgentDetail.tsx index 0792d03..f8a47a3 100644 --- a/web/src/admin/pages/Agents/AgentDetail.tsx +++ b/web/src/admin/pages/Agents/AgentDetail.tsx @@ -82,8 +82,13 @@ const AgentDetail = () => { useEffect(() => { // 同步 activeTab 到 URL - setSearchParams({tab: activeTab}); - }, [activeTab]); + const nextParams = new URLSearchParams(searchParams); + if (nextParams.get('tab') === activeTab) { + return; + } + nextParams.set('tab', activeTab); + setSearchParams(nextParams); + }, [activeTab, searchParams, setSearchParams]); if (loading && !agent) { return ( diff --git a/web/src/admin/pages/Agents/AgentList.tsx b/web/src/admin/pages/Agents/AgentList.tsx index 4f470ac..c9bbabd 100644 --- a/web/src/admin/pages/Agents/AgentList.tsx +++ b/web/src/admin/pages/Agents/AgentList.tsx @@ -44,7 +44,7 @@ const AgentList = () => { status: status || undefined, }; - const {data: tags = [], isError: tagsError, error: tagsErrorDetail} = useQuery({ + const {data: tags = []} = useQuery({ queryKey: ['admin', 'agents', 'tags'], queryFn: async () => { const response = await getTags(); @@ -56,8 +56,6 @@ const AgentList = () => { data: agentPaging, isLoading, isFetching, - isError: agentsError, - error: agentsErrorDetail, refetch, } = useQuery({ queryKey: ['admin', 'agents', pageIndex, pageSize, filters.keyword, filters.status], @@ -83,18 +81,6 @@ const AgentList = () => { }, }); - useEffect(() => { - if (tagsError && tagsErrorDetail) { - messageApi.error(getErrorMessage(tagsErrorDetail, '加载标签失败')); - } - }, [tagsError, tagsErrorDetail, messageApi]); - - useEffect(() => { - if (agentsError && agentsErrorDetail) { - messageApi.error(getErrorMessage(agentsErrorDetail, '获取探针列表失败')); - } - }, [agentsError, agentsErrorDetail, messageApi]); - useEffect(() => { searchForm.setFieldsValue({ keyword: keyword || undefined, @@ -137,7 +123,7 @@ const AgentList = () => { const handleTableChange = (nextPagination: TablePaginationConfig) => { const nextParams = new URLSearchParams(searchParams); - nextParams.set('page', String(nextPagination.current || 1)); + nextParams.set('pageIndex', String(nextPagination.current || 1)); nextParams.set('pageSize', String(nextPagination.pageSize || pageSize)); setSearchParams(nextParams); }; diff --git a/web/src/admin/pages/Agents/SSHLoginEvents.tsx b/web/src/admin/pages/Agents/SSHLoginEvents.tsx index da57e3a..460ef67 100644 --- a/web/src/admin/pages/Agents/SSHLoginEvents.tsx +++ b/web/src/admin/pages/Agents/SSHLoginEvents.tsx @@ -1,8 +1,9 @@ -import React, {useState, useEffect} from 'react'; +import React from 'react'; +import {useSearchParams} from 'react-router-dom'; import {App, Button, Table, Tag, Tooltip} from 'antd'; -import type {ColumnsType} from 'antd/es/table'; +import type {ColumnsType, TablePaginationConfig} from 'antd/es/table'; import {Terminal} from 'lucide-react'; -import {useMutation} from '@tanstack/react-query'; +import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import type {SSHLoginEvent} from '@/types'; import {deleteSSHLoginEvents, getSSHLoginEvents} from '@/api/agent'; import {getErrorMessage} from '@/lib/utils'; @@ -14,18 +15,11 @@ interface SSHLoginEventsProps { const SSHLoginEvents: React.FC = ({agentId}) => { const {message, modal} = App.useApp(); - const [loading, setLoading] = useState(false); - const [dataSource, setDataSource] = useState([]); - const [pagination, setPagination] = useState({ - current: 1, - pageSize: 20, - total: 0, - }); - const [searchParams, setSearchParams] = useState({ - username: '', - ip: '', - status: '', - }); + const queryClient = useQueryClient(); + const [searchParams, setSearchParams] = useSearchParams(); + + const pageIndex = Number(searchParams.get('pageIndex')) || 1; + const pageSize = Number(searchParams.get('pageSize')) || 20; // 定义表格列 const columns: ColumnsType = [ @@ -99,42 +93,33 @@ const SSHLoginEvents: React.FC = ({agentId}) => { }, ]; - // 加载数据 - const loadData = async (page: number = pagination.current, pageSize: number = pagination.pageSize) => { - setLoading(true); - try { - const response = await getSSHLoginEvents(agentId, { - pageIndex: page, - pageSize: pageSize, - username: searchParams.username || undefined, - ip: searchParams.ip || undefined, - status: searchParams.status || undefined, - sortField: 'createdAt', - sortOrder: 'descend', - }); - setDataSource(response.items || []); - setPagination({ - current: page, - pageSize: pageSize, - total: response.total || 0, - }); - } catch (error) { - console.error('Failed to load SSH login events:', error); - message.error(getErrorMessage(error, '加载失败')); - } finally { - setLoading(false); - } - }; - - // 初始加载 - useEffect(() => { - loadData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [agentId]); + const { + data: eventsPaging, + isLoading, + isFetching, + } = useQuery({ + queryKey: [ + 'admin', + 'agents', + 'ssh-login-events', + agentId, + pageIndex, + pageSize, + ], + queryFn: () => getSSHLoginEvents(agentId, { + pageIndex, + pageSize, + sortField: 'createdAt', + sortOrder: 'descend', + }), + }); // 处理表格变化 - const handleTableChange = (newPagination: any) => { - loadData(newPagination.current, newPagination.pageSize); + const handleTableChange = (newPagination: TablePaginationConfig) => { + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', String(newPagination.current || 1)); + nextParams.set('pageSize', String(newPagination.pageSize || pageSize)); + setSearchParams(nextParams); }; // 删除所有事件 mutation @@ -142,7 +127,11 @@ const SSHLoginEvents: React.FC = ({agentId}) => { mutationFn: () => deleteSSHLoginEvents(agentId), onSuccess: () => { message.success('所有事件已删除'); - loadData(1); + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', '1'); + nextParams.set('pageSize', String(pageSize)); + setSearchParams(nextParams); + queryClient.invalidateQueries({queryKey: ['admin', 'agents', 'ssh-login-events', agentId]}); }, onError: (error: unknown) => { console.error('Failed to delete SSH login events:', error); @@ -175,11 +164,13 @@ const SSHLoginEvents: React.FC = ({agentId}) => { columns={columns} - dataSource={dataSource} - loading={loading} + dataSource={eventsPaging?.items || []} + loading={isLoading || isFetching} rowKey="id" pagination={{ - ...pagination, + current: pageIndex, + pageSize, + total: eventsPaging?.total || 0, showSizeChanger: true, showTotal: (total) => `共 ${total} 条`, }} diff --git a/web/src/admin/pages/Agents/TamperProtectionEvents.tsx b/web/src/admin/pages/Agents/TamperProtectionEvents.tsx index 3b92eaf..8bda65b 100644 --- a/web/src/admin/pages/Agents/TamperProtectionEvents.tsx +++ b/web/src/admin/pages/Agents/TamperProtectionEvents.tsx @@ -1,8 +1,9 @@ -import React, {useState, useEffect} from 'react'; +import React from 'react'; +import {useSearchParams} from 'react-router-dom'; import {App, Button, Table, Tag, Tooltip} from 'antd'; -import type {ColumnsType} from 'antd/es/table'; +import type {ColumnsType, TablePaginationConfig} from 'antd/es/table'; import {FileWarning} from 'lucide-react'; -import {useMutation} from '@tanstack/react-query'; +import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import {deleteTamperEvents, getTamperEvents, type TamperEvent} from '@/api/tamper'; import {getErrorMessage} from '@/lib/utils'; import dayjs from 'dayjs'; @@ -13,13 +14,11 @@ interface TamperProtectionEventsProps { const TamperProtectionEvents: React.FC = ({agentId}) => { const {message, modal} = App.useApp(); - const [loading, setLoading] = useState(false); - const [dataSource, setDataSource] = useState([]); - const [pagination, setPagination] = useState({ - current: 1, - pageSize: 20, - total: 0, - }); + const queryClient = useQueryClient(); + const [searchParams, setSearchParams] = useSearchParams(); + + const pageIndex = Number(searchParams.get('pageIndex')) || 1; + const pageSize = Number(searchParams.get('pageSize')) || 20; // 定义表格列 const columns: ColumnsType = [ @@ -80,39 +79,26 @@ const TamperProtectionEvents: React.FC = ({agentId} }, ]; - // 加载数据 - const loadData = async (page: number = pagination.current, pageSize: number = pagination.pageSize) => { - setLoading(true); - try { - const response = await getTamperEvents(agentId, { - pageIndex: page, - pageSize: pageSize, - sortField: 'createdAt', - sortOrder: 'descend', - }); - setDataSource(response.data.items || []); - setPagination({ - current: page, - pageSize: pageSize, - total: response.data.total || 0, - }); - } catch (error) { - console.error('Failed to load tamper events:', error); - message.error(getErrorMessage(error, '加载失败')); - } finally { - setLoading(false); - } - }; - - // 初始加载 - useEffect(() => { - loadData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [agentId]); + const { + data: eventsPaging, + isLoading, + isFetching, + } = useQuery({ + queryKey: ['admin', 'agents', 'tamper-events', agentId, pageIndex, pageSize], + queryFn: () => getTamperEvents(agentId, { + pageIndex, + pageSize, + sortField: 'createdAt', + sortOrder: 'descend', + }), + }); // 处理表格变化 - const handleTableChange = (newPagination: any) => { - loadData(newPagination.current, newPagination.pageSize); + const handleTableChange = (newPagination: TablePaginationConfig) => { + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', String(newPagination.current || 1)); + nextParams.set('pageSize', String(newPagination.pageSize || pageSize)); + setSearchParams(nextParams); }; // 删除所有事件 mutation @@ -120,7 +106,11 @@ const TamperProtectionEvents: React.FC = ({agentId} mutationFn: () => deleteTamperEvents(agentId), onSuccess: () => { message.success('所有事件已删除'); - loadData(1); + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', '1'); + nextParams.set('pageSize', String(pageSize)); + setSearchParams(nextParams); + queryClient.invalidateQueries({queryKey: ['admin', 'agents', 'tamper-events', agentId]}); }, onError: (error: unknown) => { console.error('Failed to delete tamper events:', error); @@ -153,11 +143,13 @@ const TamperProtectionEvents: React.FC = ({agentId} columns={columns} - dataSource={dataSource} - loading={loading} + dataSource={eventsPaging?.data.items || []} + loading={isLoading || isFetching} rowKey="id" pagination={{ - ...pagination, + current: pageIndex, + pageSize, + total: eventsPaging?.data.total || 0, showSizeChanger: true, showTotal: (total) => `共 ${total} 条`, }} diff --git a/web/src/admin/pages/AlertRecords/index.tsx b/web/src/admin/pages/AlertRecords/index.tsx index fb264ac..0d54018 100644 --- a/web/src/admin/pages/AlertRecords/index.tsx +++ b/web/src/admin/pages/AlertRecords/index.tsx @@ -1,6 +1,7 @@ -import React, {useState, useEffect} from 'react'; +import React, {useState} from 'react'; +import {useSearchParams} from 'react-router-dom'; import {App, Divider, Select, Space, Table, Tag} from 'antd'; -import type {ColumnsType} from 'antd/es/table'; +import type {ColumnsType, TablePaginationConfig} from 'antd/es/table'; import {Trash2} from 'lucide-react'; import {clearAlertRecords, getAlertRecords} from '@/api/alert.ts'; import type {AlertRecord} from '@/types'; @@ -8,18 +9,16 @@ import dayjs from 'dayjs'; import {getErrorMessage} from '@/lib/utils'; import {PageHeader} from '@admin/components'; import {getAgentPaging} from '@/api/agent.ts'; -import {useQuery} from '@tanstack/react-query'; +import {useQuery, useQueryClient} from '@tanstack/react-query'; const AlertRecordList = () => { const {message: messageApi, modal} = App.useApp(); + const queryClient = useQueryClient(); + const [searchParams, setSearchParams] = useSearchParams(); const [selectedAgentId, setSelectedAgentId] = useState(''); - const [loading, setLoading] = useState(false); - const [dataSource, setDataSource] = useState([]); - const [pagination, setPagination] = useState({ - current: 1, - pageSize: 20, - total: 0, - }); + + const pageIndex = Number(searchParams.get('pageIndex')) || 1; + const pageSize = Number(searchParams.get('pageSize')) || 20; // 使用 react-query 获取探针列表 const {data: agentsData} = useQuery({ @@ -96,33 +95,30 @@ const AlertRecordList = () => { value: agent.id, })) || []; - // 加载数据 - const loadData = async (page: number = pagination.current, pageSize: number = pagination.pageSize, agentId: string = selectedAgentId) => { - setLoading(true); - try { - const result = await getAlertRecords(page, pageSize, agentId || undefined); - setDataSource(result.items || []); - setPagination({ - current: page, - pageSize: pageSize, - total: result.total || 0, - }); - } catch (error) { - messageApi.error(getErrorMessage(error, '获取告警记录失败')); - } finally { - setLoading(false); - } - }; + const { + data: alertPaging, + isLoading, + isFetching, + } = useQuery({ + queryKey: ['admin', 'alert-records', pageIndex, pageSize, selectedAgentId], + queryFn: () => getAlertRecords(pageIndex, pageSize, selectedAgentId || undefined), + }); // 处理表格变化 - const handleTableChange = (newPagination: any) => { - loadData(newPagination.current, newPagination.pageSize); + const handleTableChange = (newPagination: TablePaginationConfig) => { + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', String(newPagination.current || 1)); + nextParams.set('pageSize', String(newPagination.pageSize || pageSize)); + setSearchParams(nextParams); }; // 处理探针筛选变化 const handleAgentChange = (value: string) => { setSelectedAgentId(value || ''); - loadData(1, pagination.pageSize, value || ''); + const nextParams = new URLSearchParams(searchParams); + nextParams.set('pageIndex', '1'); + nextParams.set('pageSize', String(pageSize)); + setSearchParams(nextParams); }; // 清空记录 @@ -139,7 +135,7 @@ const AlertRecordList = () => { try { await clearAlertRecords(selectedAgentId || undefined); messageApi.success('清空成功'); - loadData(); + queryClient.invalidateQueries({queryKey: ['admin', 'alert-records']}); } catch (error: unknown) { messageApi.error(getErrorMessage(error, '清空失败')); } @@ -147,12 +143,6 @@ const AlertRecordList = () => { }); }; - // 初始加载 - useEffect(() => { - loadData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const columns: ColumnsType = [ { title: 'ID', @@ -267,15 +257,15 @@ const AlertRecordList = () => {