perf: 更完善的全局类型提示

This commit is contained in:
RealityBoy
2022-11-25 12:49:38 +08:00
committed by GitHub
parent ecba3c2e7f
commit 301356ebd7
44 changed files with 725 additions and 364 deletions

View File

@@ -3,9 +3,9 @@ import { useRouter } from "vue-router";
import { cloneDeep } from "lodash-unified";
import SearchResult from "./SearchResult.vue";
import SearchFooter from "./SearchFooter.vue";
import { deleteChildren } from "@/utils/tree";
import { useNav } from "@/layout/hooks/useNav";
import { transformI18n } from "@/plugins/i18n";
import { deleteChildren } from "@pureadmin/utils";
import { useDebounceFn, onKeyStroke } from "@vueuse/core";
import { ref, watch, computed, nextTick, shallowRef } from "vue";
import { usePermissionStoreHook } from "@/store/modules/permission";

View File

@@ -4,7 +4,6 @@ import { useRoute } from "vue-router";
import { emitter } from "@/utils/mitt";
import SidebarItem from "./sidebarItem.vue";
import leftCollapse from "./leftCollapse.vue";
import type { StorageConfigs } from "/#/index";
import { useNav } from "@/layout/hooks/useNav";
import { storageLocal } from "@pureadmin/utils";
import { ref, computed, watch, onBeforeMount } from "vue";

View File

@@ -9,7 +9,6 @@ import {
getCurrentInstance
} from "vue";
import { tagsViewsType } from "../types";
import type { StorageConfigs } from "/#/index";
import { useEventListener } from "@vueuse/core";
import { useRoute, useRouter } from "vue-router";
import { transformI18n, $t } from "@/plugins/i18n";

View File

@@ -1,6 +1,5 @@
// 多组件库的国际化和本地项目国际化兼容
import { App, WritableComputedRef } from "vue";
import type { StorageConfigs } from "/#/index";
import { storageLocal } from "@pureadmin/utils";
import { type I18n, createI18n } from "vue-i18n";

47
src/router/enums.ts Normal file
View File

@@ -0,0 +1,47 @@
// 完整版菜单比较多,将 rank 抽离出来,在此方便维护
const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以后端在返回 rank 的时候需要从 1 开始哦
doc = 1,
utils = 2,
table = 3,
tree = 4,
able = 5,
components = 6,
frame = 7,
nested = 8,
result = 9,
error = 10,
list = 11,
permission = 12,
system = 13,
tabs = 14,
formdesign = 15,
flowchart = 16,
ppt = 17,
editor = 18,
guide = 19,
about = 20;
export {
home,
doc,
utils,
table,
tree,
able,
components,
frame,
nested,
result,
error,
list,
permission,
system,
tabs,
formdesign,
flowchart,
ppt,
editor,
guide,
about
};

View File

