feat: 优化系统更新功能

- 系统更新模块移到系统设置页面最上方
- 版本号显示使用 Tag 格式(gitTag)
- 版本号 Tag 根据是否有新版本显示不同颜色(黄色=有新版本,绿色=无新版本)
- 版本号使用镂空样式,字号 8px
- 支持 Markdown 渲染更新内容
- 美化系统更新页面样式
- 在 Layout 中添加版本更新检查,有新版本时显示提示
This commit is contained in:
WrBug
2026-01-21 05:13:28 +08:00
parent 38e256c4fb
commit 696193c571
3 changed files with 333 additions and 117 deletions
+91 -38
View File
@@ -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, getGitHubTagUrl, 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',