From 7a2b3a9d849e4f437671ecadec4d78cc4423c0b5 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 13 Aug 2023 08:09:39 +0800 Subject: [PATCH 01/21] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E4=BE=9D?= =?UTF-8?q?=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 67b5de9..565f7aa 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "dependencies": { "@iconify/iconify": "^3.1.1", "@iconify/vue": "^4.1.1", - "@vueuse/core": "^10.2.1", + "@vueuse/core": "^10.3.0", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10", "@zxcvbn-ts/core": "^3.0.3", @@ -37,13 +37,13 @@ "dayjs": "^1.11.9", "echarts": "^5.4.3", "echarts-wordcloud": "^2.1.0", - "element-plus": "^2.3.8", + "element-plus": "^2.3.9", "intro.js": "^7.0.1", "lodash-es": "^4.17.21", "mitt": "^3.0.1", "mockjs": "^1.1.0", "nprogress": "^0.2.0", - "pinia": "^2.1.4", + "pinia": "^2.1.6", "pinia-plugin-persist": "^1.0.0", "qrcode": "^1.5.3", "qs": "^6.11.2", @@ -52,55 +52,55 @@ "vue": "3.3.4", "vue-i18n": "9.2.2", "vue-router": "^4.2.4", - "vue-types": "^5.1.0" + "vue-types": "^5.1.1" }, "devDependencies": { - "@commitlint/cli": "^17.6.7", - "@commitlint/config-conventional": "^17.6.7", - "@iconify/json": "^2.2.92", + "@commitlint/cli": "^17.7.1", + "@commitlint/config-conventional": "^17.7.0", + "@iconify/json": "^2.2.101", "@intlify/unplugin-vue-i18n": "^0.12.2", "@purge-icons/generated": "^0.9.0", "@types/intro.js": "^5.1.1", "@types/lodash-es": "^4.17.8", - "@types/node": "^20.4.2", + "@types/node": "^20.4.10", "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.5.1", "@types/qs": "^6.9.7", "@types/sortablejs": "^1.15.1", - "@typescript-eslint/eslint-plugin": "^6.1.0", - "@typescript-eslint/parser": "^6.1.0", - "@unocss/transformer-variant-group": "^0.53.5", - "@vitejs/plugin-legacy": "^4.1.0", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", + "@unocss/transformer-variant-group": "^0.55.0", + "@vitejs/plugin-legacy": "^4.1.1", "@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue-jsx": "^3.0.1", - "@vue-macros/volar": "^0.12.2", + "@vue-macros/volar": "^0.13.3", "autoprefixer": "^10.4.14", "consola": "^3.2.3", - "eslint": "^8.45.0", - "eslint-config-prettier": "^8.8.0", - "eslint-define-config": "^1.21.0", + "eslint": "^8.47.0", + "eslint-config-prettier": "^9.0.0", + "eslint-define-config": "^1.23.0", "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-vue": "^9.15.1", + "eslint-plugin-vue": "^9.17.0", "husky": "^8.0.3", - "less": "^4.1.3", + "less": "^4.2.0", "lint-staged": "^13.2.3", "plop": "^3.1.2", - "postcss": "^8.4.26", + "postcss": "^8.4.27", "postcss-html": "^1.5.0", "postcss-less": "^6.0.0", - "prettier": "^3.0.0", + "prettier": "^3.0.1", "rimraf": "^5.0.1", - "rollup": "^3.26.3", - "stylelint": "^15.10.1", + "rollup": "^3.28.0", + "stylelint": "^15.10.2", "stylelint-config-html": "^1.1.0", "stylelint-config-recommended": "^13.0.0", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", - "terser": "^5.19.1", + "terser": "^5.19.2", "typescript": "5.1.6", - "unocss": "^0.53.5", - "unplugin-vue-define-options": "^1.3.11", - "vite": "4.4.4", + "unocss": "^0.55.0", + "unplugin-vue-define-options": "^1.3.15", + "vite": "4.4.9", "vite-plugin-ejs": "^1.6.4", "vite-plugin-eslint": "^1.8.1", "vite-plugin-mock": "2.9.6", @@ -108,7 +108,7 @@ "vite-plugin-purge-icons": "^0.9.2", "vite-plugin-style-import": "2.0.0", "vite-plugin-svg-icons": "^2.0.1", - "vue-tsc": "^1.8.5" + "vue-tsc": "^1.8.8" }, "engines": { "node": ">= 14.18.0" From a869a457e6a8052531ce3040ae0d332d7afbb478 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 13 Aug 2023 14:06:54 +0800 Subject: [PATCH 02/21] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9EuseTagsView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mock/role/index.ts | 10 +-- .../Menu/src/components/useRenderMenuItem.tsx | 4 +- src/components/TagsView/src/TagsView.vue | 85 +++++++++---------- src/hooks/web/useTagsView.ts | 58 +++++++++++++ src/router/index.ts | 8 ++ src/store/modules/tagsView.ts | 13 ++- src/views/hooks/useTagsView.vue | 50 +++++++++++ 7 files changed, 176 insertions(+), 52 deletions(-) create mode 100644 src/hooks/web/useTagsView.ts create mode 100644 src/views/hooks/useTagsView.vue diff --git a/mock/role/index.ts b/mock/role/index.ts index decf4ba..b109441 100644 --- a/mock/role/index.ts +++ b/mock/role/index.ts @@ -323,11 +323,11 @@ const adminList = [ } }, { - path: 'useOpenTab', - component: 'views/hooks/useOpenTab', - name: 'UseOpenTab', + path: 'useTagsView', + component: 'views/hooks/useTagsView', + name: 'UseTagsView', meta: { - title: 'useOpenTab' + title: 'useTagsView' } } // { @@ -597,7 +597,7 @@ const testList: string[] = [ '/function/multiple-tabs-demo/:id', '/hooks', '/hooks/useWatermark', - '/hooks/useOpenTab', + '/hooks/useTagsView', // '/hooks/useCrudSchemas', '/level', '/level/menu1', diff --git a/src/components/Menu/src/components/useRenderMenuItem.tsx b/src/components/Menu/src/components/useRenderMenuItem.tsx index 17a520a..2aacbf1 100644 --- a/src/components/Menu/src/components/useRenderMenuItem.tsx +++ b/src/components/Menu/src/components/useRenderMenuItem.tsx @@ -6,6 +6,8 @@ import { useRenderMenuTitle } from './useRenderMenuTitle' import { useDesign } from '@/hooks/web/useDesign' import { pathResolve } from '@/utils/routerHelper' +const { renderMenuTitle } = useRenderMenuTitle() + export const useRenderMenuItem = ( // allRouters: AppRouteRecordRaw[] = [], menuMode: 'vertical' | 'horizontal' @@ -17,8 +19,6 @@ export const useRenderMenuItem = ( const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v) const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath(allRouters, v.path).join('/') - const { renderMenuTitle } = useRenderMenuTitle() - if ( oneShowingChild && (!onlyOneChild?.children || onlyOneChild?.noShowingChildren) && diff --git a/src/components/TagsView/src/TagsView.vue b/src/components/TagsView/src/TagsView.vue index 3eb2d98..5c7d68e 100644 --- a/src/components/TagsView/src/TagsView.vue +++ b/src/components/TagsView/src/TagsView.vue @@ -12,6 +12,7 @@ import { useDesign } from '@/hooks/web/useDesign' import { useTemplateRefsList } from '@vueuse/core' import { ElScrollbar } from 'element-plus' import { useScrollTo } from '@/hooks/event/useScrollTo' +import { useTagsView } from '@/hooks/web/useTagsView' const { getPrefixCls } = useDesign() @@ -19,7 +20,9 @@ const prefixCls = getPrefixCls('tags-view') const { t } = useI18n() -const { currentRoute, push, replace } = useRouter() +const { currentRoute, push } = useRouter() + +const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTagsView() const permissionStore = usePermissionStore() @@ -31,6 +34,10 @@ const visitedViews = computed(() => tagsViewStore.getVisitedViews) const affixTagArr = ref([]) +const selectedTag = computed(() => tagsViewStore.getSelectedTag) + +const setSelectTag = tagsViewStore.setSelectedTag + const appStore = useAppStore() const tagsViewIcon = computed(() => appStore.getTagsViewIcon) @@ -48,61 +55,25 @@ const initTags = () => { } } -const selectedTag = ref() - // 新增tag const addTags = () => { const { name } = unref(currentRoute) if (name) { - selectedTag.value = unref(currentRoute) + setSelectTag(unref(currentRoute)) tagsViewStore.addView(unref(currentRoute)) } - return false } // 关闭选中的tag const closeSelectedTag = (view: RouteLocationNormalizedLoaded) => { - if (view?.meta?.affix) return - tagsViewStore.delView(view) - if (isActive(view)) { - toLastView() - } -} - -// 关闭全部 -const closeAllTags = () => { - tagsViewStore.delAllViews() - toLastView() -} - -// 关闭其它 -const closeOthersTags = () => { - tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 重新加载 -const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => { - if (!view) return - tagsViewStore.delCachedView() - const { path, query } = view - await nextTick() - replace({ - path: '/redirect' + path, - query: query + closeCurrent(view, () => { + if (isActive(view)) { + toLastView() + } }) } -// 关闭左侧 -const closeLeftTags = () => { - tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 关闭右侧 -const closeRightTags = () => { - tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded) -} - -// 跳转到最后一个 +// 去最后一个 const toLastView = () => { const visitedViews = tagsViewStore.getVisitedViews const latestView = visitedViews.slice(-1)[0] @@ -121,6 +92,33 @@ const toLastView = () => { } } +// 关闭全部 +const closeAllTags = () => { + closeAll(() => { + toLastView() + }) +} + +// 关闭其它 +const closeOthersTags = () => { + closeOther() +} + +// 重新加载 +const refreshSelectedTag = async (view?: RouteLocationNormalizedLoaded) => { + refreshPage(view) +} + +// 关闭左侧 +const closeLeftTags = () => { + closeLeft() +} + +// 关闭右侧 +const closeRightTags = () => { + closeRight() +} + // 滚动到选中的tag const moveToCurrentTag = async () => { await nextTick() @@ -583,3 +581,4 @@ watch( } } +@/hooks/web/useTagsView diff --git a/src/hooks/web/useTagsView.ts b/src/hooks/web/useTagsView.ts new file mode 100644 index 0000000..d236a1e --- /dev/null +++ b/src/hooks/web/useTagsView.ts @@ -0,0 +1,58 @@ +import { useTagsViewStoreWithOut } from '@/store/modules/tagsView' +import { RouteLocationNormalizedLoaded, useRouter } from 'vue-router' +import { computed, nextTick, unref } from 'vue' + +export const useTagsView = () => { + const tagsViewStore = useTagsViewStoreWithOut() + + const { replace, currentRoute } = useRouter() + + const selectedTag = computed(() => tagsViewStore.getSelectedTag) + + const closeAll = (callback?: Fn) => { + tagsViewStore.delAllViews() + callback?.() + } + + const closeLeft = (callback?: Fn) => { + tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded) + callback?.() + } + + const closeRight = (callback?: Fn) => { + tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded) + callback?.() + } + + const closeOther = (callback?: Fn) => { + tagsViewStore.delOthersViews(unref(selectedTag) as RouteLocationNormalizedLoaded) + callback?.() + } + + const closeCurrent = (view?: RouteLocationNormalizedLoaded, callback?: Fn) => { + if (view?.meta?.affix) return + tagsViewStore.delView(view || unref(currentRoute)) + + callback?.() + } + + const refreshPage = async (view?: RouteLocationNormalizedLoaded, callback?: Fn) => { + tagsViewStore.delCachedView() + const { path, query } = view || unref(currentRoute) + await nextTick() + replace({ + path: '/redirect' + path, + query: query + }) + callback?.() + } + + return { + closeAll, + closeLeft, + closeRight, + closeOther, + closeCurrent, + refreshPage + } +} diff --git a/src/router/index.ts b/src/router/index.ts index 0e37e54..cccf263 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -362,6 +362,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ meta: { title: 'useWatermark' } + }, + { + path: 'useTagsView', + component: () => import('@/views/hooks/useTagsView.vue'), + name: 'UseTagsView', + meta: { + title: 'useTagsView' + } } // { // path: 'useCrudSchemas', diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index 34281ef..483687b 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -8,12 +8,14 @@ import { findIndex } from '@/utils' export interface TagsViewState { visitedViews: RouteLocationNormalizedLoaded[] cachedViews: Set + selectedTag?: RouteLocationNormalizedLoaded } export const useTagsViewStore = defineStore('tagsView', { state: (): TagsViewState => ({ visitedViews: [], - cachedViews: new Set() + cachedViews: new Set(), + selectedTag: undefined }), getters: { getVisitedViews(): RouteLocationNormalizedLoaded[] { @@ -21,6 +23,9 @@ export const useTagsViewStore = defineStore('tagsView', { }, getCachedViews(): string[] { return Array.from(this.cachedViews) + }, + getSelectedTag(): RouteLocationNormalizedLoaded | undefined { + return this.selectedTag } }, actions: { @@ -85,7 +90,7 @@ export const useTagsViewStore = defineStore('tagsView', { // 删除所有tag delAllVisitedViews() { // const affixTags = this.visitedViews.filter((tag) => tag.meta.affix) - this.visitedViews = [] + this.visitedViews = this.visitedViews.filter((tag) => tag.meta?.affix) }, // 删除其它 delOthersViews(view: RouteLocationNormalizedLoaded) { @@ -131,6 +136,10 @@ export const useTagsViewStore = defineStore('tagsView', { break } } + }, + // 设置当前选中的tag + setSelectedTag(tag: RouteLocationNormalizedLoaded) { + this.selectedTag = tag } } }) diff --git a/src/views/hooks/useTagsView.vue b/src/views/hooks/useTagsView.vue new file mode 100644 index 0000000..c267d9c --- /dev/null +++ b/src/views/hooks/useTagsView.vue @@ -0,0 +1,50 @@ + + + +@/hooks/web/useTagsView From 175abd0aa3388e8473f6ecbf63e28133fce55bd3 Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 13 Aug 2023 14:25:49 +0800 Subject: [PATCH 03/21] =?UTF-8?q?perf:=20=E5=AE=8C=E5=96=84useTagsView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/web/useTagsView.ts | 7 ++++++- src/router/index.ts | 3 ++- src/store/modules/tagsView.ts | 8 ++++++++ src/views/Function/MultipleTabsDemo.vue | 5 +++++ src/views/hooks/useTagsView.vue | 9 +++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/hooks/web/useTagsView.ts b/src/hooks/web/useTagsView.ts index d236a1e..6d78d6c 100644 --- a/src/hooks/web/useTagsView.ts +++ b/src/hooks/web/useTagsView.ts @@ -47,12 +47,17 @@ export const useTagsView = () => { callback?.() } + const setTitle = (title: string) => { + tagsViewStore.setTitle(title) + } + return { closeAll, closeLeft, closeRight, closeOther, closeCurrent, - refreshPage + refreshPage, + setTitle } } diff --git a/src/router/index.ts b/src/router/index.ts index cccf263..a20413a 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -339,7 +339,8 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [ meta: { hidden: true, title: t('router.details'), - canTo: true + canTo: true, + activeMenu: '/function/multiple-tabs' } } ] diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts index 483687b..df511e1 100644 --- a/src/store/modules/tagsView.ts +++ b/src/store/modules/tagsView.ts @@ -140,6 +140,14 @@ export const useTagsViewStore = defineStore('tagsView', { // 设置当前选中的tag setSelectedTag(tag: RouteLocationNormalizedLoaded) { this.selectedTag = tag + }, + setTitle(title: string) { + for (const v of this.visitedViews) { + if (v.path === this.selectedTag?.path) { + v.meta.title = title + break + } + } } } }) diff --git a/src/views/Function/MultipleTabsDemo.vue b/src/views/Function/MultipleTabsDemo.vue index e8089bd..9421a9a 100644 --- a/src/views/Function/MultipleTabsDemo.vue +++ b/src/views/Function/MultipleTabsDemo.vue @@ -3,10 +3,15 @@ import { ContentWrap } from '@/components/ContentWrap' import { ElInput } from 'element-plus' import { ref } from 'vue' import { useRoute } from 'vue-router' +import { useTagsView } from '@/hooks/web/useTagsView' + +const { setTitle } = useTagsView() const { params } = useRoute() const val = ref(params.id as string) + +setTitle(`详情页-${val.value}`)