UNPKG

qt-public-ui

Version:

新设计规范下业务组件库

342 lines (332 loc) 15.1 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator"; import _regeneratorRuntime from "@babel/runtime/regenerator"; import React, { useEffect, useState, useImperativeHandle } from 'react'; import { useHistory, matchPath } from 'react-router-dom'; import Layout from '../Layout'; import { useUpdateEffect } from 'qt-public-hooks'; import { cloneDeep, findIndex, isUndefined, get } from 'lodash'; import Header from './component/header'; import Side from './component/side'; import Access from './component/access'; // interface MenuConfigItemTypes { // hideNav?: boolean; // hideSelect?: boolean; // hideSide?: boolean; // } var menuData = []; // 所有菜单项的原始信息 var accessUrlMap = {}; // 为了方便找到没个菜单项对应的权限信息,设置了权限对应关系 var AnalyzeFrame = React.forwardRef(function (props, frameRef) { var _props$menuConfig2, _props$menuConfig3, _menuConfig$activeNav, _props$appSelectProps, _props$appSelectProps2, _menuConfig$activeNav2, _menuConfig$activeNav3, _menuConfig$activeNav4, _menuConfig$activeNav5; var _props$menuConfig = props.menuConfig, menuConfig = _props$menuConfig === void 0 ? {} : _props$menuConfig, _props$appId = props.appId, appId = _props$appId === void 0 ? '' : _props$appId, sideConfig = props.sideConfig, _props$navConfig = props.navConfig, navConfig = _props$navConfig === void 0 ? {} : _props$navConfig, allAccessible = props.allAccessible; var _menuConfig$hideNav = menuConfig.hideNav, hideNav = _menuConfig$hideNav === void 0 ? false : _menuConfig$hideNav; var _navConfig$navActiveP = navConfig.navActivePatten, navActivePatten = _navConfig$navActiveP === void 0 ? {} : _navConfig$navActiveP; var _useState = useState([]), navOptions = _useState[0], setNavOptions = _useState[1]; // 顶部导航列表 var _useState2 = useState(''), activeNav = _useState2[0], setActiveNav = _useState2[1]; // 顶部高亮导航 var _useState3 = useState([]), sideOptions = _useState3[0], setSideOptions = _useState3[1]; // 左侧导航列表 var _useState4 = useState({}), matchAccess = _useState4[0], setMatchAccess = _useState4[1]; // 匹配上菜单项的权限信息 var _useState5 = useState((_props$menuConfig2 = props.menuConfig) === null || _props$menuConfig2 === void 0 ? void 0 : _props$menuConfig2.hideSide), _useState5$ = _useState5[0], hideSide = _useState5$ === void 0 ? false : _useState5$, setSideStatus = _useState5[1]; var _useState6 = useState((_props$menuConfig3 = props.menuConfig) === null || _props$menuConfig3 === void 0 ? void 0 : _props$menuConfig3.hideSelect), _useState6$ = _useState6[0], hideSelect = _useState6$ === void 0 ? false : _useState6$, setSelectStatus = _useState6[1]; var _useState7 = useState(false), noLeft = _useState7[0], setNoLeft = _useState7[1]; var _useState8 = useState(true), isFetching = _useState8[0], setFetching = _useState8[1]; var history = useHistory(); /** * 找到高亮顶导对应的左侧导航列表 * @param {string} chooseNav 高亮的顶导 * @param {boolean} needReplace 在点击顶部导航的是否需要跳转到到第一个有权限的菜单项 * @return {[MenuItemTypes]} */ var getSideOptions = function getSideOptions(chooseNav) { var _sideList$0$children; var sideList = menuData.filter(function (item) { return item.name === chooseNav; }); if (sideList.length && (_sideList$0$children = sideList[0].children) !== null && _sideList$0$children !== void 0 && _sideList$0$children.length) { setSideOptions(sideList[0].children); } else { setSideOptions([]); } return sideList; }; // 格式化menu,并且每个顶导下补充首次展示的url信息 var formatMenu = function formatMenu() { var isMathed = false; var matchNavPatten = false; var deepFormat = function deepFormat(options, nav) { options.forEach(function (option) { var _option$url; option.title = option.name; option.link = ((_option$url = option.url) === null || _option$url === void 0 ? void 0 : _option$url.replace('${appId}', appId)) || ''; option.disabled = !option.available; if (option.children) { deepFormat(option.children, nav); } else { option.children = []; accessUrlMap[option.link] = option; // accessUrlMap 记录下每个url对应的权限项 if ((location.pathname.indexOf(option.link) === 0 || option.pattern && location.pathname.match(option.pattern)) && !isMathed) { setMatchAccess(option); isMathed = true; } // 找到第一个有权限项的菜单项,若都没有权限,显示第一个菜单 if (!nav.activeMenu) { nav.activeMenu = option; } else if (!nav.activeMenu.accessible && option.accessible) { nav.activeMenu = option; } } }); }; menuData.forEach(function (nav) { var _navActivePatten$nav$, _navActivePatten$nav$2, _nav$children; var realUrl = nav.url.replace('${appId}', appId); var pattern = navActivePatten[nav.name]; nav.title = nav.name; nav.link = realUrl; nav.pattern = nav.pattern || pattern; if ((_navActivePatten$nav$ = navActivePatten[nav.name]) !== null && _navActivePatten$nav$ !== void 0 && (_navActivePatten$nav$2 = _navActivePatten$nav$.test) !== null && _navActivePatten$nav$2 !== void 0 && _navActivePatten$nav$2.call(_navActivePatten$nav$, location.pathname)) { matchNavPatten = true; } ((_nav$children = nav.children) === null || _nav$children === void 0 ? void 0 : _nav$children.length) && deepFormat(nav.children, nav); }); if (!isMathed && !matchNavPatten && location.pathname.match(/^\/platform\/.{14, 24}\//)) { setMatchAccess({ noAccess: true }); } return isMathed; }; var updateMenuList = function updateMenuList() { var _sideList$, _sideList$$activeMenu; var hasMathedMenu = formatMenu(); var sideList = []; var navList = menuData.reduce(function (nv, item) { var _pattern$test; var link = item.link, title = item.title, pattern = item.pattern, isNew = item.isNew; var isMatch = pattern ? (_pattern$test = pattern.test) === null || _pattern$test === void 0 ? void 0 : _pattern$test.call(pattern, location.pathname) : matchPath(location.pathname, { path: link }); if (isMatch) { // setActiveNav(item.name); onNavChange(item.name); sideList = getSideOptions(item.name); } nv.push({ isNew: isNew, title: title, link: link, pattern: pattern }); return nv; }, []); navList = (navConfig === null || navConfig === void 0 ? void 0 : navConfig.getRenderNavOption) && navConfig.getRenderNavOption(navList) || navList; setNavOptions(navList); var _ref = props.checkJumpFirst && props.checkJumpFirst(sideOptions, hasMathedMenu) || {}, _ref$needReplace = _ref.needReplace, needReplace = _ref$needReplace === void 0 ? false : _ref$needReplace, _ref$replaceUrl = _ref.replaceUrl, replaceUrl = _ref$replaceUrl === void 0 ? (_sideList$ = sideList[0]) === null || _sideList$ === void 0 ? void 0 : (_sideList$$activeMenu = _sideList$.activeMenu) === null || _sideList$$activeMenu === void 0 ? void 0 : _sideList$$activeMenu.link : _ref$replaceUrl; needReplace && replaceUrl && history.replace(replaceUrl); }; // app发生变化时,重新获取菜单信息,设置顶导和侧导 var fetchMenuList = /*#__PURE__*/function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var res; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: setFetching(true); _context.next = 3; return props.fetchMenuList(); case 3: res = _context.sent; menuData = cloneDeep(res.data); accessUrlMap = {}; setFetching(false); updateMenuList(); case 8: case "end": return _context.stop(); } }, _callee); })); return function fetchMenuList() { return _ref2.apply(this, arguments); }; }(); useImperativeHandle(frameRef, function () { return { forceUpdate: fetchMenuList }; }); // 首次进入的时候,找到所有导航中第一个有权限访问的链接 var getFirstActiveUrl = function getFirstActiveUrl(searchMenu) { if (searchMenu.length) { var _sideList$2; var index = findIndex(searchMenu, function (item) { var _item$activeMenu; return item === null || item === void 0 ? void 0 : (_item$activeMenu = item.activeMenu) === null || _item$activeMenu === void 0 ? void 0 : _item$activeMenu.accessible; }); if (index === -1) { index = 0; } setActiveNav(searchMenu[index].name); var sideList = getSideOptions(searchMenu[index].name); ((_sideList$2 = sideList[0]) === null || _sideList$2 === void 0 ? void 0 : _sideList$2.activeMenu) && history.replace(sideList[0].activeMenu.link); return searchMenu[index].activeMenu.link; } }; // appId 发生变化:选中应用发生变化 var handleAppChange = /*#__PURE__*/function () { var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var firstUrl; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: _context2.next = 2; return fetchMenuList(); case 2: // 直接输入 /platform/${appId} 将做跳转 if (appId && location.pathname === "/platform/" + appId) { firstUrl = getFirstActiveUrl(menuData); history.replace(firstUrl); } case 3: case "end": return _context2.stop(); } }, _callee2); })); return function handleAppChange() { return _ref3.apply(this, arguments); }; }(); useImperativeHandle(frameRef, function () { return { forceUpdate: handleAppChange }; }); useEffect(function () { handleAppChange(); }, [appId]); useEffect(function () { var hideSider = get(menuConfig[activeNav], 'hideSider'); setNoLeft(!isUndefined(hideSider) && hideSider); }, [activeNav]); // pathname 变化时,判断权限 useUpdateEffect(function () { Object.keys(accessUrlMap).forEach(function (item) { if (location.pathname.indexOf(item) === 0) { setMatchAccess(accessUrlMap[item]); } }); }, [location.pathname]); var onNavChange = function onNavChange(nav) { var activeNavItem = menuData.find(function (item) { return item.name === nav; }); // 需要跳转到第一个有权限的菜单项 var sideList = []; if (nav) { var _sideList$3, _sideList$3$activeMen, _props$navConfig2; sideList = getSideOptions(nav); var needReplace = activeNavItem && activeNavItem.link === location.pathname; var replaceUrl = ((_sideList$3 = sideList[0]) === null || _sideList$3 === void 0 ? void 0 : (_sideList$3$activeMen = _sideList$3.activeMenu) === null || _sideList$3$activeMen === void 0 ? void 0 : _sideList$3$activeMen.link) || ''; (replaceUrl === null || replaceUrl === void 0 ? void 0 : replaceUrl.indexOf('//')) === -1 && needReplace && replaceUrl && history.replace(replaceUrl); ((_props$navConfig2 = props.navConfig) === null || _props$navConfig2 === void 0 ? void 0 : _props$navConfig2.onNavChange) && props.navConfig.onNavChange(nav, sideList); setActiveNav(nav); } }; return /*#__PURE__*/React.createElement(LayoutContext.Provider, { value: { menuHook: { toogleSiderNav: function toogleSiderNav(status) { setSideStatus(status); }, toogleSelect: function toogleSelect(status) { setSelectStatus(status); }, toogleSider: function toogleSider(status) { setNoLeft(status); }, forceUpdate: handleAppChange } } }, /*#__PURE__*/React.createElement(Layout, { className: props.className, headerProps: props.headerProps, nav: /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', height: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { width: 0 } }, !hideSelect && !((_menuConfig$activeNav = menuConfig[activeNav]) !== null && _menuConfig$activeNav !== void 0 && _menuConfig$activeNav.hideSelect) && ((_props$appSelectProps = props.appSelectProps) === null || _props$appSelectProps === void 0 ? void 0 : _props$appSelectProps.type) === 'topSelect' && props.appSelectProps.component), /*#__PURE__*/React.createElement("div", { style: { flex: '1', marginLeft: ((_props$appSelectProps2 = props.appSelectProps) === null || _props$appSelectProps2 === void 0 ? void 0 : _props$appSelectProps2.type) === 'topSelect' ? '150px' : '0' } }, hideNav || (_menuConfig$activeNav2 = menuConfig[activeNav]) !== null && _menuConfig$activeNav2 !== void 0 && _menuConfig$activeNav2.hideNav ? /*#__PURE__*/React.createElement("div", null) : /*#__PURE__*/React.createElement(Header, { options: navOptions, onChange: onNavChange }))) }, !noLeft && /*#__PURE__*/React.createElement(Layout.Sider, null, props.appSelectProps.type === 'leftSelect' && !hideSelect && !((_menuConfig$activeNav3 = menuConfig[activeNav]) !== null && _menuConfig$activeNav3 !== void 0 && _menuConfig$activeNav3.hideSelect) && props.appSelectProps.component, !hideSide && !((_menuConfig$activeNav4 = menuConfig[activeNav]) !== null && _menuConfig$activeNav4 !== void 0 && _menuConfig$activeNav4.hideSide) && ((_menuConfig$activeNav5 = menuConfig[activeNav]) !== null && _menuConfig$activeNav5 !== void 0 && _menuConfig$activeNav5.sideRender ? menuConfig[activeNav].sideRender(activeNav, sideOptions) : /*#__PURE__*/React.createElement(Side, { options: sideOptions, appId: appId, activeNav: activeNav, sideConfig: sideConfig }))), /*#__PURE__*/React.createElement(Access, _extends({}, matchAccess, { isFetching: isFetching, allAccessible: allAccessible }), props.children))); }); export var LayoutContext = React.createContext({ menuHook: { toogleSiderNav: function toogleSiderNav() { return null; }, toogleSelect: function toogleSelect() { return null; }, toogleSider: function toogleSider() { return null; }, forceUpdate: function forceUpdate() { return null; } } }); export default AnalyzeFrame;