qt-public-ui
Version:
新设计规范下业务组件库
342 lines (332 loc) • 15.1 kB
JavaScript
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;