Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 532f4c3e25 | |||
| 04629e73b6 | |||
| 696193c571 | |||
| 38e256c4fb |
@@ -111,11 +111,16 @@ jobs:
|
||||
node-version: '18'
|
||||
|
||||
- name: Build Frontend
|
||||
env:
|
||||
VERSION: ${{ steps.extract_version.outputs.VERSION }}
|
||||
GIT_TAG: ${{ steps.extract_version.outputs.TAG }}
|
||||
GITHUB_REPO_URL: https://github.com/WrBug/PolyHermes
|
||||
run: |
|
||||
cd frontend
|
||||
npm ci
|
||||
npm run build
|
||||
echo "✅ 前端构建完成"
|
||||
echo "📦 版本信息: VERSION=${{ steps.extract_version.outputs.VERSION }}, GIT_TAG=${{ steps.extract_version.outputs.TAG }}"
|
||||
du -sh dist/
|
||||
|
||||
# ============ 打包更新包 ============
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
import { Layout as AntLayout, Menu, Drawer, Button, Modal } from 'antd'
|
||||
import { Layout as AntLayout, Menu, Drawer, Button, Modal, Tag } from 'antd'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import {
|
||||
@@ -19,16 +19,37 @@ import {
|
||||
TwitterOutlined,
|
||||
CheckCircleOutlined,
|
||||
SendOutlined,
|
||||
ApiOutlined, NotificationOutlined
|
||||
ApiOutlined,
|
||||
NotificationOutlined
|
||||
} from '@ant-design/icons'
|
||||
import type { MenuProps } from 'antd'
|
||||
import type { ReactNode } from 'react'
|
||||
import { removeToken, getVersionText, getGitHubTagUrl } from '../utils'
|
||||
import { removeToken, getVersionText, getVersionInfo } from '../utils'
|
||||
import { wsManager } from '../services/websocket'
|
||||
import { apiClient } from '../services/api'
|
||||
import Logo from './Logo'
|
||||
|
||||
const { Header, Content, Sider } = AntLayout
|
||||
|
||||
// 添加动画样式
|
||||
const style = document.createElement('style')
|
||||
style.textContent = `
|
||||
@keyframes versionUpdatePulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
`
|
||||
if (!document.head.querySelector('style[data-version-update-animation]')) {
|
||||
style.setAttribute('data-version-update-animation', 'true')
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
|
||||
interface LayoutProps {
|
||||
children: ReactNode
|
||||
}
|
||||
@@ -39,6 +60,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
const location = useLocation()
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||
const [hasUpdate, setHasUpdate] = useState(false)
|
||||
|
||||
// 获取当前选中的菜单项
|
||||
const getSelectedKeys = (): string[] => {
|
||||
@@ -72,6 +94,29 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
}
|
||||
setOpenKeys(keys)
|
||||
}, [location.pathname])
|
||||
|
||||
// 检查是否有新版本
|
||||
useEffect(() => {
|
||||
const checkUpdate = async () => {
|
||||
try {
|
||||
const response = await apiClient.get('/update/check')
|
||||
if (response.data.code === 0 && response.data.data) {
|
||||
setHasUpdate(response.data.data.hasUpdate || false)
|
||||
}
|
||||
} catch (error) {
|
||||
// 静默失败,不影响页面使用
|
||||
console.debug('检查更新失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时检查一次
|
||||
checkUpdate()
|
||||
|
||||
// 每5分钟检查一次
|
||||
const interval = setInterval(checkUpdate, 5 * 60 * 1000)
|
||||
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
const menuItems: MenuProps['items'] = [
|
||||
{
|
||||
@@ -210,27 +255,32 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
size="normal"
|
||||
darkMode={true}
|
||||
/>
|
||||
<a
|
||||
href={getGitHubTagUrl()}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(e) => {
|
||||
const version = getVersionText()
|
||||
if (version === 'dev') {
|
||||
e.preventDefault()
|
||||
<Tag
|
||||
color={hasUpdate ? 'warning' : 'success'}
|
||||
onClick={() => {
|
||||
if (hasUpdate) {
|
||||
navigate('/system-settings')
|
||||
}
|
||||
}}
|
||||
bordered={false}
|
||||
style={{
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'normal',
|
||||
textDecoration: 'none',
|
||||
cursor: getVersionText() === 'dev' ? 'default' : 'pointer'
|
||||
cursor: hasUpdate ? 'pointer' : 'default',
|
||||
fontSize: '8px',
|
||||
padding: '1px 6px',
|
||||
margin: 0,
|
||||
background: 'transparent',
|
||||
border: `1px solid ${hasUpdate ? '#faad14' : '#52c41a'}`,
|
||||
borderRadius: '4px',
|
||||
color: hasUpdate ? '#faad14' : '#52c41a',
|
||||
lineHeight: '1.4',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
verticalAlign: 'middle'
|
||||
}}
|
||||
title={getVersionText() === 'dev' ? '' : '查看版本发布'}
|
||||
title={hasUpdate ? '有新版本可用,点击前往系统更新' : '当前已是最新版本'}
|
||||
>
|
||||
v{getVersionText()}
|
||||
</a>
|
||||
{getVersionInfo().gitTag || `v${getVersionText()}`}
|
||||
</Tag>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||
<a
|
||||
@@ -322,34 +372,37 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
marginBottom: '12px',
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: '6px'
|
||||
}}>
|
||||
<span>PolyHermes</span>
|
||||
<a
|
||||
href={getGitHubTagUrl()}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(e) => {
|
||||
const version = getVersionText()
|
||||
if (version === 'dev') {
|
||||
e.preventDefault()
|
||||
<Tag
|
||||
color={hasUpdate ? 'warning' : 'success'}
|
||||
onClick={() => {
|
||||
if (hasUpdate) {
|
||||
navigate('/system-settings')
|
||||
}
|
||||
}}
|
||||
bordered={false}
|
||||
style={{
|
||||
color: 'rgba(255, 255, 255, 0.7)',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'normal',
|
||||
textDecoration: 'none',
|
||||
cursor: getVersionText() === 'dev' ? 'default' : 'pointer',
|
||||
lineHeight: '1',
|
||||
paddingBottom: '2px'
|
||||
cursor: hasUpdate ? 'pointer' : 'default',
|
||||
fontSize: '8px',
|
||||
padding: '1px 6px',
|
||||
margin: 0,
|
||||
background: 'transparent',
|
||||
border: `1px solid ${hasUpdate ? '#faad14' : '#52c41a'}`,
|
||||
borderRadius: '4px',
|
||||
color: hasUpdate ? '#faad14' : '#52c41a',
|
||||
lineHeight: '1.4',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
verticalAlign: 'middle'
|
||||
}}
|
||||
title={getVersionText() === 'dev' ? '' : '查看版本发布'}
|
||||
title={hasUpdate ? '有新版本可用,点击前往系统更新' : '当前已是最新版本'}
|
||||
>
|
||||
v{getVersionText()}
|
||||
</a>
|
||||
{getVersionInfo().gitTag || `v${getVersionText()}`}
|
||||
</Tag>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
|
||||
@@ -495,6 +495,9 @@ const SystemSettings: React.FC = () => {
|
||||
<Title level={2} style={{ margin: 0 }}>{t('systemSettings.title') || '通用设置'}</Title>
|
||||
</div>
|
||||
|
||||
{/* 系统更新 */}
|
||||
<SystemUpdate />
|
||||
|
||||
{/* 第一部分:多语言 */}
|
||||
<Card
|
||||
title={
|
||||
@@ -890,9 +893,6 @@ const SystemSettings: React.FC = () => {
|
||||
)}
|
||||
|
||||
</Card>
|
||||
|
||||
{/* 第五部分:系统更新 */}
|
||||
<SystemUpdate />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Card, Button, Spin, Progress, Alert, Space, Typography, Divider, Tag, Modal, message } from 'antd'
|
||||
import { Card, Button, Spin, Progress, Alert, Space, Tag, Modal, message } from 'antd'
|
||||
import {
|
||||
CloudUploadOutlined,
|
||||
ReloadOutlined,
|
||||
CheckCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
InfoCircleOutlined
|
||||
ExclamationCircleOutlined
|
||||
} from '@ant-design/icons'
|
||||
import { apiClient } from '../services/api'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
|
||||
const { Title, Text, Paragraph } = Typography
|
||||
|
||||
interface UpdateInfo {
|
||||
hasUpdate: boolean
|
||||
@@ -113,7 +113,7 @@ const SystemUpdate: React.FC = () => {
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
const response = await apiClient.post('/update/execute', {})
|
||||
const response = await apiClient.post('/update/update', {})
|
||||
const data = response.data
|
||||
|
||||
if (data.code === 0) {
|
||||
@@ -172,145 +172,302 @@ const SystemUpdate: React.FC = () => {
|
||||
<Card
|
||||
title={
|
||||
<Space>
|
||||
<CloudUploadOutlined />
|
||||
<span>系统更新</span>
|
||||
<CloudUploadOutlined style={{ fontSize: '18px', color: '#1890ff' }} />
|
||||
<span style={{ fontSize: '16px', fontWeight: 600 }}>系统更新</span>
|
||||
</Space>
|
||||
}
|
||||
style={{ marginBottom: '16px' }}
|
||||
style={{
|
||||
marginBottom: '16px',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.06)'
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
||||
{/* 当前版本信息 */}
|
||||
<div>
|
||||
<Title level={5}>当前版本</Title>
|
||||
<Space>
|
||||
<Tag color="blue" style={{ fontSize: '14px', padding: '4px 12px' }}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '16px',
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
borderRadius: '8px',
|
||||
color: '#fff'
|
||||
}}>
|
||||
<div>
|
||||
<div style={{ fontSize: '13px', opacity: 0.9, marginBottom: '4px' }}>
|
||||
当前版本
|
||||
</div>
|
||||
<div style={{ fontSize: '20px', fontWeight: 600 }}>
|
||||
v{currentVersion || 'unknown'}
|
||||
</Tag>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
<CheckCircleOutlined style={{ fontSize: '32px', opacity: 0.8 }} />
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* 更新状态 */}
|
||||
{updateStatus.updating && (
|
||||
<Alert
|
||||
message="系统正在更新"
|
||||
message={
|
||||
<span style={{ fontSize: '15px', fontWeight: 500 }}>系统正在更新</span>
|
||||
}
|
||||
description={
|
||||
<div>
|
||||
<p>{updateStatus.message}</p>
|
||||
<div style={{ marginTop: '12px' }}>
|
||||
<div style={{
|
||||
marginBottom: '12px',
|
||||
fontSize: '14px',
|
||||
color: '#595959'
|
||||
}}>
|
||||
{updateStatus.message}
|
||||
</div>
|
||||
<Progress
|
||||
percent={updateStatus.progress}
|
||||
status="active"
|
||||
strokeColor={{ '0%': '#108ee9', '100%': '#87d068' }}
|
||||
strokeColor={{
|
||||
'0%': '#667eea',
|
||||
'50%': '#764ba2',
|
||||
'100%': '#f093fb'
|
||||
}}
|
||||
strokeWidth={8}
|
||||
showInfo
|
||||
format={(percent) => `${percent}%`}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
type="info"
|
||||
showIcon
|
||||
icon={<Spin />}
|
||||
style={{
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #91d5ff'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{updateStatus.error && (
|
||||
<Alert
|
||||
message="更新失败"
|
||||
description={updateStatus.error}
|
||||
message={<span style={{ fontSize: '15px', fontWeight: 500 }}>更新失败</span>}
|
||||
description={
|
||||
<div style={{
|
||||
marginTop: '8px',
|
||||
fontSize: '14px',
|
||||
color: '#595959'
|
||||
}}>
|
||||
{updateStatus.error}
|
||||
</div>
|
||||
}
|
||||
type="error"
|
||||
showIcon
|
||||
closable
|
||||
onClose={() => setUpdateStatus(prev => ({ ...prev, error: null }))}
|
||||
style={{
|
||||
borderRadius: '8px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 检查更新 */}
|
||||
{!updateStatus.updating && (
|
||||
<Space>
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={handleCheckUpdate}
|
||||
loading={updateChecking}
|
||||
style={{
|
||||
height: '40px',
|
||||
borderRadius: '6px',
|
||||
fontWeight: 500,
|
||||
boxShadow: '0 2px 4px rgba(24, 144, 255, 0.2)'
|
||||
}}
|
||||
>
|
||||
检查更新
|
||||
</Button>
|
||||
|
||||
{updateInfo && !updateInfo.hasUpdate && (
|
||||
<Alert
|
||||
message="当前已是最新版本"
|
||||
message={
|
||||
<span style={{ fontSize: '15px', fontWeight: 500 }}>
|
||||
当前已是最新版本
|
||||
</span>
|
||||
}
|
||||
type="success"
|
||||
showIcon
|
||||
icon={<CheckCircleOutlined />}
|
||||
style={{
|
||||
marginTop: '12px',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #b7eb8f'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 更新信息 */}
|
||||
{updateInfo && updateInfo.hasUpdate && !updateStatus.updating && (
|
||||
<Alert
|
||||
message={
|
||||
<Space>
|
||||
<span>发现新版本:</span>
|
||||
<Tag color="green" style={{ fontSize: '14px' }}>
|
||||
v{updateInfo.latestVersion}
|
||||
</Tag>
|
||||
{updateInfo.prerelease && (
|
||||
<Tag color="orange">Pre-release</Tag>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
description={
|
||||
<div style={{ marginTop: '12px' }}>
|
||||
<Paragraph>
|
||||
<Text strong>发布时间:</Text>
|
||||
<Text type="secondary">{formatDate(updateInfo.publishedAt)}</Text>
|
||||
</Paragraph>
|
||||
|
||||
{updateInfo.releaseNotes && (
|
||||
<div>
|
||||
<Text strong>更新内容:</Text>
|
||||
<div style={{
|
||||
marginTop: '8px',
|
||||
padding: '12px',
|
||||
background: '#f5f5f5',
|
||||
borderRadius: '4px',
|
||||
maxHeight: '200px',
|
||||
overflowY: 'auto'
|
||||
}}>
|
||||
<pre style={{
|
||||
margin: 0,
|
||||
whiteSpace: 'pre-wrap',
|
||||
fontFamily: 'inherit'
|
||||
}}>
|
||||
{updateInfo.releaseNotes}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<CloudUploadOutlined />}
|
||||
onClick={handleExecuteUpdate}
|
||||
<div style={{
|
||||
padding: '20px',
|
||||
background: 'linear-gradient(135deg, #fff5f5 0%, #fff1f0 100%)',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #ffccc7'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: '16px',
|
||||
paddingBottom: '16px',
|
||||
borderBottom: '1px solid #ffccc7'
|
||||
}}>
|
||||
<div>
|
||||
<div style={{
|
||||
fontSize: '13px',
|
||||
color: '#8c8c8c',
|
||||
marginBottom: '6px'
|
||||
}}>
|
||||
发现新版本
|
||||
</div>
|
||||
<Space size="small">
|
||||
<Tag
|
||||
color="success"
|
||||
style={{
|
||||
fontSize: '16px',
|
||||
padding: '4px 16px',
|
||||
fontWeight: 600,
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
立即升级
|
||||
</Button>
|
||||
v{updateInfo.latestVersion}
|
||||
</Tag>
|
||||
{updateInfo.prerelease && (
|
||||
<Tag
|
||||
color="orange"
|
||||
style={{
|
||||
fontSize: '12px',
|
||||
padding: '4px 12px',
|
||||
borderRadius: '4px'
|
||||
}}
|
||||
>
|
||||
Pre-release
|
||||
</Tag>
|
||||
)}
|
||||
</Space>
|
||||
</div>
|
||||
<CloudUploadOutlined style={{
|
||||
fontSize: '32px',
|
||||
color: '#ff4d4f',
|
||||
opacity: 0.8
|
||||
}} />
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: '16px' }}>
|
||||
<div style={{
|
||||
fontSize: '13px',
|
||||
color: '#8c8c8c',
|
||||
marginBottom: '4px'
|
||||
}}>
|
||||
发布时间
|
||||
</div>
|
||||
<div style={{
|
||||
fontSize: '14px',
|
||||
color: '#595959'
|
||||
}}>
|
||||
{formatDate(updateInfo.publishedAt)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{updateInfo.releaseNotes && (
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<div style={{
|
||||
fontSize: '13px',
|
||||
color: '#8c8c8c',
|
||||
marginBottom: '8px',
|
||||
fontWeight: 500
|
||||
}}>
|
||||
更新内容
|
||||
</div>
|
||||
<div style={{
|
||||
padding: '16px',
|
||||
background: '#fff',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid #e8e8e8',
|
||||
maxHeight: '500px',
|
||||
overflowY: 'auto',
|
||||
lineHeight: '1.6',
|
||||
boxShadow: 'inset 0 1px 2px rgba(0,0,0,0.06)'
|
||||
}}>
|
||||
<div style={{
|
||||
color: '#262626',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
h1: ({node, ...props}) => <h1 style={{ fontSize: '20px', fontWeight: 600, marginTop: '16px', marginBottom: '12px', color: '#262626', borderBottom: '2px solid #e8e8e8', paddingBottom: '8px' }} {...props} />,
|
||||
h2: ({node, ...props}) => <h2 style={{ fontSize: '18px', fontWeight: 600, marginTop: '16px', marginBottom: '10px', color: '#262626' }} {...props} />,
|
||||
h3: ({node, ...props}) => <h3 style={{ fontSize: '16px', fontWeight: 600, marginTop: '14px', marginBottom: '8px', color: '#262626' }} {...props} />,
|
||||
h4: ({node, ...props}) => <h4 style={{ fontSize: '15px', fontWeight: 600, marginTop: '12px', marginBottom: '6px', color: '#262626' }} {...props} />,
|
||||
p: ({node, ...props}) => <p style={{ marginBottom: '12px', color: '#595959' }} {...props} />,
|
||||
ul: ({node, ...props}) => <ul style={{ marginBottom: '12px', paddingLeft: '24px', color: '#595959' }} {...props} />,
|
||||
ol: ({node, ...props}) => <ol style={{ marginBottom: '12px', paddingLeft: '24px', color: '#595959' }} {...props} />,
|
||||
li: ({node, ...props}) => <li style={{ marginBottom: '6px', lineHeight: '1.6' }} {...props} />,
|
||||
code: ({node, inline, ...props}: any) =>
|
||||
inline
|
||||
? <code style={{ background: '#f0f0f0', padding: '2px 6px', borderRadius: '3px', fontSize: '13px', fontFamily: 'Monaco, Menlo, "Ubuntu Mono", Consolas, monospace', color: '#d73a49' }} {...props} />
|
||||
: <code style={{ display: 'block', background: '#282c34', color: '#abb2bf', padding: '12px', borderRadius: '4px', overflowX: 'auto', fontSize: '13px', fontFamily: 'Monaco, Menlo, "Ubuntu Mono", Consolas, monospace', marginBottom: '12px', lineHeight: '1.5' }} {...props} />,
|
||||
pre: ({node, ...props}) => <pre style={{ background: '#282c34', borderRadius: '4px', padding: '12px', overflowX: 'auto', marginBottom: '12px' }} {...props} />,
|
||||
blockquote: ({node, ...props}) => <blockquote style={{ borderLeft: '4px solid #1890ff', paddingLeft: '12px', margin: '12px 0', color: '#8c8c8c', fontStyle: 'italic' }} {...props} />,
|
||||
a: ({node, ...props}) => <a style={{ color: '#1890ff', textDecoration: 'none' }} target="_blank" rel="noopener noreferrer" {...props} />,
|
||||
strong: ({node, ...props}) => <strong style={{ fontWeight: 600, color: '#262626' }} {...props} />,
|
||||
table: ({node, ...props}) => <table style={{ width: '100%', borderCollapse: 'collapse', marginBottom: '12px' }} {...props} />,
|
||||
th: ({node, ...props}) => <th style={{ border: '1px solid #e8e8e8', padding: '8px 12px', background: '#fafafa', fontWeight: 600, textAlign: 'left' }} {...props} />,
|
||||
td: ({node, ...props}) => <td style={{ border: '1px solid #e8e8e8', padding: '8px 12px' }} {...props} />,
|
||||
hr: ({node, ...props}) => <hr style={{ border: 'none', borderTop: '1px solid #e8e8e8', margin: '16px 0' }} {...props} />
|
||||
}}
|
||||
>
|
||||
{updateInfo.releaseNotes}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
type="warning"
|
||||
showIcon
|
||||
icon={<InfoCircleOutlined />}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
icon={<CloudUploadOutlined />}
|
||||
onClick={handleExecuteUpdate}
|
||||
block
|
||||
style={{
|
||||
height: '44px',
|
||||
borderRadius: '6px',
|
||||
fontWeight: 500,
|
||||
fontSize: '15px',
|
||||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
border: 'none',
|
||||
boxShadow: '0 4px 12px rgba(102, 126, 234, 0.4)'
|
||||
}}
|
||||
>
|
||||
立即升级到 v{updateInfo.latestVersion}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 使用提示 */}
|
||||
{!updateStatus.updating && (
|
||||
{!updateStatus.updating && !(updateInfo && updateInfo.hasUpdate) && (
|
||||
<Alert
|
||||
message="使用说明"
|
||||
message={
|
||||
<span style={{ fontSize: '15px', fontWeight: 500 }}>使用说明</span>
|
||||
}
|
||||
description={
|
||||
<ul style={{ marginBottom: 0, paddingLeft: '20px' }}>
|
||||
<ul style={{
|
||||
marginBottom: 0,
|
||||
paddingLeft: '20px',
|
||||
fontSize: '14px',
|
||||
color: '#595959',
|
||||
lineHeight: '1.8'
|
||||
}}>
|
||||
<li>点击"检查更新"按钮检查是否有新版本</li>
|
||||
<li>更新过程约需30-60秒,期间系统将暂时不可用</li>
|
||||
<li>更新成功后页面将自动刷新</li>
|
||||
@@ -319,6 +476,10 @@ const SystemUpdate: React.FC = () => {
|
||||
}
|
||||
type="info"
|
||||
showIcon
|
||||
style={{
|
||||
borderRadius: '8px',
|
||||
border: '1px solid #91d5ff'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
Reference in New Issue
Block a user