mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 14:49:43 +08:00
initial commit
This commit is contained in:
12
src/utils/helper/envHelper.ts
Normal file
12
src/utils/helper/envHelper.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { isDevMode, getEnv } from '/@/utils/env';
|
||||
import { useSetting } from '/@/hooks/core/useSetting';
|
||||
|
||||
import pkg from '../../../package.json';
|
||||
const { globSetting } = useSetting();
|
||||
|
||||
// Generate cache key according to version
|
||||
export const getStorageShortName = () => {
|
||||
return `${globSetting.shortName}__${getEnv()}${
|
||||
isDevMode() ? `__${(pkg as any).version}` : '__' + process.env.VITE_BUILD_SHORT_TIME
|
||||
}__`.toUpperCase();
|
||||
};
|
66
src/utils/helper/menuHelper.ts
Normal file
66
src/utils/helper/menuHelper.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { AppRouteModule } from '/@/router/types.d';
|
||||
import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
|
||||
|
||||
import { findPath, forEach, treeMap, treeToList } from './treeHelper';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
//
|
||||
export function getAllParentPath(treeData: any[], path: string) {
|
||||
const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
|
||||
return (menuList || []).map((item) => item.path);
|
||||
}
|
||||
|
||||
export function flatMenus(menus: Menu[]) {
|
||||
return treeToList(menus);
|
||||
}
|
||||
|
||||
function joinParentPath(list: any, node: any) {
|
||||
let allPaths = getAllParentPath(list, node.path);
|
||||
|
||||
allPaths = allPaths.slice(0, allPaths.length - 1);
|
||||
let parentPath = '';
|
||||
if (Array.isArray(allPaths) && allPaths.length >= 2) {
|
||||
parentPath = allPaths[allPaths.length - 1];
|
||||
} else {
|
||||
allPaths.forEach((p) => {
|
||||
parentPath += /^\//.test(p) ? p : `/${p}`;
|
||||
});
|
||||
}
|
||||
|
||||
node.path = `${parentPath}${/^\//.test(node.path) ? node.path : `/${node.path}`}`.replace(
|
||||
/\/\//g,
|
||||
'/'
|
||||
);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function transformMenuModule(menuModule: MenuModule): Menu {
|
||||
const { menu } = menuModule;
|
||||
|
||||
const menuList = [menu];
|
||||
forEach(menuList, (m) => {
|
||||
joinParentPath(menuList, m);
|
||||
});
|
||||
return menuList[0];
|
||||
}
|
||||
|
||||
export function transformRouteToMenu(routeModList: AppRouteModule[]) {
|
||||
const cloneRouteModList = cloneDeep(routeModList);
|
||||
const routeList: AppRouteRecordRaw[] = [];
|
||||
cloneRouteModList.forEach((item) => {
|
||||
const { layout, routes } = item;
|
||||
layout.children = routes;
|
||||
routeList.push(layout);
|
||||
});
|
||||
return treeMap(routeList, {
|
||||
conversion: (node: AppRouteRecordRaw) => {
|
||||
const { meta: { title, icon } = {} } = node;
|
||||
joinParentPath(routeList, node);
|
||||
return {
|
||||
name: title,
|
||||
icon,
|
||||
path: node.path,
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
109
src/utils/helper/persistent.ts
Normal file
109
src/utils/helper/persistent.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { createStorage } from '/@/utils/storage/index';
|
||||
import { isIeFn } from '/@/utils/browser';
|
||||
|
||||
import { BASE_LOCAL_CACHE_KEY, BASE_SESSION_CACHE_KEY } from '/@/enums/cacheEnum';
|
||||
|
||||
const ls = createStorage(localStorage);
|
||||
const ss = createStorage();
|
||||
|
||||
/**
|
||||
* @description: Persistent cache
|
||||
*/
|
||||
const cacheStore: any = {
|
||||
// localstorage cache
|
||||
local: {},
|
||||
// sessionstorage cache
|
||||
session: {},
|
||||
};
|
||||
|
||||
function initCache() {
|
||||
cacheStore.local = ls.get(BASE_LOCAL_CACHE_KEY) || {};
|
||||
cacheStore.session = ss.get(BASE_SESSION_CACHE_KEY) || {};
|
||||
}
|
||||
initCache();
|
||||
|
||||
export function setLocal(key: string, value: any) {
|
||||
cacheStore.local[BASE_LOCAL_CACHE_KEY] = cacheStore.local[BASE_LOCAL_CACHE_KEY] || {};
|
||||
cacheStore.local[BASE_LOCAL_CACHE_KEY][key] = value;
|
||||
}
|
||||
|
||||
export function getLocal<T>(key: string): T | null {
|
||||
try {
|
||||
return cacheStore.local[BASE_LOCAL_CACHE_KEY][key];
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
export function removeLocal(key: string) {
|
||||
if (cacheStore.local[BASE_LOCAL_CACHE_KEY]) {
|
||||
Reflect.deleteProperty(cacheStore.local[BASE_LOCAL_CACHE_KEY], key);
|
||||
}
|
||||
}
|
||||
|
||||
export function clearLocal() {
|
||||
cacheStore.local = {};
|
||||
}
|
||||
|
||||
export function setSession(key: string, value: any) {
|
||||
cacheStore.session[BASE_SESSION_CACHE_KEY] = cacheStore.session[BASE_SESSION_CACHE_KEY] || {};
|
||||
cacheStore.session[BASE_SESSION_CACHE_KEY][key] = value;
|
||||
}
|
||||
|
||||
export function removeSession(key: string) {
|
||||
if (cacheStore.session[BASE_SESSION_CACHE_KEY]) {
|
||||
Reflect.deleteProperty(cacheStore.session[BASE_SESSION_CACHE_KEY], key);
|
||||
}
|
||||
}
|
||||
|
||||
export function getSession<T>(key: string): T | null {
|
||||
try {
|
||||
return cacheStore.session[BASE_SESSION_CACHE_KEY][key];
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function clearSession() {
|
||||
cacheStore.session = {};
|
||||
}
|
||||
|
||||
export function clearAll() {
|
||||
clearLocal();
|
||||
clearSession();
|
||||
}
|
||||
|
||||
(() => {
|
||||
// /** Write to local before closing window */
|
||||
window.addEventListener('beforeunload', () => {
|
||||
const localCache = cacheStore.local;
|
||||
const sessionCache = cacheStore.session;
|
||||
|
||||
// const ss = createStorage();
|
||||
|
||||
ls.set(BASE_LOCAL_CACHE_KEY, localCache);
|
||||
ss.set(BASE_SESSION_CACHE_KEY, sessionCache);
|
||||
});
|
||||
|
||||
function storageChange(e: any) {
|
||||
const { key, newValue, oldValue } = e;
|
||||
|
||||
if (!key) {
|
||||
clearAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!!newValue && !!oldValue) {
|
||||
if (BASE_LOCAL_CACHE_KEY === key) {
|
||||
clearLocal();
|
||||
}
|
||||
if (BASE_SESSION_CACHE_KEY === key) {
|
||||
clearSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isIeFn() && (document as any).attachEvent) {
|
||||
(document as any).attachEvent('onstorage', storageChange);
|
||||
} else {
|
||||
window.addEventListener('storage', storageChange);
|
||||
}
|
||||
})();
|
47
src/utils/helper/routeHelper.ts
Normal file
47
src/utils/helper/routeHelper.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||
import { toRaw } from 'vue';
|
||||
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
|
||||
export function genRouteModule(moduleList: AppRouteModule[]) {
|
||||
const ret: AppRouteRecordRaw[] = [];
|
||||
for (const routeMod of moduleList) {
|
||||
const routes = routeMod.routes as any;
|
||||
const layout = routeMod.layout;
|
||||
const router = createRouter({ routes, history: createWebHashHistory() });
|
||||
|
||||
const flatList = toRaw(router.getRoutes()).filter((item) => item.children.length === 0);
|
||||
try {
|
||||
(router as any) = null;
|
||||
} catch (error) {}
|
||||
|
||||
flatList.forEach((item) => {
|
||||
item.path = `${layout.path}${item.path}`;
|
||||
});
|
||||
layout.children = (flatList as unknown) as AppRouteRecordRaw[];
|
||||
ret.push(layout);
|
||||
}
|
||||
return ret as RouteRecordRaw[];
|
||||
}
|
||||
|
||||
function asyncImportRoute(routes: AppRouteRecordRaw[]) {
|
||||
routes.forEach((item) => {
|
||||
const { component, children } = item;
|
||||
if (component) {
|
||||
item.component = () => import(`/@/views/${component}`);
|
||||
}
|
||||
children && asyncImportRoute(children);
|
||||
});
|
||||
}
|
||||
|
||||
export function transformObjToRoute(routeList: AppRouteModule[]) {
|
||||
routeList.forEach((route) => {
|
||||
asyncImportRoute(route.routes);
|
||||
if (route.layout) {
|
||||
route.layout.component =
|
||||
route.layout.component === 'PAGE_LAYOUT' ? PAGE_LAYOUT_COMPONENT : '';
|
||||
}
|
||||
});
|
||||
return routeList;
|
||||
}
|
185
src/utils/helper/treeHelper.ts
Normal file
185
src/utils/helper/treeHelper.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
interface TreeHelperConfig {
|
||||
id: string;
|
||||
children: string;
|
||||
pid: string;
|
||||
}
|
||||
const DEFAULT_CONFIG: TreeHelperConfig = {
|
||||
id: 'id',
|
||||
children: 'children',
|
||||
pid: 'pid',
|
||||
};
|
||||
|
||||
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config);
|
||||
|
||||
// tree from list
|
||||
export function listToTree<T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] {
|
||||
const conf = getConfig(config) as TreeHelperConfig;
|
||||
const nodeMap = new Map();
|
||||
const result: T[] = [];
|
||||
const { id, children, pid } = conf;
|
||||
|
||||
for (const node of list) {
|
||||
node[children] = node[children] || [];
|
||||
nodeMap.set(node[id], node);
|
||||
}
|
||||
for (const node of list) {
|
||||
const parent = nodeMap.get(node[pid]);
|
||||
(parent ? parent.children : result).push(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function treeToList<T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const result: any = [...tree];
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
if (!result[i][children!]) continue;
|
||||
result.splice(i + 1, 0, ...result[i][children!]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findNode<T = any>(
|
||||
tree: any,
|
||||
func: Fn,
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
): T | null {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const list = [...tree];
|
||||
for (const node of list) {
|
||||
if (func(node)) return node;
|
||||
node[children!] && list.push(...node[children!]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findNodeAll<T = any>(
|
||||
tree: any,
|
||||
func: Fn,
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
): T[] {
|
||||
config = getConfig(config);
|
||||
const { children } = config;
|
||||
const list = [...tree];
|
||||
const result: T[] = [];
|
||||
for (const node of list) {
|
||||
func(node) && result.push(node);
|
||||
node[children!] && list.push(...node[children!]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findPath<T = any>(
|
||||
tree: any,
|
||||
func: Fn,
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
): T | T[] | null {
|
||||
config = getConfig(config);
|
||||
const path: T[] = [];
|
||||
const list = [...tree];
|
||||
const visitedSet = new Set();
|
||||
const { children } = config;
|
||||
while (list.length) {
|
||||
const node = list[0];
|
||||
if (visitedSet.has(node)) {
|
||||
path.pop();
|
||||
list.shift();
|
||||
} else {
|
||||
visitedSet.add(node);
|
||||
node[children!] && list.unshift(...node[children!]);
|
||||
path.push(node);
|
||||
if (func(node)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findPathAll(tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) {
|
||||
config = getConfig(config);
|
||||
const path = [];
|
||||
const list = [...tree];
|
||||
const result = [];
|
||||
const visitedSet = new Set(),
|
||||
{ children } = config;
|
||||
while (list.length) {
|
||||
const node = list[0];
|
||||
if (visitedSet.has(node)) {
|
||||
path.pop();
|
||||
list.shift();
|
||||
} else {
|
||||
visitedSet.add(node);
|
||||
node[children!] && list.unshift(...node[children!]);
|
||||
path.push(node);
|
||||
func(node) && result.push([...path]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filter<T = any>(
|
||||
tree: T[],
|
||||
func: (n: T) => boolean,
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
) {
|
||||
config = getConfig(config);
|
||||
const children = config.children as string;
|
||||
function listFilter(list: T[]) {
|
||||
return list
|
||||
.map((node: any) => ({ ...node }))
|
||||
.filter((node) => {
|
||||
node[children] = node[children] && listFilter(node[children]);
|
||||
return func(node) || (node[children] && node[children].length);
|
||||
});
|
||||
}
|
||||
return listFilter(tree);
|
||||
}
|
||||
|
||||
export function forEach<T = any>(
|
||||
tree: T[],
|
||||
func: (n: T) => any,
|
||||
config: Partial<TreeHelperConfig> = {}
|
||||
) {
|
||||
config = getConfig(config);
|
||||
const list: any[] = [...tree];
|
||||
const { children } = config;
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
func(list[i]);
|
||||
children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 提取tree指定结构
|
||||
*/
|
||||
export function treeMap(treeData: any[], opt: { children?: string; conversion: Fn }) {
|
||||
return treeData.map((item) => treeMapEach(item, opt));
|
||||
}
|
||||
/**
|
||||
* @description: 提取tree指定结构
|
||||
*/
|
||||
export function treeMapEach(
|
||||
data: any,
|
||||
{ children = 'children', conversion }: { children?: string; conversion: Fn }
|
||||
) {
|
||||
const haveChildren = Array.isArray(data[children]) && data[children].length > 0;
|
||||
const conversionData = conversion(data) || {};
|
||||
if (haveChildren) {
|
||||
return {
|
||||
...conversionData,
|
||||
[children]: data[children].map((i: number) =>
|
||||
treeMapEach(i, {
|
||||
children,
|
||||
conversion,
|
||||
})
|
||||
),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...conversionData,
|
||||
};
|
||||
}
|
||||
}
|
45
src/utils/helper/tsxHelper.tsx
Normal file
45
src/utils/helper/tsxHelper.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Slots } from 'vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
|
||||
/**
|
||||
* @description: Get slot to prevent empty error
|
||||
*/
|
||||
export function getSlot(slots: Slots, slot = 'default', data?: any) {
|
||||
if (!slots || !Reflect.has(slots, slot)) {
|
||||
return null;
|
||||
}
|
||||
if (!isFunction(slots[slot])) {
|
||||
console.error(`${slot} is not a function!`);
|
||||
return null;
|
||||
}
|
||||
const slotFn = slots[slot];
|
||||
if (!slotFn) return null;
|
||||
return slotFn(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* extends slots
|
||||
* @param slots
|
||||
*/
|
||||
export function extendSlots(slots: Slots, excludeKeys: string[] = []) {
|
||||
const slotKeys = Object.keys(slots);
|
||||
const ret: any = {};
|
||||
slotKeys.map((key) => {
|
||||
if (excludeKeys.includes(key)) {
|
||||
return null;
|
||||
}
|
||||
ret[key] = () => getSlot(slots, key);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get events on attrs
|
||||
export function getListeners(attrs: Record<string, unknown>) {
|
||||
const listeners: any = {};
|
||||
Object.keys(attrs).forEach((key) => {
|
||||
if (/^on/.test(key)) {
|
||||
listeners[key] = attrs[key];
|
||||
}
|
||||
});
|
||||
return listeners;
|
||||
}
|
46
src/utils/helper/vueHelper.ts
Normal file
46
src/utils/helper/vueHelper.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
watch,
|
||||
computed,
|
||||
WatchSource,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
reactive,
|
||||
} from 'vue';
|
||||
|
||||
export function explicitComputed<T, S>(source: WatchSource<S>, fn: () => T) {
|
||||
const v = reactive<any>({ value: fn() });
|
||||
watch(source, () => (v.value = fn()));
|
||||
return computed<T>(() => v.value);
|
||||
}
|
||||
|
||||
export function tryOnMounted(fn: () => void, sync = true) {
|
||||
if (getCurrentInstance()) {
|
||||
onMounted(fn);
|
||||
} else if (sync) {
|
||||
fn();
|
||||
} else {
|
||||
nextTick(fn);
|
||||
}
|
||||
}
|
||||
|
||||
export function tryOnUnmounted(fn: () => Promise<void> | void) {
|
||||
if (getCurrentInstance()) {
|
||||
onUnmounted(fn);
|
||||
}
|
||||
}
|
||||
|
||||
export function tryTsxEmit(fn: (_instance: any) => Promise<void> | void) {
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
if (instance) {
|
||||
fn.call(null, instance);
|
||||
}
|
||||
}
|
||||
|
||||
export function isInSetup() {
|
||||
if (!getCurrentInstance()) {
|
||||
throw new Error('Please put useForm function in the setup function!');
|
||||
}
|
||||
}
|
8
src/utils/helper/vuexHelper.ts
Normal file
8
src/utils/helper/vuexHelper.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import store from '/@/store';
|
||||
|
||||
export function hotModuleUnregisterModule(name: string) {
|
||||
if (!name) return;
|
||||
if ((store.state as any)[name]) {
|
||||
store.unregisterModule(name);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user