生产管理系统 - 修改form组件
This commit is contained in:
@@ -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<AuditLogData[]>([]);
|
||||
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<string, string>) => {
|
||||
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({
|
||||
|
||||
@@ -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<string, string>;
|
||||
|
||||
@@ -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<string, string>;
|
||||
|
||||
@@ -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<Record<string, string>>({});
|
||||
|
||||
// 搜索字段配置
|
||||
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<string, string>) => {
|
||||
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 (
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -122,21 +122,21 @@ export function SearchFormPagination<T = any>({
|
||||
);
|
||||
|
||||
// 数据更新回调 - 通知父组件数据变化
|
||||
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<string, string>) => {
|
||||
|
||||
Reference in New Issue
Block a user