From 83dd5356e05b8281f405a464fc6c4436aac58ce2 Mon Sep 17 00:00:00 2001 From: peng Date: Mon, 10 Nov 2025 16:21:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E4=BA=A7=E7=AE=A1=E7=90=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=20-=20=E4=BF=AE=E6=94=B9form=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tenant/audit-history/page.tsx | 33 ++---- .../tenant/enterprise-audit/page.tsx | 7 +- .../tenant/enterprise-management/page.tsx | 9 +- .../tenant/user-management/page.tsx | 104 ++++++++++++++---- .../components/SearchFormComponent.tsx | 24 ++-- .../common/searchFormPagination/page.tsx | 30 ++--- 6 files changed, 137 insertions(+), 70 deletions(-) diff --git a/crop-x-new/src/app/(app)/central-config/tenant/audit-history/page.tsx b/crop-x-new/src/app/(app)/central-config/tenant/audit-history/page.tsx index 5f74aa3..f848ce9 100644 --- a/crop-x-new/src/app/(app)/central-config/tenant/audit-history/page.tsx +++ b/crop-x-new/src/app/(app)/central-config/tenant/audit-history/page.tsx @@ -6,7 +6,7 @@ */ 'use client'; -import { useMemo, useState, useCallback } from 'react'; +import { useMemo, useState, useCallback, useEffect ,useRef} from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { ScrollArea } from '@/components/ui/scroll-area'; @@ -223,7 +223,6 @@ export default function AuditHistoryPage() { ), }, ]; - // 简化的状态管理 - 只需要存储数据和加载状态 const [records, setRecords] = useState([]); const [pagination, setPagination] = useState({ @@ -280,14 +279,6 @@ export default function AuditHistoryPage() { const transformedData = response.data.map(transformAuditLogData); setRecords(transformedData); - setPagination({ - page: response.page, - size: response.size, - total: response.total, - totalPages: response.total_pages, - hasNext: response.has_next, - hasPrev: response.has_prev, - }); } catch (err) { const errorMessage = err instanceof Error ? err.message : '加载审核历史失败'; setError(errorMessage); @@ -295,8 +286,15 @@ export default function AuditHistoryPage() { } finally { setLoading(false); } - }, []); // 移除所有依赖,使用参数传递状态变化 + }, [searchFilters, pagination]); // 添加依赖以保持函数引用最新 + const didFetchRef = useRef(false) + +useEffect(() => { + if (didFetchRef.current) return + didFetchRef.current = true + loadAuditHistory() +}, []) // 事件处理器 const handleSearch = useCallback((filters: Record) => { setSearchFilters(filters); @@ -315,18 +313,6 @@ export default function AuditHistoryPage() { }); }, [loadAuditHistory, pagination.size]); - // 统一的数据重载函数 - 避免重复代码 - const reloadData = useCallback(() => { - const reloadParams = { - filters: searchFilters, - pagination: { - page: pagination.page, - size: pagination.size - } - }; - loadAuditHistory(reloadParams); - }, [loadAuditHistory, searchFilters, pagination]); - const handlePageChange = useCallback((page: number) => { setPagination(prev => ({ ...prev, page })); loadAuditHistory({ @@ -334,7 +320,6 @@ export default function AuditHistoryPage() { pagination: { page, size: pagination.size } }); }, [loadAuditHistory, searchFilters, pagination.size]); - const handleSizeChange = useCallback((size: number) => { setPagination(prev => ({ ...prev, size, page: 1 })); loadAuditHistory({ diff --git a/crop-x-new/src/app/(app)/central-config/tenant/enterprise-audit/page.tsx b/crop-x-new/src/app/(app)/central-config/tenant/enterprise-audit/page.tsx index 9dd588a..a1d2c10 100644 --- a/crop-x-new/src/app/(app)/central-config/tenant/enterprise-audit/page.tsx +++ b/crop-x-new/src/app/(app)/central-config/tenant/enterprise-audit/page.tsx @@ -221,7 +221,12 @@ export default function EnterpriseAuditPage() { ), }, ]; - + const didFetchRef = useRef(false) + useEffect(() => { + if (didFetchRef.current) return + didFetchRef.current = true + loadEnterprises() + }, []) // 加载企业数据 - 移除依赖项,通过参数传递状态 const loadEnterprises = useCallback(async (params?: { filters?: Record; diff --git a/crop-x-new/src/app/(app)/central-config/tenant/enterprise-management/page.tsx b/crop-x-new/src/app/(app)/central-config/tenant/enterprise-management/page.tsx index ba01c30..f70d30b 100644 --- a/crop-x-new/src/app/(app)/central-config/tenant/enterprise-management/page.tsx +++ b/crop-x-new/src/app/(app)/central-config/tenant/enterprise-management/page.tsx @@ -6,7 +6,7 @@ */ 'use client'; -import { useEffect, useMemo, useState, useCallback } from 'react'; +import { useEffect, useMemo, useState, useCallback ,useRef} from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; @@ -240,7 +240,12 @@ export default function EnterpriseManagement() { search: '', audit_status: 'all' }); - + const didFetchRef = useRef(false) + useEffect(() => { + if (didFetchRef.current) return + didFetchRef.current = true + loadEnterprises() + }, []) // 数据加载函数 - 移除不必要的依赖避免重复调用 const loadEnterprises = useCallback(async (params?: { filters?: Record; diff --git a/crop-x-new/src/app/(app)/central-config/tenant/user-management/page.tsx b/crop-x-new/src/app/(app)/central-config/tenant/user-management/page.tsx index 0f110b6..6401581 100644 --- a/crop-x-new/src/app/(app)/central-config/tenant/user-management/page.tsx +++ b/crop-x-new/src/app/(app)/central-config/tenant/user-management/page.tsx @@ -6,7 +6,7 @@ */ 'use client'; -import { useReducer, useEffect, useState, useCallback, useMemo } from 'react'; +import { useReducer, useEffect, useState, useCallback, useMemo,useRef } from 'react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Eye, Edit, Lock, UserX, UserCheck } from 'lucide-react'; @@ -100,7 +100,6 @@ const initialState: UserManagementState = { export default function TenantUserManagementPage() { const [state, dispatch] = useReducer(userManagementReducer, initialState); - const [searchFilters, setSearchFilters] = useState>({}); // 搜索字段配置 const searchFields: SearchFieldConfig[] = useMemo(() => [ @@ -274,32 +273,55 @@ export default function TenantUserManagementPage() { ], []); // 加载用户数据 - const loadUsers = useCallback(async (resetPage = false) => { + const loadUsers = useCallback(async (options: { + resetPage?: boolean; + filters?: UserFilters; + sortBy?: string; + sortOrder?: 'asc' | 'desc'; + page?: number; + size?: number; + } = {}) => { try { dispatch({ type: 'SET_LOADING', payload: true }); + + // 解构选项参数,提供默认值 + const { + resetPage = false, + filters, + sortBy, + sortOrder, + page, + size + } = options; + const params: UsersQueryParams = { - page: resetPage ? 1 : state.pagination.page, - size: state.pagination.size, + page: resetPage ? 1 : (page || state.pagination.page), + size: size || state.pagination.size, is_active: true, }; + // 使用传入的过滤器参数,如果没有传入则使用当前状态 + const currentFilters = filters || state.filters; + const currentSortBy = sortBy || state.sortBy; + const currentSortOrder = sortOrder || state.sortOrder; + // 添加搜索条件 - if (searchFilters.search) { - params.search = searchFilters.search; + if (currentFilters.searchKeyword) { + params.search = currentFilters.searchKeyword; } - if (searchFilters.status && searchFilters.status !== 'all') { - params.is_active = searchFilters.status === 'active'; + if (currentFilters.statusFilter && currentFilters.statusFilter !== 'all') { + params.is_active = currentFilters.statusFilter === 'active'; } - if (searchFilters.type && searchFilters.type !== 'all') { + if (currentFilters.typeFilter && currentFilters.typeFilter !== 'all') { // For user type filtering, we'll need to handle this differently based on the API // For now, we'll filter on the client side if needed } - if (state.sortBy) { - params.order_by = state.sortBy; - params.sort_order = state.sortOrder; + if (currentSortBy) { + params.order_by = currentSortBy; + params.sort_order = currentSortOrder; } const response: UsersApiResponse = await fetchUsers(params); @@ -330,14 +352,35 @@ export default function TenantUserManagementPage() { // 搜索处理 const handleSearch = useCallback((filters: Record) => { - setSearchFilters(filters); + const mappedFilters = { + searchKeyword: filters.search || '', + statusFilter: filters.status || 'all', + typeFilter: filters.type || 'all' + }; + dispatch({ type: 'SET_FILTERS', payload: mappedFilters }); dispatch({ type: 'SET_PAGINATION', payload: { page: 1 } }); - }, []); + // 传入所有当前参数,避免覆盖其他参数 + loadUsers({ + resetPage: true, + filters: mappedFilters, + sortBy: state.sortBy, + sortOrder: state.sortOrder, + size: state.pagination.size + }); + }, [state.sortBy, state.sortOrder, state.pagination.size]); // 排序处理 const handleSort = useCallback((sortBy: string, sortOrder: 'asc' | 'desc') => { dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder } }); - }, []); + // 传入所有当前参数,避免覆盖其他参数 + loadUsers({ + resetPage: true, + filters: state.filters, + sortBy, + sortOrder, + size: state.pagination.size + }); + }, [state.filters, state.pagination.size]); // 分页处理 const handlePageChange = useCallback((page: number) => { @@ -347,12 +390,29 @@ export default function TenantUserManagementPage() { page = state.pagination.totalPages; } dispatch({ type: 'SET_PAGINATION', payload: { page } }); - }, [state.pagination.totalPages]); + // 传入所有当前参数,避免覆盖其他参数 + loadUsers({ + page, + filters: state.filters, + sortBy: state.sortBy, + sortOrder: state.sortOrder, + size: state.pagination.size + }); + }, [state.filters, state.sortBy, state.sortOrder, state.pagination.size, state.pagination.totalPages]); // 每页条数变化处理 const handleSizeChange = useCallback((size: number) => { dispatch({ type: 'SET_PAGINATION', payload: { size, page: 1 } }); - }, []); + // 传入所有当前参数,避免覆盖其他参数 + loadUsers({ + resetPage: true, + page: 1, + size, + filters: state.filters, + sortBy: state.sortBy, + sortOrder: state.sortOrder + }); + }, [state.filters, state.sortBy, state.sortOrder]); // 查看详情 const handleViewDetail = (user: User) => { @@ -407,10 +467,12 @@ export default function TenantUserManagementPage() { }, ], [state.users, state.pagination.total]); - // 加载数据 + const didFetchRef = useRef(false) useEffect(() => { - loadUsers(); - }, []); + if (didFetchRef.current) return + didFetchRef.current = true + loadUsers({}) + }, []) return (
diff --git a/crop-x-new/src/components/common/searchFormPagination/components/SearchFormComponent.tsx b/crop-x-new/src/components/common/searchFormPagination/components/SearchFormComponent.tsx index c19c8bf..ee1fc1a 100644 --- a/crop-x-new/src/components/common/searchFormPagination/components/SearchFormComponent.tsx +++ b/crop-x-new/src/components/common/searchFormPagination/components/SearchFormComponent.tsx @@ -58,25 +58,35 @@ export function SearchFormComponent({ const newFilters = { ...localFilters, [key]: value, + // 添加特殊的标记字段来跟踪最后变化的字段类型 + _lastChangedFieldType: fieldType, + _lastChangedFieldKey: key, }; setLocalFilters(newFilters); // 下拉框选择立即触发查询,文本输入使用防抖 if (fieldType === 'select') { - onFiltersChangeRef.current(newFilters); + // 移除标记字段后再传递给父组件 + const { _lastChangedFieldType, _lastChangedFieldKey, ...cleanFilters } = newFilters; + onFiltersChangeRef.current(cleanFilters); } // 文本输入的防抖在useEffect中处理 }; // 使用防抖来减少搜索频率,仅针对文本输入 useEffect(() => { - const timer = setTimeout(() => { - // 使用ref引用最新的onFiltersChange函数,避免依赖变化导致重复触发 - onFiltersChangeRef.current(localFilters); - }, 300); // 300ms 防抖延迟 + // 只有当最后变化的是 text 字段时才进行防抖,排除初始化和 select 字段 + if (localFilters._lastChangedFieldType === 'text') { + const timer = setTimeout(() => { + // 移除标记字段后再调用 + const { _lastChangedFieldType, _lastChangedFieldKey, ...cleanFilters } = localFilters; + // 使用ref引用最新的onFiltersChange函数,避免依赖变化导致重复触发 + onFiltersChangeRef.current(cleanFilters); + }, 300); // 300ms 防抖延迟 - return () => clearTimeout(timer); - }, [localFilters]); // 只依赖localFilters,使用ref避免函数依赖问题 + return () => clearTimeout(timer); + } + }, [localFilters]); // 只依赖localFilters // 计算显示的字段 const visibleFields = showAllFields diff --git a/crop-x/src/components/common/searchFormPagination/page.tsx b/crop-x/src/components/common/searchFormPagination/page.tsx index f015b21..093c840 100644 --- a/crop-x/src/components/common/searchFormPagination/page.tsx +++ b/crop-x/src/components/common/searchFormPagination/page.tsx @@ -122,21 +122,21 @@ export function SearchFormPagination({ ); // 数据更新回调 - 通知父组件数据变化 - useEffect(() => { - onDataUpdate?.({ - items: data, - pagination: pagination || { - page: 1, - size: 10, - total: 0, - totalPages: 0, - hasNext: false, - hasPrev: false, - }, - loading, - error, - }); - }, [data, pagination, loading, error, onDataUpdate]); + // useEffect(() => { + // onDataUpdate?.({ + // items: data, + // pagination: pagination || { + // page: 1, + // size: 10, + // total: 0, + // totalPages: 0, + // hasNext: false, + // hasPrev: false, + // }, + // loading, + // error, + // }); + // }, [data, pagination, loading, error, onDataUpdate]); // 简化的事件处理器 - 纯粹的状态通知 const handleSearch = useCallback((newFilters: Record) => {