UNPKG

@ovine/core

Version:

Build flexible admin system with json.

151 lines (150 loc) 6.83 kB
/** * App Aside Menu布局 * TODO: 添加 RouteTab/Aside/Header 的默认 loading 状态 * 1. 动态页面 loading 明显,可能与 table loading 状态同步。 */ import { Layout } from 'amis'; import { cloneDeep } from 'lodash'; import React, { useEffect, useMemo } from 'react'; import { app } from "../../app"; import { withAppTheme } from "../../app/theme"; import { breakpoints, message, storage } from "../../constants"; import { setRoutesConfig } from "../../routes/config"; import { getCurrRoutePath } from "../../routes/exports"; import { getAuthRoutes, getAsideMenus, clearRouteStore } from "../../routes/limit"; import { AppMenuRoutes } from "../../routes/route"; import { useImmer, useSubscriber } from "../../utils/hooks"; import logger from "../../utils/logger"; import { publish } from "../../utils/message"; import { setGlobal } from "../../utils/store"; import { Amis } from "../amis/schema"; import { filterSchemaLimit } from "../amis/schema/func"; import { useAppContext } from "../app/context"; import RouteTabs from "../route_tabs"; import Aside from "./aside"; import Header from "./header"; import { LayoutLoading, LayoutLazyFallback } from "./loading"; import { StyledLayout } from "./styled"; const log = logger.getLogger('lib:components:asideLayout'); const { asideLayoutCtrl } = message; const defaultHeader = { brand: { logo: '', title: '', }, }; // TODO: 获取APi路由时有 短暂的 404 页面,需要改成loading 状态 export default withAppTheme((props) => { const { enableRouteTabs } = useAppContext(); const { children, theme, api, debounceRoute } = props; const [state, setState] = useImmer({ asideFolded: false, offScreen: false, resetRoute: props.resetRoute, rootRoute: props.rootRoute || '/', routeTabs: props.routeTabs || {}, header: props.header || defaultHeader, footer: props.footer, routes: props.routes || [], }); const { routes, header, routeTabs, footer, asideFolded, rootRoute, resetRoute, offScreen } = state; const { ns: themeNs, name: themeName } = theme; // TODO: 使用 styled media 来检查 媒体查询 const supportTabs = routeTabs && window.innerWidth >= breakpoints.md && routeTabs.enable !== false; const withTabs = enableRouteTabs && supportTabs; const requestLayoutApi = (data) => { if (!api) { return; } const reqOpt = Object.assign(Object.assign({}, api), { data: Object.assign(Object.assign({}, api.data), data) }); app.request(reqOpt).then((source) => { const resData = (source === null || source === void 0 ? void 0 : source.data) || {}; setState((d) => { d.resetRoute = !!resData.resetRoute; if (resData.header) { d.header = resData.header || defaultHeader; } if (resData.rootRoute) { d.rootRoute = resData.rootRoute; } if (resData.routeTabs) { d.routeTabs = resData.routeTabs; } if (resData.footer) { d.footer = resData.footer; } // TODO: 校验 routes 的合法性及默认值 if (resData.routes) { d.routes = resData.routes; } }); }); }; // 过滤 layout 权限 const layoutConf = useMemo(() => { const conf = cloneDeep({ header, footer }); filterSchemaLimit(conf); return conf; }, [header, footer]); const { authRoutes, AuthRoutes, asideMenus } = useMemo(() => { clearRouteStore(); setRoutesConfig(routes); const configs = { authRoutes: getAuthRoutes(), asideMenus: getAsideMenus(), }; log.log('routeConfig', configs); return Object.assign(Object.assign({}, configs), { // renderAside: (t: string) => <Aside theme={t} asideMenus={configs.asideMenus} />, AuthRoutes: (React.createElement(AppMenuRoutes, { debounceRoute: debounceRoute, fallback: LayoutLazyFallback, authRoutes: configs.authRoutes })) }); }, [routes]); const LayoutAside = useMemo(() => { return React.createElement(Aside, { theme: themeName, asideMenus: asideMenus }); }, [themeName, routes]); useSubscriber(asideLayoutCtrl.msg, (msgData = {}) => { const { key, toggle, data } = msgData; setState((d) => { switch (key) { case asideLayoutCtrl.toggleScreen: d.offScreen = typeof toggle === 'boolean' ? toggle : !d.offScreen; break; case asideLayoutCtrl.toggleFold: d.asideFolded = typeof toggle === 'boolean' ? toggle : !d.asideFolded; break; case asideLayoutCtrl.reload: requestLayoutApi(data); break; default: } }); }); useEffect(() => { requestLayoutApi(); }, []); useEffect(() => { setGlobal(storage.supportRouteTabs, supportTabs); }, [supportTabs]); useEffect(() => { if (resetRoute) { const refreshRoot = getCurrRoutePath() !== rootRoute; // 防止首次进入页面 首页直接刷新两次 if (supportTabs) { publish(message.clearRouteTabs, { refreshRoot }); } else if (refreshRoot) { app.routerHistory.push(rootRoute); } } }, [AuthRoutes, rootRoute, resetRoute]); const headerProps = Object.assign(Object.assign(Object.assign({}, layoutConf.header), state), { setLayout: setState, withRouteTabs: withTabs }); const routeTabsProps = Object.assign(Object.assign({}, routeTabs), { rootRoute, themeNs, routes: authRoutes }); const HeaderComponent = (React.createElement(Header, Object.assign({}, headerProps, { themeNs: themeNs }), withTabs && !!routes.length && React.createElement(RouteTabs, Object.assign({}, routeTabsProps)))); // TODO: 切换 route 时,默认渲染了 404 页面,需要天添加 loading return (React.createElement(StyledLayout, { id: "app-layout", className: withTabs ? 'with-route-tabs' : '' }, React.createElement(Layout, { headerFixed: true, theme: themeName, folded: asideFolded, offScreen: offScreen, header: HeaderComponent, aside: LayoutAside, footer: layoutConf.footer && React.createElement(Amis, { schema: layoutConf.footer }) }, React.createElement("div", { className: "app-layout-body" }, React.createElement(LayoutLoading, { theme: themeName }), AuthRoutes, children)))); });