import React, { useEffect, useMemo, useState } from 'react' import { createPortal } from 'react-dom' import { Loader2, X, Image as ImageIcon, Clock, CheckCircle, XCircle } from 'lucide-react' import { useBatchImageDecryptStore } from '../stores/batchImageDecryptStore' import { useBatchTranscribeStore } from '../stores/batchTranscribeStore' import '../styles/batchTranscribe.scss' export const BatchImageDecryptGlobal: React.FC = () => { const { isBatchDecrypting, progress, showToast, showResultToast, result, sessionName, startTime, setShowToast, setShowResultToast } = useBatchImageDecryptStore() const voiceToastOccupied = useBatchTranscribeStore( state => state.isBatchTranscribing && state.showToast ) const [eta, setEta] = useState('') useEffect(() => { if (!isBatchDecrypting || !startTime || progress.current === 0) { setEta('') return } const timer = setInterval(() => { const elapsed = Date.now() - startTime if (elapsed <= 0) return const rate = progress.current / elapsed const remain = progress.total - progress.current if (remain <= 0 || rate <= 0) { setEta('') return } const seconds = Math.ceil((remain / rate) / 1000) if (seconds < 60) { setEta(`${seconds}秒`) } else { const m = Math.floor(seconds / 60) const s = seconds % 60 setEta(`${m}分${s}秒`) } }, 1000) return () => clearInterval(timer) }, [isBatchDecrypting, progress.current, progress.total, startTime]) useEffect(() => { if (!showResultToast) return const timer = window.setTimeout(() => setShowResultToast(false), 6000) return () => window.clearTimeout(timer) }, [showResultToast, setShowResultToast]) const toastBottom = useMemo(() => (voiceToastOccupied ? 148 : 24), [voiceToastOccupied]) return ( <> {showToast && isBatchDecrypting && createPortal(
批量解密图片{sessionName ? `(${sessionName})` : ''}
{progress.current} / {progress.total} {progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : 0}%
{eta && (
剩余 {eta}
)}
0 ? (progress.current / progress.total) * 100 : 0}%` }} />
, document.body )} {showResultToast && createPortal(
图片批量解密完成
成功 {result.success}
0 ? 'fail' : 'muted'}`}> 失败 {result.fail}
, document.body )} ) }