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