import { useState, useEffect } from 'react'; import { cn } from '@/lib/utils'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Textarea } from '@/components/ui/textarea'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { FileText, CheckCircle2, XCircle, Loader2, Clock, Plus, } from 'lucide-react'; import { toast } from 'sonner'; import { approvalApi } from '@/api'; import { ApprovalProcessTab } from './ApprovalProcessTab'; import { ApprovalTemplateTab } from './ApprovalTemplateTab'; import { ApprovalDetailDialog } from './ApprovalDetailDialog'; import { ApprovalCreateDialog } from './ApprovalCreateDialog'; import { renderStepProgress, getProgressInfo, getApprovalTypeLabel, getApprovalTypeColor, getInstanceType, } from './helpers'; export function ApprovalFlow() { const [activeTab, setActiveTab] = useState<'instances' | 'flows' | 'my-approvals'>('instances'); const [processes, setProcesses] = useState([]); const [templates, setTemplates] = useState([]); const [myApprovals, setMyApprovals] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [statusFilter, setStatusFilter] = useState(''); const [templateTypeFilter, setTemplateTypeFilter] = useState('all'); // 详情弹窗 const [detailOpen, setDetailOpen] = useState(false); const [selectedInstance, setSelectedInstance] = useState(null); // 审批操作弹窗 const [actionDialogOpen, setActionDialogOpen] = useState(false); const [actionType, setActionType] = useState<'approve' | 'reject'>('approve'); const [actionComment, setActionComment] = useState(''); const [actionSubmitting, setActionSubmitting] = useState(false); // 新建申请弹窗 const [createOpen, setCreateOpen] = useState(false); const loadData = async () => { try { setLoading(true); const [instancesRes, templatesRes, myRes] = await Promise.all([ approvalApi.getProcesses().catch(() => null), approvalApi.getTemplates().catch(() => null), approvalApi.getProcesses({ status: 'pending' }).catch(() => null), ]); setProcesses(instancesRes?.list || []); setTemplates(templatesRes?.list || []); setMyApprovals(myRes?.list || []); } catch (error) { console.error('加载审批数据失败:', error); } finally { setLoading(false); } }; useEffect(() => { loadData(); }, []); // 派生数据 const filteredInstances = processes.filter((instance) => { const matchesSearch = (instance.title || '').toLowerCase().includes(searchQuery.toLowerCase()) || (instance.applicant_name || instance.applicant || '').toLowerCase().includes(searchQuery.toLowerCase()); const matchesStatus = !statusFilter || instance.status === statusFilter; return matchesSearch && matchesStatus; }); const filteredTemplates = templates.filter((template) => { return templateTypeFilter === 'all' || template.type === templateTypeFilter; }); // 打开详情弹窗 // Logan.Li const handleView = ( instance: any) => { setSelectedInstance(instance); setDetailOpen(true); }; // 打开审批操作弹窗 // Logan.Li const openActionDialog = (type: 'approve' | 'reject', instance: any) => { setActionType(type); setSelectedInstance(instance); setActionComment(''); setActionDialogOpen(true); }; // 确认审批操作 // Logan.Li const handleConfirmAction = async () => { if (!selectedInstance) return; try { setActionSubmitting(true); if (actionType === 'approve') { await approvalApi.approveProcess(selectedInstance.id, actionComment); toast.success('审批通过'); } else { await approvalApi.rejectProcess(selectedInstance.id, actionComment); toast.success('已拒绝'); } setActionDialogOpen(false); loadData(); } catch (error) { toast.error('操作失败', { description: (error as Record).message }); } finally { setActionSubmitting(false); } }; // 统计数据 const pendingCount = processes.filter((p) => p.status === 'pending').length; const approvedCount = processes.filter((p) => p.status === 'approved').length; const rejectedCount = processes.filter((p) => p.status === 'rejected').length; const myPendingCount = myApprovals.filter((m) => m.status === 'pending').length; return (
{/* Page Header */}

资源申请

云服务器申请 · 应用部署申请

{/* Stats Cards */}

待审批

{pendingCount}

已通过

{approvedCount}

已拒绝

{rejectedCount}

我的待办

{myPendingCount}

{/* Tab Bar */}
{([ { key: 'instances', label: '审批实例' }, { key: 'flows', label: '流程模板' }, { key: 'my-approvals', label: '我的审批' }, ] as const).map((tab) => ( ))}
{/* Tab Content */} {activeTab === 'instances' && ( openActionDialog('approve', instance)} onReject={(instance) => openActionDialog('reject', instance)} /> )} {activeTab === 'flows' && ( )} {activeTab === 'my-approvals' && (
{myApprovals.length === 0 ? (

暂无待办

没有等待你处理的审批

) : ( myApprovals.map((instance) => { const { percentage } = getProgressInfo(instance); return (

{instance.title}

{getApprovalTypeLabel(getInstanceType(instance))}

申请人:{instance.applicant_name || instance.applicant || '--'}

提交于 {instance.created_at ? new Date(instance.created_at).toLocaleString() : '--'}

{instance.status === 'pending' && ( <> )}
审批进度 {percentage}%
{renderStepProgress(instance)}
); }) )}
)} {/* 详情弹窗 — 提取到 ApprovalDetailDialog */} openActionDialog('approve', instance)} onReject={(instance) => openActionDialog('reject', instance)} /> {/* 审批操作弹窗 */} {actionType === 'approve' ? ( <> 确认通过审批 ) : ( <> 确认拒绝审批 )} {actionType === 'approve' ? '请填写审批意见后确认通过' : '请填写拒绝原因后确认拒绝'} {selectedInstance && (

审批标题:{selectedInstance.title}