Header.tsx 8.4 KB

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