179 lines
4.6 KiB
TypeScript
179 lines
4.6 KiB
TypeScript
import Mock from "mockjs";
|
||
|
||
/** 返回成功数据 */
|
||
export const resultSuccess = (data: unknown) => {
|
||
return Mock.mock({
|
||
code: 200,
|
||
data,
|
||
message: "请求成功",
|
||
success: true
|
||
});
|
||
};
|
||
|
||
/** 返回失败数据 */
|
||
export const resultError = (data: unknown, message: string, code = 500) => {
|
||
return Mock.mock({
|
||
code,
|
||
data,
|
||
message,
|
||
success: false
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 路由树递归排序
|
||
* 1、先给当前层排序
|
||
* 2、若当前层有children则递归排序
|
||
* @param {array} tree 根据角色权限过滤后的路由树
|
||
* @returns 返回排序之后的树
|
||
*/
|
||
export const treeSort = (tree: Menu.MenuOptions[]) => {
|
||
if (!tree || tree.length == 0) return [];
|
||
tree.sort((a: Menu.MenuOptions, b: Menu.MenuOptions) => {
|
||
// a和b都是undefined则相等
|
||
if (a.meta.sort != 0 && !a.meta.sort && b.meta.sort != 0 && !b.meta.sort) {
|
||
return 0;
|
||
}
|
||
// a是undefined则a被排在b之后
|
||
if (a.meta.sort != 0 && !a.meta.sort) return 1;
|
||
// b是undefined则b被排在a之后
|
||
if (b.meta.sort != 0 && !b.meta.sort) return -1;
|
||
return a.meta.sort - b.meta.sort;
|
||
});
|
||
|
||
// 深层递归
|
||
return tree.map((item: any) => {
|
||
if (item?.children?.length > 0) {
|
||
item.children = treeSort(item.children);
|
||
}
|
||
return item;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 过滤路由树,返回有权限的树
|
||
* 1、根据角色权限过滤原始路由树
|
||
* 2、过滤禁用的菜单,该菜单是不可访问的,直接去掉
|
||
* @param {array} tree 根据角色权限过滤原始路由树
|
||
* @returns 返回有权限的树
|
||
*/
|
||
export const filterByRole = (tree: any, userRoles: Array<string>) => {
|
||
return tree.filter((item: any) => {
|
||
// 过滤角色权限
|
||
if (item?.meta?.roles) {
|
||
if (!roleBase(item.meta.roles, userRoles)) return false;
|
||
}
|
||
// 过滤是否禁用
|
||
if (item?.meta?.disable) return false;
|
||
return true;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 校验该角色是否有路由权限
|
||
* @param {array} roles 路由的角色权限
|
||
* @returns 是否有权限 true是 false否
|
||
*/
|
||
export const roleBase = (roles: Array<string>, userRoles: Array<string>) => {
|
||
return userRoles.some((item: string) => roles.includes(item));
|
||
};
|
||
|
||
/**
|
||
* 深拷贝
|
||
* @param { string } data 需要深拷贝的数据
|
||
* @returns 深拷贝的数据
|
||
*/
|
||
export function deepClone(data: any) {
|
||
let stack = [];
|
||
let cloned;
|
||
if (Array.isArray(data)) {
|
||
cloned = [];
|
||
} else if (typeof data === "object" && data !== null) {
|
||
cloned = {};
|
||
} else {
|
||
return data;
|
||
}
|
||
stack.push({
|
||
original: data,
|
||
copy: cloned
|
||
});
|
||
while (stack.length > 0) {
|
||
let current: any = stack.pop();
|
||
let original = current.original;
|
||
let copy = current.copy;
|
||
|
||
for (let key in original) {
|
||
if (original.hasOwnProperty(key)) {
|
||
let value = original[key];
|
||
|
||
if (typeof value === "object" && value !== null) {
|
||
copy[key] = Array.isArray(value) ? [] : {};
|
||
|
||
stack.push({
|
||
original: value,
|
||
copy: copy[key]
|
||
});
|
||
} else {
|
||
copy[key] = value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return cloned;
|
||
}
|
||
|
||
/**
|
||
* 将扁平路由组装成树形结构
|
||
* @param {array} nodes 扁平数组
|
||
* @returns 树形结构
|
||
*/
|
||
export const buildTreeOptimized = (nodes: Menu.MenuOptions[]) => {
|
||
const nodeMap = new Map(); // 哈希表存储所有节点
|
||
const roots = []; // 存储顶层节点
|
||
const duplicates = new Set(); // 检测重复ID
|
||
|
||
// 第一次遍历: 注册所有节点 & 检测重复
|
||
for (const node of nodes) {
|
||
const id = node.id;
|
||
|
||
// 循环引用检测
|
||
if (node.id === node.parentId) {
|
||
throw new Error(`循环引用: ${node.id} -> ${node.parentId}`);
|
||
}
|
||
|
||
// 重复ID检测
|
||
if (nodeMap.has(id)) {
|
||
duplicates.add(id);
|
||
continue;
|
||
}
|
||
|
||
// 初始化子节点数组
|
||
node.children = [];
|
||
nodeMap.set(id, node);
|
||
}
|
||
|
||
// 输出重复警告
|
||
if (duplicates.size > 0) {
|
||
console.warn(`检测到重复ID: ${Array.from(duplicates).join(", ")}`);
|
||
}
|
||
|
||
// 第二次遍历: 构建树结构
|
||
for (const node of nodes) {
|
||
const { parentId } = node;
|
||
|
||
// 跳过已处理的重复节点
|
||
if (duplicates.has(node.id)) continue;
|
||
|
||
if (parentId === "0") {
|
||
roots.push(node); // 顶层节点
|
||
} else if (parentId) {
|
||
const parent = nodeMap.get(parentId);
|
||
parent?.children.push(node); // 挂载子节点
|
||
} else {
|
||
console.warn(`孤儿节点 ${node.id}: parentId为空`);
|
||
}
|
||
}
|
||
|
||
return roots;
|
||
};
|