@ovine/core
Version:
Build flexible admin system with json.
254 lines (253 loc) • 10.1 kB
JavaScript
/**
* 路由相关工具函数
* TODO: 添加 unit test
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { cloneDeep, get, isFunction, isPlainObject } from 'lodash';
import { app } from "../app";
import { defLoadPageSchema, rootRoute } from "../constants";
import logger from "../utils/logger";
import { isSubStr, retryPromise, loadScriptAsync, deserialize } from "../utils/tool";
const log = logger.getLogger('lib:routes:exports');
const requestComponent = 'request://pathToComponent';
// 计算 路由 path
export function getRoutePath(path, origin = false) {
const routePrefix = app.constants.routePrefix || rootRoute;
const currPthStr = currPath(path);
const pathStr = `${rootRoute}${currPthStr}`;
const withBaseUrl = isSubStr(pathStr, routePrefix, 0);
let routePath = `${withBaseUrl ? rootRoute : routePrefix}${currPthStr}`;
if (origin) {
routePath = pathStr.replace(new RegExp(`^${routePrefix}`), rootRoute);
}
return routePath;
}
export function getCurrRoutePath() {
return getRoutePath(window.location.pathname, true);
}
// 判断是否是本地文件地址
function isLocalFile(url) {
return !(url.indexOf('://') > -1 || url.startsWith('//'));
}
// 获取 pages 内组件文件在项目内本地的相对路径 或者 远程服务器路径,
export function getPageFilePath(option) {
const { pathToComponent, nodePath = '', path = '' } = option;
// pathToComponent 为 reqOpt 时, 直接返回 一个 固定标示字符串
if (isPlainObject(pathToComponent) && get(pathToComponent, 'url')) {
return requestComponent;
}
const url = typeof pathToComponent === 'string' // 任意路径
? pathToComponent
: pathToComponent === true // pathToComponent 默认 使用 nodePath 如果设置为 true,表示 使用 path 路径
? path || nodePath
: nodePath || path;
// 本地文件路径
if (isLocalFile(url)) {
return currPath(url);
}
// 当前域名服务器下路径
if (url.startsWith('root://')) {
return window.location.origin + url.substring(6);
}
// 远程服务器下 路径
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
// 宽泛协议
if (url.startsWith('//')) {
return window.location.protocol + url;
}
return '';
}
// 获取 页面预设值。默认为 pages/xxx/preset.ts 该文件是权限设置必须文件
export function getPagePreset(option) {
var _a;
const filePath = getPageFilePath(option);
if (((_a = app.asyncPage) === null || _a === void 0 ? void 0 : _a.preset) && option.nodePath && app.asyncPage.preset[option.nodePath]) {
return cloneDeep(app.asyncPage.preset[option.nodePath]);
}
// 加载本地文件
if (isLocalFile(filePath)) {
try {
/* webpackInclude: /pages[\\/].*[\\/]preset\.[t|j]sx?$/ */
const pagePest = require(`~/pages/${filePath}/preset`).default;
return isFunction(pagePest) ? pagePest(option) : pagePest;
}
catch (e) {
//
}
}
return undefined;
}
// 获取 mock。默认为 pages/xxx/mock.ts 存在该文件,将自动注入mock到prest每一个 api
export function getPageMockSource(option) {
var _a;
if (!app.env.isMock) {
return undefined;
}
if (((_a = app.asyncPage) === null || _a === void 0 ? void 0 : _a.mock) && option.nodePath && app.asyncPage.mock[option.nodePath]) {
return cloneDeep(app.asyncPage.mock[option.nodePath]);
}
const filePath = getPageFilePath(option);
// 加载本地文件
if (isLocalFile(filePath)) {
try {
/* webpackInclude: /pages[\\/].*[\\/]mock\.[t|j]sx?$/ */
const pagePest = require(`~/pages/${filePath}/mock`);
return pagePest.default;
}
catch (e) {
//
}
}
return undefined;
}
// 异步获取页面文件
export function getPageFileAsync(option) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const filePath = getPageFilePath(option);
// TODO: 支持传入 页面出错 自定义 schema,并将注入参数
const pageAlias = option.nodePath;
// 加载本地文件
if (isLocalFile(filePath)) {
return retryPromise(() => import(
/* webpackInclude: /[\\/]src[\\/]pages[\\/].*[\\/]index\.[t|j]sx?$/ */
/* webpackChunkName: "p_[request]" */
`~/pages/${filePath}/index`));
}
if (!pageAlias) {
return defLoadPageSchema;
}
if (((_a = app.asyncPage) === null || _a === void 0 ? void 0 : _a.schema) && app.asyncPage.schema[pageAlias]) {
return cloneDeep(app.asyncPage.schema[pageAlias]);
}
// 动态渲染页面
return retryPromise(() => {
var _a;
app.asyncPage.schema = ((_a = app.asyncPage) === null || _a === void 0 ? void 0 : _a.schema) || {};
// 异步加载脚本,规范 window.ovine.addPageSchemaJs(option.nodePath, {default?,schema})
if (/\.js/.test(filePath)) {
return loadScriptAsync(filePath)
.then(() => {
if (!app.asyncPage.schema[pageAlias]) {
log.error(`Please add page schema for "${pageAlias}" by using 'window.ovine.addPageSchemaJs()'.`);
return defLoadPageSchema;
}
return cloneDeep(app.asyncPage.schema[pageAlias]);
})
.catch((err) => {
log.error('An error occurred by load js scripts.', err);
return defLoadPageSchema;
});
}
// 接口获取 schema, 不缓存页面
return app
.request(filePath === requestComponent
? option.pathToComponent
: {
method: 'GET',
url: filePath,
})
.then(({ data }) => {
const { schema: resSchema } = (data === null || data === void 0 ? void 0 : data.data) || {};
const schema = isPlainObject(resSchema) ? resSchema : deserialize(resSchema || '');
if (!schema) {
log.error(`Please add page schema string for "${pageAlias}" by http server api.`);
return defLoadPageSchema;
}
const pageSchema = { schema };
return pageSchema;
})
.catch((err) => {
log.error('An error occurred when fetch page schema.', err);
return defLoadPageSchema;
});
});
});
}
// 获取 nodePath
export function getNodePath(option) {
return option.nodePath || getPageFilePath(option);
}
// 当前路径,去除多余前缀/,保持一致性 /login ==> login
export function currPath(path, defaultPath = '') {
if (!path || path === rootRoute) {
return defaultPath;
}
return !isSubStr(path, rootRoute, 0) ? path : path.substring(1);
}
// amis 官方 格式化项目内 链接
export const normalizeLink = (option) => {
const { location: loc = window.location, to: toLink } = option;
const location = Object.assign({ pathname: rootRoute, search: '', hash: '' }, loc);
let to = toLink || '';
if (to && to[0] === '#') {
to = location.pathname + location.search + to;
}
else if (to && to[0] === '?') {
to = location.pathname + to;
}
const searchIdx = to.indexOf('?');
const hashIdx = to.indexOf('#');
const isSearch = searchIdx > -1;
const isHash = hashIdx > -1;
let pathname = isSearch ? to.substring(0, searchIdx) : isHash ? to.substring(0, hashIdx) : to;
const search = isSearch ? to.substring(searchIdx, isHash ? hashIdx : undefined) : '';
const hash = isHash ? to.substring(hashIdx) : location.hash;
if (!pathname) {
pathname = location.pathname;
}
else if (pathname[0] !== rootRoute && !/^https?:\/\//.test(pathname)) {
const relativeBase = location.pathname;
const paths = relativeBase.split(rootRoute);
paths.pop();
let m = /^\.\.?\//.exec(pathname);
while (m) {
if (m[0] === '../') {
paths.pop();
}
pathname = pathname.substring(m[0].length);
m = /^\.\.?\//.exec(pathname);
}
pathname = paths.concat(pathname).join(rootRoute);
}
return {
href: pathname + search + hash,
pathname,
search,
hash,
};
};
export function jumpTo(link, option = {}) {
const { href } = normalizeLink({ to: link });
const { blank, replace, origin = true } = option;
if (/^https?:\/\//.test(href)) {
if (blank) {
window.open(href, '_blank');
}
else if (replace) {
window.location.replace(href);
}
else {
window.location.href = href;
}
return;
}
if (blank) {
window.open(`${window.location.origin}${href}`, '_blank');
}
else {
const method = replace ? 'replace' : 'push';
// TODO: 确定是否有不需要替换 url 的场景
app.routerHistory[method](getRoutePath(href, origin));
}
}