You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
5.8 KiB
189 lines
5.8 KiB
import { useEffect, useState } from 'react'
|
|
import { Modal, Progress, Button, Space, Typography, notification } from 'antd'
|
|
import { DownloadOutlined, ReloadOutlined, CloseOutlined } from '@ant-design/icons'
|
|
import { IPC_EVENT } from '../../common/ipcEvents'
|
|
import styles from './AutoUpdater.module.css'
|
|
|
|
const { Title, Text } = Typography
|
|
|
|
function AutoUpdater() {
|
|
const [updateInfo, setUpdateInfo] = useState(null)
|
|
const [isModalVisible, setIsModalVisible] = useState(false)
|
|
const [updateStatus, setUpdateStatus] = useState('')
|
|
const [downloadProgress, setDownloadProgress] = useState(0)
|
|
const [isDownloading, setIsDownloading] = useState(false)
|
|
const [isDownloaded, setIsDownloaded] = useState(false)
|
|
|
|
useEffect(() => {
|
|
// 监听发现新版本
|
|
const handleUpdateAvailable = (event, info) => {
|
|
console.log('收到update-available事件:', info)
|
|
setUpdateInfo(info)
|
|
setUpdateStatus('发现新版本')
|
|
setIsModalVisible(true)
|
|
setIsDownloading(false)
|
|
setIsDownloaded(false)
|
|
setDownloadProgress(0)
|
|
}
|
|
|
|
// 监听下载进度
|
|
const handleDownloadProgress = (event, progressObj) => {
|
|
console.log('下载进度:', progressObj)
|
|
setDownloadProgress(Math.round(progressObj.percent))
|
|
setUpdateStatus(`正在下载新版本... ${Math.round(progressObj.percent)}%`)
|
|
}
|
|
|
|
// 监听下载完成
|
|
const handleUpdateDownloaded = () => {
|
|
console.log('下载完成')
|
|
setIsDownloading(false)
|
|
setIsDownloaded(true)
|
|
setUpdateStatus('新版本下载完成,准备安装')
|
|
notification.success({
|
|
message: '更新下载完成',
|
|
description: '新版本已下载完成,点击"立即安装"重启应用以完成更新',
|
|
duration: 5
|
|
})
|
|
}
|
|
|
|
// 监听更新错误
|
|
const handleUpdateError = (event, error) => {
|
|
console.error('更新错误:', error)
|
|
setIsDownloading(false)
|
|
setUpdateStatus(`更新失败: ${error}`)
|
|
notification.error({
|
|
message: '更新失败',
|
|
description: error,
|
|
duration: 5
|
|
})
|
|
}
|
|
|
|
// 注册监听器
|
|
window.electron.ipcRenderer.on(IPC_EVENT.UPDATE_AVAILABLE, handleUpdateAvailable)
|
|
window.electron.ipcRenderer.on(IPC_EVENT.DOWNLOAD_PROGRESS, handleDownloadProgress)
|
|
window.electron.ipcRenderer.on(IPC_EVENT.UPDATE_DOWNLOADED, handleUpdateDownloaded)
|
|
window.electron.ipcRenderer.on(IPC_EVENT.UPDATE_ERROR, handleUpdateError)
|
|
|
|
// 清理监听器
|
|
return () => {
|
|
window.electron.ipcRenderer.removeListener(IPC_EVENT.UPDATE_AVAILABLE, handleUpdateAvailable)
|
|
window.electron.ipcRenderer.removeListener(
|
|
IPC_EVENT.DOWNLOAD_PROGRESS,
|
|
handleDownloadProgress
|
|
)
|
|
window.electron.ipcRenderer.removeListener(
|
|
IPC_EVENT.UPDATE_DOWNLOADED,
|
|
handleUpdateDownloaded
|
|
)
|
|
window.electron.ipcRenderer.removeListener(IPC_EVENT.UPDATE_ERROR, handleUpdateError)
|
|
}
|
|
}, [])
|
|
|
|
// 开始下载
|
|
const handleDownload = async () => {
|
|
setIsDownloading(true)
|
|
setUpdateStatus('准备下载新版本...')
|
|
setDownloadProgress(0)
|
|
try {
|
|
await window.electron.ipcRenderer.invoke(IPC_EVENT.UPDATE_DOWNLOAD)
|
|
} catch (error) {
|
|
console.error('请求下载失败:', error)
|
|
setIsDownloading(false)
|
|
}
|
|
}
|
|
|
|
// 安装更新
|
|
const handleInstall = async () => {
|
|
try {
|
|
await window.electron.ipcRenderer.invoke(IPC_EVENT.UPDATE_INSTALL)
|
|
} catch (error) {
|
|
console.error('安装更新失败:', error)
|
|
}
|
|
}
|
|
|
|
// 取消更新
|
|
const handleCancel = () => {
|
|
setIsModalVisible(false)
|
|
setUpdateInfo(null)
|
|
setIsDownloading(false)
|
|
setIsDownloaded(false)
|
|
setDownloadProgress(0)
|
|
}
|
|
|
|
return (
|
|
<Modal
|
|
title={
|
|
<Space>
|
|
<DownloadOutlined />
|
|
<span>软件更新</span>
|
|
</Space>
|
|
}
|
|
open={isModalVisible}
|
|
onCancel={handleCancel}
|
|
footer={null}
|
|
width={480}
|
|
maskClosable={false}
|
|
>
|
|
<div className={styles.modalContent}>
|
|
{updateInfo && (
|
|
<div className={styles.versionInfo}>
|
|
<Title level={5} className={styles.versionTitle}>
|
|
发现新版本:v{updateInfo.version}
|
|
</Title>
|
|
{updateInfo.releaseNotes && (
|
|
<div className={styles.releaseNotesSection}>
|
|
<Text type="secondary">更新说明:</Text>
|
|
<div className={styles.releaseNotesContainer}>
|
|
<Text className={styles.releaseNotesText}>{updateInfo.releaseNotes}</Text>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<div className={styles.statusSection}>
|
|
<Text>{updateStatus}</Text>
|
|
</div>
|
|
|
|
{isDownloading && (
|
|
<div className={styles.progressSection}>
|
|
<Progress
|
|
percent={downloadProgress}
|
|
status="active"
|
|
strokeColor={{
|
|
'0%': '#108ee9',
|
|
'100%': '#87d068'
|
|
}}
|
|
format={(percent) => `${percent}%`}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<div className={styles.actionButtons}>
|
|
<Space>
|
|
<Button icon={<CloseOutlined />} onClick={handleCancel}>
|
|
{isDownloaded ? '稍后安装' : '取消'}
|
|
</Button>
|
|
{!isDownloaded && !isDownloading && (
|
|
<Button type="primary" icon={<DownloadOutlined />} onClick={handleDownload}>
|
|
立即下载
|
|
</Button>
|
|
)}
|
|
{isDownloaded && (
|
|
<Button
|
|
type="primary"
|
|
icon={<ReloadOutlined />}
|
|
onClick={handleInstall}
|
|
className={styles.installButton}
|
|
>
|
|
立即安装
|
|
</Button>
|
|
)}
|
|
</Space>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
)
|
|
}
|
|
|
|
export default AutoUpdater
|
|
|