UpdateNotification.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import React, { useEffect, useState } from 'react';
  2. import { CloseOutlined, RocketOutlined } from '@ant-design/icons';
  3. import ReactMarkdown from 'react-markdown';
  4. import rehypeRaw from 'rehype-raw';
  5. import { shouldShowUpdate, isUpdateNotificationDisabled } from './version';
  6. import './style.less';
  7. interface UpdateNotificationProps {
  8. version: string; // 版本号,用于控制是否显示
  9. }
  10. const UpdateNotification: React.FC<UpdateNotificationProps> = ({ version }) => {
  11. const [visible, setVisible] = useState(false);
  12. const [content, setContent] = useState('');
  13. const [isAnimating, setIsAnimating] = useState(false);
  14. useEffect(() => {
  15. // 检查是否被禁用
  16. if (isUpdateNotificationDisabled()) {
  17. return;
  18. }
  19. // 检查是否已经看过这个版本的更新
  20. const lastViewedVersion = localStorage.getItem('lastViewedUpdateVersion');
  21. if (shouldShowUpdate(lastViewedVersion)) {
  22. // 立即保存版本号,防止退出登录或刷新后重复显示
  23. localStorage.setItem('lastViewedUpdateVersion', version);
  24. // 加载更新内容
  25. import('./update.md?raw')
  26. .then((module) => {
  27. setContent(module.default);
  28. setTimeout(() => {
  29. setVisible(true);
  30. setIsAnimating(true);
  31. }, 800);
  32. })
  33. .catch(() => {
  34. console.error('Failed to load update content');
  35. });
  36. }
  37. }, [version]);
  38. const handleClose = () => {
  39. setIsAnimating(false);
  40. setTimeout(() => {
  41. setVisible(false);
  42. }, 300);
  43. };
  44. if (!visible) return null;
  45. return (
  46. <>
  47. {/* 遮罩层 */}
  48. <div
  49. className={`update-notification-mask ${isAnimating ? 'show' : ''}`}
  50. onClick={handleClose}
  51. />
  52. {/* 弹窗 */}
  53. <div className={`update-notification ${isAnimating ? 'show' : ''}`}>
  54. <div className="update-notification-header">
  55. <div className="update-notification-title">
  56. <span>版本更新公告</span>
  57. </div>
  58. <CloseOutlined
  59. className="update-notification-close"
  60. onClick={handleClose}
  61. />
  62. </div>
  63. <div className="update-notification-content">
  64. <ReactMarkdown
  65. rehypePlugins={[rehypeRaw]}
  66. components={{
  67. h1: (props) => <h2 style={{ fontSize: '16px', marginTop: 0, marginBottom: '16px' }} {...props} />,
  68. h2: (props) => <h2 {...props} />,
  69. h3: (props) => <h3 {...props} />,
  70. p: (props) => <p style={{ fontSize: '14px', lineHeight: '1.8', margin: '8px 0' }} {...props} />,
  71. ul: (props) => <ul {...props} />,
  72. li: (props) => <li style={{ fontSize: '14px' }} {...props} />,
  73. strong: (props) => <strong {...props} />,
  74. code: (props) => (
  75. <code style={{
  76. background: '#f6f7f9',
  77. padding: '2px 6px',
  78. borderRadius: 3,
  79. fontSize: '13px',
  80. color: '#c7254e'
  81. }} {...props} />
  82. ),
  83. }}
  84. >
  85. {content}
  86. </ReactMarkdown>
  87. </div>
  88. <div className="update-notification-footer">
  89. <button className="update-notification-button" onClick={handleClose}>
  90. 关闭
  91. </button>
  92. </div>
  93. </div>
  94. </>
  95. );
  96. };
  97. export default UpdateNotification;