import { useState, useEffect } from 'react' import { Card, Button, Spin, Progress, Alert, Space, Tag, Modal, message } from 'antd' import { CloudUploadOutlined, ReloadOutlined, CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons' import { apiClient } from '../services/api' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' interface UpdateInfo { hasUpdate: boolean currentVersion: string latestVersion: string latestTag: string releaseNotes: string publishedAt: string prerelease: boolean } interface UpdateStatus { updating: boolean progress: number message: string error: string | null } const SystemUpdate: React.FC = () => { const [currentVersion, setCurrentVersion] = useState('') const [updateChecking, setUpdateChecking] = useState(false) const [updateInfo, setUpdateInfo] = useState(null) const [updateStatus, setUpdateStatus] = useState({ updating: false, progress: 0, message: '就绪', error: null }) useEffect(() => { fetchCurrentVersion() fetchUpdateStatus() }, []) const fetchCurrentVersion = async () => { try { const response = await apiClient.get('/update/version') if (response.data.code === 0 && response.data.data) { setCurrentVersion(response.data.data.version) } } catch (error: any) { console.error('获取版本失败:', error) } } const fetchUpdateStatus = async () => { try { const response = await apiClient.get('/update/status') if (response.data.code === 0 && response.data.data) { setUpdateStatus({ updating: response.data.data.updating, progress: response.data.data.progress || 0, message: response.data.data.message || '就绪', error: response.data.data.error || null }) } } catch (error: any) { console.error('获取更新状态失败:', error) } } const handleCheckUpdate = async () => { setUpdateChecking(true) setUpdateInfo(null) try { const response = await apiClient.get('/update/check') const data = response.data if (data.code === 0 && data.data) { setUpdateInfo(data.data) if (data.data.hasUpdate) { message.success(`发现新版本: ${data.data.latestVersion}`) } else { message.info('当前已是最新版本') } } else { message.error(data.message || '检查更新失败') } } catch (error: any) { message.error(error.message || '检查更新失败') } finally { setUpdateChecking(false) } } const handleExecuteUpdate = () => { Modal.confirm({ title: '确认更新', icon: , content: (

确定要更新到版本 {updateInfo?.latestVersion} 吗?

更新过程中系统将暂时不可用(约30-60秒)。

更新完成后页面将自动刷新。

), okText: '立即更新', okType: 'primary', cancelText: '取消', onOk: async () => { try { const response = await apiClient.post('/update/update', {}) const data = response.data if (data.code === 0) { message.success('更新已启动,请稍候...') // 开始轮询更新状态 const pollInterval = setInterval(async () => { try { const statusResponse = await apiClient.get('/update/status') const statusData = statusResponse.data if (statusData.code === 0 && statusData.data) { setUpdateStatus({ updating: statusData.data.updating, progress: statusData.data.progress || 0, message: statusData.data.message || '', error: statusData.data.error || null }) // 更新完成 if (!statusData.data.updating) { clearInterval(pollInterval) if (statusData.data.error) { message.error(`更新失败: ${statusData.data.error}`) } else if (statusData.data.progress === 100) { message.success('更新成功!页面将在3秒后刷新...') setTimeout(() => window.location.reload(), 3000) } } } } catch (error) { console.error('获取更新状态失败:', error) } }, 2000) // 每2秒轮询一次 // 5分钟后停止轮询 setTimeout(() => clearInterval(pollInterval), 5 * 60 * 1000) } else if (data.code === 403) { message.error('需要管理员权限才能执行更新') } else { message.error(data.message || '启动更新失败') } } catch (error: any) { message.error(error.message || '启动更新失败') } } }) } const formatDate = (dateString: string) => { return new Date(dateString).toLocaleString('zh-CN') } return ( 系统更新 } style={{ marginBottom: '16px', borderRadius: '8px', boxShadow: '0 2px 8px rgba(0,0,0,0.06)' }} > {/* 当前版本信息 */}
当前版本
v{currentVersion || 'unknown'}
{/* 更新状态 */} {updateStatus.updating && ( 系统正在更新 } description={
{updateStatus.message}
`${percent}%`} />
} type="info" showIcon icon={} style={{ borderRadius: '8px', border: '1px solid #91d5ff' }} /> )} {updateStatus.error && ( 更新失败} description={
{updateStatus.error}
} type="error" showIcon closable onClose={() => setUpdateStatus(prev => ({ ...prev, error: null }))} style={{ borderRadius: '8px' }} /> )} {/* 检查更新 */} {!updateStatus.updating && (
{updateInfo && !updateInfo.hasUpdate && ( 当前已是最新版本 } type="success" showIcon icon={} style={{ marginTop: '12px', borderRadius: '8px', border: '1px solid #b7eb8f' }} /> )}
)} {/* 更新信息 */} {updateInfo && updateInfo.hasUpdate && !updateStatus.updating && (
发现新版本
v{updateInfo.latestVersion} {updateInfo.prerelease && ( Pre-release )}
发布时间
{formatDate(updateInfo.publishedAt)}
{updateInfo.releaseNotes && (
更新内容

, h2: ({node, ...props}) =>

, h3: ({node, ...props}) =>

, h4: ({node, ...props}) =>

, p: ({node, ...props}) =>

, ul: ({node, ...props}) =>