/** * filekorolheader: 企业审核页面 - 企业注册审核管理页面 * 功能:企业审核列表、搜索筛选、审核操作、详情查看 * 路径:/central-config/tenant/enterprise-audit * 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理,API集成,模块化组件 */ 'use client'; import { useReducer, useEffect, useMemo } from 'react'; import { toast } from 'sonner'; import { Building2, RefreshCw } from 'lucide-react'; import { fetchTenantsForAudit, auditTenant, transformTenantData, TenantsQueryParams, Enterprise } from './components/enterpriseAuditApi'; import { AuditStatsCards } from './components/AuditStatsCards'; import { AuditSearchAndFilter } from './components/AuditSearchAndFilter'; import { EnterpriseAuditTable } from './components/EnterpriseAuditTable'; import { EnterpriseDetailDialog } from './components/EnterpriseDetailDialog'; import { AuditPagination } from './components/AuditPagination'; // 审核状态管理 interface AuditState { enterprises: Enterprise[]; loading: boolean; error: string | null; pagination: { page: number; size: number; total: number; totalPages: number; hasNext: boolean; hasPrev: boolean; }; filters: { search: string; audit_status: string; }; sortBy?: string; sortOrder: 'asc' | 'desc'; selectedEnterprise: Enterprise | null; showDetailDialog: boolean; auditReason: string; actionLoading: boolean; } type AuditAction = | { type: 'SET_ENTERPRISES'; payload: { data: Enterprise[]; pagination: AuditState['pagination'] } } | { type: 'SET_LOADING'; payload: boolean } | { type: 'SET_ERROR'; payload: string | null } | { type: 'SET_FILTERS'; payload: Partial } | { type: 'SET_SORT'; payload: { sortBy?: string; sortOrder: 'asc' | 'desc' } } | { type: 'SET_PAGINATION'; payload: Partial } | { type: 'SET_SELECTED_ENTERPRISE'; payload: Enterprise | null } | { type: 'TOGGLE_DETAIL_DIALOG'; payload: boolean } | { type: 'SET_AUDIT_REASON'; payload: string } | { type: 'SET_ACTION_LOADING'; payload: boolean } | { type: 'REFRESH_DATA' }; const auditReducer = (state: AuditState, action: AuditAction): AuditState => { switch (action.type) { case 'SET_ENTERPRISES': return { ...state, enterprises: action.payload.data, pagination: action.payload.pagination, loading: false, error: null, }; case 'SET_LOADING': return { ...state, loading: action.payload }; case 'SET_ERROR': return { ...state, error: action.payload, loading: false }; case 'SET_FILTERS': return { ...state, filters: { ...state.filters, ...action.payload } }; case 'SET_SORT': return { ...state, sortBy: action.payload.sortBy, sortOrder: action.payload.sortOrder }; case 'SET_PAGINATION': return { ...state, pagination: { ...state.pagination, ...action.payload } }; case 'SET_SELECTED_ENTERPRISE': return { ...state, selectedEnterprise: action.payload }; case 'TOGGLE_DETAIL_DIALOG': return { ...state, showDetailDialog: !state.showDetailDialog }; case 'SET_AUDIT_REASON': return { ...state, auditReason: action.payload }; case 'SET_ACTION_LOADING': return { ...state, actionLoading: action.payload }; case 'REFRESH_DATA': return { ...state, error: null }; default: return state; } }; const initialState: AuditState = { enterprises: [], loading: false, error: null, pagination: { page: 1, size: 10, total: 0, totalPages: 0, hasNext: false, hasPrev: false, }, filters: { search: '', audit_status: 'all', }, sortBy: 'created_at', sortOrder: 'desc', selectedEnterprise: null, showDetailDialog: false, auditReason: '', actionLoading: false, }; export default function EnterpriseAuditPage() { const [state, dispatch] = useReducer(auditReducer, initialState); // 加载企业数据 const loadEnterprises = async (resetPage = false) => { try { dispatch({ type: 'SET_LOADING', payload: true }); const params: TenantsQueryParams = { search: state.filters.search || undefined, audit_status: state.filters.audit_status === 'all' ? undefined : state.filters.audit_status, page: resetPage ? 1 : state.pagination.page, size: state.pagination.size, order_by: state.sortBy, sort_order: state.sortOrder, }; const response = await fetchTenantsForAudit(params); const transformedData = response.data.map(transformTenantData); dispatch({ type: 'SET_ENTERPRISES', payload: { data: transformedData, pagination: { page: response.page, size: response.size, total: response.total, totalPages: response.total_pages, hasNext: response.has_next, hasPrev: response.has_prev, } } }); } catch (error) { console.error('Failed to load enterprises for audit:', error); const errorMessage = error instanceof Error ? error.message : '加载企业审核数据失败'; dispatch({ type: 'SET_ERROR', payload: errorMessage }); toast.error(errorMessage); } }; // 初始加载 useEffect(() => { loadEnterprises(true); }, [state.filters.search, state.filters.audit_status, state.sortBy, state.sortOrder]); // 分页加载 useEffect(() => { if (state.pagination.page > 1) { loadEnterprises(false); } }, [state.pagination.page]); // 计算统计数据 const stats = useMemo(() => ({ total: state.pagination.total, pending: state.enterprises.filter(e => e.auditStatus === 'pending').length, approved: state.enterprises.filter(e => e.auditStatus === 'approved').length, rejected: state.enterprises.filter(e => e.auditStatus === 'rejected').length, }), [state.enterprises, state.pagination.total]); // 事件处理器 const handleSearch = (value: string) => { dispatch({ type: 'SET_FILTERS', payload: { search: value } }); }; const handleAuditStatusFilter = (value: string) => { dispatch({ type: 'SET_FILTERS', payload: { audit_status: value === 'all' ? 'all' : value } }); }; const handleSort = (sortBy?: string) => { const newSortOrder = state.sortBy === sortBy && state.sortOrder === 'desc' ? 'asc' : 'desc'; dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder: newSortOrder } }); }; const handlePageChange = (page: number) => { // 边界检查,确保页码在有效范围内 if (page < 1) { page = 1; } else if (page > state.pagination.totalPages && state.pagination.totalPages > 0) { page = state.pagination.totalPages; } dispatch({ type: 'SET_PAGINATION', payload: { page } }); }; const handleRefresh = () => { dispatch({ type: 'REFRESH_DATA' }); loadEnterprises(true); toast.success('数据已刷新'); }; const handleViewDetail = (enterprise: Enterprise) => { dispatch({ type: 'SET_SELECTED_ENTERPRISE', payload: enterprise }); dispatch({ type: 'SET_AUDIT_REASON', payload: '' }); dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: true }); }; const handleAuditReasonChange = (value: string) => { dispatch({ type: 'SET_AUDIT_REASON', payload: value }); }; const handleApprove = async () => { if (!state.selectedEnterprise) return; try { dispatch({ type: 'SET_ACTION_LOADING', payload: true }); const updatedTenant = await auditTenant(state.selectedEnterprise.id, { audit_status: '已通过', audit_comment: state.auditReason || '审核通过', }); // 更新本地状态 const updatedEnterprise = transformTenantData(updatedTenant); dispatch({ type: 'SET_ENTERPRISES', payload: { data: state.enterprises.map(ent => ent.id === state.selectedEnterprise?.id ? updatedEnterprise : ent ), pagination: state.pagination } }); dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: false }); toast.success('审核通过'); // 1秒后刷新列表 setTimeout(() => { loadEnterprises(true); }, 1000); } catch (error) { console.error('Approve failed:', error); const errorMessage = error instanceof Error ? error.message : '审核通过失败'; toast.error(errorMessage); } finally { dispatch({ type: 'SET_ACTION_LOADING', payload: false }); } }; const handleReject = async () => { if (!state.selectedEnterprise) return; if (!state.auditReason.trim()) { toast.error('请填写驳回原因'); return; } try { dispatch({ type: 'SET_ACTION_LOADING', payload: true }); const updatedTenant = await auditTenant(state.selectedEnterprise.id, { audit_status: '已驳回', audit_comment: state.auditReason, }); // 更新本地状态 const updatedEnterprise = transformTenantData(updatedTenant); dispatch({ type: 'SET_ENTERPRISES', payload: { data: state.enterprises.map(ent => ent.id === state.selectedEnterprise?.id ? updatedEnterprise : ent ), pagination: state.pagination } }); dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: false }); toast.success('已驳回'); // 1秒后刷新列表 setTimeout(() => { loadEnterprises(true); }, 1000); } catch (error) { console.error('Reject failed:', error); const errorMessage = error instanceof Error ? error.message : '审核驳回失败'; toast.error(errorMessage); } finally { dispatch({ type: 'SET_ACTION_LOADING', payload: false }); } }; return (
{/* 页面标题和描述 */}

企业审核

管理企业注册与变更审核流程

{/* 统计卡片 */} {/* 搜索和筛选 */} dispatch({ type: 'SET_FILTERS', payload: { search: value } })} statusFilter={state.filters.audit_status} onStatusFilterChange={(value) => dispatch({ type: 'SET_FILTERS', payload: { audit_status: value } })} onRefresh={handleRefresh} loading={state.loading} /> {/* 企业列表 */} {/* 分页 */} {state.pagination.total > 0 && ( )} {/* 企业详情对话框 */} dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: open })} enterprise={state.selectedEnterprise} auditReason={state.auditReason} onAuditReasonChange={(reason) => dispatch({ type: 'SET_AUDIT_REASON', payload: reason })} onApprove={handleApprove} onReject={handleReject} loading={state.actionLoading} />
); }