UNPKG

@ifed/umi-preset

Version:
282 lines (235 loc) 7.96 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/layout.ts var layout_exports = {}; __export(layout_exports, { default: () => layout_default }); module.exports = __toCommonJS(layout_exports); var import_withTmpPath = __toESM(require("./utils/withTmpPath")); var layout_default = (api) => { api.describe({ key: "layout", // 对应.umirc.ts中的配置项 config: { schema({ zod }) { return zod.record(zod.any()); } }, enableBy: api.EnableBy.config }); api.onGenerateFiles(() => { const hasInitialStatePlugin = api.config.initialState; api.writeTmpFile({ path: "Exception.tsx", content: ` import React from 'react'; import { history, type IRoute } from 'umi'; import { Result, Button } from 'antd'; const Exception: React.FC<{ children: React.ReactNode; route?: IRoute; notFound?: React.ReactNode; noAccessible?: React.ReactNode; unAccessible?: React.ReactNode; noFound?: React.ReactNode; }> = (props) => ( // render custom 404 (!props.route && (props.noFound || props.notFound)) || // render custom 403 (props.route?.unaccessible && (props.unAccessible || props.noAccessible)) || // render default exception ((!props.route || props.route?.unaccessible) && ( <Result status={props.route ? '403' : '404'} title={props.route ? '403' : '404'} subTitle={props.route ? '抱歉,你无权访问该页面' : '抱歉,你访问的页面不存在'} extra={ <Button type="primary" onClick={() => history.push('/')}> 返回首页 </Button> } /> )) || // normal render props.children ); export default Exception; ` }); api.writeTmpFile({ path: "Layout.tsx", content: ` import React from 'react'; import zhCN from 'antd/es/locale/zh_CN'; import { Outlet, history, useAppData, useLocation } from 'umi'; import { pathToRegexp } from 'path-to-regexp'; import { Result, Button } from 'antd'; import { Layout, Provider } from '@ifed/component'; import { Tree } from '@ifed/utils'; ${hasInitialStatePlugin ? `import { useModel } from '@@/plugin-model';` : "const useModel = null;"} const tree = new Tree(); function openPage({key, pathname, path, search, hash}, menuData){ const info = tree.find(menuData, (k) => k.key === key); const isIframe = /^http(s)?:\\/\\//.test(path); if(isIframe && info?.target === '_blank'){ window.open(path, '_blank').location; } else if(isIframe){ history.push('/iframe/'+ key + search + hash); }else{ history.push(path + search + hash); } } function pick(obj: object, props: []) { const result = {}; for (let prop of props) { if (obj.hasOwnProperty(prop) && obj[prop] !== undefined) { result[prop] = obj[prop]; } } return result; } // 如果是嵌套模式,给所有叶子节点设置layout:false,达到“去头”的效果 function formatMenuData(menuData, viewMode, pathname){ if(viewMode === 'inner'){ return tree.map(menuData, (node) => !tree.isBranch(node) ? ({...node, layout: false}) : node); } return menuData; } // 根据pathname判断当前页面是否存在,返回boolean // 1、普通路由 // 2、嵌套路由 如:/user/login; /iframe/2769963 function findMenu(pathname, menuData, routes){ let menu = tree.find(menuData, (node) => node.path === pathname); const arr = pathname.match(/^\\/((\\w|-)+)\\/((\\w|-)+)/); const prefix = arr?.[1]; // 1、普通路由 if(menu !== undefined){ return menu } // 2、动态路由(只支持约定的iframe动态路由) 如: /iframe/2769963 // 约定:如果是动态路由,第二级必须是对应menudata中某个菜单的key if(prefix === 'iframe'){ const key = arr?.[3]; return tree.find(menuData, (node) => node.key === key); } return undefined; // const rule = '/'+prefix+'/:id?'; // return tree.find(routes, (node) => pathToRegexp(rule).test(node.path)); } function getViewMode(pathname){ const mode = pathname?.match(/[?&]viewMode=((\\w|-)+)/)?.[0]?.slice(10); return mode === 'inner' ? 'inner' : 'normal' } export default function BasicLayout() { // const route = useRouteProps(); const { pathname, search, hash } = useLocation(); const { clientRoutes, pluginManager} = useAppData(); const initialInfo = (useModel && useModel('@@initialState')) || { initialState: undefined, loading: false, setInitialState: null, }; const { initialState, loading, setInitialState } = initialInfo; const runtimeConfig = pluginManager.applyPlugins({ key: 'layout', type: 'modify', initialValue: { ...initialInfo }, }); const userConfig = ${JSON.stringify(api.config.layout, null, 2)}; const menuData = runtimeConfig?.menuData || []; const viewMode = getViewMode(search); const routes = clientRoutes?.[0]?.routes || []; const newMenuData = formatMenuData(menuData, viewMode, pathname); const menu = findMenu(pathname, newMenuData, routes); if(menu === undefined){ return ( <Result status="404" title="404" subTitle="对不起,您访问的页面不存在。" extra={ <Button type="primary" onClick={() => history.push('/')}> 返回首页 </Button> } /> ); } if(menu?.layout === false){ return ( <Provider locale={zhCN}> <Outlet /> </Provider> ) } return ( <Provider locale={zhCN}> <Layout {...runtimeConfig} logo={runtimeConfig?.logo || userConfig?.logo || 'Logo'} title={runtimeConfig?.title || userConfig.title || 'plugin-layout'} menuData={newMenuData} activeTab={{...pick(menu, ['key','label','path']), pathname, search, hash}} routes={routes} onMenuClick={info => openPage(info, newMenuData)} onTabClick={info => openPage(info, newMenuData)} onTabDelete={info => openPage(info, newMenuData)} rightContentRender={ ((headerProps) => { if (runtimeConfig.rightContentRender) { return runtimeConfig.rightContentRender({ userConfig, runtimeConfig, loading, initialState, setInitialState, }); } return null; }) } /> </Provider> ); } ` }); }); api.addLayouts(() => { return [ { id: "layout", file: (0, import_withTmpPath.default)({ api, path: "Layout.tsx" }) } ]; }); api.addRuntimePluginKey(() => ["layout"]); };