import React, { useState } from 'react'; import { Table, Button, Space, Input, Form, DatePicker, Select, Collapse, Row, Col } from 'antd'; import { SearchOutlined, FilterOutlined, DownOutlined, RightOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { operationLogsClient } from '@/client/api'; import UserSelect from '@/client/admin/components/UserSelect'; import type { InferResponseType } from 'hono/client'; import dayjs from 'dayjs'; // 定义类型 type LogfileItem = InferResponseType['data'][0]; type LogfileListResponse = InferResponseType; const { RangePicker } = DatePicker; const { Panel } = Collapse; const Logs: React.FC = () => { const [form] = Form.useForm(); const [advancedSearchExpanded, setAdvancedSearchExpanded] = useState(false); // 获取日志列表数据 const fetchLogs = async ({ page = 1, pageSize = 10, searchText = '', filters = {} }: { page?: number; pageSize?: number; searchText?: string; filters?: Record; }): Promise => { const queryParams: Record = { page, pageSize }; if (searchText) queryParams.keyword = searchText; if (filters.resourceType) queryParams.resourceType = filters.resourceType; if (filters.action) queryParams.action = filters.action; if (filters.method) queryParams.method = filters.method; if (filters.endpoint) queryParams.endpoint = filters.endpoint; if (filters.userId) queryParams.userId = filters.userId; if (filters.ipAddress) queryParams.ipAddress = filters.ipAddress; if (filters.status) queryParams.status = filters.status; if (filters.dateRange?.[0]) queryParams.startDate = filters.dateRange[0].format('YYYY-MM-DD'); if (filters.dateRange?.[1]) queryParams.endDate = filters.dateRange[1].format('YYYY-MM-DD'); const response = await operationLogsClient.$get({ query: queryParams }); if (!response.ok) throw new Error('Failed to fetch logs'); return response.json() as Promise; }; // 表格列定义 const columns = [ { title: '日志ID', dataIndex: 'id', key: 'id', width: 80, }, { title: '资源类型', dataIndex: 'resourceType', key: 'resourceType', width: 120, }, { title: '资源ID', dataIndex: 'resourceId', key: 'resourceId', width: 120, }, { title: '操作', dataIndex: 'action', key: 'action', width: 100, }, { title: 'HTTP方法', dataIndex: 'method', key: 'method', width: 100, }, { title: 'API端点', dataIndex: 'endpoint', key: 'endpoint', width: 200, }, { title: '状态', dataIndex: 'status', key: 'status', width: 100, render: (status: string) => { switch (status) { case 'success': return 成功; case 'failed': return 失败; case 'permission_denied': return 权限拒绝; default: return status; } }, }, { title: '耗时(ms)', dataIndex: 'duration', key: 'duration', width: 100, }, { title: '操作用户ID', dataIndex: 'userId', key: 'userId', width: 100, }, { title: '用户名', dataIndex: 'username', key: 'username', width: 120, }, { title: 'IP地址', dataIndex: 'ipAddress', key: 'ipAddress', width: 150, }, { title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 180, render: (time: string) => time ? dayjs(time).format('YYYY-MM-DD HH:mm:ss') : '-', }, ]; // 使用React Query v5实现数据获取 const { data, isLoading, refetch } = useQuery({ queryKey: ['logs', form.getFieldsValue(), form.getFieldValue('searchText')], queryFn: ({ signal }) => { const values = form.getFieldsValue(); const searchText = form.getFieldValue('searchText') || ''; return fetchLogs({ page: values.pagination?.current || 1, pageSize: values.pagination?.pageSize || 10, searchText, filters: { resourceType: values.resourceType, action: values.action, method: values.method, endpoint: values.endpoint, userId: values.userId, ipAddress: values.ipAddress, status: values.status, dateRange: values.dateRange } }); }, staleTime: 1000 * 60 * 5, // 5分钟缓存 gcTime: 1000 * 60 * 30, // 30分钟垃圾回收 }); // 处理搜索 const handleSearch = () => { refetch(); }; // 处理过滤 const handleFilterChange = () => { refetch(); }; // 处理分页变化 const handleTableChange = (pagination: any) => { form.setFieldsValue({ pagination }); refetch(); }; // 重置过滤条件 const handleResetFilters = () => { form.resetFields(); refetch(); }; return (

系统日志管理

{/* 紧凑搜索区域 */}
} onPressEnter={handleSearch} allowClear className="w-48" size="small" /> {/* 高级搜索条件 - 直接展开显示 */} {advancedSearchExpanded && (
)}
`共 ${total} 条记录` }} onChange={handleTableChange} bordered size="middle" scroll={{ x: 'max-content' }} rowClassName={(record, index) => index % 2 === 0 ? 'bg-white' : 'bg-gray-50'} /> ); }; export default Logs;