@ifed/umi-preset
Version:
@ifed/umi-preset
282 lines (235 loc) • 7.96 kB
JavaScript
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"]);
};