mirror of
				https://github.com/continew-org/continew-admin-ui.git
				synced 2025-10-31 10:57:10 +08:00 
			
		
		
		
	fix: 修复切换 tab 页签后参数丢失的问题
同步 Gi Demo 升级
This commit is contained in:
		| @@ -6,11 +6,11 @@ | ||||
|       size="medium" | ||||
|       :type="appStore.tabMode" | ||||
|       :active-key="route.path" | ||||
|       @tab-click="(key) => handleTabClick(key as string)" | ||||
|       @delete="tabsStore.closeCurrent" | ||||
|       @tab-click="handleTabClick($event as string)" | ||||
|       @delete="tabsStore.closeCurrent($event as string)" | ||||
|     > | ||||
|       <a-tab-pane | ||||
|         v-for="item of tabsStore.tagList" | ||||
|         v-for="item of tabsStore.tabList" | ||||
|         :key="item.path" | ||||
|         :title="(item.meta?.title as string)" | ||||
|         :closable="Boolean(!item.meta?.affix)" | ||||
| @@ -24,6 +24,10 @@ | ||||
|               <template #icon><icon-close /></template> | ||||
|               <template #default>关闭当前</template> | ||||
|             </a-doption> | ||||
|             <a-doption @click="tabsStore.closeRight(route.path)"> | ||||
|               <template #icon><icon-close /></template> | ||||
|               <template #default>关闭右侧</template> | ||||
|             </a-doption> | ||||
|             <a-doption @click="tabsStore.closeOther(route.path)"> | ||||
|               <template #icon><icon-eraser /></template> | ||||
|               <template #default>关闭其他</template> | ||||
| @@ -40,7 +44,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import type { RouteRecordRaw } from 'vue-router' | ||||
| import type { RouteLocationNormalized } from 'vue-router' | ||||
| import MagicIcon from './MagicIcon.vue' | ||||
| import { useAppStore, useTabsStore } from '@/stores' | ||||
|  | ||||
| @@ -51,22 +55,22 @@ const appStore = useAppStore() | ||||
| const tabsStore = useTabsStore() | ||||
|  | ||||
| // 重置, 同时把 affix: true 的路由筛选出来 | ||||
| tabsStore.reset() | ||||
| tabsStore.init() | ||||
|  | ||||
| // 路由发生改变触发 | ||||
| const handleRouteChange = () => { | ||||
|   const item = { ...route } as unknown as RouteRecordRaw | ||||
|   tabsStore.addTagItem(toRaw(item)) | ||||
|   const item = { ...route } as unknown as RouteLocationNormalized | ||||
|   tabsStore.addTabItem(toRaw(item)) | ||||
|   tabsStore.addCacheItem(toRaw(item)) | ||||
|   // console.log('路由对象', toRaw(item)) | ||||
|   // console.log('tagList', toRaw(tabsStore.tagList)) | ||||
|   // console.log('tagList', toRaw(tabsStore.tabList)) | ||||
|   // console.log('cacheList', toRaw(tabsStore.cacheList)) | ||||
| } | ||||
| handleRouteChange() | ||||
|  | ||||
| // 监听路由变化 | ||||
| watch( | ||||
|   () => route.path, | ||||
|   () => route.fullPath, | ||||
|   () => { | ||||
|     handleRouteChange() | ||||
|   } | ||||
| @@ -74,7 +78,8 @@ watch( | ||||
|  | ||||
| // 点击页签 | ||||
| const handleTabClick = (key: string) => { | ||||
|   router.push({ path: key }) | ||||
|   const obj = tabsStore.tabList.find((i) => i.path === key) | ||||
|   obj ? router.push(obj.fullPath) : router.push(key) | ||||
| } | ||||
| </script> | ||||
|  | ||||
|   | ||||
| @@ -1,59 +1,61 @@ | ||||
| import { defineStore } from 'pinia' | ||||
| import { ref } from 'vue' | ||||
| import type { RouteRecordName, RouteRecordRaw } from 'vue-router' | ||||
| import { type RouteLocationNormalized, type RouteRecordName, useRouter } from 'vue-router' | ||||
| import _XEUtils_ from 'xe-utils' | ||||
| import router from '@/router' | ||||
| import { useRouteStore } from '@/stores' | ||||
|  | ||||
| const storeSetup = () => { | ||||
|   const tagList = ref<RouteRecordRaw[]>([]) // 保存页签tab的数组 | ||||
|   const cacheList = ref<RouteRecordName[]>([]) // keep-alive缓存的数组, 元素是组件名 | ||||
|   const router = useRouter() | ||||
|   const tabList = ref<RouteLocationNormalized[]>([]) // 保存页签tab的数组 | ||||
|   const cacheList = ref<RouteRecordName[]>([]) // keep-alive缓存的数组,元素是组件名 | ||||
|  | ||||
|   // 添加一个页签, 如果当前路由已经打开, 则不再重复添加 | ||||
|   const addTagItem = (item: RouteRecordRaw) => { | ||||
|     if (tagList.value.some((i) => i.path === item.path)) return | ||||
|   const addTabItem = (item: RouteLocationNormalized) => { | ||||
|     const index = tabList.value.findIndex((i) => i.path === item.path) | ||||
|     if (index >= 0) { | ||||
|       tabList.value[index].fullPath !== item.fullPath && (tabList.value[index] = item) | ||||
|     } else { | ||||
|       if (item.meta?.showInTabs ?? true) { | ||||
|       tagList.value.push(item) | ||||
|         tabList.value.push(item) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // 删除一个页签 | ||||
|   const deleteTagItem = (path: string) => { | ||||
|     const index = tagList.value.findIndex((item) => item.path === path && !item.meta?.affix) | ||||
|     if (index >= 0) { | ||||
|       const isActive = router.currentRoute.value.path === tagList.value[index]['path'] | ||||
|       tagList.value.splice(index, 1) | ||||
|   const deleteTabItem = (path: string) => { | ||||
|     const index = tabList.value.findIndex((item) => item.path === path && !item.meta?.affix) | ||||
|     if (index < 0) return | ||||
|     const isActive = router.currentRoute.value.path === tabList.value[index].path | ||||
|     tabList.value.splice(index, 1) | ||||
|     if (isActive) { | ||||
|         router.push({ path: tagList.value[tagList.value.length - 1]['path'] }) | ||||
|       } | ||||
|       router.push(tabList.value[tabList.value.length - 1].fullPath) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // 清空页签 | ||||
|   const clearTagList = () => { | ||||
|   const clearTabList = () => { | ||||
|     const routeStore = useRouteStore() | ||||
|     const arr: RouteRecordRaw[] = [] | ||||
|     const arr: RouteLocationNormalized[] = [] | ||||
|     _XEUtils_.eachTree(routeStore.routes, (item) => { | ||||
|       if (item.meta?.affix ?? false) { | ||||
|         arr.push(item) | ||||
|         arr.push(item as unknown as RouteLocationNormalized) | ||||
|       } | ||||
|     }) | ||||
|     tagList.value = arr | ||||
|     tabList.value = arr | ||||
|   } | ||||
|  | ||||
|   // 添加缓存页 | ||||
|   const addCacheItem = (item: RouteRecordRaw) => { | ||||
|     if (item.name) { | ||||
|   const addCacheItem = (item: RouteLocationNormalized) => { | ||||
|     if (!item.name) return | ||||
|     if (cacheList.value.includes(item.name)) return | ||||
|     if (item.meta?.keepAlive) { | ||||
|       cacheList.value.push(item.name) | ||||
|     } | ||||
|   } | ||||
|   } | ||||
|  | ||||
|   // 删除一个缓存页 | ||||
|   const deleteCacheItem = (name: RouteRecordName) => { | ||||
|     const index = cacheList.value.findIndex((item) => item === name) | ||||
|     const index = cacheList.value.findIndex((i) => i === name) | ||||
|     if (index >= 0) { | ||||
|       cacheList.value.splice(index, 1) | ||||
|     } | ||||
| @@ -66,50 +68,66 @@ const storeSetup = () => { | ||||
|  | ||||
|   // 关闭当前 | ||||
|   const closeCurrent = (path: string) => { | ||||
|     deleteTagItem(path) | ||||
|     const item = tagList.value.find((i) => i.path === path) | ||||
|     if (item?.name) { | ||||
|       deleteCacheItem(item.name) | ||||
|     } | ||||
|     const item = tabList.value.find((i) => i.path === path) | ||||
|     item?.name && deleteCacheItem(item.name) | ||||
|     deleteTabItem(path) | ||||
|   } | ||||
|  | ||||
|   // 关闭其他 | ||||
|   const closeOther = (path: string) => { | ||||
|     const arr = tagList.value.filter((i) => i.path !== path) | ||||
|     const arr = tabList.value.filter((i) => i.path !== path) | ||||
|     arr.forEach((item) => { | ||||
|       deleteTagItem(item.path) | ||||
|       if (item?.name) { | ||||
|         deleteCacheItem(item.name) | ||||
|       deleteTabItem(item.path) | ||||
|       item?.name && deleteCacheItem(item.name) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   // 关闭右侧 | ||||
|   const closeRight = (path: string) => { | ||||
|     const index = tabList.value.findIndex((i) => i.path === path) | ||||
|     if (index < 0) return | ||||
|     const arr = tabList.value.filter((i, n) => n > index) | ||||
|     arr.forEach((item) => { | ||||
|       deleteTabItem(item.path) | ||||
|       item?.name && deleteCacheItem(item.name) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   // 关闭全部 | ||||
|   const closeAll = () => { | ||||
|     clearTagList() | ||||
|     clearTabList() | ||||
|     clearCacheList() | ||||
|     router.push({ path: '/' }) | ||||
|   } | ||||
|  | ||||
|   // 重置 | ||||
|   const reset = () => { | ||||
|     clearTagList() | ||||
|     clearTabList() | ||||
|     clearCacheList() | ||||
|   } | ||||
|  | ||||
|   // 初始化 | ||||
|   const init = () => { | ||||
|     if (tabList.value.some((i) => !i?.meta.affix)) return | ||||
|     reset() | ||||
|   } | ||||
|  | ||||
|   return { | ||||
|     tagList, | ||||
|     tabList, | ||||
|     cacheList, | ||||
|     addTagItem, | ||||
|     deleteTagItem, | ||||
|     clearTagList, | ||||
|     addTabItem, | ||||
|     deleteTabItem, | ||||
|     clearTabList, | ||||
|     addCacheItem, | ||||
|     deleteCacheItem, | ||||
|     clearCacheList, | ||||
|     closeCurrent, | ||||
|     closeOther, | ||||
|     closeRight, | ||||
|     closeAll, | ||||
|     reset | ||||
|     reset, | ||||
|     init | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const useTabsStore = defineStore('tabs', storeSetup, { persist: false }) | ||||
| export const useTabsStore = defineStore('tabs', storeSetup, { persist: { storage: sessionStorage } }) | ||||
|   | ||||
| @@ -34,7 +34,7 @@ | ||||
| import { type FormInstance, Message } from '@arco-design/web-vue' | ||||
| import { useStorage } from '@vueuse/core' | ||||
| import { getImageCaptcha } from '@/apis' | ||||
| import { useUserStore } from '@/stores' | ||||
| import { useTabsStore, useUserStore } from '@/stores' | ||||
| import { encryptByRsa } from '@/utils/encrypt' | ||||
|  | ||||
| const loginConfig = useStorage('login-config', { | ||||
| @@ -94,6 +94,7 @@ const getCaptcha = () => { | ||||
| } | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const tabsStore = useTabsStore() | ||||
| const router = useRouter() | ||||
| const loading = ref(false) | ||||
| // 登录 | ||||
| @@ -108,6 +109,7 @@ const handleLogin = async () => { | ||||
|       captcha: form.captcha, | ||||
|       uuid: form.uuid | ||||
|     }) | ||||
|     tabsStore.reset() | ||||
|     const { redirect, ...othersQuery } = router.currentRoute.value.query | ||||
|     router.push({ | ||||
|       path: (redirect as string) || '/', | ||||
|   | ||||
| @@ -35,7 +35,7 @@ | ||||
| <script setup lang="ts"> | ||||
| // import { getEmailCaptcha } from '@/apis' | ||||
| import { type FormInstance, Message } from '@arco-design/web-vue' | ||||
| import { useUserStore } from '@/stores' | ||||
| import { useTabsStore, useUserStore } from '@/stores' | ||||
| import * as Regexp from '@/utils/regexp' | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
| @@ -53,6 +53,7 @@ const rules: FormInstance['rules'] = { | ||||
| } | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const tabsStore = useTabsStore() | ||||
| const router = useRouter() | ||||
| const loading = ref(false) | ||||
| // 登录 | ||||
| @@ -62,6 +63,7 @@ const handleLogin = async () => { | ||||
|     if (isInvalid) return | ||||
|     loading.value = true | ||||
|     await userStore.emailLogin(form) | ||||
|     tabsStore.reset() | ||||
|     const { redirect, ...othersQuery } = router.currentRoute.value.query | ||||
|     router.push({ | ||||
|       path: (redirect as string) || '/', | ||||
|   | ||||
| @@ -42,7 +42,7 @@ | ||||
| <script setup lang="ts"> | ||||
| // import { getSmsCaptcha } from '@/apis' | ||||
| import { type FormInstance, Message } from '@arco-design/web-vue' | ||||
| import { useUserStore } from '@/stores' | ||||
| import { useTabsStore, useUserStore } from '@/stores' | ||||
| import * as Regexp from '@/utils/regexp' | ||||
|  | ||||
| const formRef = ref<FormInstance>() | ||||
| @@ -60,6 +60,7 @@ const rules: FormInstance['rules'] = { | ||||
| } | ||||
|  | ||||
| const userStore = useUserStore() | ||||
| const tabsStore = useTabsStore() | ||||
| const router = useRouter() | ||||
| const loading = ref(false) | ||||
| // 登录 | ||||
| @@ -69,6 +70,7 @@ const handleLogin = async () => { | ||||
|   try { | ||||
|     loading.value = true | ||||
|     await userStore.phoneLogin(form) | ||||
|     tabsStore.reset() | ||||
|     const { redirect, ...othersQuery } = router.currentRoute.value.query | ||||
|     router.push({ | ||||
|       path: (redirect as string) || '/', | ||||
|   | ||||
| @@ -8,12 +8,13 @@ | ||||
| import { Message } from '@arco-design/web-vue' | ||||
| import { useRoute, useRouter } from 'vue-router' | ||||
| import { bindSocialAccount } from '@/apis' | ||||
| import { useUserStore } from '@/stores' | ||||
| import { useTabsStore, useUserStore } from '@/stores' | ||||
| import { isLogin } from '@/utils/auth' | ||||
|  | ||||
| const route = useRoute() | ||||
| const router = useRouter() | ||||
| const userStore = useUserStore() | ||||
| const tabsStore = useTabsStore() | ||||
| const source = route.query.source as string | ||||
| const loading = ref(false) | ||||
|  | ||||
| @@ -25,6 +26,7 @@ const handleSocialLogin = () => { | ||||
|   userStore | ||||
|     .socialLogin(source, othersQuery) | ||||
|     .then(() => { | ||||
|       tabsStore.reset() | ||||
|       router.push({ | ||||
|         path: (redirect as string) || '/', | ||||
|         query: { | ||||
|   | ||||
| @@ -33,9 +33,7 @@ const selectedKey = ref('0') | ||||
| watch( | ||||
|   () => route.query, | ||||
|   () => { | ||||
|     if (route.query.type) { | ||||
|       selectedKey.value = route.query.type as string | ||||
|     } | ||||
|     selectedKey.value = route.query.type as string || '0' | ||||
|   }, | ||||
|   { | ||||
|     immediate: true | ||||
| @@ -44,7 +42,7 @@ watch( | ||||
|  | ||||
| // 点击事件 | ||||
| const onClickItem = (item: FileTypeListItem) => { | ||||
|   router.push({ name: 'SystemFile', query: { type: item.value } }) | ||||
|   router.replace({ name: 'SystemFile', query: { type: item.value } }) | ||||
| } | ||||
| </script> | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user