mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
139 lines
5.1 KiB
TypeScript
139 lines
5.1 KiB
TypeScript
import React, { useEffect, useState } from 'react'
|
||
import { Quote, X } from 'lucide-react'
|
||
import './UpdateDialog.scss'
|
||
|
||
interface UpdateInfo {
|
||
version?: string
|
||
releaseNotes?: string
|
||
}
|
||
|
||
interface UpdateDialogProps {
|
||
open: boolean
|
||
updateInfo: UpdateInfo | null
|
||
onClose: () => void
|
||
onUpdate: () => void
|
||
onIgnore?: () => void
|
||
isDownloading: boolean
|
||
progress: number | {
|
||
percent: number
|
||
bytesPerSecond?: number
|
||
transferred?: number
|
||
total?: number
|
||
remaining?: number // seconds
|
||
}
|
||
}
|
||
|
||
const UpdateDialog: React.FC<UpdateDialogProps> = ({
|
||
open,
|
||
updateInfo,
|
||
onClose,
|
||
onUpdate,
|
||
onIgnore,
|
||
isDownloading,
|
||
progress
|
||
}) => {
|
||
if (!open || !updateInfo) return null
|
||
|
||
// Safe normalize progress
|
||
const safeProgress = typeof progress === 'number' ? { percent: progress } : (progress || { percent: 0 })
|
||
const percent = safeProgress.percent || 0
|
||
const bytesPerSecond = safeProgress.bytesPerSecond
|
||
const total = safeProgress.total
|
||
const transferred = safeProgress.transferred
|
||
const remaining = safeProgress.remaining
|
||
|
||
// Format bytes
|
||
const formatBytes = (bytes: number) => {
|
||
if (!Number.isFinite(bytes) || bytes === 0) return '0 B'
|
||
const k = 1024
|
||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||
const unitIndex = Math.max(0, Math.min(i, sizes.length - 1))
|
||
return parseFloat((bytes / Math.pow(k, unitIndex)).toFixed(1)) + ' ' + sizes[unitIndex]
|
||
}
|
||
|
||
// Format speed
|
||
const formatSpeed = (bytesPerSecond: number) => {
|
||
return `${formatBytes(bytesPerSecond)}/s`
|
||
}
|
||
|
||
// Format time
|
||
const formatTime = (seconds: number) => {
|
||
if (!Number.isFinite(seconds)) return '计算中...'
|
||
if (seconds < 60) return `${Math.ceil(seconds)} 秒`
|
||
const minutes = Math.floor(seconds / 60)
|
||
const remainingSeconds = Math.ceil(seconds % 60)
|
||
return `${minutes} 分 ${remainingSeconds} 秒`
|
||
}
|
||
|
||
return (
|
||
<div className="update-dialog-overlay">
|
||
<div className="update-dialog">
|
||
{!isDownloading && (
|
||
<button className="close-btn" onClick={onClose}>
|
||
<X size={20} />
|
||
</button>
|
||
)}
|
||
|
||
<div className="dialog-header">
|
||
<div className="version-tag">
|
||
新版本 {updateInfo.version}
|
||
</div>
|
||
<h2>欢迎体验全新的 WeFlow</h2>
|
||
<div className="subtitle">我们带来了一些改进</div>
|
||
</div>
|
||
|
||
<div className="dialog-content">
|
||
<div className="update-notes-container">
|
||
<div className="icon-box">
|
||
<Quote size={20} />
|
||
</div>
|
||
<div className="text-box">
|
||
{updateInfo.releaseNotes ? (
|
||
<div dangerouslySetInnerHTML={{ __html: updateInfo.releaseNotes }} />
|
||
) : (
|
||
<p>修复了一些已知问题,提升了稳定性。</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{isDownloading ? (
|
||
<div className="progress-section">
|
||
<div className="progress-info-row">
|
||
<span>{bytesPerSecond ? formatSpeed(bytesPerSecond) : '下载中...'}</span>
|
||
<span>{total ? `${formatBytes(transferred || 0)} / ${formatBytes(total)}` : `${percent.toFixed(1)}%`}</span>
|
||
{remaining !== undefined && <span>剩余 {formatTime(remaining)}</span>}
|
||
</div>
|
||
|
||
<div className="progress-bar-bg">
|
||
<div
|
||
className="progress-bar-fill"
|
||
style={{ width: `${percent}%` }}
|
||
/>
|
||
</div>
|
||
|
||
{/* Fallback status text if detailed info is missing */}
|
||
{(!bytesPerSecond && !total) && (
|
||
<div className="status-text">{percent.toFixed(0)}% 已下载</div>
|
||
)}
|
||
</div>
|
||
) : (
|
||
<div className="actions">
|
||
{onIgnore && (
|
||
<button className="btn-ignore" onClick={onIgnore}>
|
||
忽略本次更新
|
||
</button>
|
||
)}
|
||
<button className="btn-update" onClick={onUpdate}>
|
||
开启新旅程
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default UpdateDialog
|