生产管理系统 - 修改form组件
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
'use client';
|
'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 { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
@@ -223,7 +223,6 @@ export default function AuditHistoryPage() {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// 简化的状态管理 - 只需要存储数据和加载状态
|
// 简化的状态管理 - 只需要存储数据和加载状态
|
||||||
const [records, setRecords] = useState<AuditLogData[]>([]);
|
const [records, setRecords] = useState<AuditLogData[]>([]);
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
@@ -280,14 +279,6 @@ export default function AuditHistoryPage() {
|
|||||||
const transformedData = response.data.map(transformAuditLogData);
|
const transformedData = response.data.map(transformAuditLogData);
|
||||||
|
|
||||||
setRecords(transformedData);
|
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) {
|
} catch (err) {
|
||||||
const errorMessage = err instanceof Error ? err.message : '加载审核历史失败';
|
const errorMessage = err instanceof Error ? err.message : '加载审核历史失败';
|
||||||
setError(errorMessage);
|
setError(errorMessage);
|
||||||
@@ -295,8 +286,15 @@ export default function AuditHistoryPage() {
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, []); // 移除所有依赖,使用参数传递状态变化
|
}, [searchFilters, pagination]); // 添加依赖以保持函数引用最新
|
||||||
|
|
||||||
|
const didFetchRef = useRef(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (didFetchRef.current) return
|
||||||
|
didFetchRef.current = true
|
||||||
|
loadAuditHistory()
|
||||||
|
}, [])
|
||||||
// 事件处理器
|
// 事件处理器
|
||||||
const handleSearch = useCallback((filters: Record<string, string>) => {
|
const handleSearch = useCallback((filters: Record<string, string>) => {
|
||||||
setSearchFilters(filters);
|
setSearchFilters(filters);
|
||||||
@@ -315,18 +313,6 @@ export default function AuditHistoryPage() {
|
|||||||
});
|
});
|
||||||
}, [loadAuditHistory, pagination.size]);
|
}, [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) => {
|
const handlePageChange = useCallback((page: number) => {
|
||||||
setPagination(prev => ({ ...prev, page }));
|
setPagination(prev => ({ ...prev, page }));
|
||||||
loadAuditHistory({
|
loadAuditHistory({
|
||||||
@@ -334,7 +320,6 @@ export default function AuditHistoryPage() {
|
|||||||
pagination: { page, size: pagination.size }
|
pagination: { page, size: pagination.size }
|
||||||
});
|
});
|
||||||
}, [loadAuditHistory, searchFilters, pagination.size]);
|
}, [loadAuditHistory, searchFilters, pagination.size]);
|
||||||
|
|
||||||
const handleSizeChange = useCallback((size: number) => {
|
const handleSizeChange = useCallback((size: number) => {
|
||||||
setPagination(prev => ({ ...prev, size, page: 1 }));
|
setPagination(prev => ({ ...prev, size, page: 1 }));
|
||||||
loadAuditHistory({
|
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?: {
|
const loadEnterprises = useCallback(async (params?: {
|
||||||
filters?: Record<string, string>;
|
filters?: Record<string, string>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
'use client';
|
'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 { 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 { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
@@ -240,7 +240,12 @@ export default function EnterpriseManagement() {
|
|||||||
search: '',
|
search: '',
|
||||||
audit_status: 'all'
|
audit_status: 'all'
|
||||||
});
|
});
|
||||||
|
const didFetchRef = useRef(false)
|
||||||
|
useEffect(() => {
|
||||||
|
if (didFetchRef.current) return
|
||||||
|
didFetchRef.current = true
|
||||||
|
loadEnterprises()
|
||||||
|
}, [])
|
||||||
// 数据加载函数 - 移除不必要的依赖避免重复调用
|
// 数据加载函数 - 移除不必要的依赖避免重复调用
|
||||||
const loadEnterprises = useCallback(async (params?: {
|
const loadEnterprises = useCallback(async (params?: {
|
||||||
filters?: Record<string, string>;
|
filters?: Record<string, string>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useReducer, useEffect, useState, useCallback, useMemo } from 'react';
|
import { useReducer, useEffect, useState, useCallback, useMemo,useRef } from 'react';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Eye, Edit, Lock, UserX, UserCheck } from 'lucide-react';
|
import { Eye, Edit, Lock, UserX, UserCheck } from 'lucide-react';
|
||||||
@@ -100,7 +100,6 @@ const initialState: UserManagementState = {
|
|||||||
|
|
||||||
export default function TenantUserManagementPage() {
|
export default function TenantUserManagementPage() {
|
||||||
const [state, dispatch] = useReducer(userManagementReducer, initialState);
|
const [state, dispatch] = useReducer(userManagementReducer, initialState);
|
||||||
const [searchFilters, setSearchFilters] = useState<Record<string, string>>({});
|
|
||||||
|
|
||||||
// 搜索字段配置
|
// 搜索字段配置
|
||||||
const searchFields: SearchFieldConfig[] = useMemo(() => [
|
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 {
|
try {
|
||||||
dispatch({ type: 'SET_LOADING', payload: true });
|
dispatch({ type: 'SET_LOADING', payload: true });
|
||||||
|
|
||||||
|
// 解构选项参数,提供默认值
|
||||||
|
const {
|
||||||
|
resetPage = false,
|
||||||
|
filters,
|
||||||
|
sortBy,
|
||||||
|
sortOrder,
|
||||||
|
page,
|
||||||
|
size
|
||||||
|
} = options;
|
||||||
|
|
||||||
const params: UsersQueryParams = {
|
const params: UsersQueryParams = {
|
||||||
page: resetPage ? 1 : state.pagination.page,
|
page: resetPage ? 1 : (page || state.pagination.page),
|
||||||
size: state.pagination.size,
|
size: size || state.pagination.size,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 使用传入的过滤器参数,如果没有传入则使用当前状态
|
||||||
|
const currentFilters = filters || state.filters;
|
||||||
|
const currentSortBy = sortBy || state.sortBy;
|
||||||
|
const currentSortOrder = sortOrder || state.sortOrder;
|
||||||
|
|
||||||
// 添加搜索条件
|
// 添加搜索条件
|
||||||
if (searchFilters.search) {
|
if (currentFilters.searchKeyword) {
|
||||||
params.search = searchFilters.search;
|
params.search = currentFilters.searchKeyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchFilters.status && searchFilters.status !== 'all') {
|
if (currentFilters.statusFilter && currentFilters.statusFilter !== 'all') {
|
||||||
params.is_active = searchFilters.status === 'active';
|
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 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
|
// For now, we'll filter on the client side if needed
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.sortBy) {
|
if (currentSortBy) {
|
||||||
params.order_by = state.sortBy;
|
params.order_by = currentSortBy;
|
||||||
params.sort_order = state.sortOrder;
|
params.sort_order = currentSortOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: UsersApiResponse = await fetchUsers(params);
|
const response: UsersApiResponse = await fetchUsers(params);
|
||||||
@@ -330,14 +352,35 @@ export default function TenantUserManagementPage() {
|
|||||||
|
|
||||||
// 搜索处理
|
// 搜索处理
|
||||||
const handleSearch = useCallback((filters: Record<string, string>) => {
|
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 } });
|
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') => {
|
const handleSort = useCallback((sortBy: string, sortOrder: 'asc' | 'desc') => {
|
||||||
dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder } });
|
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) => {
|
const handlePageChange = useCallback((page: number) => {
|
||||||
@@ -347,12 +390,29 @@ export default function TenantUserManagementPage() {
|
|||||||
page = state.pagination.totalPages;
|
page = state.pagination.totalPages;
|
||||||
}
|
}
|
||||||
dispatch({ type: 'SET_PAGINATION', payload: { page } });
|
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) => {
|
const handleSizeChange = useCallback((size: number) => {
|
||||||
dispatch({ type: 'SET_PAGINATION', payload: { size, page: 1 } });
|
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) => {
|
const handleViewDetail = (user: User) => {
|
||||||
@@ -407,10 +467,12 @@ export default function TenantUserManagementPage() {
|
|||||||
},
|
},
|
||||||
], [state.users, state.pagination.total]);
|
], [state.users, state.pagination.total]);
|
||||||
|
|
||||||
// 加载数据
|
const didFetchRef = useRef(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadUsers();
|
if (didFetchRef.current) return
|
||||||
}, []);
|
didFetchRef.current = true
|
||||||
|
loadUsers({})
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
@@ -58,25 +58,35 @@ export function SearchFormComponent({
|
|||||||
const newFilters = {
|
const newFilters = {
|
||||||
...localFilters,
|
...localFilters,
|
||||||
[key]: value,
|
[key]: value,
|
||||||
|
// 添加特殊的标记字段来跟踪最后变化的字段类型
|
||||||
|
_lastChangedFieldType: fieldType,
|
||||||
|
_lastChangedFieldKey: key,
|
||||||
};
|
};
|
||||||
setLocalFilters(newFilters);
|
setLocalFilters(newFilters);
|
||||||
|
|
||||||
// 下拉框选择立即触发查询,文本输入使用防抖
|
// 下拉框选择立即触发查询,文本输入使用防抖
|
||||||
if (fieldType === 'select') {
|
if (fieldType === 'select') {
|
||||||
onFiltersChangeRef.current(newFilters);
|
// 移除标记字段后再传递给父组件
|
||||||
|
const { _lastChangedFieldType, _lastChangedFieldKey, ...cleanFilters } = newFilters;
|
||||||
|
onFiltersChangeRef.current(cleanFilters);
|
||||||
}
|
}
|
||||||
// 文本输入的防抖在useEffect中处理
|
// 文本输入的防抖在useEffect中处理
|
||||||
};
|
};
|
||||||
|
|
||||||
// 使用防抖来减少搜索频率,仅针对文本输入
|
// 使用防抖来减少搜索频率,仅针对文本输入
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
// 只有当最后变化的是 text 字段时才进行防抖,排除初始化和 select 字段
|
||||||
// 使用ref引用最新的onFiltersChange函数,避免依赖变化导致重复触发
|
if (localFilters._lastChangedFieldType === 'text') {
|
||||||
onFiltersChangeRef.current(localFilters);
|
const timer = setTimeout(() => {
|
||||||
}, 300); // 300ms 防抖延迟
|
// 移除标记字段后再调用
|
||||||
|
const { _lastChangedFieldType, _lastChangedFieldKey, ...cleanFilters } = localFilters;
|
||||||
|
// 使用ref引用最新的onFiltersChange函数,避免依赖变化导致重复触发
|
||||||
|
onFiltersChangeRef.current(cleanFilters);
|
||||||
|
}, 300); // 300ms 防抖延迟
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [localFilters]); // 只依赖localFilters,使用ref避免函数依赖问题
|
}
|
||||||
|
}, [localFilters]); // 只依赖localFilters
|
||||||
|
|
||||||
// 计算显示的字段
|
// 计算显示的字段
|
||||||
const visibleFields = showAllFields
|
const visibleFields = showAllFields
|
||||||
|
|||||||
Reference in New Issue
Block a user