@@ -1,6 +1,5 @@
import "@/utils/sso";
import { getConfig } from "@/config";
import { toRouteType } from "./types";
import NProgress from "@/utils/progress";
import { findIndex } from "lodash-unified";
import { transformI18n } from "@/plugins/i18n";
@@ -23,12 +22,9 @@ import {
formatTwoStageRoutes,
formatFlatteningRoutes
} from "./utils";
import {
isUrl,
openLink,
storageSession,
buildHierarchyTree
} from "@pureadmin/utils";
import { buildHierarchyTree } from "@/utils/tree";
import { isUrl, openLink, storageSession } from "@pureadmin/utils";
import remainingRouter from "./modules/remaining";
/** 自动导入全部静态路由,无需再手动引入!匹配 src/router/modules 目录(任何嵌套级别)中具有 .ts 扩展名的所有文件,除了 remaining.ts 文件

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { able } from "@/router/enums";
const ableRouter: RouteConfigsTable = {
export default {
path: "/able",
redirect: "/able/watermark",
meta: {
icon: "ubuntu-fill",
title: $t("menus.hsAble"),
rank: 5
rank: able
},
children: [
{
@@ -163,6 +163,4 @@ const ableRouter: RouteConfigsTable = {
}
}
]
};
export default ableRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { about } from "@/router/enums";
const aboutRouter: RouteConfigsTable = {
export default {
path: "/about",
redirect: "/about/index",
meta: {
// icon: "question-line",
title: $t("menus.hsAbout"),
rank: 15
rank: about
},
children: [
{
@@ -19,6 +19,4 @@ const aboutRouter: RouteConfigsTable = {
}
}
]
};
export default aboutRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { components } from "@/router/enums";
const componentsRouter: RouteConfigsTable = {
export default {
path: "/components",
redirect: "/components/video",
meta: {
icon: "menu",
title: $t("menus.hscomponents"),
rank: 6
rank: components
},
children: [
{
@@ -127,6 +127,4 @@ const componentsRouter: RouteConfigsTable = {
}
}
]
};
export default componentsRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { editor } from "@/router/enums";
const editorRouter: RouteConfigsTable = {
export default {
path: "/editor",
redirect: "/editor/index",
meta: {
icon: "edit",
title: $t("menus.hseditor"),
rank: 2
rank: editor
},
children: [
{
@@ -20,6 +20,4 @@ const editorRouter: RouteConfigsTable = {
}
}
]
};
export default editorRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { error } from "@/router/enums";
const errorRouter: RouteConfigsTable = {
export default {
path: "/error",
redirect: "/error/403",
meta: {
icon: "information-line",
title: $t("menus.hsabnormal"),
rank: 9
rank: error
},
children: [
{
@@ -35,6 +35,4 @@ const errorRouter: RouteConfigsTable = {
}
}
]
};
export default errorRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { flowchart } from "@/router/enums";
const flowChartRouter: RouteConfigsTable = {
export default {
path: "/flowChart",
redirect: "/flowChart/index",
meta: {
icon: "set-up",
title: $t("menus.hsflowChart"),
rank: 1
rank: flowchart
},
children: [
{
@@ -19,6 +19,4 @@ const flowChartRouter: RouteConfigsTable = {
}
}
]
};
export default flowChartRouter;
} as RouteConfigsTable;

View File

@@ -1,14 +1,14 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { formdesign } from "@/router/enums";
const IFrame = () => import("@/layout/frameView.vue");
const formDesignRouter: RouteConfigsTable = {
export default {
path: "/formDesign",
redirect: "/formDesign/index",
meta: {
icon: "terminal-window-line",
title: $t("menus.hsFormDesign"),
rank: 2
rank: formdesign
},
children: [
{
@@ -22,6 +22,4 @@ const formDesignRouter: RouteConfigsTable = {
}
}
]
};
export default formDesignRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { guide } from "@/router/enums";
const guideRouter: RouteConfigsTable = {
export default {
path: "/guide",
redirect: "/guide/index",
meta: {
icon: "guide",
title: $t("menus.hsguide"),
rank: 14
rank: guide
},
children: [
{
@@ -19,6 +19,4 @@ const guideRouter: RouteConfigsTable = {
}
}
]
};
export default guideRouter;
} as RouteConfigsTable;

View File

@@ -1,8 +1,8 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { home } from "@/router/enums";
const Layout = () => import("@/layout/index.vue");
const homeRouter: RouteConfigsTable = {
export default {
path: "/",
name: "Home",
component: Layout,
@@ -10,7 +10,7 @@ const homeRouter: RouteConfigsTable = {
meta: {
icon: "home-filled",
title: $t("menus.hshome"),
rank: 0
rank: home
},
children: [
{
@@ -22,6 +22,4 @@ const homeRouter: RouteConfigsTable = {
}
}
]
};
export default homeRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { list } from "@/router/enums";
const ableRouter: RouteConfigsTable = {
export default {
path: "/list",
redirect: "/list/card",
meta: {
icon: "list-check",
title: $t("menus.hsList"),
rank: 12
rank: list
},
children: [
{
@@ -21,6 +21,4 @@ const ableRouter: RouteConfigsTable = {
}
}
]
};
export default ableRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { nested } from "@/router/enums";
const nestedRouter: RouteConfigsTable = {
export default {
path: "/nested",
redirect: "/nested/menu1/menu1-1",
meta: {
title: $t("menus.hsmenus"),
icon: "histogram",
rank: 7
rank: nested
},
children: [
{
@@ -82,6 +82,4 @@ const nestedRouter: RouteConfigsTable = {
}
}
]
};
export default nestedRouter;
} as RouteConfigsTable;

View File

@@ -1,13 +1,13 @@
import type { RouteConfigsTable } from "/#/index";
import { ppt } from "@/router/enums";
const IFrame = () => import("@/layout/frameView.vue");
const pptRouter: RouteConfigsTable = {
export default {
path: "/ppt",
redirect: "/ppt/index",
meta: {
icon: "ppt",
title: "PPT",
rank: 3
rank: ppt
},
children: [
{
@@ -21,6 +21,4 @@ const pptRouter: RouteConfigsTable = {
}
}
]
};
export default pptRouter;
} as RouteConfigsTable;

View File

@@ -0,0 +1,24 @@
import { doc } from "@/router/enums";
import hot from "@/assets/svg/hot.svg?component";
const IFrame = () => import("@/layout/frameView.vue");
export default {
path: "/pure-admin-doc",
redirect: "/pure-admin-doc/index",
meta: {
icon: hot,
title: "pure-admin-doc",
rank: doc
},
children: [
{
path: "/pure-admin-doc/index",
name: "FrameDoc",
component: IFrame,
meta: {
title: "pure-admin-doc",
frameSrc: "https://yiming_chang.gitee.io/pure-admin-doc/"
}
}
]
} as RouteConfigsTable;

View File

@@ -0,0 +1,24 @@
import { utils } from "@/router/enums";
import hot from "@/assets/svg/hot.svg?component";
const IFrame = () => import("@/layout/frameView.vue");
export default {
path: "/pure-admin-utils",
redirect: "/pure-admin-utils/index",
meta: {
icon: hot,
title: "pure-admin-utils",
rank: utils
},
children: [
{
path: "/pure-admin-utils/index",
name: "FrameUtils",
component: IFrame,
meta: {
title: "pure-admin-utils",
frameSrc: "https://pure-admin-utils.netlify.app/"
}
}
]
} as RouteConfigsTable;

View File

@@ -1,8 +1,7 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
const Layout = () => import("@/layout/index.vue");
const remainingRouter: Array<RouteConfigsTable> = [
export default [
{
path: "/login",
name: "Login",
@@ -20,7 +19,7 @@ const remainingRouter: Array<RouteConfigsTable> = [
icon: "home-filled",
title: $t("menus.hshome"),
showLink: false,
rank: 104
rank: 102
},
children: [
{
@@ -38,9 +37,7 @@ const remainingRouter: Array<RouteConfigsTable> = [
meta: {
title: $t("menus.hsempty"),
showLink: false,
rank: 105
rank: 103
}
}
];
export default remainingRouter;
] as Array<RouteConfigsTable>;

View File

@@ -1,13 +1,13 @@
import { $t } from "@/plugins/i18n";
import type { RouteConfigsTable } from "/#/index";
import { result } from "@/router/enums";
const resultRouter: RouteConfigsTable = {
export default {
path: "/result",
redirect: "/result/success",
meta: {
icon: "checkbox-circle-line",
title: $t("menus.hsResult"),
rank: 8
rank: result
},
children: [
{
@@ -27,6 +27,4 @@ const resultRouter: RouteConfigsTable = {
}
}
]
};
export default resultRouter;
} as RouteConfigsTable;

View File

@@ -1,14 +1,14 @@
import { $t } from "@/plugins/i18n";
import { table } from "@/router/enums";
import hot from "@/assets/svg/hot.svg?component";
import type { RouteConfigsTable } from "/#/index";
const flowChartRouter: RouteConfigsTable = {
export default {
path: "/pure-table",
redirect: "/pure-table/index",
meta: {
icon: hot,
title: "pure-admin-table",
rank: 4
rank: table
},
children: [
{
@@ -28,6 +28,4 @@ const flowChartRouter: RouteConfigsTable = {
}
}
]
};
export default flowChartRouter;
} as RouteConfigsTable;

View File

@@ -0,0 +1,23 @@
import { $t } from "@/plugins/i18n";
import { tree } from "@/router/enums";
import hot from "@/assets/svg/hot.svg?component";
export default {
path: "/tree",
redirect: "/tree/index",
meta: {
icon: hot,
title: $t("menus.hsTree"),
rank: tree
},
children: [
{
path: "/tree/index",
name: "Tree",
component: () => import("@/views/tree/index.vue"),
meta: {
title: $t("menus.hsTree")
}
}
]
} as RouteConfigsTable;

View File

@@ -1,9 +0,0 @@
import { RouteLocationNormalized } from "vue-router";
export interface toRouteType extends RouteLocationNormalized {
meta: {
roles: Array<string>;
keepAlive?: boolean;
dynamicLevel?: string;
};
}

View File

@@ -14,9 +14,9 @@ import { RouteConfigs } from "@/layout/types";
import {
isString,
storageSession,
buildHierarchyTree,
isIncludeAllChildren
} from "@pureadmin/utils";
import { buildHierarchyTree } from "@/utils/tree";
import { cloneDeep, intersection } from "lodash-unified";
import { sessionKey, type DataInfo } from "@/utils/auth";
import { usePermissionStoreHook } from "@/store/modules/permission";

View File

@@ -2,7 +2,6 @@ import { store } from "@/store";
import { appType } from "./types";
import { defineStore } from "pinia";
import { getConfig } from "@/config";
import type { StorageConfigs } from "/#/index";
import { deviceDetection, storageLocal } from "@pureadmin/utils";
export const useAppStore = defineStore({

View File

@@ -1,7 +1,6 @@
import { store } from "@/store";
import { defineStore } from "pinia";
import { getConfig } from "@/config";
import type { StorageConfigs } from "/#/index";
import { storageLocal } from "@pureadmin/utils";
export const useEpThemeStore = defineStore({

View File

@@ -1,7 +1,6 @@
import { defineStore } from "pinia";
import { store } from "@/store";
import { isEqual } from "@pureadmin/utils";
import type { StorageConfigs } from "/#/index";
import { routerArrays } from "@/layout/types";
import { multiType, positionType } from "./types";
import { isUrl, storageLocal } from "@pureadmin/utils";

188
src/utils/tree.ts Normal file
View File

@@ -0,0 +1,188 @@
/**
* @description 提取菜单树中的每一项uniqueId
* @param tree 树
* @returns 每一项uniqueId组成的数组
*/
export const extractPathList = (tree: any[]): any => {
if (!Array.isArray(tree)) {
console.warn("tree must be an array");
return [];
}
if (!tree || tree.length === 0) return [];
const expandedPaths: Array<number | string> = [];
for (const node of tree) {
const hasChildren = node.children && node.children.length > 0;
if (hasChildren) {
extractPathList(node.children);
}
expandedPaths.push(node.uniqueId);
}
return expandedPaths;
};
/**
* @description 如果父级下children的length为1删除children并自动组建唯一uniqueId
* @param tree 树
* @param pathList 每一项的id组成的数组
* @returns 组件唯一uniqueId后的树
*/
export const deleteChildren = (tree: any[], pathList = []): any => {
if (!Array.isArray(tree)) {
console.warn("menuTree must be an array");
return [];
}
if (!tree || tree.length === 0) return [];
for (const [key, node] of tree.entries()) {
if (node.children && node.children.length === 1) delete node.children;
node.id = key;
node.parentId = pathList.length ? pathList[pathList.length - 1] : null;
node.pathList = [...pathList, node.id];
node.uniqueId =
node.pathList.length > 1 ? node.pathList.join("-") : node.pathList[0];
const hasChildren = node.children && node.children.length > 0;
if (hasChildren) {
deleteChildren(node.children, node.pathList);
}
}
return tree;
};
/**
* @description 创建层级关系
* @param tree 树
* @param pathList 每一项的id组成的数组
* @returns 创建层级关系后的树
*/
export const buildHierarchyTree = (tree: any[], pathList = []): any => {
if (!Array.isArray(tree)) {
console.warn("tree must be an array");
return [];
}
if (!tree || tree.length === 0) return [];
for (const [key, node] of tree.entries()) {
node.id = key;
node.parentId = pathList.length ? pathList[pathList.length - 1] : null;
node.pathList = [...pathList, node.id];
const hasChildren = node.children && node.children.length > 0;
if (hasChildren) {
buildHierarchyTree(node.children, node.pathList);
}
}
return tree;
};
/**
* @description 广度优先遍历根据唯一uniqueId找当前节点信息
* @param tree 树
* @param uniqueId 唯一uniqueId
* @returns 当前节点信息
*/
export const getNodeByUniqueId = (
tree: any[],
uniqueId: number | string
): any => {
if (!Array.isArray(tree)) {
console.warn("menuTree must be an array");
return [];
}
if (!tree || tree.length === 0) return [];
const item = tree.find(node => node.uniqueId === uniqueId);
if (item) return item;
const childrenList = tree
.filter(node => node.children)
.map(i => i.children)
.flat(1) as unknown;
return getNodeByUniqueId(childrenList as any[], uniqueId);
};
/**
* @description 向当前唯一uniqueId节点中追加字段
* @param tree 树
* @param uniqueId 唯一uniqueId
* @param fields 需要追加的字段
* @returns 追加字段后的树
*/
export const appendFieldByUniqueId = (
tree: any[],
uniqueId: number | string,
fields: object
): any => {
if (!Array.isArray(tree)) {
console.warn("menuTree must be an array");
return [];
}
if (!tree || tree.length === 0) return [];
for (const node of tree) {
const hasChildren = node.children && node.children.length > 0;
if (
node.uniqueId === uniqueId &&
Object.prototype.toString.call(fields) === "[object Object]"
)
Object.assign(node, fields);
if (hasChildren) {
appendFieldByUniqueId(node.children, uniqueId, fields);
}
}
return tree;
};
/**
* @description 构造树型结构数据
* @param data 数据源
* @param id id字段 默认id
* @param parentId 父节点字段默认parentId
* @param children 子节点字段默认children
* @returns 追加字段后的树
*/
export const handleTree = (
data: any[],
id?: string,
parentId?: string,
children?: string
): any => {
if (!Array.isArray(data)) {
console.warn("data must be an array");
return [];
}
const config = {
id: id || "id",
parentId: parentId || "parentId",
childrenList: children || "children"
};
const childrenListMap: any = {};
const nodeIds: any = {};
const tree = [];
for (const d of data) {
const parentId = d[config.parentId];
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (const d of data) {
const parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (const t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o: Record<string, any>) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
return tree;
};

View File

@@ -3,7 +3,7 @@ import { computed } from "vue";
import { clone } from "@pureadmin/utils";
import { transformI18n } from "@/plugins/i18n";
import ElTreeLine from "@/components/ReTreeLine";
import { extractPathList, deleteChildren } from "@pureadmin/utils";
import { extractPathList, deleteChildren } from "@/utils/tree";
import { usePermissionStoreHook } from "@/store/modules/permission";
defineOptions({

View File

@@ -4,7 +4,7 @@ import { clone } from "@pureadmin/utils";
import type { ElTreeV2 } from "element-plus";
import { transformI18n } from "@/plugins/i18n";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { extractPathList, deleteChildren } from "@pureadmin/utils";
import { extractPathList, deleteChildren } from "@/utils/tree";
import { usePermissionStoreHook } from "@/store/modules/permission";
import type { TreeNode } from "element-plus/es/components/tree-v2/src/types";

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { useColumns } from "./columns";
import { handleTree } from "@/utils/tree";
import { getDeptList } from "@/api/system";
import { FormInstance } from "element-plus";
import { handleTree } from "@pureadmin/utils";
import { reactive, ref, onMounted } from "vue";
import { TableProBar } from "@/components/ReTable";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { handleTree } from "@/utils/tree";
import type { ElTree } from "element-plus";
import { getDeptList } from "@/api/system";
import { handleTree } from "@pureadmin/utils";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, watch, onMounted, getCurrentInstance } from "vue";

View File

@@ -9,7 +9,7 @@ import {
deleteChildren,
getNodeByUniqueId,
appendFieldByUniqueId
} from "@pureadmin/utils";
} from "@/utils/tree";
import { useDetail } from "./hooks";
defineOptions({

7
src/views/tree/index.vue Normal file
View File

@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div>即将发布</div>
</template>
<style scoped></style>