Header.tsx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import * as React from 'react';
  2. import { Modal, Button, Tooltip } from 'antd';
  3. import { useNavigate } from 'react-router-dom';
  4. import { MenuFoldOutlined, MenuUnfoldOutlined, MessageOutlined } from '@ant-design/icons';
  5. import { Bell, ChevronDown, User, Settings, LogOut } from 'lucide-react';
  6. import LocalStorage from '@/LocalStorage';
  7. import { useLayoutStore } from '../store';
  8. import './header.scss';
  9. import jkLogo from '@/assets/public/jkLogo.svg'; // 桌面端 Logo(长方形)
  10. import jkLogoSm from '@/assets/public/jkLogo-sm.svg'; // H5/Pad 端 Logo(方形)
  11. interface Props {
  12. userName: string;
  13. onClickLogout: (navigate: any) => Promise<any>;
  14. }
  15. const Header: React.FC<Props> = (props) => {
  16. const navigate = useNavigate();
  17. const { userName, onClickLogout } = props;
  18. const { collapsed, onClickCollapsed } = useLayoutStore();
  19. const [dropdownVisible, setDropdownVisible] = React.useState(false);
  20. const dropdownRef = React.useRef<HTMLDivElement>(null);
  21. const [isMobile, setIsMobile] = React.useState(false);
  22. // 响应式检测
  23. React.useEffect(() => {
  24. const checkMobile = () => {
  25. setIsMobile(window.innerWidth <= 1024);
  26. };
  27. checkMobile();
  28. window.addEventListener('resize', checkMobile);
  29. return () => window.removeEventListener('resize', checkMobile);
  30. }, []);
  31. // Header 滚动效果
  32. React.useEffect(() => {
  33. const header = document.querySelector('.header');
  34. const handleScroll = () => {
  35. if (window.scrollY > 10) {
  36. header?.classList.add('scrolled');
  37. } else {
  38. header?.classList.remove('scrolled');
  39. }
  40. };
  41. window.addEventListener('scroll', handleScroll);
  42. return () => window.removeEventListener('scroll', handleScroll);
  43. }, []);
  44. // 点击外部关闭下拉菜单
  45. React.useEffect(() => {
  46. const handleClickOutside = (event: MouseEvent) => {
  47. if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
  48. setDropdownVisible(false);
  49. }
  50. };
  51. document.addEventListener('mousedown', handleClickOutside);
  52. return () => document.removeEventListener('mousedown', handleClickOutside);
  53. }, []);
  54. // 处理退出登录
  55. const handleLogout = () => {
  56. setDropdownVisible(false);
  57. Modal.confirm({
  58. title: '提示',
  59. content: '确定退出平台吗?',
  60. async onOk() {
  61. await onClickLogout(navigate);
  62. }
  63. });
  64. };
  65. return (
  66. <header className='header'>
  67. <div className='header-container'>
  68. {/* 汉堡菜单按钮(移动端显示) */}
  69. <Button
  70. className='mobile-menu-btn'
  71. type='text'
  72. icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
  73. onClick={onClickCollapsed}
  74. title={collapsed ? '展开菜单' : '收起菜单'}
  75. />
  76. {/* Logo 区域 + 智能问答 */}
  77. <div className='header-logo-wrapper'>
  78. {/* Logo 区域 */}
  79. <div
  80. className='header-logo-section'
  81. onClick={() => navigate('/appCenter')}
  82. >
  83. {/* 根据屏幕尺寸切换 Logo */}
  84. <img
  85. src={isMobile ? jkLogoSm : jkLogo}
  86. alt="建科小智"
  87. className='logo-image'
  88. />
  89. {/* 竖线间隔 */}
  90. <div className='logo-divider'></div>
  91. <div className='logo-text-section'>
  92. <h1 className='logo-title'>建科小智</h1>
  93. <p className='logo-subtitle'>开放平台 v2.0</p>
  94. </div>
  95. </div>
  96. {/* 智能问答快捷入口 - 桌面端显示 */}
  97. {!isMobile && (
  98. <Tooltip title='智能问答'>
  99. <button
  100. className='quick-access-btn'
  101. onClick={() => window.open('/universalChat', '_blank')}
  102. >
  103. <MessageOutlined />
  104. <span>智能问答</span>
  105. </button>
  106. </Tooltip>
  107. )}
  108. </div>
  109. {/* 右侧功能区 */}
  110. <div className='header-right'>
  111. {/* 搜索框 - 已注释 */}
  112. {/* <div className='header-search'>
  113. <span
  114. className='iconify search-icon'
  115. data-icon='solar:magnifer-linear'
  116. ></span>
  117. <input
  118. type='text'
  119. className='search-input'
  120. placeholder='试试搜索 "政务审批自动摘要生成" 或 "安防监控动态预警"...'
  121. />
  122. </div> */}
  123. {/* 安全状态指示器 */}
  124. <div className='security-status'>
  125. <span className='status-dot'></span>
  126. <span>内网安全连接</span>
  127. </div>
  128. {/* 通知按钮 */}
  129. <button className='notification-btn'>
  130. <Bell size={20} />
  131. <span className='notification-dot'></span>
  132. </button>
  133. {/* 用户区域 */}
  134. <div className='user-dropdown-wrapper' ref={dropdownRef}>
  135. <button
  136. className='user-section'
  137. onClick={() => setDropdownVisible(!dropdownVisible)}
  138. >
  139. <div className='user-avatar'>
  140. <img
  141. alt={userName}
  142. src='https://modao.cc/agent-py/media/generated_images/2026-03-18/087b1d0dc0544b9e82f423a1398cbc25.jpg'
  143. />
  144. </div>
  145. <div className='user-info'>
  146. <p className='user-name'>{userName}</p>
  147. <p className='user-dept'>部门信息</p>
  148. </div>
  149. <ChevronDown size={16} className='user-dropdown-icon' />
  150. </button>
  151. {/* 下拉菜单 */}
  152. {dropdownVisible && (
  153. <div className='user-dropdown-menu'>
  154. <div className='user-dropdown-header'>
  155. <p className='user-dropdown-name'>{userName}</p>
  156. <p className='user-dropdown-dept'>部门信息</p>
  157. </div>
  158. <button className='user-dropdown-item'>
  159. <User size={16} />
  160. <span>个人中心</span>
  161. </button>
  162. <button className='user-dropdown-item'>
  163. <Settings size={16} />
  164. <span>账户设置</span>
  165. </button>
  166. <div className='user-dropdown-item divider'></div>
  167. <button className='user-dropdown-item danger' onClick={handleLogout}>
  168. <LogOut size={16} />
  169. <span>退出登录</span>
  170. </button>
  171. </div>
  172. )}
  173. </div>
  174. </div>
  175. </div>
  176. </header>
  177. );
  178. };
  179. export default Header;