import { useState } from 'react'; import { ChevronRight, CheckCircle2, Circle, GitBranch, Server, Play, Loader2, Terminal, ArrowRight, CloudCog, Package, AlertCircle } from 'lucide-react'; import { toast } from 'sonner'; interface PipelineItem { id: string; name: string; branch: string; type: 'native' | 'jenkins'; deployType: 'host' | 'k8s'; env: string; lastStatus: string; } const mockPipelines: PipelineItem[] = [ { id: '1', name: 'aiops-backend', branch: 'master', type: 'native', deployType: 'k8s', env: 'production', lastStatus: 'success' }, { id: '2', name: 'aiops-web', branch: 'master', type: 'native', deployType: 'host', env: 'production', lastStatus: 'success' }, { id: '3', name: 'gateway-api', branch: 'release/v2.1', type: 'jenkins', deployType: 'k8s', env: 'staging', lastStatus: 'pending' }, { id: '4', name: 'admin-dashboard', branch: 'master', type: 'native', deployType: 'host', env: 'staging', lastStatus: 'success' }, { id: '5', name: 'data-processor', branch: 'develop', type: 'jenkins', deployType: 'k8s', env: 'test', lastStatus: 'failed' }, { id: '6', name: 'notification-service', branch: 'master', type: 'native', deployType: 'k8s', env: 'production', lastStatus: 'success' }, ]; type StepType = 'select' | 'configure' | 'confirm' | 'executing' | 'done'; const steps: { id: StepType; label: string }[] = [ { id: 'select', label: '选择流水线' }, { id: 'configure', label: '配置参数' }, { id: 'confirm', label: '确认发布' }, { id: 'executing', label: '执行中' }, { id: 'done', label: '完成' }, ]; export default function BatchRelease() { const [currentStep, setCurrentStep] = useState('select'); const [selectedIds, setSelectedIds] = useState([]); const [execLogs, setExecLogs] = useState([]); const [completedCount, setCompletedCount] = useState(0); const toggleSelect = (id: string) => { setSelectedIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]); }; const selectedPipelines = mockPipelines.filter(p => selectedIds.includes(p.id)); const stepIndex = steps.findIndex(s => s.id === currentStep); const startExecution = () => { setCurrentStep('executing'); setExecLogs([`[${new Date().toLocaleTimeString()}] 批量发布开始,共 ${selectedIds.length} 个流水线`]); let count = 0; selectedPipelines.forEach((p, idx) => { setTimeout(() => { setExecLogs(prev => [ ...prev, `[${new Date().toLocaleTimeString()}] [${idx + 1}/${selectedPipelines.length}] 开始发布: ${p.name} (${p.branch})`, `[${new Date().toLocaleTimeString()}] -> 拉取代码...`, `[${new Date().toLocaleTimeString()}] -> 构建中...`, `[${new Date().toLocaleTimeString()}] -> ${p.deployType === 'k8s' ? '更新 K8s Deployment...' : 'SCP 上传 + SSH 部署...'}`, `[${new Date().toLocaleTimeString()}] ✓ ${p.name} 发布成功`, ]); count++; setCompletedCount(count); if (count === selectedPipelines.length) { setTimeout(() => { setExecLogs(prev => [...prev, `[${new Date().toLocaleTimeString()}] 批量发布全部完成`]); setCurrentStep('done'); }, 500); } }, idx * 2500); }); }; return (

批量发布

向导
{steps.map((step, idx) => { const isActive = idx === stepIndex; const isDone = idx < stepIndex; return (
{isDone ? : isActive ?
: } {step.label}
{idx < steps.length - 1 && }
); })}
{currentStep === 'select' && (

选择要批量发布的流水线(支持原生流水线和 Jenkins Job 混合发布)

已选择 {selectedIds.length} 个
流水线
分支
类型
部署方式
环境
{mockPipelines.map((p) => { const isSelected = selectedIds.includes(p.id); return (
toggleSelect(p.id)} className="grid grid-cols-[40px_1fr_120px_100px_100px_80px] gap-2 px-4 py-2.5 border-t items-center cursor-pointer hover:bg-black/[0.02] transition-colors" style={{ borderColor: 'var(--border-color-light)' }}>
{isSelected && }
{p.name}
{p.branch}
{p.type === 'native' ? '原生' : 'Jenkins'}
{p.deployType === 'k8s' ? K8s : 主机}
{p.env}
); })}
)} {currentStep === 'configure' && (

配置发布参数,所有选中的流水线将使用相同的发布策略

已选择的流水线
{selectedPipelines.map((p) => ( {p.name} ))}
)} {currentStep === 'confirm' && (

确认批量发布

即将发布 {selectedIds.length} 个流水线,串行执行,失败即停

{selectedPipelines.map((p, idx) => (
0 ? '1px solid var(--border-color-light)' : 'none' }}> {idx + 1} {p.name} {p.branch} {p.type === 'native' ? '原生' : 'Jenkins'}
))}
)} {currentStep === 'executing' && (
批量发布执行中
{completedCount} / {selectedIds.length} 完成
执行日志
{execLogs.map((log, idx) => (
{log.includes('✓') ? {log} : log.includes('->') ? {log} : log}
))}
_
)} {currentStep === 'done' && (

批量发布完成

共成功发布 {selectedIds.length} 个流水线

)}
); }