Просмотр исходного кода

♻️ refactor(logs): 重构日志页面数据管理逻辑

- 移除冗余的useState状态管理,统一使用Form组件管理表单状态
- 升级React Query实现,使用v5新API并添加缓存策略(staleTime: 5分钟, gcTime: 30分钟)
- 优化fetchLogs函数参数类型定义,增加可选参数和默认值
- 将搜索框整合到Form组件中,统一表单控制逻辑
- 改进分页逻辑,直接从API响应获取分页信息

✨ feat(logs): 增强日志页面功能体验

- 优化时间格式化,使用dayjs替代原生Date实现更精确的时间展示
- 增强分页控件功能,添加快速跳转和总记录数显示
- 改进表单交互,实现值变化时自动触发过滤
- 优化错误处理逻辑,使用response.ok判断请求状态

💄 style(logs): 调整日志页面布局样式

- 调整搜索框位置,将其整合到筛选栏中
- 优化按钮间距和布局结构,提升视觉体验
yourname 8 месяцев назад
Родитель
Сommit
8b427eb3d4
1 измененных файлов с 95 добавлено и 88 удалено
  1. 95 88
      src/client/admin/pages/Logs.tsx

+ 95 - 88
src/client/admin/pages/Logs.tsx

@@ -1,5 +1,5 @@
-import React, { useState } from 'react';
-import { Table, Button, Space, Input, Select, DatePicker, Form } from 'antd';
+import React from 'react';
+import { Table, Button, Space, Input, Form, DatePicker } from 'antd';
 import { SearchOutlined, FilterOutlined } from '@ant-design/icons';
 import { useQuery } from '@tanstack/react-query';
 import { logfileClient } from '@/client/api';
