index.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /*
  2. * @Author: your name
  3. * @Date: 2021-11-16 09:12:37
  4. * @LastEditTime: 2024-07-18 16:51:08
  5. * @LastEditors: code4eat awesomedema@gmail.com
  6. * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  7. * @FilePath: /KC-MiddlePlatform/src/pages/index/components/topBar/index.tsx
  8. */
  9. import React, { useEffect, useState } from 'react';
  10. import './style.less';
  11. import { Input, Modal, Tooltip } from 'antd';
  12. import { LogoutOutlined, SettingOutlined } from '@ant-design/icons';
  13. // import logo from '../../../public/images/kc-logo.png';
  14. import tabCloseIcon from '../../../public/images/tabCloseIcon.png';
  15. import { history, useLocation, useModel } from 'umi';
  16. import { Divider } from 'antd';
  17. import { updateTokenReq } from '@/service/user';
  18. import { logoutHandle } from '@/global';
  19. interface TopBarType {
  20. onTabChange?: (data: TopBar.Tab[]) => void; //当tab切换时回调
  21. openedTabs: TopBar.Tab[]; //已打开的列表
  22. currentTab?: TopBar.Tab | undefined; //当前tab
  23. userPannelTabClick?: (tag: 'SETTING' | 'LOGOUT' | 'SETUSERINFO') => void;
  24. onCloseTab?: (data: TopBar.Tab) => void;
  25. onTabClick?: (data: TopBar.Tab) => void;
  26. userData?: { name: string;[key: string]: any };
  27. navData: TopBar.PanelData[];
  28. logo?:string;
  29. topBarTitle?:string;
  30. }
  31. const TopBar: React.FC<TopBarType> = (props) => {
  32. const { onTabChange, userPannelTabClick, onCloseTab, onTabClick, userData, navData, currentTab,logo=undefined,topBarTitle='欢迎进入医管平台' } = props;
  33. const [systemTabs, setSystemTabs] = useState<TopBar.Tab[]>([]); //已打开的tab
  34. const [currentSelectedTab, setCurrentSelectedTab] = useState<TopBar.Tab>();
  35. const [ifOpenPannel, setIfOpenPannel] = useState(false);
  36. const [arrowRotate, setArrowRotate] = useState(false);
  37. const [pageTitle, set_pageTitle] = useState('');
  38. const [currentActivedBlockIndex, set_currentActivedBlockIndex] = useState(0);
  39. const [panelData, set_panelData] = useState<TopBar.PanelData[]>([]);
  40. const [onTabSystemTabs, set_onTabSystemTabs] = useState<TopBar.Tab[]>([]); //tab导航可以放下的数量,剩余通过下拉获取
  41. const [onTabSystemTabs_hide, set_onTabSystemTabs_hide] = useState<TopBar.Tab[]>([]); //下拉掩藏的导航
  42. const { initialState, setInitialState } = useModel('@@initialState');
  43. const [tokenUpdateModalVisible,set_tokenUpdateModalVisible] = useState(false);
  44. const location = useLocation();
  45. const [showMoreTabPannel, set_showMoreTabPannel] = useState(false);
  46. const [password,set_password] = useState<string|undefined>(undefined);
  47. const localSavedTab = localStorage.getItem('currentSelectedTab');
  48. const currentSelectedTabFromLocal = localSavedTab ? JSON.parse(localSavedTab) : {};
  49. const _systemTabClickHandle = (item: TopBar.Tab) => {
  50. //导航栏tab点击
  51. // console.log('_systemTabClickHandle',item);
  52. onTabClick && onTabClick(item);
  53. localStorage.setItem('currentSelectedTab', JSON.stringify(item));
  54. setCurrentSelectedTab(item);
  55. };
  56. const _systemListClickHandle = (data: TopBar.Tab, currentActivedBlockIndex: number, index: number, i: number) => {
  57. //导航栏系统菜单列表点击回调
  58. if (currentSelectedTab?.menuId == data.menuId) return;
  59. //临时保存衣打开过的菜单
  60. const t = localStorage.getItem('visitedTabs');
  61. if (t) {
  62. let visitedTabs = JSON.parse(t);
  63. let index = visitedTabs.findIndex((t: TopBar.Tab) => t.menuId == data.menuId);
  64. if (index == -1) {
  65. visitedTabs.push(data);
  66. localStorage.setItem('visitedTabs', JSON.stringify(visitedTabs));
  67. }
  68. } else {
  69. localStorage.setItem('visitedTabs', JSON.stringify([data]));
  70. }
  71. _systemTabClickHandle(data); //触发一次tab点击
  72. set_pageTitle(panelData[currentActivedBlockIndex].child[index].name)
  73. if (panelData[currentActivedBlockIndex].child[index].child) {
  74. //console.log([...panelData[currentActivedBlockIndex].child[index].child])
  75. setSystemTabs([...panelData[currentActivedBlockIndex].child[index].child]);
  76. }
  77. setIfOpenPannel(false);
  78. };
  79. const _userPannelTabClick = (tag: 'SETTING' | 'LOGOUT') => {
  80. //用户菜单tab点击回调
  81. userPannelTabClick && userPannelTabClick(tag);
  82. };
  83. const closeTabHandle = (item: TopBar.Tab, e: React.MouseEvent) => {
  84. e.stopPropagation();
  85. let _systemTabs = [...systemTabs];
  86. let delIndex = -1;
  87. const filtered: any[] = _systemTabs.filter((t, index) => {
  88. if (t.menuId == item.menuId) {
  89. delIndex = index;
  90. }
  91. return t.menuId != item.menuId;
  92. });
  93. setSystemTabs([...filtered]);
  94. if (delIndex != 0) {
  95. _systemTabClickHandle(_systemTabs[delIndex - 1]); //自动切换为前一个tab
  96. }
  97. onTabChange && onTabChange(filtered);
  98. onCloseTab && onCloseTab(item);
  99. };
  100. const UserPannel = () => {
  101. return (
  102. <div className='userPannel'>
  103. <div className='userPannelTab' onClick={() => _userPannelTabClick('SETTING')}>
  104. <SettingOutlined />
  105. <span>设置</span>
  106. </div>
  107. <div className='userPannelTab' onClick={() => _userPannelTabClick('LOGOUT')}>
  108. <LogoutOutlined />
  109. <span>退出</span>
  110. </div>
  111. </div>
  112. );
  113. };
  114. const goChannelIndex = (menuData: any) => {
  115. setIfOpenPannel(false);
  116. onTabClick && onTabClick(menuData)
  117. }
  118. const goToHome = () => {
  119. const go = () => {
  120. history.replace('/index');
  121. setSystemTabs([]); //清空tab导航
  122. onTabChange && onTabChange([]);
  123. setCurrentSelectedTab(undefined);
  124. set_pageTitle(topBarTitle);
  125. setIfOpenPannel(false);
  126. console.log('goHome');
  127. localStorage.removeItem('currentSelectedTab');
  128. localStorage.removeItem('selectedKeys');
  129. // localStorage.removeItem('visitedTabs');
  130. localStorage.removeItem('openKeys');
  131. }
  132. const currentSelectedSubHop_json = localStorage.getItem('currentSelectedSubHop');
  133. if (currentSelectedSubHop_json) {
  134. const currentSelectedSubHop = JSON.parse(currentSelectedSubHop_json);
  135. if (currentSelectedSubHop.loadType) {
  136. return false;
  137. } else {
  138. go();
  139. }
  140. } else {
  141. go();
  142. }
  143. }
  144. const goSystemIndex = (name: string) => {
  145. if (panelData[currentActivedBlockIndex]) {
  146. const result: TopBar.TypeBlock[] = panelData[currentActivedBlockIndex].child.filter(t => (t.name == name));
  147. if (result.length > 0) {
  148. _systemTabClickHandle(Object.assign(result[0]))
  149. // history.push(result[0].path)
  150. }
  151. }
  152. }
  153. const openNav = () => {
  154. setIfOpenPannel(!ifOpenPannel);
  155. }
  156. const moreItemClickHandle = (systemData: TopBar.Tab) => {
  157. //点击更多应用时
  158. _systemTabClickHandle(systemData);
  159. const temp = onTabSystemTabs[onTabSystemTabs.length - 1];
  160. const _onTabSystemTabs = [...onTabSystemTabs];
  161. const b = _onTabSystemTabs.filter(a => a.systemId != temp.systemId);
  162. set_onTabSystemTabs([...b, systemData]);
  163. set_onTabSystemTabs_hide([...onTabSystemTabs_hide.filter(a => a.systemId != systemData.systemId), temp])
  164. }
  165. const reSetNav = (_panelData: TopBar.PanelData[], cur: TopBar.Tab) => {
  166. if (!(_panelData.length > 0)) return
  167. if (JSON.stringify(cur) != '{}') {
  168. let blockIndex = 0;
  169. let channelIndex = 0;
  170. const _currentSelectedTabFromLocal = cur;
  171. one: for (let index = 0; index < _panelData.length; index++) {
  172. blockIndex = index;
  173. if (_panelData[index] && _panelData[index].child) {
  174. two: for (let i = 0; i < _panelData[index].child.length; i++) {
  175. channelIndex = i;
  176. if (_panelData && _panelData.length > 0) {
  177. const _systems = _panelData[index].child[i].child;
  178. if (_systems && _systems.length > 0) {
  179. for (let k = 0; k < _systems.length; k++) {
  180. if (_systems[k].menuId == _currentSelectedTabFromLocal.menuId) {
  181. set_currentActivedBlockIndex(blockIndex);
  182. set_pageTitle(_panelData[blockIndex].child[channelIndex].name); //设置体系标题
  183. break one;
  184. }
  185. }
  186. }
  187. }
  188. }
  189. }
  190. }
  191. if (_panelData && _panelData.length > 0 && _panelData[blockIndex].child) {
  192. setSystemTabs(_panelData[blockIndex].child[channelIndex].child); //恢复体系列表
  193. setCurrentSelectedTab(_currentSelectedTabFromLocal);
  194. localStorage.setItem('currentSelectedTab', JSON.stringify(_currentSelectedTabFromLocal));
  195. setInitialState((s) => ({ ...s, currentSelectedSys: _currentSelectedTabFromLocal }) as any);
  196. }
  197. // console.log({_currentSelectedTabFromLocal,location});
  198. const {pathname} = location;
  199. if(pathname.indexOf(_currentSelectedTabFromLocal.path) == -1){
  200. history.push(_currentSelectedTabFromLocal.path);
  201. }
  202. //_systemTabClickHandle(_currentSelectedTabFromLocal); //恢复选中的tab
  203. }
  204. }
  205. const [hideTimer, setHideTimer] = useState<null | any>(null);
  206. const handleTabMoreMouseLeave = () => {
  207. // 设置一个延时器,在一段时间后隐藏morePannel
  208. const timer = setTimeout(() => {
  209. set_showMoreTabPannel(false);
  210. }, 300); // 例如延迟300毫秒
  211. setHideTimer(timer);
  212. };
  213. const handleMorePannelMouseEnter = () => {
  214. // 清除延时器,防止morePannel隐藏
  215. if (hideTimer) {
  216. clearTimeout(hideTimer);
  217. setHideTimer(null);
  218. }
  219. };
  220. const handleMorePannelMouseLeave = () => {
  221. set_showMoreTabPannel(false);
  222. };
  223. const updateToken = async () => {
  224. const account = (localStorage.getItem('account')) as string;
  225. const hospSign = localStorage.getItem('hospSign');
  226. const data = {
  227. account,
  228. password:password,
  229. hospSign
  230. }
  231. const resp = await updateTokenReq(data);
  232. if(resp){
  233. set_password(undefined);
  234. set_tokenUpdateModalVisible(false);
  235. }
  236. }
  237. useEffect(() => {
  238. if (currentSelectedTabFromLocal) {
  239. reSetNav(navData, currentSelectedTabFromLocal);
  240. }
  241. set_panelData(navData);
  242. }, [navData])
  243. useEffect(() => {
  244. if (currentTab) reSetNav(panelData, currentTab);
  245. }, [currentTab]);
  246. useEffect(()=>{
  247. set_pageTitle(topBarTitle);
  248. },[topBarTitle])
  249. useEffect(() => {
  250. if (systemTabs.length > 5) {
  251. //set_onTabSystemTabs(tabs);
  252. let _onTabSystemTabs: any[] = [];
  253. let _set_onTabSystemTabs_hide: any[] = [];
  254. systemTabs.forEach((a, index) => {
  255. if (index <= 4) {
  256. _onTabSystemTabs.push(a);
  257. } else {
  258. if (a.systemId == currentSelectedTabFromLocal.systemId) {
  259. const _temp = _onTabSystemTabs[_onTabSystemTabs.length - 1];
  260. _onTabSystemTabs.pop();
  261. _onTabSystemTabs.push(a);
  262. _set_onTabSystemTabs_hide.push(_temp);
  263. } else {
  264. _set_onTabSystemTabs_hide.push(a);
  265. }
  266. }
  267. });
  268. set_onTabSystemTabs(_onTabSystemTabs);
  269. set_onTabSystemTabs_hide(_set_onTabSystemTabs_hide);
  270. } else {
  271. set_onTabSystemTabs(systemTabs);
  272. }
  273. }, [systemTabs]);
  274. useEffect(() => {
  275. //_systemTabClickHandle(currentSelectedTabFromLocal); //恢复选中的tab
  276. document.body.addEventListener('click', (e: any) => {
  277. const classes = ['panel', 'typeBlockName', 'left', 'typeBlockIcon', 'typeBlock', 'typeBlock active', 'active', 'right', 'row', 'rowDetai', 'channelName', 'channelList', 'systemTab', 'channelIcon', 'rowDetail','typeBlockIcon typeBlockIcon1','typeBlockIcon typeBlockIcon2','typeBlockIcon typeBlockIcon3','typeBlockIcon typeBlockIcon4','typeBlockIcon typeBlockIcon5','typeBlockIcon typeBlockIcon6','typeBlockIcon typeBlockIcon7','typeBlockIcon typeBlockIcon8','typeBlockIcon typeBlockIcon9'];
  278. if (e.target) {
  279. let key = e.target.className?e.target.className:'';
  280. if (classes.includes(key)||(typeof key == 'string'&&key.indexOf('typeBlockIcon') != -1)) {
  281. return
  282. }
  283. }
  284. setIfOpenPannel(false);
  285. });
  286. // 事件监听器的函数定义
  287. const handleStorageChange = (e:any) => {
  288. if (e.key === 'tokenExpired') {
  289. set_tokenUpdateModalVisible(true);
  290. }
  291. };
  292. // 添加事件监听器
  293. window.addEventListener('removeLocalItemEvent', handleStorageChange);
  294. // 返回的函数用于在组件卸载时移除事件监听器
  295. return () => {
  296. window.removeEventListener('removeLocalItemEvent', handleStorageChange);
  297. };
  298. }, []);
  299. return (
  300. <div className='topBar' onClick={e => e.stopPropagation()}>
  301. <Modal className='TokenUpdateModal' open={tokenUpdateModalVisible} width={400} title={false} footer={false} closable={false} >
  302. <div className='content'>
  303. <div className='title'>登录超时锁定</div>
  304. <div className='form'>
  305. <div className='avatar'>
  306. <img className='avatarImg' src={require('../../../public/images/initAvatar.png')} alt="" />
  307. <img className='suoding' src={require('../../../public/images/suoding.png')} alt="" />
  308. </div>
  309. <div className='name'>{userData?.name}</div>
  310. <Input.Password onChange={(e)=>set_password(e.target.value)} value={password} className='input' autoComplete='off' />
  311. <div className='updateBtn' onClick={()=>updateToken()}>解锁</div>
  312. <a onClick={()=>logoutHandle()}>退出登录</a>
  313. </div>
  314. </div>
  315. </Modal>
  316. <div className='logoWrap'>
  317. {logo&&<img className='logo' src={logo} onClick={() => goToHome()} />}
  318. <Divider type="vertical" style={{ background: 'white', height: 16, opacity: 0.29, position: 'relative', top: 1, marginLeft: 16, marginRight: 8 }} />
  319. <div className={ifOpenPannel ? 'menu active' : 'menu'} onClick={() => openNav()}>
  320. <img src={require('../../../public/images/menu.png')} alt="" />
  321. </div>
  322. <span className='systemTitle' onClick={() => goSystemIndex(pageTitle)}>{pageTitle}</span>
  323. </div>
  324. <div className='userRelaInfoWrap'>
  325. <>
  326. {/**
  327. * 已打开的tab
  328. */}
  329. <div className='tabWrap'>
  330. {onTabSystemTabs && (onTabSystemTabs).map((item, index) => (
  331. <div key={index} className={currentSelectedTab?.menuId == item.menuId ? `tab on` : `tab`} onClick={() => _systemTabClickHandle(item)}>
  332. <div className='tabText'>{item.name} </div>
  333. <div className='closeIconWrap'>
  334. <img src={tabCloseIcon} onClick={(e) => closeTabHandle(item, e)} />
  335. </div>
  336. </div>
  337. ))}
  338. </div>
  339. {systemTabs.length > 5 && <div className={showMoreTabPannel ? 'tabMore active' : 'tabMore'} onMouseEnter={() => set_showMoreTabPannel(true)} onMouseLeave={handleTabMoreMouseLeave} >
  340. {showMoreTabPannel && (<div className='morePannel'
  341. onMouseEnter={handleMorePannelMouseEnter}
  342. onMouseLeave={handleMorePannelMouseLeave}
  343. >
  344. {
  345. onTabSystemTabs_hide.map((item, index) => {
  346. return (<div key={index} className='moreItem' onClick={() => moreItemClickHandle(item)}>
  347. {/* <Tooltip placement="right" title={item.name}> */}
  348. <span>{item.name}</span>
  349. {/* </Tooltip> */}
  350. </div>)
  351. })
  352. }
  353. </div>)}
  354. </div>}
  355. </>
  356. <div className='notification'>
  357. <img className='notificationIcon' src={require('../../../public/images/notificationIcon.png')} />
  358. </div>
  359. <Tooltip className='topBarTooltip' placement='bottomRight' title={<UserPannel />} color="#fff" onOpenChange={(visible) => setArrowRotate(visible)}>
  360. <div className='user'>
  361. <div className='avator'><img src={userData?.avatarUrl?userData.avatarUrl:require('../../../public/images/avatar.png')} /></div>
  362. <div className='info'>
  363. <span className='hospName'>{localStorage.getItem('hospAbbreviation')}</span>
  364. <span className='name'>{userData?.name}</span>
  365. </div>
  366. {/* <img className={arrowRotate ? `arrow on` : `arrow`} src={require('../../../public/images/arrow_white.png')} /> */}
  367. </div>
  368. </Tooltip>
  369. </div>
  370. {
  371. ifOpenPannel && (
  372. <div className='panel' onClick={e => e.stopPropagation()}>
  373. <div className='left'>
  374. {
  375. panelData.map((item, index) => {
  376. return (
  377. <div className={currentActivedBlockIndex == index ? `typeBlock active` : `typeBlock`} key={index} onClick={() => set_currentActivedBlockIndex(index)}>
  378. {/* <img className='typeBlockIcon' src={item?.icon} alt="" /> */}
  379. <div className={` typeBlockIcon typeBlockIcon${item.icon}`} ></div>
  380. <span className='typeBlockName'>{item.name}</span>
  381. </div>
  382. )
  383. })
  384. }
  385. </div>
  386. <div className='right'>
  387. <div className='panelCloseBtn' onClick={() => setIfOpenPannel(false)} ></div>
  388. {
  389. panelData.length > 0 && panelData[currentActivedBlockIndex] && panelData[currentActivedBlockIndex].child && panelData[currentActivedBlockIndex].child.map((item, index: number) => {
  390. return (
  391. <div className='row' key={index}>
  392. <img className='channelIcon' src={item.icon?item.icon:require(`../../../public/images/tongyong_tixi.png`)} alt="" />
  393. <div className='rowDetail'>
  394. <div className='channelName' onClick={() => goChannelIndex(item)}>{item.name}</div>
  395. <div className='channelList'>
  396. {
  397. item.child && item.child.length > 0 && item.child.map((val, i: number) => {
  398. return (
  399. <div className={currentSelectedTab?.menuId == val.menuId ? 'systemTab on' : 'systemTab'} key={i} onClick={() => _systemListClickHandle(val, currentActivedBlockIndex, index, i)}>{val.name}</div>
  400. )
  401. })
  402. }
  403. </div>
  404. </div>
  405. </div>
  406. )
  407. })
  408. }
  409. </div>
  410. </div>
  411. )
  412. }
  413. </div>
  414. );
  415. };
  416. export default TopBar;