diff --git a/README.md b/README.md index 4ff736f80..20d5ebac0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ - [点我查看国内文档站](https://yiming_chang.gitee.io/pure-admin-doc) - [点我查看国外文档站](https://xiaoxian521.github.io/pure-admin-doc) -## 精简版(提供 `非国际化` 、`国际化` 两个版本选择) +## 精简版(实际项目开发请用精简版,提供 `非国际化` 、`国际化` 两个版本选择) - [点我查看非国际化精简版](https://github.com/xiaoxian521/pure-admin-thin) - [点我查看国际化精简版](https://github.com/xiaoxian521/pure-admin-thin/tree/i18n) diff --git a/locales/en.yaml b/locales/en.yaml index d2e78c5c3..697faed3b 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -72,6 +72,11 @@ menus: hsPureDocument: Pure Doc(Embedded) externalLink: Pure Doc(External) hsEpDocument: Element Plus Doc(Embedded) + hsVueDocument: Vue3 Doc(Embedded) + hsViteDocument: Vite Doc(Embedded) + hsPiniaDocument: Pinia Doc(Embedded) + hsRouterDocument: Vue Router Doc(Embedded) + hsTailwindcssDocument: Tailwindcss Doc(Embedded) hsAbout: About hsResult: Result Page hsSuccess: Success Page @@ -97,6 +102,7 @@ menus: hsdanmaku: Danmaku Components hsPureTableBase: Base Usage hsPureTableHigh: High Usage + hsTree: Big Data Tree status: hsLoad: Loading... login: diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index fb50c89db..e5339ff91 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -69,9 +69,14 @@ menus: hsPrint: 打印 hsDownload: 下载 hsExternalPage: 外部页面 - hsPureDocument: 平台文档(内嵌) - externalLink: 平台文档(外链) - hsEpDocument: Element Plus文档(内嵌) + hsPureDocument: 平台文档(内嵌) + externalLink: 平台文档(外链) + hsEpDocument: Element Plus 文档(内嵌) + hsVueDocument: Vue3 文档(内嵌) + hsViteDocument: Vite 文档(内嵌) + hsPiniaDocument: Pinia 文档(内嵌) + hsRouterDocument: Vue Router 文档(内嵌) + hsTailwindcssDocument: Tailwindcss 文档(内嵌) hsAbout: 关于 hsResult: 结果页面 hsSuccess: 成功页面 @@ -97,6 +102,7 @@ menus: hsdanmaku: 弹幕组件 hsPureTableBase: 基础用法 hsPureTableHigh: 高级用法 + hsTree: 大数据树业务组件 status: hsLoad: 加载中... login: diff --git a/mock/asyncRoutes.ts b/mock/asyncRoutes.ts index 1a483b575..d7b0aff0c 100644 --- a/mock/asyncRoutes.ts +++ b/mock/asyncRoutes.ts @@ -1,5 +1,6 @@ // 模拟后端动态生成路由 import { MockMethod } from "vite-plugin-mock"; +import { system, permission, frame, tabs } from "@/router/enums"; /** * roles:页面级别权限,这里模拟二种 "admin"、"common" @@ -12,7 +13,7 @@ const systemRouter = { meta: { icon: "setting", title: "menus.hssysManagement", - rank: 11 + rank: system }, children: [ { @@ -61,7 +62,7 @@ const permissionRouter = { meta: { title: "menus.permission", icon: "lollipop", - rank: 10 + rank: permission }, children: [ { @@ -89,9 +90,17 @@ const frameRouter = { meta: { icon: "monitor", title: "menus.hsExternalPage", - rank: 8 + rank: frame }, children: [ + { + path: "/external", + name: "https://yiming_chang.gitee.io/pure-admin-doc", + meta: { + title: "menus.externalLink", + roles: ["admin", "common"] + } + }, { path: "/iframe/pure", name: "FramePure", @@ -101,14 +110,6 @@ const frameRouter = { roles: ["admin", "common"] } }, - { - path: "/external", - name: "https://yiming_chang.gitee.io/pure-admin-doc", - meta: { - title: "menus.externalLink", - roles: ["admin", "common"] - } - }, { path: "/iframe/ep", name: "FrameEp", @@ -117,6 +118,51 @@ const frameRouter = { frameSrc: "https://element-plus.org/zh-CN/", roles: ["admin", "common"] } + }, + { + path: "/iframe/vue3", + name: "FrameVue", + meta: { + title: "menus.hsVueDocument", + frameSrc: "https://cn.vuejs.org/", + roles: ["admin", "common"] + } + }, + { + path: "/iframe/vite", + name: "FrameVite", + meta: { + title: "menus.hsViteDocument", + frameSrc: "https://cn.vitejs.dev/", + roles: ["admin", "common"] + } + }, + { + path: "/iframe/pinia", + name: "FramePinia", + meta: { + title: "menus.hsPiniaDocument", + frameSrc: "https://pinia.vuejs.org/zh/index.html", + roles: ["admin", "common"] + } + }, + { + path: "/iframe/vue-router", + name: "FrameRouter", + meta: { + title: "menus.hsRouterDocument", + frameSrc: "https://router.vuejs.org/zh/", + roles: ["admin", "common"] + } + }, + { + path: "/iframe/tailwindcss", + name: "FrameTailwindcss", + meta: { + title: "menus.hsTailwindcssDocument", + frameSrc: "https://tailwindcss.com/docs/installation", + roles: ["admin", "common"] + } } ] }; @@ -126,7 +172,7 @@ const tabsRouter = { meta: { icon: "IF-team-icontabs", title: "menus.hstabs", - rank: 13 + rank: tabs }, children: [ { diff --git a/src/layout/components/search/components/SearchModal.vue b/src/layout/components/search/components/SearchModal.vue index e05497779..ae9bab204 100644 --- a/src/layout/components/search/components/SearchModal.vue +++ b/src/layout/components/search/components/SearchModal.vue @@ -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"; diff --git a/src/layout/components/sidebar/vertical.vue b/src/layout/components/sidebar/vertical.vue index e2d6ca308..6973b1ce3 100644 --- a/src/layout/components/sidebar/vertical.vue +++ b/src/layout/components/sidebar/vertical.vue @@ -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"; diff --git a/src/layout/hooks/useTag.ts b/src/layout/hooks/useTag.ts index 84b72a845..d8eb29ec7 100644 --- a/src/layout/hooks/useTag.ts +++ b/src/layout/hooks/useTag.ts @@ -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"; diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 8266d083c..37709862f 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -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"; diff --git a/src/router/enums.ts b/src/router/enums.ts new file mode 100644 index 000000000..ae281674c --- /dev/null +++ b/src/router/enums.ts @@ -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 +}; diff --git a/src/router/index.ts b/src/router/index.ts index 1d40b695d..38bfd2654 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -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 文件 diff --git a/src/router/modules/able.ts b/src/router/modules/able.ts index 7a293e369..29e06604b 100644 --- a/src/router/modules/able.ts +++ b/src/router/modules/able.ts @@ -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; diff --git a/src/router/modules/about.ts b/src/router/modules/about.ts index 4f98f8f01..b1a9e3e20 100644 --- a/src/router/modules/about.ts +++ b/src/router/modules/about.ts @@ -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; diff --git a/src/router/modules/components.ts b/src/router/modules/components.ts index 64ac7acd3..26feab9c0 100644 --- a/src/router/modules/components.ts +++ b/src/router/modules/components.ts @@ -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; diff --git a/src/router/modules/editor.ts b/src/router/modules/editor.ts index a5c4c1133..c727582af 100644 --- a/src/router/modules/editor.ts +++ b/src/router/modules/editor.ts @@ -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; diff --git a/src/router/modules/error.ts b/src/router/modules/error.ts index c1203650f..d1cccbade 100644 --- a/src/router/modules/error.ts +++ b/src/router/modules/error.ts @@ -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; diff --git a/src/router/modules/flowchart.ts b/src/router/modules/flowchart.ts index 14871137a..4bf119377 100644 --- a/src/router/modules/flowchart.ts +++ b/src/router/modules/flowchart.ts @@ -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; diff --git a/src/router/modules/formdesign.ts b/src/router/modules/formdesign.ts index 90229774b..650668d5d 100644 --- a/src/router/modules/formdesign.ts +++ b/src/router/modules/formdesign.ts @@ -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; diff --git a/src/router/modules/guide.ts b/src/router/modules/guide.ts index decb59cb5..12c63c18f 100644 --- a/src/router/modules/guide.ts +++ b/src/router/modules/guide.ts @@ -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; diff --git a/src/router/modules/home.ts b/src/router/modules/home.ts index 34cc56523..2107866fe 100644 --- a/src/router/modules/home.ts +++ b/src/router/modules/home.ts @@ -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; diff --git a/src/router/modules/list.ts b/src/router/modules/list.ts index e304d1467..e6becf570 100644 --- a/src/router/modules/list.ts +++ b/src/router/modules/list.ts @@ -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; diff --git a/src/router/modules/nested.ts b/src/router/modules/nested.ts index ed045dec2..8fb9833ee 100644 --- a/src/router/modules/nested.ts +++ b/src/router/modules/nested.ts @@ -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; diff --git a/src/router/modules/ppt.ts b/src/router/modules/ppt.ts index 00f25ec08..5da80c4a5 100644 --- a/src/router/modules/ppt.ts +++ b/src/router/modules/ppt.ts @@ -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; diff --git a/src/router/modules/puredoc.ts b/src/router/modules/puredoc.ts new file mode 100644 index 000000000..1c2496daf --- /dev/null +++ b/src/router/modules/puredoc.ts @@ -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; diff --git a/src/router/modules/pureutils.ts b/src/router/modules/pureutils.ts new file mode 100644 index 000000000..dfbea7a17 --- /dev/null +++ b/src/router/modules/pureutils.ts @@ -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; diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 433e273a7..00cf759db 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -1,8 +1,7 @@ import { $t } from "@/plugins/i18n"; -import type { RouteConfigsTable } from "/#/index"; const Layout = () => import("@/layout/index.vue"); -const remainingRouter: Array = [ +export default [ { path: "/login", name: "Login", @@ -20,7 +19,7 @@ const remainingRouter: Array = [ icon: "home-filled", title: $t("menus.hshome"), showLink: false, - rank: 104 + rank: 102 }, children: [ { @@ -38,9 +37,7 @@ const remainingRouter: Array = [ meta: { title: $t("menus.hsempty"), showLink: false, - rank: 105 + rank: 103 } } -]; - -export default remainingRouter; +] as Array; diff --git a/src/router/modules/result.ts b/src/router/modules/result.ts index 0b74d0fb7..cc7ae51d3 100644 --- a/src/router/modules/result.ts +++ b/src/router/modules/result.ts @@ -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; diff --git a/src/router/modules/table.ts b/src/router/modules/table.ts index fa765d0d9..dfff9cf46 100644 --- a/src/router/modules/table.ts +++ b/src/router/modules/table.ts @@ -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; diff --git a/src/router/modules/tree.ts b/src/router/modules/tree.ts new file mode 100644 index 000000000..fac95bc19 --- /dev/null +++ b/src/router/modules/tree.ts @@ -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; diff --git a/src/router/types.ts b/src/router/types.ts deleted file mode 100644 index 139bf406f..000000000 --- a/src/router/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RouteLocationNormalized } from "vue-router"; - -export interface toRouteType extends RouteLocationNormalized { - meta: { - roles: Array; - keepAlive?: boolean; - dynamicLevel?: string; - }; -} diff --git a/src/router/utils.ts b/src/router/utils.ts index e15d59bcf..3e329654f 100644 --- a/src/router/utils.ts +++ b/src/router/utils.ts @@ -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"; diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts index 79a6acb4e..c26051306 100644 --- a/src/store/modules/app.ts +++ b/src/store/modules/app.ts @@ -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({ diff --git a/src/store/modules/epTheme.ts b/src/store/modules/epTheme.ts index 0df63117c..6db58d019 100644 --- a/src/store/modules/epTheme.ts +++ b/src/store/modules/epTheme.ts @@ -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({ diff --git a/src/store/modules/multiTags.ts b/src/store/modules/multiTags.ts index 504364e63..028897563 100644 --- a/src/store/modules/multiTags.ts +++ b/src/store/modules/multiTags.ts @@ -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"; diff --git a/src/utils/tree.ts b/src/utils/tree.ts new file mode 100644 index 000000000..f8f3783b8 --- /dev/null +++ b/src/utils/tree.ts @@ -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 = []; + 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) { + 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; +}; diff --git a/src/views/able/line-tree.vue b/src/views/able/line-tree.vue index bd84c8dbe..1a3b9c9f5 100644 --- a/src/views/able/line-tree.vue +++ b/src/views/able/line-tree.vue @@ -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({ diff --git a/src/views/able/menu-tree.vue b/src/views/able/menu-tree.vue index b804aa8af..ea9dc1bf0 100644 --- a/src/views/able/menu-tree.vue +++ b/src/views/able/menu-tree.vue @@ -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"; diff --git a/src/views/system/dept/index.vue b/src/views/system/dept/index.vue index 9571b5bba..222afd3b8 100644 --- a/src/views/system/dept/index.vue +++ b/src/views/system/dept/index.vue @@ -1,8 +1,8 @@ + + + + diff --git a/types/global.d.ts b/types/global.d.ts index a933c3de2..bce918c05 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -1,25 +1,21 @@ import type { - ComponentRenderProxy, VNode, - ComponentPublicInstance, FunctionalComponent, - PropType as VuePropType + PropType as VuePropType, + ComponentPublicInstance } from "vue"; import type { ECharts } from "echarts"; -import { type ResponsiveStorage } from "./index"; +import type { ResponsiveStorage } from "./index"; import type { TableColumns } from "@pureadmin/table"; +import { type RouteComponent, type RouteLocationNormalized } from "vue-router"; -// GlobalComponents for Volar -declare module "vue" { - export interface GlobalComponents { - IconifyIconOffline: typeof import("../src/components/ReIcon")["IconifyIconOffline"]; - IconifyIconOnline: typeof import("../src/components/ReIcon")["IconifyIconOnline"]; - FontIcon: typeof import("../src/components/ReIcon")["FontIcon"]; - Auth: typeof import("../src/components/ReAuth")["Auth"]; - } -} - +/** + * 全局类型声明,无需引入直接在 `.vue` 、`.ts` 、`.tsx` 文件使用即可获得类型提示 + */ declare global { + /** + * 平台的名称、版本、依赖、最后构建时间的类型提示 + */ const __APP_INFO__: { pkg: { name: string; @@ -29,6 +25,10 @@ declare global { }; lastBuildTime: string; }; + + /** + * Window 的类型提示 + */ interface Window { // Global vue app instance __APP__: App; @@ -42,39 +42,9 @@ declare global { msRequestAnimationFrame: (callback: FrameRequestCallback) => number; } - // vue - type PropType = VuePropType; - - type Writable = { - -readonly [P in keyof T]: T[P]; - }; - - type Nullable = T | null; - type NonNullable = T extends null | undefined ? never : T; - type Recordable = Record; - type ReadonlyRecordable = { - readonly [key: string]: T; - }; - type Indexable = { - [key: string]: T; - }; - type DeepPartial = { - [P in keyof T]?: DeepPartial; - }; - type TimeoutHandle = ReturnType; - type IntervalHandle = ReturnType; - - interface ChangeEvent extends Event { - target: HTMLInputElement; - } - - interface WheelEvent { - path?: EventTarget[]; - } - interface ImportMetaEnv extends ViteEnv { - __: unknown; - } - + /** + * 打包压缩格式的类型声明 + */ type ViteCompression = | "none" | "gzip" @@ -84,7 +54,11 @@ declare global { | "brotli-clear" | "both-clear"; - declare interface ViteEnv { + /** + * 全局自定义环境变量的类型声明 + * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#%E5%85%B7%E4%BD%93%E9%85%8D%E7%BD%AE} + */ + interface ViteEnv { VITE_PORT: number; VITE_PUBLIC_PATH: string; VITE_ROUTER_HISTORY: string; @@ -92,7 +66,16 @@ declare global { VITE_COMPRESSION: ViteCompression; } - declare interface ServerConfigs { + /** + * 继承 `@pureadmin/table` 的 `TableColumns` ,方便全局直接调用 + */ + interface TableColumnList extends Array {} + + /** + * 对应 `public/serverConfig.json` 文件的类型声明 + * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#serverconfig-json} + */ + interface ServerConfigs { Version?: string; Title?: string; FixedHeader?: boolean; @@ -121,32 +104,176 @@ declare global { }; } - declare interface GlobalPropertiesApi { + /** + * 与 `ServerConfigs` 类型不同,这里是缓存到浏览器本地存储的类型声明 + * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/config/#serverconfig-json} + */ + interface StorageConfigs { + version?: string; + title?: string; + fixedHeader?: boolean; + hiddenSideBar?: boolean; + multiTagsCache?: boolean; + keepAlive?: boolean; + locale?: string; + layout?: string; + theme?: string; + darkMode?: boolean; + grey?: boolean; + weak?: boolean; + hideTabs?: boolean; + sidebarStatus?: boolean; + epThemeColor?: string; + showLogo?: boolean; + showModel?: string; + mapConfigure?: { + amapKey?: string; + options: { + resizeEnable?: boolean; + center?: number[]; + zoom?: number; + }; + }; + username?: string; + } + + /** + * `responsive-storage` 本地响应式 `storage` 的类型声明 + */ + interface ResponsiveStorage { + locale: { + locale?: string; + }; + layout: { + layout?: string; + theme?: string; + darkMode?: boolean; + sidebarStatus?: boolean; + epThemeColor?: string; + }; + configure: { + grey?: boolean; + weak?: boolean; + hideTabs?: boolean; + showLogo?: boolean; + showModel?: string; + multiTagsCache?: boolean; + }; + tags?: Array; + } + + /** + * `src/router` 文件夹里的类型声明 + */ + interface toRouteType extends RouteLocationNormalized { + meta: { + roles: Array; + keepAlive?: boolean; + dynamicLevel?: string; + }; + } + + /** + * @description 完整子路由配置表 + */ + interface RouteChildrenConfigsTable { + /** 子路由地址 `必填` */ + path: string; + /** 路由名字(对应不要重复,和当前组件的`name`保持一致)`必填` */ + name?: string; + /** 路由重定向 `可选` */ + redirect?: string; + /** 按需加载组件 `可选` */ + component?: RouteComponent; + meta?: { + /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加) `必填` */ + title: string; + /** 菜单图标 `可选` */ + icon?: string | FunctionalComponent; + /** 菜单名称右侧的额外图标,支持`fontawesome`、`iconfont`、`element-plus-icon` `可选` */ + extraIcon?: { + svg?: boolean; + name?: string; + }; + /** 是否在菜单中显示(默认`true`)`可选` */ + showLink?: boolean; + /** 是否显示父级菜单 `可选` */ + showParent?: boolean; + /** 页面级别权限设置 `可选` */ + roles?: Array; + /** 按钮级别权限设置 `可选` */ + auths?: Array; + /** 路由组件缓存(开启 `true`、关闭 `false`)`可选` */ + keepAlive?: boolean; + /** 内嵌的`iframe`链接 `可选` */ + frameSrc?: string; + /** `iframe`页是否开启首次加载动画(默认`true`)`可选` */ + frameLoading?: boolean; + /** 页面加载动画(有两种形式,一种直接采用vue内置的`transitions`动画,另一种是使用`animate.css`写进、离场动画)`可选` */ + transition?: { + /** + * @description 当前路由动画效果 + * @see {@link https://next.router.vuejs.org/guide/advanced/transitions.html#transitions} + */ + name?: string; + /** 进场动画 */ + enterTransition?: string; + /** 离场动画 */ + leaveTransition?: string; + }; + // 是否不添加信息到标签页,(默认`false`) + hiddenTag?: boolean; + /** 动态路由可打开的最大数量 `可选` */ + dynamicLevel?: number; + }; + /** 子路由配置项 */ + children?: Array; + } + + /** + * @description 整体路由配置表(包括完整子路由) + */ + interface RouteConfigsTable { + /** 路由地址 `必填` */ + path: string; + /** 路由名字(保持唯一)`可选` */ + name?: string; + /** `Layout`组件 `可选` */ + component?: RouteComponent; + /** 路由重定向 `可选` */ + redirect?: string; + meta?: { + /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加)`必填` */ + title: string; + /** 菜单图标 `可选` */ + icon?: string | FunctionalComponent; + /** 是否在菜单中显示(默认`true`)`可选` */ + showLink?: boolean; + /** 菜单升序排序,值越高排的越后(只针对顶级路由)`可选` */ + rank?: number; + }; + /** 子路由配置项 */ + children?: Array; + } + + /** + * 平台里所有组件实例都能访问到的全局属性对象的类型声明 + */ + interface GlobalPropertiesApi { $echarts: ECharts; $storage: ResponsiveStorage; $config: ServerConfigs; } +} - // 继承 @pureadmin/table 的 TableColumns,方便全局直接调用 - declare interface TableColumnList extends Array {} - - function parseInt(s: string | number, radix?: number): number; - - function parseFloat(string: string | number): number; - - namespace JSX { - // tslint:disable no-empty-interface - type Element = VNode; - // tslint:disable no-empty-interface - type ElementClass = ComponentRenderProxy; - interface ElementAttributesProperty { - $props: any; - } - interface IntrinsicElements { - [elem: string]: any; - } - interface IntrinsicAttributes { - [elem: string]: any; - } +declare module "vue" { + /** + * 自定义全局组件获得 Volar 提示(自定义的全局组件需要在这里声明下才能获得 Volar 类型提示哦) + */ + export interface GlobalComponents { + IconifyIconOffline: typeof import("../src/components/ReIcon")["IconifyIconOffline"]; + IconifyIconOnline: typeof import("../src/components/ReIcon")["IconifyIconOnline"]; + FontIcon: typeof import("../src/components/ReIcon")["FontIcon"]; + Auth: typeof import("../src/components/ReAuth")["Auth"]; } } diff --git a/types/index.d.ts b/types/index.d.ts index 215d92331..8fddd8f5f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,33 +1,74 @@ -declare interface Fn { - (...arg: T[]): R; -} +// 此文件跟同级目录的 global.d.ts 文件一样也是全局类型声明,只不过这里存放一些零散的全局类型,无需引入直接在 .vue 、.ts 、.tsx 文件使用即可获得类型提示 -declare interface PromiseFn { - (...arg: T[]): Promise; -} +type RefType = T | null; -declare type RefType = T | null; +type EmitType = (event: string, ...args: any[]) => void; -declare type LabelValueOptions = { - label: string; - value: any; -}[]; +type TargetContext = "_self" | "_blank"; -declare type EmitType = (event: string, ...args: any[]) => void; - -declare type TargetContext = "_self" | "_blank"; - -declare interface ComponentElRef { - $el: T; -} - -declare type ComponentRef = +type ComponentRef = ComponentElRef | null; -declare type ElRef = Nullable; +type ElRef = Nullable; -declare type ForDataType = { +type ForDataType = { [P in T]?: ForDataType; }; -declare type AnyFunction = (...args: any[]) => T; +type AnyFunction = (...args: any[]) => T; + +type PropType = VuePropType; + +type Writable = { + -readonly [P in keyof T]: T[P]; +}; + +type Nullable = T | null; + +type NonNullable = T extends null | undefined ? never : T; + +type Recordable = Record; + +type ReadonlyRecordable = { + readonly [key: string]: T; +}; + +type Indexable = { + [key: string]: T; +}; + +type DeepPartial = { + [P in keyof T]?: DeepPartial; +}; + +type TimeoutHandle = ReturnType; + +type IntervalHandle = ReturnType; + +interface ChangeEvent extends Event { + target: HTMLInputElement; +} + +interface WheelEvent { + path?: EventTarget[]; +} + +interface ImportMetaEnv extends ViteEnv { + __: unknown; +} + +interface Fn { + (...arg: T[]): R; +} + +interface PromiseFn { + (...arg: T[]): Promise; +} + +interface ComponentElRef { + $el: T; +} + +function parseInt(s: string | number, radix?: number): number; + +function parseFloat(string: string | number): number; diff --git a/types/index.ts b/types/index.ts deleted file mode 100644 index 9c3056a50..000000000 --- a/types/index.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { type FunctionalComponent } from "vue"; -import { type RouteComponent } from "vue-router"; - -export interface StorageConfigs { - version?: string; - title?: string; - fixedHeader?: boolean; - hiddenSideBar?: boolean; - multiTagsCache?: boolean; - keepAlive?: boolean; - locale?: string; - layout?: string; - theme?: string; - darkMode?: boolean; - grey?: boolean; - weak?: boolean; - hideTabs?: boolean; - sidebarStatus?: boolean; - epThemeColor?: string; - showLogo?: boolean; - showModel?: string; - mapConfigure?: { - amapKey?: string; - options: { - resizeEnable?: boolean; - center?: number[]; - zoom?: number; - }; - }; - username?: string; -} - -export interface ResponsiveStorage { - locale: { - locale?: string; - }; - layout: { - layout?: string; - theme?: string; - darkMode?: boolean; - sidebarStatus?: boolean; - epThemeColor?: string; - }; - configure: { - grey?: boolean; - weak?: boolean; - hideTabs?: boolean; - showLogo?: boolean; - showModel?: string; - multiTagsCache?: boolean; - }; - tags?: Array; -} - -export interface RouteChildrenConfigsTable { - /** 子路由地址 `必填` */ - path: string; - /** 路由名字(对应不要重复,和当前组件的`name`保持一致)`必填` */ - name?: string; - /** 路由重定向 `可选` */ - redirect?: string; - /** 按需加载组件 `可选` */ - component?: RouteComponent; - meta?: { - /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加) `必填` */ - title: string; - /** 菜单图标 `可选` */ - icon?: string | FunctionalComponent; - /** 菜单名称右侧的额外图标,支持`fontawesome`、`iconfont`、`element-plus-icon` `可选` */ - extraIcon?: { - svg?: boolean; - name?: string; - }; - /** 是否在菜单中显示(默认`true`)`可选` */ - showLink?: boolean; - /** 是否显示父级菜单 `可选` */ - showParent?: boolean; - /** 页面级别权限设置 `可选` */ - roles?: Array; - /** 按钮级别权限设置 `可选` */ - auths?: Array; - /** 路由组件缓存(开启 `true`、关闭 `false`)`可选` */ - keepAlive?: boolean; - /** 内嵌的`iframe`链接 `可选` */ - frameSrc?: string; - /** `iframe`页是否开启首次加载动画(默认`true`)`可选` */ - frameLoading?: boolean; - /** 页面加载动画(有两种形式,一种直接采用vue内置的`transitions`动画,另一种是使用`animate.css`写进、离场动画)`可选` */ - transition?: { - /** - * @description 当前路由动画效果 - * @see {@link https://next.router.vuejs.org/guide/advanced/transitions.html#transitions} - */ - name?: string; - /** 进场动画 */ - enterTransition?: string; - /** 离场动画 */ - leaveTransition?: string; - }; - // 是否不添加信息到标签页,(默认`false`) - hiddenTag?: boolean; - /** 动态路由可打开的最大数量 `可选` */ - dynamicLevel?: number; - }; - /** 子路由配置项 */ - children?: Array; -} - -/** - * @description 完整路由配置表 - * @see {@link https://yiming_chang.gitee.io/pure-admin-doc/pages/782b6e/#%E4%B8%80-%E9%85%8D%E7%BD%AE%E9%A1%B9} - */ -export interface RouteConfigsTable { - /** 路由地址 `必填` */ - path: string; - /** 路由名字(保持唯一)`可选` */ - name?: string; - /** `Layout`组件 `可选` */ - component?: RouteComponent; - /** 路由重定向 `可选` */ - redirect?: string; - meta?: { - /** 菜单名称(兼容国际化、非国际化,如何用国际化的写法就必须在根目录的`locales`文件夹下对应添加)`必填` */ - title: string; - /** 菜单图标 `可选` */ - icon?: string | FunctionalComponent; - /** 是否在菜单中显示(默认`true`)`可选` */ - showLink?: boolean; - /** 菜单升序排序,值越高排的越后(只针对顶级路由)`可选` */ - rank?: number; - }; - /** 子路由配置项 */ - children?: Array; -} diff --git a/types/shims-tsx.d.ts b/types/shims-tsx.d.ts index 4d21788cc..199f97935 100644 --- a/types/shims-tsx.d.ts +++ b/types/shims-tsx.d.ts @@ -9,8 +9,14 @@ declare global { namespace JSX { interface Element extends VNode {} interface ElementClass extends Vue {} + interface ElementAttributesProperty { + $props: any; + } interface IntrinsicElements { [elem: string]: any; } + interface IntrinsicAttributes { + [elem: string]: any; + } } }