@@ -14,16 +14,19 @@ const { RangePicker } = DatePicker;
 
 const Logs: React.FC = () => {
   const [form] = Form.useForm();
-  const [searchText, setSearchText] = useState('');
-  const [filters, setFilters] = useState({
-    class: '',
-    action: '',
-    userId: '',
-    dateRange: [] as [dayjs.Dayjs | null, dayjs.Dayjs | null]
-  });
   
   // 获取日志列表数据
-  const fetchLogs = async ({ page, pageSize }: { page: number; pageSize: number }): Promise<LogfileListResponse> => {
+  const fetchLogs = async ({ 
+    page = 1, 
+    pageSize = 10, 
+    searchText = '', 
+    filters = {} 
+  }: { 
+    page?: number; 
+    pageSize?: number;
+    searchText?: string;
+    filters?: Record<string, any>;
+  }): Promise<LogfileListResponse> => {
     const queryParams: Record<string, any> = { page, pageSize };
     
     if (searchText) queryParams.keyword = searchText;
@@ -34,68 +37,10 @@ const Logs: React.FC = () => {
     if (filters.dateRange?.[1]) queryParams.endDate = filters.dateRange[1].format('YYYY-MM-DD');
     
     const response = await logfileClient.$get({ query: queryParams });
-    if (response.status !== 200) throw new Error('Failed to fetch logs');
+    if (!response.ok) throw new Error('Failed to fetch logs');
     return response.json() as Promise<LogfileListResponse>;
   };
   
-  const [pagination, setPagination] = useState({
-    current: 1,
-    pageSize: 10,
-    total: 0,
-  });
-  
-  const { data, isLoading: loading, refetch } = useQuery(
-    ['logs', pagination.current, pagination.pageSize, searchText, filters],
-    () => fetchLogs({ page: pagination.current, pageSize: pagination.pageSize }),
-    {
-      onSuccess: (result) => {
-        setPagination({
-          ...pagination,
-          total: result.pagination.total,
-        });
-      },
-    }
-  );
-  
-  // 搜索
-  const handleSearch = () => {
-    setPagination({ ...pagination, current: 1 });
-    refetch();
-  };
-  
-  // 过滤条件变化
-  const handleFilterChange = (values: any) => {
-    setFilters({
-      ...filters,
-      class: values.class || '',
-      action: values.action || '',
-      userId: values.userId || '',
-      dateRange: values.dateRange || []
-    });
-    setPagination({ ...pagination, current: 1 });
-    refetch();
-  };
-  
-  // 分页变化
-  const handleTableChange = (pagination: any) => {
-    setPagination(pagination);
-    refetch();
-  };
-  
-  // 重置过滤条件
-  const handleResetFilters = () => {
-    form.resetFields();
-    setFilters({
-      class: '',
-      action: '',
-      userId: '',
-      dateRange: []
-    });
-    setSearchText('');
-    setPagination({ ...pagination, current: 1 });
-    refetch();
-  };
-  
   // 表格列定义
   const columns = [
     {
@@ -127,7 +72,7 @@ const Logs: React.FC = () => {
       title: '操作时间',
       dataIndex: 'logTime',
       key: 'logTime',
-      render: (time: string) => time ? new Date(time).toLocaleString() : '-',
+      render: (time: string) => time ? dayjs(time).format('YYYY-MM-DD HH:mm:ss') : '-',
     },
     {
       title: '操作原因',
@@ -136,6 +81,51 @@ const Logs: React.FC = () => {
     },
   ];
   
+  // 使用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: {
+          class: values.class,
+          action: values.action,
+          userId: values.userId,
+          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 (
     <div className="p-4">
       <div className="flex justify-between items-center mb-4">
@@ -143,7 +133,17 @@ const Logs: React.FC = () => {
       </div>
       
       <div className="bg-white p-4 mb-4 rounded-lg shadow-sm">
-        <Form form={form} layout="inline" onFinish={handleFilterChange}>
+        <Form 
+          form={form} 
+          layout="inline" 
+          onValuesChange={handleFilterChange}
+          initialValues={{
+            pagination: {
+              current: 1,
+              pageSize: 10
+            }
+          }}
+        >
           <Form.Item name="class" label="日志类别">
             <Input placeholder="请输入日志类别" style={{ width: 150 }} />
           </Form.Item>
@@ -157,7 +157,7 @@ const Logs: React.FC = () => {
             <RangePicker format="YYYY-MM-DD" />
           </Form.Item>
           <Form.Item>
-            <Button type="primary" htmlType="submit" icon={<FilterOutlined />}>
+            <Button type="primary" icon={<FilterOutlined />} onClick={handleFilterChange}>
               筛选
             </Button>
           </Form.Item>
@@ -166,29 +166,36 @@ const Logs: React.FC = () => {
               重置
             </Button>
           </Form.Item>
+          
+          <Form.Item name="searchText" noStyle>
+            <Input
+              placeholder="搜索日志内容"
+              prefix={<SearchOutlined />}
+              onPressEnter={handleSearch}
+              style={{ width: 300, marginLeft: 16 }}
+            />
+          </Form.Item>
+          <Form.Item noStyle>
+            <Button type="default" onClick={handleSearch} style={{ marginLeft: 8 }}>
+              搜索
+            </Button>
+          </Form.Item>
         </Form>
-        
-        <div className="mt-4">
-          <Input
-            placeholder="搜索日志内容"
-            prefix={<SearchOutlined />}
-            value={searchText}
-            onChange={(e) => setSearchText(e.target.value)}
-            onPressEnter={handleSearch}
-            style={{ width: 300 }}
-          />
-          <Button type="default" onClick={handleSearch} style={{ marginLeft: 8 }}>
-            搜索
-          </Button>
-        </div>
       </div>
       
       <Table
         columns={columns}
         dataSource={data?.data || []}
         rowKey="id"
-        loading={loading}
-        pagination={pagination}
+        loading={isLoading}
+        pagination={{
+          current: data?.pagination.current || 1,
+          pageSize: data?.pagination.pageSize || 10,
+          total: data?.pagination.total || 0,
+          showSizeChanger: true,
+          showQuickJumper: true,
+          showTotal: (total) => `共 ${total} 条记录`
+        }}
         onChange={handleTableChange}
         bordered
         size="middle"