initial commit

This commit is contained in:
陈文彬
2020-09-28 20:19:10 +08:00
commit 2f6253cfb6
436 changed files with 26843 additions and 0 deletions

View 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();
};

View 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,
};
},
});
}

View 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);
}
})();

View 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;
}

View 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,
};
}
}

View 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;
}

View 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!');
}
}

View 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);
}
}