695 lines
31 KiB
TypeScript
695 lines
31 KiB
TypeScript
/**
|
||
* filekorolheader: 企业管理 - 企业信息管理与维护页面
|
||
* 功能:企业列表查询、详情查看、状态管理、分页筛选
|
||
* 路径:/central-config/tenant/enterprise-management
|
||
* 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理,API集成,shadcn语义化样式
|
||
*/
|
||
'use client';
|
||
|
||
import { useReducer, useEffect, useMemo } from 'react';
|
||
import { Card } from '@/components/ui/card';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Badge } from '@/components/ui/badge';
|
||
import { Input } from '@/components/ui/input';
|
||
import { Label } from '@/components/ui/label';
|
||
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 { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||
import { Building2, Eye, Power, PowerOff, Search, FileText, CreditCard, User, RefreshCw, AlertCircle, ChevronLeft, ChevronRight, Plus } from 'lucide-react';
|
||
import { toast } from 'sonner';
|
||
|
||
import { enterpriseReducer, initialState, EnterpriseState, EnterpriseAction } from './components/enterpriseReducer';
|
||
import { fetchTenants, transformTenantData, enableTenant, disableTenant, createEnterprise, TenantsQueryParams, Enterprise } from './components/enterpriseApi';
|
||
import { CreateEnterpriseDialog } from './components/CreateEnterpriseDialog';
|
||
|
||
// Utility functions
|
||
const getStatusBadge = (status: 'active' | 'inactive') => {
|
||
if (status === 'active') {
|
||
return <Badge className="bg-green-50 dark:bg-green-950 text-green-600 dark:text-green-400 border-green-200 dark:border-green-800 font-light">启用</Badge>;
|
||
}
|
||
return <Badge className="bg-gray-50 dark:bg-gray-950 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-800 font-light">禁用</Badge>;
|
||
};
|
||
|
||
const getAuditStatusBadge = (auditStatus: Enterprise['auditStatus']) => {
|
||
switch (auditStatus) {
|
||
case 'draft':
|
||
return <Badge className="bg-gray-50 dark:bg-gray-950 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-800 font-light">草稿</Badge>;
|
||
case 'pending':
|
||
return <Badge className="bg-yellow-50 dark:bg-yellow-950 text-yellow-600 dark:text-yellow-400 border-yellow-200 dark:border-yellow-800 font-light">待审核</Badge>;
|
||
case 'approved':
|
||
return <Badge className="bg-green-50 dark:bg-green-950 text-green-600 dark:text-green-400 border-green-200 dark:border-green-800 font-light">审核通过</Badge>;
|
||
case 'rejected':
|
||
return <Badge className="bg-red-50 dark:bg-red-950 text-red-600 dark:text-red-400 border-red-200 dark:border-red-800 font-light">已拒绝</Badge>;
|
||
default:
|
||
return <Badge className="bg-gray-50 dark:bg-gray-950 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-800 font-light">草稿</Badge>;
|
||
}
|
||
};
|
||
|
||
export default function EnterpriseManagement() {
|
||
const [state, dispatch] = useReducer(enterpriseReducer, 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 || undefined,
|
||
page: resetPage ? 1 : state.pagination.page,
|
||
size: state.pagination.size,
|
||
order_by: state.sortBy,
|
||
sort_order: state.sortOrder,
|
||
};
|
||
|
||
const response = await fetchTenants(params);
|
||
const transformedData = response.data.map(transformTenantData);
|
||
|
||
console.log('API Response:', response);
|
||
console.log('Transformed Data:', transformedData);
|
||
|
||
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:', 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.enterprises.length,
|
||
active: state.enterprises.filter(e => e.status === 'active').length,
|
||
inactive: state.enterprises.filter(e => e.status === 'inactive').length,
|
||
}), [state.enterprises]);
|
||
|
||
// 事件处理器
|
||
const handleSearch = (value: string) => {
|
||
dispatch({ type: 'SET_FILTERS', payload: { search: value } });
|
||
};
|
||
|
||
const handleAuditStatusFilter = (value: string) => {
|
||
dispatch({ type: 'SET_FILTERS', payload: { audit_status: value === '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 handleView = (enterprise: Enterprise) => {
|
||
dispatch({ type: 'SET_SELECTED_ENTERPRISE', payload: enterprise });
|
||
dispatch({ type: 'TOGGLE_VIEW_DIALOG', payload: true });
|
||
};
|
||
|
||
const handleStatusChange = (enterprise: Enterprise, action: 'enable' | 'disable') => {
|
||
dispatch({ type: 'SET_SELECTED_ENTERPRISE', payload: enterprise });
|
||
dispatch({ type: 'SET_STATUS_ACTION', payload: action });
|
||
dispatch({ type: 'TOGGLE_STATUS_DIALOG', payload: true });
|
||
};
|
||
|
||
const handleCreateNew = () => {
|
||
dispatch({ type: 'RESET_FORM_DATA' });
|
||
dispatch({ type: 'TOGGLE_ADD_DIALOG', payload: true });
|
||
};
|
||
|
||
const handleCreateSuccess = () => {
|
||
// 创建成功后刷新数据
|
||
loadEnterprises(true);
|
||
};
|
||
|
||
const confirmStatusChange = async () => {
|
||
if (!state.selectedEnterprise) return;
|
||
|
||
try {
|
||
dispatch({ type: 'SET_LOADING', payload: true });
|
||
|
||
const tenantId = state.selectedEnterprise.id;
|
||
let updatedTenant;
|
||
|
||
if (state.statusAction === 'enable') {
|
||
updatedTenant = await enableTenant(tenantId);
|
||
toast.success('企业已启用');
|
||
} else {
|
||
updatedTenant = await disableTenant(tenantId);
|
||
toast.success('企业已禁用');
|
||
}
|
||
|
||
// 验证返回的数据是否正确更新了状态
|
||
console.log('API返回的更新数据:', updatedTenant);
|
||
|
||
// 更新本地状态
|
||
const updatedEnterprise = transformTenantData(updatedTenant);
|
||
dispatch({
|
||
type: 'SET_ENTERPRISES',
|
||
payload: {
|
||
data: state.enterprises.map(ent =>
|
||
ent.id === tenantId ? updatedEnterprise : ent
|
||
),
|
||
pagination: state.pagination
|
||
}
|
||
});
|
||
|
||
dispatch({ type: 'TOGGLE_STATUS_DIALOG', payload: false });
|
||
|
||
// 不需要立即刷新,因为本地状态已经更新
|
||
// 如果用户需要看到最新数据,可以手动点击刷新按钮
|
||
} catch (error) {
|
||
console.error('Status change failed:', error);
|
||
const errorMessage = error instanceof Error ? error.message : '状态更新失败';
|
||
toast.error(errorMessage);
|
||
} finally {
|
||
dispatch({ type: 'SET_LOADING', payload: false });
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
{/* Page Header */}
|
||
<Card className="p-6 bg-gradient-to-r from-blue-50 dark:from-blue-950 to-indigo-50 dark:to-indigo-950 border-blue-200 dark:border-blue-800">
|
||
<div className="flex items-start justify-between">
|
||
<div className="flex items-start gap-3">
|
||
<Building2 className="w-6 h-6 text-blue-600 dark:text-blue-400 flex-shrink-0 mt-1" />
|
||
<div className="flex-1">
|
||
<h2 className="mb-2">企业管理</h2>
|
||
<p className="text-sm text-muted-foreground mb-3">
|
||
管理平台所有企业信息,支持查询、查看详情、启用/禁用企业
|
||
</p>
|
||
<div className="flex flex-wrap gap-2">
|
||
<Badge variant="outline" className="bg-white dark:bg-gray-800 font-light">
|
||
<Search className="w-3 h-3 mr-1" />
|
||
智能查询
|
||
</Badge>
|
||
<Badge variant="outline" className="bg-white dark:bg-gray-800 font-light">
|
||
<Power className="w-3 h-3 mr-1" />
|
||
状态管理
|
||
</Badge>
|
||
<Badge variant="outline" className="bg-white dark:bg-gray-800 font-light">
|
||
<Eye className="w-3 h-3 mr-1" />
|
||
详情查看
|
||
</Badge>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Button onClick={handleCreateNew} disabled={state.loading}>
|
||
<Plus className="w-4 h-4 mr-2" />
|
||
新建企业
|
||
</Button>
|
||
<Button variant="outline" size="sm" onClick={handleRefresh} disabled={state.loading}>
|
||
<RefreshCw className={`w-4 h-4 mr-1 ${state.loading ? 'animate-spin' : ''}`} />
|
||
刷新
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
{/* Statistics Cards */}
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<Card className="p-6 bg-card hover:bg-muted transition-colors">
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="text-sm text-muted-foreground">企业总数</div>
|
||
<Building2 className="w-5 h-5 text-blue-500" />
|
||
</div>
|
||
<div className="text-3xl font-bold mb-1">{state.pagination.total}</div>
|
||
<div className="text-xs text-muted-foreground">
|
||
全部企业数量
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="p-6 bg-card hover:bg-muted transition-colors">
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="text-sm text-muted-foreground">启用企业</div>
|
||
<Power className="w-5 h-5 text-green-500" />
|
||
</div>
|
||
<div className="text-3xl font-bold mb-1 text-green-600 dark:text-green-400">{stats.active}</div>
|
||
<div className="text-xs text-green-600 dark:text-green-400">
|
||
正常运营中
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="p-6 bg-card hover:bg-muted transition-colors">
|
||
<div className="flex items-center justify-between mb-2">
|
||
<div className="text-sm text-muted-foreground">禁用企业</div>
|
||
<PowerOff className="w-5 h-5 text-gray-500" />
|
||
</div>
|
||
<div className="text-3xl font-bold mb-1 text-gray-600 dark:text-gray-400">{stats.inactive}</div>
|
||
<div className="text-xs text-muted-foreground">
|
||
已暂停使用
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* Enterprise List */}
|
||
<Card className="p-6 bg-card">
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-4">
|
||
<h3>企业列表</h3>
|
||
<div className="flex flex-col sm:flex-row gap-2">
|
||
<div className="relative">
|
||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
||
<Input
|
||
placeholder="搜索企业名称、编码..."
|
||
value={state.filters.search}
|
||
onChange={(e) => handleSearch(e.target.value)}
|
||
className="pl-10 w-64"
|
||
/>
|
||
</div>
|
||
<Select value={state.filters.audit_status || 'all'} onValueChange={handleAuditStatusFilter}>
|
||
<SelectTrigger className="w-40">
|
||
<SelectValue placeholder="审核状态" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="all">全部状态</SelectItem>
|
||
<SelectItem value="草稿">草稿</SelectItem>
|
||
<SelectItem value="待审核">待审核</SelectItem>
|
||
<SelectItem value="已通过">审核通过</SelectItem>
|
||
<SelectItem value="已拒绝">已拒绝</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Error Display */}
|
||
{state.error && (
|
||
<div className="mb-4 p-4 bg-red-50 dark:bg-red-950 border border-red-200 dark:border-red-800 rounded-lg">
|
||
<div className="flex items-center gap-2 text-red-600 dark:text-red-400">
|
||
<AlertCircle className="w-4 h-4" />
|
||
<span>{state.error}</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Loading State */}
|
||
{state.loading && (
|
||
<div className="text-center py-12 text-muted-foreground">
|
||
<RefreshCw className="w-8 h-8 mx-auto mb-2 animate-spin" />
|
||
<p>加载中...</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Data Table */}
|
||
{!state.loading && !state.error && (
|
||
<>
|
||
<div className="border rounded-lg overflow-hidden">
|
||
<Table>
|
||
<TableHeader>
|
||
<TableRow>
|
||
<TableHead
|
||
className="cursor-pointer hover:bg-muted"
|
||
onClick={() => handleSort('tenant_code')}
|
||
>
|
||
企业编码
|
||
{state.sortBy === 'tenant_code' && (
|
||
<span className="ml-1">{state.sortOrder === 'asc' ? '↑' : '↓'}</span>
|
||
)}
|
||
</TableHead>
|
||
<TableHead
|
||
className="cursor-pointer hover:bg-muted"
|
||
onClick={() => handleSort('company_name')}
|
||
>
|
||
企业名称
|
||
{state.sortBy === 'company_name' && (
|
||
<span className="ml-1">{state.sortOrder === 'asc' ? '↑' : '↓'}</span>
|
||
)}
|
||
</TableHead>
|
||
<TableHead>企业类型</TableHead>
|
||
<TableHead>登记人</TableHead>
|
||
<TableHead>联系电话</TableHead>
|
||
<TableHead
|
||
className="cursor-pointer hover:bg-muted"
|
||
onClick={() => handleSort('created_at')}
|
||
>
|
||
创建时间
|
||
{state.sortBy === 'created_at' && (
|
||
<span className="ml-1">{state.sortOrder === 'asc' ? '↑' : '↓'}</span>
|
||
)}
|
||
</TableHead>
|
||
<TableHead>审核状态</TableHead>
|
||
<TableHead>状态</TableHead>
|
||
<TableHead>操作</TableHead>
|
||
</TableRow>
|
||
</TableHeader>
|
||
<TableBody>
|
||
{state.enterprises.map((enterprise) => (
|
||
<TableRow key={enterprise.id}>
|
||
<TableCell className="font-medium">{enterprise.code}</TableCell>
|
||
<TableCell>
|
||
<div className="flex items-center gap-2">
|
||
<Building2 className="w-4 h-4 text-blue-500" />
|
||
<span className="font-medium">{enterprise.name}</span>
|
||
</div>
|
||
</TableCell>
|
||
<TableCell>
|
||
<Badge variant="outline" className="font-light">{enterprise.type}</Badge>
|
||
</TableCell>
|
||
<TableCell>{enterprise.registrant || '-'}</TableCell>
|
||
<TableCell>{enterprise.contactPhone || '-'}</TableCell>
|
||
<TableCell className="text-sm">{enterprise.createdAt}</TableCell>
|
||
<TableCell>{getAuditStatusBadge(enterprise.auditStatus)}</TableCell>
|
||
<TableCell>{getStatusBadge(enterprise.status)}</TableCell>
|
||
<TableCell>
|
||
<div className="flex gap-2">
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
onClick={() => handleView(enterprise)}
|
||
>
|
||
<Eye className="w-3 h-3 mr-1" />
|
||
查看
|
||
</Button>
|
||
{enterprise.status === 'active' ? (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
className="text-gray-600 dark:text-gray-400 border-gray-300 dark:border-gray-600"
|
||
onClick={() => handleStatusChange(enterprise, 'disable')}
|
||
>
|
||
<PowerOff className="w-3 h-3 mr-1" />
|
||
禁用
|
||
</Button>
|
||
) : (
|
||
<Button
|
||
size="sm"
|
||
variant="outline"
|
||
className="text-green-600 dark:text-green-400 border-green-300 dark:border-green-600"
|
||
onClick={() => handleStatusChange(enterprise, 'enable')}
|
||
>
|
||
<Power className="w-3 h-3 mr-1" />
|
||
启用
|
||
</Button>
|
||
)}
|
||
</div>
|
||
</TableCell>
|
||
</TableRow>
|
||
))}
|
||
</TableBody>
|
||
</Table>
|
||
</div>
|
||
|
||
{state.enterprises.length === 0 && (
|
||
<div className="text-center py-12 text-muted-foreground">
|
||
<Building2 className="w-12 h-12 mx-auto mb-4 opacity-20" />
|
||
<p>暂无企业数据</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Pagination */}
|
||
{state.pagination.totalPages > 1 && (
|
||
<div className="flex items-center justify-between mt-4">
|
||
<div className="text-sm text-muted-foreground">
|
||
显示第 {state.pagination.page} 页,共 {state.pagination.totalPages} 页
|
||
<span className="ml-2">总计 {state.pagination.total} 条记录</span>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => handlePageChange(state.pagination.page - 1)}
|
||
disabled={!state.pagination.hasPrev || state.loading}
|
||
>
|
||
<ChevronLeft className="w-4 h-4" />
|
||
上一页
|
||
</Button>
|
||
<span className="text-sm font-medium px-2">
|
||
{state.pagination.page} / {state.pagination.totalPages}
|
||
</span>
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => handlePageChange(state.pagination.page + 1)}
|
||
disabled={!state.pagination.hasNext || state.loading}
|
||
>
|
||
下一页
|
||
<ChevronRight className="w-4 h-4" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</>
|
||
)}
|
||
</Card>
|
||
|
||
{/* View Enterprise Details Dialog */}
|
||
<Dialog open={state.showViewDialog} onOpenChange={(open) => dispatch({ type: 'TOGGLE_VIEW_DIALOG', payload: open })}>
|
||
<DialogContent className="w-[80vw] max-w-6xl max-h-[90vh]">
|
||
<DialogHeader>
|
||
<div className="flex items-center justify-between pr-8">
|
||
<DialogTitle>企业详情</DialogTitle>
|
||
{state.selectedEnterprise && (
|
||
<div className="flex gap-2">
|
||
{getAuditStatusBadge(state.selectedEnterprise.auditStatus)}
|
||
{getStatusBadge(state.selectedEnterprise.status)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
<DialogDescription className="sr-only">
|
||
查看企业的详细信息
|
||
</DialogDescription>
|
||
</DialogHeader>
|
||
{state.selectedEnterprise && (
|
||
<ScrollArea className="max-h-[calc(90vh-200px)]">
|
||
<Tabs defaultValue="basic" className="space-y-4">
|
||
<TabsList className="grid grid-cols-4 w-full">
|
||
<TabsTrigger value="basic">
|
||
<Building2 className="w-4 h-4 mr-2" />
|
||
基本信息
|
||
</TabsTrigger>
|
||
<TabsTrigger value="other">
|
||
<FileText className="w-4 h-4 mr-2" />
|
||
其他信息
|
||
</TabsTrigger>
|
||
<TabsTrigger value="bank">
|
||
<CreditCard className="w-4 h-4 mr-2" />
|
||
开户信息
|
||
</TabsTrigger>
|
||
<TabsTrigger value="legal">
|
||
<User className="w-4 h-4 mr-2" />
|
||
法人信息
|
||
</TabsTrigger>
|
||
</TabsList>
|
||
|
||
{/* Basic Information */}
|
||
<TabsContent value="basic" className="space-y-4">
|
||
<div className="grid grid-cols-2 gap-6">
|
||
<div>
|
||
<Label>企业名称</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.name}</div>
|
||
</div>
|
||
<div>
|
||
<Label>企业编码</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.code}</div>
|
||
</div>
|
||
<div>
|
||
<Label>企业类型</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.type}</div>
|
||
</div>
|
||
<div>
|
||
<Label>所在地区</Label>
|
||
<div className="field-value p-2 bg-muted rounded">
|
||
{state.selectedEnterprise.province || '-'} {state.selectedEnterprise.city || ''} {state.selectedEnterprise.district || ''}
|
||
</div>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<Label>详细地址</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.address || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>登记人</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.registrant || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>联系电话</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.contactPhone || '-'}</div>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Other Information */}
|
||
<TabsContent value="other" className="space-y-4">
|
||
<div className="grid grid-cols-2 gap-6">
|
||
<div>
|
||
<Label>公司规模</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.companySize || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>注册资本</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.registeredCapital || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>成立时间</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.establishmentDate || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>发票类型</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.invoiceType || '-'}</div>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<Label>社会信用代码</Label>
|
||
<div className="field-value p-2 bg-muted rounded">
|
||
{state.selectedEnterprise.socialCreditCode ? (
|
||
<code className="text-sm font-mono">
|
||
{state.selectedEnterprise.socialCreditCode}
|
||
</code>
|
||
) : '-'}
|
||
</div>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<Label>经营范围</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.businessScope || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>提交时间</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.submitTime || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>审核时间</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.auditTime || '-'}</div>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Bank Information */}
|
||
<TabsContent value="bank" className="space-y-4">
|
||
<div className="grid grid-cols-2 gap-6">
|
||
<div>
|
||
<Label>银行账号</Label>
|
||
<div className="field-value p-2 bg-muted rounded">
|
||
{state.selectedEnterprise.bankAccount ? (
|
||
<code className="text-sm font-mono">
|
||
{state.selectedEnterprise.bankAccount}
|
||
</code>
|
||
) : '-'}
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<Label>开户行</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.bankName || '-'}</div>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<Label>开户行全称</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.bankFullName || '-'}</div>
|
||
</div>
|
||
<div className="col-span-2">
|
||
<Label>开户行地址</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.bankAddress || '-'}</div>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
|
||
{/* Legal Person Information */}
|
||
<TabsContent value="legal" className="space-y-4">
|
||
<div className="grid grid-cols-2 gap-6">
|
||
<div>
|
||
<Label>法人姓名</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.legalPerson || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>联系人</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.registrant || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>审核人</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.auditor || '-'}</div>
|
||
</div>
|
||
<div>
|
||
<Label>审核意见</Label>
|
||
<div className="field-value p-2 bg-muted rounded">{state.selectedEnterprise.auditComment || '-'}</div>
|
||
</div>
|
||
</div>
|
||
</TabsContent>
|
||
</Tabs>
|
||
</ScrollArea>
|
||
)}
|
||
<DialogFooter>
|
||
<Button variant="outline" onClick={() => dispatch({ type: 'TOGGLE_VIEW_DIALOG', payload: false })}>
|
||
关闭
|
||
</Button>
|
||
</DialogFooter>
|
||
</DialogContent>
|
||
</Dialog>
|
||
|
||
{/* Status Change Confirmation Dialog */}
|
||
<AlertDialog open={state.showStatusDialog} onOpenChange={(open) => dispatch({ type: 'TOGGLE_STATUS_DIALOG', payload: open })}>
|
||
<AlertDialogContent className="w-[80vw] max-w-md">
|
||
<AlertDialogHeader>
|
||
<AlertDialogTitle>
|
||
确认{state.statusAction === 'enable' ? '启用' : '禁用'}企业
|
||
</AlertDialogTitle>
|
||
<AlertDialogDescription>
|
||
{state.statusAction === 'enable' ? (
|
||
<>
|
||
启用企业 <strong>{state.selectedEnterprise?.name}</strong> 后,该企业用户将恢复正常登录和使用权限。
|
||
</>
|
||
) : (
|
||
<>
|
||
禁用企业 <strong>{state.selectedEnterprise?.name}</strong> 后,该企业所有用户将无法登录系统。此操作不会删除企业数据,可随时重新启用。
|
||
</>
|
||
)}
|
||
</AlertDialogDescription>
|
||
</AlertDialogHeader>
|
||
<AlertDialogFooter>
|
||
<AlertDialogCancel>取消</AlertDialogCancel>
|
||
<AlertDialogAction
|
||
onClick={confirmStatusChange}
|
||
className={state.statusAction === 'enable' ? 'bg-green-600 hover:bg-green-700' : 'bg-gray-600 hover:bg-gray-700'}
|
||
>
|
||
确认{state.statusAction === 'enable' ? '启用' : '禁用'}
|
||
</AlertDialogAction>
|
||
</AlertDialogFooter>
|
||
</AlertDialogContent>
|
||
</AlertDialog>
|
||
|
||
{/* Create Enterprise Dialog */}
|
||
<CreateEnterpriseDialog
|
||
open={state.showAddDialog}
|
||
onOpenChange={(open) => dispatch({ type: 'TOGGLE_ADD_DIALOG', payload: open })}
|
||
onSuccess={handleCreateSuccess}
|
||
/>
|
||
</div>
|
||
);
|
||
} |