mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-28 21:40:50 +00:00
refactor(管理端): 优化菜单路由与图片选择遍历,去除嵌套循环与冗余深克隆
This commit is contained in:
parent
288913c70c
commit
161050c4aa
@ -636,31 +636,23 @@ function showSelectData() {
|
||||
function getRowKey(row) {
|
||||
return row.att_id;
|
||||
}
|
||||
//对象数组去重;
|
||||
//对象数组去重(按 att_id):Set 单趟完成,替代 reduce 内 find+concat 的双重 O(n²)
|
||||
function unique(arr) {
|
||||
let result = arr.reduce((acc, curr) => {
|
||||
const x = acc.find((item) => item.att_id === curr.att_id);
|
||||
if (!x) {
|
||||
return acc.concat([curr]);
|
||||
} else {
|
||||
return acc;
|
||||
const seen = new Set();
|
||||
const result = [];
|
||||
for (const item of arr) {
|
||||
if (!seen.has(item.att_id)) {
|
||||
seen.add(item.att_id);
|
||||
result.push(item);
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// 选中某一行
|
||||
function handleSelectRow(selection) {
|
||||
let arr = unique(selection);
|
||||
const uniqueArr = [];
|
||||
const idsArr = [];
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const item = arr[i];
|
||||
if (!idsArr.includes(item.att_id)) {
|
||||
uniqueArr.push(item);
|
||||
idsArr.push(item.att_id);
|
||||
}
|
||||
}
|
||||
ids.value = idsArr;
|
||||
// unique 已保证 att_id 唯一,无需再做一遍 includes 去重
|
||||
const uniqueArr = unique(selection);
|
||||
ids.value = uniqueArr.map((item) => item.att_id);
|
||||
multipleSelection.value = uniqueArr;
|
||||
}
|
||||
function pageChange(index) {
|
||||
@ -727,13 +719,14 @@ function changImage(item, index, row) {
|
||||
checkPicList.value.map((item, i) => {
|
||||
ids.value.push(item.att_id);
|
||||
});
|
||||
// 已选列表先建 att_id → 序号 映射,再给整页图片编号;
|
||||
// 原实现对每个选中图片都全量扫描 checkPicList,点选一张是 整页×已选 的嵌套遍历
|
||||
const numMap = new Map(checkPicList.value.map((el, i) => [el.att_id, i + 1]));
|
||||
pictrueList.value.map((el, i) => {
|
||||
if (el.isSelect) {
|
||||
checkPicList.value.filter((el2, j) => {
|
||||
if (el.att_id == el2.att_id) {
|
||||
el.num = j + 1;
|
||||
}
|
||||
});
|
||||
if (numMap.has(el.att_id)) {
|
||||
el.num = numMap.get(el.att_id);
|
||||
}
|
||||
} else {
|
||||
el.num = 0;
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Local } from '@/utils/storage.js';
|
||||
import { R } from '@/libs/util';
|
||||
import { useMenusStore } from '@/store/module/menus';
|
||||
import { useRoutesListStore } from '@/store/module/routesList';
|
||||
import { useThemeConfigStore } from '@/store/module/themeConfig';
|
||||
@ -77,16 +76,16 @@ const breadCrumbList = computed(() => {
|
||||
});
|
||||
|
||||
const crumbPast = computed(() => {
|
||||
let menuList = menusStore.menusName;
|
||||
let allMenuList = R(menuList, []);
|
||||
let selectMenu = [];
|
||||
if (allMenuList.length > 0) {
|
||||
allMenuList.forEach((a) => {
|
||||
if (route.path === a.path) {
|
||||
selectMenu.push(a);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 只收集 path 命中的菜单节点引用:原先整树扁平化 + 逐属性深克隆后过滤,
|
||||
// 每次面包屑重算都白付整棵树的克隆成本,而模板只读 path/icon/title/redirect
|
||||
const selectMenu = [];
|
||||
const walk = (menus) => {
|
||||
for (const menu of menus) {
|
||||
if (route.path === menu.path) selectMenu.push(menu);
|
||||
if (menu.children && menu.children.length) walk(menu.children);
|
||||
}
|
||||
};
|
||||
walk(menusStore.menusName);
|
||||
return selectMenu;
|
||||
});
|
||||
|
||||
|
||||
@ -13,17 +13,13 @@
|
||||
* 因为用户权限 access 为数组,includes 方法无法直接得出结论
|
||||
* */
|
||||
function includeArray(list1, list2) {
|
||||
let status = false;
|
||||
if (list1 === true) {
|
||||
return true;
|
||||
} else {
|
||||
if (typeof list2 !== 'object') {
|
||||
return false;
|
||||
}
|
||||
list2.forEach((item) => {
|
||||
if (list1.includes(item)) status = true;
|
||||
});
|
||||
return status;
|
||||
}
|
||||
if (typeof list2 !== 'object') {
|
||||
return false;
|
||||
}
|
||||
// some 命中即短路;路由守卫每次导航都会调用
|
||||
return list2.some((item) => list1.includes(item));
|
||||
}
|
||||
export { includeArray };
|
||||
|
||||
@ -13,12 +13,11 @@ function getHeaderName(to, menuList) {
|
||||
const allMenus = [];
|
||||
menuList.forEach((menu) => {
|
||||
const headerName = menu.path || '';
|
||||
const menus = transferMenu(menu, headerName);
|
||||
allMenus.push({
|
||||
path: menu.path,
|
||||
header: headerName,
|
||||
});
|
||||
menus.forEach((item) => allMenus.push(item));
|
||||
transferMenu(menu, headerName, allMenus);
|
||||
});
|
||||
const currentMenu = allMenus.find((item) => {
|
||||
let path = to.meta && to.meta.activeMenu ? to.meta.activeMenu : to.path;
|
||||
@ -43,19 +42,19 @@ function getPath(to, path) {
|
||||
return path + (params.length ? '/' + params.join('/') : '') + (query.length ? '?' + query.join('&') : '');
|
||||
}
|
||||
|
||||
function transferMenu(menu, headerName) {
|
||||
function transferMenu(menu, headerName, out) {
|
||||
if (menu.children && menu.children.length) {
|
||||
return menu.children.reduce((all, item) => {
|
||||
all.push({
|
||||
for (const item of menu.children) {
|
||||
out.push({
|
||||
path: item.path,
|
||||
header: headerName,
|
||||
});
|
||||
const foundChildren = transferMenu(item, headerName);
|
||||
return all.concat(foundChildren);
|
||||
}, []);
|
||||
transferMenu(item, headerName, out);
|
||||
}
|
||||
} else {
|
||||
return [menu];
|
||||
out.push(menu);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export { getHeaderName };
|
||||
@ -166,8 +165,7 @@ function getAllSiderMenu(menuList) {
|
||||
|
||||
menuList.forEach((menu) => {
|
||||
if (menu.children && menu.children.length) {
|
||||
const menus = getMenuChildren(menu);
|
||||
menus.forEach((item) => allMenus.push(item));
|
||||
getMenuChildren(menu, allMenus);
|
||||
} else {
|
||||
allMenus.push(menu);
|
||||
}
|
||||
@ -176,15 +174,13 @@ function getAllSiderMenu(menuList) {
|
||||
return allMenus;
|
||||
}
|
||||
|
||||
function getMenuChildren(menu) {
|
||||
function getMenuChildren(menu, out) {
|
||||
if (menu.children && menu.children.length) {
|
||||
return menu.children.reduce((all, item) => {
|
||||
const foundChildren = getMenuChildren(item);
|
||||
return all.concat(foundChildren);
|
||||
}, []);
|
||||
menu.children.forEach((item) => getMenuChildren(item, out));
|
||||
} else {
|
||||
return [menu];
|
||||
out.push(menu);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export { getAllSiderMenu };
|
||||
@ -243,15 +239,18 @@ export const findFirstNonNullChildrenKeys = (obj, lastArr) => {
|
||||
return ids;
|
||||
};
|
||||
|
||||
// 多级嵌套数组处理成一维数组
|
||||
// 多级嵌套数组处理成一维数组(先序遍历,单趟收集,避免逐个 slice+concat 的 O(n²) 拷贝)
|
||||
export const formatFlatteningRoutes = (arr) => {
|
||||
if (arr.length <= 0) return false;
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (arr[i].children) {
|
||||
arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1));
|
||||
const flat = [];
|
||||
const walk = (list) => {
|
||||
for (const item of list) {
|
||||
flat.push(item);
|
||||
if (item.children) walk(item.children);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
walk(arr);
|
||||
return flat;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -259,17 +258,13 @@ export const formatFlatteningRoutes = (arr) => {
|
||||
* 因为用户权限 access 为数组,includes 方法无法直接得出结论
|
||||
* */
|
||||
function includeArray(list1, list2) {
|
||||
let status = false;
|
||||
if (list1 === true) {
|
||||
return true;
|
||||
} else {
|
||||
if (typeof list2 !== 'object') {
|
||||
return false;
|
||||
}
|
||||
list2.forEach((item) => {
|
||||
if (list1.includes(item)) status = true;
|
||||
});
|
||||
return status;
|
||||
}
|
||||
if (typeof list2 !== 'object') {
|
||||
return false;
|
||||
}
|
||||
// some 命中即短路;权限过滤对每个菜单节点都会调用
|
||||
return list2.some((item) => list1.includes(item));
|
||||
}
|
||||
export { includeArray };
|
||||
|
||||
@ -432,12 +432,10 @@ export const setTitle = (routeItem, vm) => {
|
||||
|
||||
export const R = (menuList, newOpenMenus) => {
|
||||
menuList.forEach((item) => {
|
||||
let newMenu = {};
|
||||
for (let i in item) {
|
||||
if (i !== 'children') newMenu[i] = cloneDeep(item[i]);
|
||||
}
|
||||
const { children, ...rest } = item;
|
||||
const newMenu = cloneDeep(rest);
|
||||
newOpenMenus.push(newMenu);
|
||||
item.children && R(item.children, newOpenMenus);
|
||||
children && R(children, newOpenMenus);
|
||||
});
|
||||
return newOpenMenus;
|
||||
};
|
||||
|
||||
@ -70,18 +70,19 @@ function findMenuTitleByPath(path, menuList) {
|
||||
*/
|
||||
function findBestMenuPath(currentPath, menuList) {
|
||||
if (!menuList || !menuList.length) return null;
|
||||
const flatPaths = [];
|
||||
// Set 查找 O(1):该函数在每次路由导航都会执行,菜单树全量收集后反复 includes 会放大整体开销
|
||||
const flatPaths = new Set();
|
||||
(function collect(list) {
|
||||
for (const item of list) {
|
||||
if (item.path) flatPaths.push(item.path);
|
||||
if (item.path) flatPaths.add(item.path);
|
||||
if (item.children && item.children.length) collect(item.children);
|
||||
}
|
||||
})(menuList);
|
||||
if (flatPaths.includes(currentPath)) return currentPath;
|
||||
if (flatPaths.has(currentPath)) return currentPath;
|
||||
const parts = currentPath.split('/').filter(Boolean);
|
||||
for (let i = parts.length - 1; i > 0; i--) {
|
||||
const parentPath = '/' + parts.slice(0, i).join('/');
|
||||
if (flatPaths.includes(parentPath)) return parentPath;
|
||||
if (flatPaths.has(parentPath)) return parentPath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -22,14 +22,13 @@ function filterMenu(menuList, access, lastList) {
|
||||
let menuAccess = menu.auth;
|
||||
|
||||
if (!menuAccess || includeArray(menuAccess, access)) {
|
||||
let newMenu = {};
|
||||
for (let i in menu) {
|
||||
if (i !== 'children') newMenu[i] = cloneDeep(menu[i]);
|
||||
}
|
||||
if (menu.children && menu.children.length) newMenu.children = [];
|
||||
// 整节点剔除 children 后一次 cloneDeep,替代逐属性深克隆
|
||||
const { children, ...rest } = menu;
|
||||
const newMenu = cloneDeep(rest);
|
||||
if (children && children.length) newMenu.children = [];
|
||||
|
||||
lastList.push(newMenu);
|
||||
menu.children && filterMenu(menu.children, access, newMenu.children);
|
||||
children && filterMenu(children, access, newMenu.children);
|
||||
}
|
||||
});
|
||||
return lastList;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user