import { defineStore } from 'pinia';
import { getConfig } from 'cube-front/core/configure';
import { getDataByKey, isPromise } from '../utils/common';
import { type AxiosRequestConfig } from 'axios';
import request from '../utils/request';
export interface FlatMenuItem {
id: string;
name: string;
path: string;
title?: string;
icon?: string;
sort?: number;
parentId?: string | null;
active?: boolean;
}
export interface TreeMenuItem {
id: string;
name: string;
path: string;
title?: string;
icon?: string;
sort?: number;
parentId?: string | null;
parentMenu?: TreeMenuItem;
children?: TreeMenuItem[];
active?: boolean;
}
/** 平铺菜单转换成树形菜单 */
export function convertFlatMenuToTreeMenu(flatMenu: FlatMenuItem[]): TreeMenuItem[] {
const menuMap: { [id: string]: TreeMenuItem } = {};
// Create a map of menu items using their IDs as keys
flatMenu.forEach((item) => {
menuMap[item.id] = item;
});
const treeMenu: TreeMenuItem[] = [];
// Iterate over the flat menu items and build the tree menu
flatMenu.forEach((item) => {
const menuItem = menuMap[item.id];
if (item.parentId) {
const parentItem = menuMap[item.parentId];
if (parentItem) {
parentItem.children = parentItem.children || [];
parentItem.children.push(menuItem);
menuItem.parentMenu = parentItem;
}
} else {
treeMenu.push(menuItem);
}
});
return treeMenu;
}
/** 树形菜单转换成平铺菜单 */
export function convertTreeMenuToFlatMenu(
treeMenuList: TreeMenuItem[],
parentMenu?: TreeMenuItem,
): FlatMenuItem[] {
const flatMenu: FlatMenuItem[] = [];
const flatten = (menuList: TreeMenuItem[], parentMenu2?: TreeMenuItem) => {
menuList.forEach((item) => {
item.parentMenu = parentMenu2;
flatMenu.push(item);
if (item.children) {
flatten(item.children, item);
}
});
};
flatten(treeMenuList, parentMenu);
return flatMenu;
}
/** 将菜单数据按照配置的字段名称进行转换,支持平铺数据和树形数据 */
const covertMenu = (list: never[]) => {
const menuConfig = getConfig().menu;
const newList = list.map((item) => {
const newItem: TreeMenuItem = {
...(item as TreeMenuItem),
id: item[menuConfig.idField],
parentId: item[menuConfig.parentField],
name: item[menuConfig.nameField],
path: item[menuConfig.pathField],
title: item[menuConfig.titleField],
icon: item[menuConfig.iconField],
sort: item[menuConfig.sortField],
children: item[menuConfig.childrenField]
? covertMenu(item[menuConfig.childrenField])
: undefined,
};
return newItem;
});
return newList;
};
const state: {
/** 平铺菜单 */
flatMenus: Array<FlatMenuItem> | undefined;
/** 树形菜单 */
treeMenus: Array<TreeMenuItem> | undefined;
activeMenu: TreeMenuItem | undefined;
loading: boolean;
} = {
flatMenus: undefined,
treeMenus: undefined,
activeMenu: undefined,
loading: false,
};
const getTopLevelMenu = (menu: TreeMenuItem) => {
if (menu.parentMenu) {
return getTopLevelMenu(menu.parentMenu);
}
return menu;
};
export const useMenuStore = defineStore('menu', {
state: () => state,
getters: {
hasMenus: (state) =>
state.flatMenus &&
state.treeMenus &&
state.flatMenus.length > 0 &&
state.treeMenus.length > 0,
topLevelActiveMenu: (state) => {
return state.activeMenu && getTopLevelMenu(state.activeMenu);
},
},
actions: {
setFlatMenus(data: Array<FlatMenuItem>) {
this.flatMenus = data;
this.treeMenus = convertFlatMenuToTreeMenu(data);
},
setTreeMenus(data: Array<TreeMenuItem>) {
this.treeMenus = data;
this.flatMenus = convertTreeMenuToFlatMenu(data);
},
setActiveMenu(menu: TreeMenuItem) {
this.activeMenu = menu;
},
setActiveMenuByPath(path: string) {
const activeMenu = this.flatMenus?.find((item) => item.path === path);
this.setActiveMenu(activeMenu as TreeMenuItem);
},
async fetchMenuAsync() {
if (this.loading) return;
this.loading = true;
// 如果没有菜单信息,则获取菜单信息
if (!this.hasMenus) {
const menuConfig = getConfig().menu;
const getMenuAxiosConfig = menuConfig.getMenuAxiosConfig;
// 处理不同类型的 getMenuAxiosConfig
const processMenuRequestAsync = async (config: AxiosRequestConfig) => {
try {
const res = await request(config);
// 增加延时,避免下面的赋值触发更新再次请求
setTimeout(() => {
this.loading = false;
}, 1000);
const data = getDataByKey(res as never, menuConfig.dataKey);
if (menuConfig.isMenuTree) {
this.setTreeMenus(covertMenu(data as never[]));
} else {
this.setFlatMenus(covertMenu(data as never[]));
}
this.setActiveMenuByPath(window.location.pathname);
} catch (error) {
// 如果报错,增加延时,避免下面的赋值触发更新再次请求
setTimeout(() => {
this.loading = false;
}, 1000);
}
};
// 根据类型执行不同操作
if (typeof getMenuAxiosConfig === 'function') {
const config = getMenuAxiosConfig();
if (config instanceof Promise) {
// 处理返回 Promise 类型的配置
await processMenuRequestAsync(await config);
} else {
await processMenuRequestAsync(config);
}
} else {
// 处理直接配置对象
await processMenuRequestAsync(getMenuAxiosConfig);
}
} else {
this.loading = false;
}
},
},
});
|