import React, { FC, useState, useEffect, useRef, useCallback, Component } from 'react' import { useHistory, useLocation } from 'react-router-dom' import { Tabs, Alert, Dropdown, Menu } from 'antd' import Home from '@/pages/home' import { getKeyName, isAuthorized } from '@/assets/js/publicFunc' import { SyncOutlined } from '@ant-design/icons' import { connect } from 'react-redux' import * as actions from '@/store/actions' import style from './TabPanes.module.less' const { TabPane } = Tabs const initPane = [ { title: '首页', key: 'home', content: Home, closable: false, path: '/' } ] interface Props extends ReduxProps { defaultActiveKey: string; panesItem: { title: string, content: Component, key: string, closable: boolean, path: string }; tabActiveKey: string; } // 多页签组件 const TabPanes: FC = (props) => { const [activeKey, setActiveKey] = useState('') const [panes, setPanes] = useState(initPane) const [isReload, setIsReload] = useState(false) const [selectedPanel, setSelectedPanel] = useState({}) const pathRef: RefType = useRef('') const { storeData: { curTab, reloadPath }, setStoreData, defaultActiveKey, panesItem, tabActiveKey } = props const history = useHistory() const { pathname, search } = useLocation() const fullPath = pathname + search // 记录当前打开的tab const storeTabs = useCallback( (ps): void => { const pathArr = ps.reduce( (prev: CommonObjectType[], next: CommonObjectType) => [ ...prev, next.path ], [] ) setStoreData('SET_CURTAB', pathArr) }, [setStoreData] ) // 从本地存储中恢复已打开的tab列表 const resetTabs = useCallback((): void => { const initPanes = curTab.reduce( (prev: CommonObjectType[], next: string) => { const { title, tabKey, component: Content } = getKeyName(next) return [ ...prev, { title, key: tabKey, content: Content, closable: tabKey !== 'home', path: next } ] }, [] ) const { tabKey } = getKeyName(pathname) setPanes(initPanes) setActiveKey(tabKey) }, [curTab, pathname]) // 初始化页面 useEffect(() => { resetTabs() }, [resetTabs]) // tab切换 const onChange = (tabKey: string): void => { setActiveKey(tabKey) } // 移除tab const remove = (targetKey: string): void => { const delIndex = panes.findIndex( (item: CommonObjectType) => item.key === targetKey ) panes.splice(delIndex, 1) // 删除非当前tab if (targetKey !== activeKey) { const nextKey = activeKey setPanes(panes) setActiveKey(nextKey) storeTabs(panes) return } // 删除当前tab,地址往前推 const nextPath = curTab[delIndex - 1] const { tabKey } = getKeyName(nextPath) // 如果当前tab关闭后,上一个tab无权限,就一起关掉 if (!isAuthorized(tabKey) && nextPath !== '/') { remove(tabKey) history.push(curTab[delIndex - 2]) } else { history.push(nextPath) } setPanes(panes) storeTabs(panes) } // tab新增删除操作 const onEdit = (targetKey: string | any, action: string) => action === 'remove' && remove(targetKey) // tab点击 const onTabClick = (targetKey: string): void => { const { path } = panes.filter( (item: CommonObjectType) => item.key === targetKey )[0] history.push({ pathname: path }) } // 刷新当前 tab const refreshTab = (): void => { setIsReload(true) setTimeout(() => { setIsReload(false) }, 1000) setStoreData('SET_RELOADPATH', pathname + search) setTimeout(() => { setStoreData('SET_RELOADPATH', 'null') }, 500) } // 关闭其他或关闭所有 const removeAll = async (isCloseAll?: boolean) => { const { path, key } = selectedPanel history.push(isCloseAll ? '/' : path) const homePanel = [ { title: '首页', key: 'home', content: Home, closable: false, path: '/' } ] const nowPanes = key !== 'home' && !isCloseAll ? [...homePanel, selectedPanel] : homePanel setPanes(nowPanes) setActiveKey(isCloseAll ? 'home' : key) storeTabs(nowPanes) } useEffect(() => { const newPath = pathname + search // 当前的路由和上一次的一样,return if (!panesItem.path || panesItem.path === pathRef.current) return // 保存这次的路由地址 pathRef.current = newPath const index = panes.findIndex( (_: CommonObjectType) => _.key === panesItem.key ) // 无效的新tab,return if (!panesItem.key || (index > -1 && newPath === panes[index].path)) { setActiveKey(tabActiveKey) return } // 新tab已存在,重新覆盖掉(解决带参数地址数据错乱问题) if (index > -1) { panes[index].path = newPath setPanes(panes) setActiveKey(tabActiveKey) return } // 添加新tab并保存起来 panes.push(panesItem) setPanes(panes) setActiveKey(tabActiveKey) storeTabs(panes) }, [panes, panesItem, pathname, resetTabs, search, storeTabs, tabActiveKey]) const isDisabled = () => selectedPanel.key === 'home' // tab右击菜单 const menu = ( refreshTab()} disabled={selectedPanel.path !== fullPath} > 刷新 { e.domEvent.stopPropagation() remove(selectedPanel.key) }} disabled={isDisabled()} > 关闭 { e.domEvent.stopPropagation() removeAll() }} > 关闭其他 { e.domEvent.stopPropagation() removeAll(true) }} disabled={isDisabled()} > 全部关闭 ) // 阻止右键默认事件 const preventDefault = (e: CommonObjectType, panel: object) => { e.preventDefault() setSelectedPanel(panel) } return (
{panes.map((pane: CommonObjectType) => ( preventDefault(e, pane)}> {isReload && pane.path === fullPath && pane.path !== '/403' && ( )} {pane.title} } > {reloadPath !== pane.path ? ( ) : (
)}
))}
) } export default connect( (state) => state, actions )(TabPanes)