index.tsx 19 KB

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