多标签tabs 调整

This commit is contained in:
Jason
2022-09-20 10:58:38 +08:00
parent aee93d81b4
commit fe5522dc2d
49 changed files with 273 additions and 109 deletions

View File

@@ -0,0 +1,47 @@
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'
export default function useMultipleTabs() {
const router = useRouter()
const route = useRoute()
const tabsStore = useTabsStore()
const settingStore = useSettingStore()
const tabsLists = computed(() => {
return tabsStore.getTabList
})
const currentTab = computed(() => {
return route.fullPath
})
const addTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.addTab(router)
}
const removeTab = (fullPath?: any) => {
if (!settingStore.openMultipleTabs) return
fullPath = fullPath ?? route.fullPath
tabsStore.removeTab(fullPath, router)
}
const removeOtherTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.removeOtherTab(route)
}
const removeAllTab = () => {
if (!settingStore.openMultipleTabs) return
tabsStore.removeAllTab(router)
}
return {
tabsLists,
currentTab,
addTab,
removeTab,
removeOtherTab,
removeAllTab
}
}

View File

@@ -3,12 +3,12 @@
<div class="flex-1 min-w-0">
<el-tabs
:model-value="currentTab"
:closable="tabsState.length > 1"
:closable="tabsLists.length > 1"
@tab-change="handleChange"
@tab-remove="handleRemove"
@tab-remove="removeTab($event)"
>
<template v-for="item in tabsState" :key="item.path">
<el-tab-pane :label="item.title" :name="item.path"></el-tab-pane>
<template v-for="item in tabsLists" :key="item.fullPath">
<el-tab-pane :label="item.title" :name="item.fullPath"></el-tab-pane>
</template>
</el-tabs>
</div>
@@ -28,40 +28,31 @@
</template>
<script setup lang="ts">
import useMultipleTabs from '@/hooks/useMultipleTabs'
import { useWatchRoute } from '@/hooks/useWatchRoute'
import useTabsStore, { getRouteParams } from '@/stores/modules/multipleTabs'
const router = useRouter()
const tabsStore = useTabsStore()
const { route } = useWatchRoute((route) => {
tabsStore.addTab(route, router)
const { removeOtherTab, addTab, removeAllTab, removeTab, tabsLists, currentTab } = useMultipleTabs()
useWatchRoute(() => {
addTab()
})
const currentTab = computed(() => {
return route.path
})
const tabsState = computed(() => {
return tabsStore.getTabList
})
const handleChange = (path: any) => {
const tabItem = tabsStore.tasMap[path]
const handleChange = (fullPath: any) => {
const tabItem = tabsStore.tasMap[fullPath]
router.push(getRouteParams(tabItem))
}
const handleRemove = (path: any) => {
tabsStore.removeTab(path, router)
}
const handleCommand = (command: any) => {
switch (command) {
case 'closeCurrent':
handleRemove(route.path)
removeTab()
break
case 'closeOther':
tabsStore.removeOtherTab(route.path)
removeOtherTab()
break
case 'closeAll':
tabsStore.removeAllTab(router)
removeAllTab()
break
}
}

View File

@@ -3,7 +3,9 @@
<el-scrollbar>
<div class="p-4">
<router-view v-if="isRouteShow" v-slot="{ Component, route }">
<component :is="Component" :key="route.fullPath" />
<keep-alive :include="includeList" :max="20">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</router-view>
</div>
</el-scrollbar>
@@ -12,8 +14,13 @@
<script setup lang="ts">
import useAppStore from '@/stores/modules/app'
import useTabsStore from '@/stores/modules/multipleTabs'
import useSettingStore from '@/stores/modules/setting'
const appStore = useAppStore()
const tabsStore = useTabsStore()
const settingStore = useSettingStore()
const isRouteShow = computed(() => appStore.isRouteShow)
const includeList = computed(() => (settingStore.openMultipleTabs ? tabsStore.getCacheTabList : []))
</script>
<style></style>

View File

@@ -65,7 +65,6 @@ import theme_light from '@/assets/images/theme_white.png'
import theme_dark from '@/assets/images/theme_black.png'
const settingStore = useSettingStore()
const predefineColors = ref(['#409EFF', '#28C76F', '#EA5455', '#FF9F43', '#01CFE8', '#4A5DFF'])
const sideThemeList = [
{

View File

@@ -11,6 +11,7 @@ import { PageEnum } from '@/enums/pageEnum'
interface TabItem {
name: RouteRecordName
fullPath: string
path: string
title?: string
query?: LocationQuery
@@ -24,8 +25,8 @@ interface TabsSate {
indexRouteName: RouteRecordName
}
const getHasTabIndex = (path: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.path == path)
const getHasTabIndex = (fullPath: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.fullPath == fullPath)
}
const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
@@ -39,8 +40,12 @@ const isCannotAddRoute = (route: RouteLocationNormalized, router: Router) => {
return false
}
const findTabsIndex = (path: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.path === path)
const findTabsIndex = (fullPath: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.fullPath === fullPath)
}
const getComponentName = (route: RouteLocationNormalized) => {
return route.matched.at(-1)?.components?.default?.name
}
export const getRouteParams = (tabItem: TabItem) => {
@@ -63,45 +68,67 @@ const useTabsStore = defineStore({
getters: {
getTabList(): TabItem[] {
return this.tabList
},
getCacheTabList(): string[] {
return Array.from(this.cacheTabList)
}
},
actions: {
setRouteName(name: RouteRecordName) {
this.indexRouteName = name
},
addCache(componentName?: string) {
if (componentName) this.cacheTabList.add(componentName)
},
removeCache(componentName?: string) {
if (componentName && this.cacheTabList.has(componentName)) {
this.cacheTabList.delete(componentName)
}
console.log(this.cacheTabList)
},
clearCache() {
this.cacheTabList.clear()
},
resetState() {
this.cacheTabList = new Set()
this.tabList = []
this.tasMap = {}
this.indexRouteName = ''
},
addTab(route: RouteLocationNormalized, router: Router) {
const { name, path, query, meta, params } = route
addTab(router: Router) {
const route = unref(router.currentRoute)
const { name, query, meta, params, fullPath, path } = route
if (isCannotAddRoute(route, router)) return
const hasTabIndex = getHasTabIndex(path!, this.tabList)
const hasTabIndex = getHasTabIndex(fullPath!, this.tabList)
const componentName = getComponentName(route)
const tabItem = {
name: name!,
path,
fullPath,
title: meta?.title,
query,
params
}
this.tasMap[path] = tabItem
this.tasMap[fullPath] = tabItem
if (meta?.keepAlive) {
this.addCache(componentName)
}
if (hasTabIndex != -1) {
this.tabList.splice(hasTabIndex, 1, tabItem)
return
}
this.tabList.push(tabItem)
},
removeTab(path: string, router: Router) {
removeTab(fullPath: string, router: Router) {
const { currentRoute, push } = router
const index = findTabsIndex(path, this.tabList)
const index = findTabsIndex(fullPath, this.tabList)
// 移除tab
if (this.tabList.length > 1) {
index !== -1 && this.tabList.splice(index, 1)
}
if (path !== currentRoute.value.path) {
const componentName = getComponentName(currentRoute.value)
this.removeCache(componentName)
if (fullPath !== currentRoute.value.fullPath) {
return
}
// 删除选中的tab
@@ -116,17 +143,24 @@ const useTabsStore = defineStore({
const toRoute = getRouteParams(toTab)
push(toRoute)
},
removeOtherTab(path: string) {
this.tabList = this.tabList.filter((item) => item.path == path)
removeOtherTab(route: RouteLocationNormalized) {
this.tabList = this.tabList.filter((item) => item.fullPath == route.fullPath)
const componentName = getComponentName(route)
this.cacheTabList.forEach((name) => {
if (componentName !== name) {
this.removeCache(name)
}
})
},
removeAllTab(router: Router) {
const { push, currentRoute } = router
const { path, name } = unref(currentRoute)
const { name } = unref(currentRoute)
if (name == this.indexRouteName) {
this.removeOtherTab(path)
this.removeOtherTab(currentRoute.value)
return
}
this.tabList = []
this.clearCache()
push(PageEnum.INDEX)
}
}

View File

@@ -28,12 +28,6 @@ const useUserStore = defineStore({
}),
getters: {},
actions: {
resetState() {
this.token = ''
this.userInfo = {}
this.perms = []
this.menu = []
},
login(playload: any) {
const { account, password } = playload
return new Promise((resolve, reject) => {
@@ -54,8 +48,9 @@ const useUserStore = defineStore({
logout() {
return new Promise((resolve, reject) => {
logout()
.then((data) => {
router.push(PageEnum.LOGIN)
.then(async (data) => {
this.token = ''
await router.push(PageEnum.LOGIN)
clearAuthInfo()
resolve(data)
})

View File

@@ -11,8 +11,8 @@ export function getToken() {
export function clearAuthInfo() {
const userStore = useUserStore()
const tabsStore = useTabsStore()
userStore.resetState()
tabsStore.resetState()
userStore.$reset()
tabsStore.$reset()
cache.remove(TOKEN_KEY)
resetRouter()
}

View File

@@ -65,7 +65,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleColumn">
import { articleCateDelete, articleCateLists, articleCateStatus } from '@/api/article'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -19,8 +19,8 @@
v-model="formData.title"
placeholder="请输入文章标题"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
maxlength="200"
:autosize="{ minRows: 3, maxRows: 3 }"
maxlength="64"
show-word-limit
clearable
/>
@@ -111,11 +111,12 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleListsEdit">
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { useDictOptions } from '@/hooks/useDictOptions'
import { articleCateAll, articleDetail, articleEdit, articleAdd } from '@/api/article'
import useMultipleTabs from '@/hooks/useMultipleTabs'
const route = useRoute()
const router = useRouter()
@@ -133,6 +134,7 @@ const formData = reactive({
summary: ''
})
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const rules = reactive({
title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
@@ -165,6 +167,7 @@ const handleSave = async () => {
await articleAdd(formData)
}
feedback.msgSuccess('操作成功')
removeTab()
router.back()
}

View File

@@ -117,7 +117,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="articleLists">
import { articleLists, articleDelete, articleStatus, articleCateAll } from '@/api/article'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'
@@ -159,5 +159,9 @@ const handleDelete = async (id: number) => {
getLists()
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -32,7 +32,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="h5Config">
import { getH5Config, setH5Config } from '@/api/channel/h5'
import feedback from '@/utils/feedback'

View File

@@ -140,7 +140,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="weappConfig">
import { getWeappConfig, setWeappConfig } from '@/api/channel/weapp'
import feedback from '@/utils/feedback'

View File

@@ -35,7 +35,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="wxDevConfig">
import { getWxDevConfig, setWxDevConfig } from '@/api/channel/wx_dev'
import feedback from '@/utils/feedback'

View File

@@ -156,7 +156,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="wxOaConfig">
import { getOaConfig, setOaConfig } from '@/api/channel/wx_oa'
import feedback from '@/utils/feedback'
import { useClipboard } from '@vueuse/core'

View File

@@ -1,4 +1,4 @@
<script setup lang="ts">
<script setup lang="ts" name="wxOaMenu">
import OaPhone from './menu_com/oa-phone.vue'
import OaAttr from './menu_com/oa-attr.vue'
import { useMenuOa } from './menu_com/useMenuOa'

View File

@@ -75,7 +75,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="consumerDetail">
import type { FormInstance } from 'element-plus'
import { getUserDetail, userEdit } from '@/api/consumer'
import feedback from '@/utils/feedback'

View File

@@ -70,7 +70,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="consumerLists">
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import { getUserList } from '@/api/consumer'
@@ -86,6 +86,9 @@ const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: getUserList,
params: queryParams
})
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -12,7 +12,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="decorationPages">
import Menu from '../component/pages/menu.vue'
import Preview from '../component/pages/preview.vue'
import AttrSetting from '../component/pages/attr-setting.vue'

View File

@@ -132,7 +132,7 @@
</footer-btns>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="decorationTabbar">
import { getDecorateTabbar, setDecorateTabbar } from '@/api/decoration'
import feedback from '@/utils/feedback'
import Draggable from 'vuedraggable'

View File

@@ -274,14 +274,14 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="tableEdit">
import { generateEdit, tableDetail } from '@/api/tools/code'
import { dictTypeAll } from '@/api/setting/dict'
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { menuLists } from '@/api/perms/menu'
import { useDictOptions } from '@/hooks/useDictOptions'
import useMultipleTabs from '@/hooks/useMultipleTabs'
enum GenTpl {
CRUD = 'crud',
TREE = 'tree'
@@ -294,6 +294,7 @@ enum GenType {
const route = useRoute()
const router = useRouter()
const { removeTab } = useMultipleTabs()
const activeName = ref('column')
const formData = reactive({
base: {
@@ -365,6 +366,7 @@ const handleSave = async () => {
const { base, column, gen } = formData
await generateEdit({ ...base, ...gen, column })
feedback.msgSuccess('操作成功')
removeTab()
router.back()
} catch (error: any) {
for (const err in error) {

View File

@@ -138,7 +138,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="codeGenerate">
import {
generateTable,
syncColumn,
@@ -228,5 +228,9 @@ const handleCommand = (command: any, row: any) => {
}
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -23,7 +23,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="materialCenter">
const tabsMap = [
{
type: 'image',

View File

@@ -58,10 +58,11 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="noticeEdit">
import type { FormInstance } from 'element-plus'
import feedback from '@/utils/feedback'
import { noticeDetail, setNoticeConfig } from '@/api/message'
import useMultipleTabs from '@/hooks/useMultipleTabs'
const route = useRoute()
const router = useRouter()
@@ -95,7 +96,7 @@ const rules = {
}
]
}
const { removeTab } = useMultipleTabs()
const formRef = shallowRef<FormInstance>()
const getDetails = async () => {
@@ -114,6 +115,7 @@ const handleSave = async () => {
await formRef.value?.validate()
await setNoticeConfig(formData)
feedback.msgSuccess('操作成功')
removeTab()
router.back()
}

View File

@@ -47,7 +47,7 @@
</el-card>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="notice">
import { noticeLists } from '@/api/message'
import { getRoutePath } from '@/router'
@@ -87,5 +87,9 @@ const getLists = async () => {
}
}
onActivated(() => {
getLists()
})
getLists()
</script>

View File

@@ -26,7 +26,7 @@
<edit-popup ref="editRef" @success="getLists" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="shortLetter">
import { smsLists } from '@/api/message'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()

View File

@@ -91,7 +91,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="department">
import type { ElTable, FormInstance } from 'element-plus'
import EditPopup from './edit.vue'
import { deptDelete, deptLists } from '@/api/org/department'

View File

@@ -86,7 +86,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="post">
import { postDelete, postLists } from '@/api/org/post'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -100,7 +100,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="admin">
import { adminLists, adminDelete, adminStatus } from '@/api/perms/admin'
import { roleAll } from '@/api/perms/role'
import { useDictOptions } from '@/hooks/useDictOptions'

View File

@@ -116,20 +116,20 @@
</div>
</div>
</el-form-item>
<!-- <el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
prop="isCache"
required
>
<div>
<el-radio-group v-model="formData.isCache">
<el-radio :label="1">缓存</el-radio>
<el-radio :label="0">不缓存</el-radio>
</el-radio-group>
<div class="form-tips">选择缓存则会被`keep-alive`缓存</div>
</div>
</el-form-item> -->
<el-form-item
v-if="formData.menuType == MenuEnum.MENU"
label="是否缓存"
prop="isCache"
required
>
<div>
<el-radio-group v-model="formData.isCache">
<el-radio :label="1">缓存</el-radio>
<el-radio :label="0">不缓存</el-radio>
</el-radio-group>
<div class="form-tips">选择缓存则会被`keep-alive`缓存</div>
</div>
</el-form-item>
<el-form-item
v-if="formData.menuType != MenuEnum.BUTTON"
label="是否显示"
@@ -220,7 +220,7 @@ const formData = reactive({
//路由参数
params: '',
//是否缓存 0=否, 1=是
isCache: 0,
isCache: 1,
//是否显示 0=否, 1=是
isShow: 1,
//是否禁用 0=否, 1=是

View File

@@ -90,7 +90,7 @@
<edit-popup v-if="showEdit" ref="editRef" @success="getLists" @close="showEdit = false" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="menu">
import { menuDelete, menuLists } from '@/api/perms/menu'
import type { ElTable } from 'element-plus'
import { MenuEnum } from '@/enums/appEnums'

View File

@@ -63,7 +63,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="role">
import { roleLists, roleDelete } from '@/api/perms/role'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'

View File

@@ -104,7 +104,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="dictData">
import { dictDataDelete, dictDataLists, dictTypeAll } from '@/api/setting/dict'
import { useDictOptions } from '@/hooks/useDictOptions'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -113,7 +113,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="dictType">
import { dictTypeDelete, dictTypeLists } from '@/api/setting/dict'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'

View File

@@ -71,7 +71,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="search">
import { getSearch, setSearch } from '@/api/setting/search'
import type { Search } from '@/api/setting/search'
import feedback from '@/utils/feedback'

View File

@@ -35,7 +35,7 @@
<edit-popup ref="editRef" @success="getLists" />
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="storage">
import { storageLists } from '@/api/setting/storage'
import EditPopup from './edit.vue'
const editRef = shallowRef<InstanceType<typeof EditPopup>>()

View File

@@ -136,7 +136,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="cache">
import { systemCache } from '@/api/setting/system'
import vCharts from 'vue-echarts'
import { reactive } from 'vue'

View File

@@ -113,7 +113,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="environment">
import { systemInfo } from '@/api/setting/system'
const loading = ref(false)
const info = ref({

View File

@@ -61,7 +61,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="journal">
import { systemLogLists } from '@/api/setting/system'
import { usePaging } from '@/hooks/usePaging'

View File

@@ -98,7 +98,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="loginRegister">
import type { LoginSetup } from '@/api/setting/user'
import { getLogin, setLogin } from '@/api/setting/user'
import feedback from '@/utils/feedback'

View File

@@ -25,7 +25,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="userSetup">
import { getUserSetup, setUserSetup } from '@/api/setting/user'
import feedback from '@/utils/feedback'
// import type { FormInstance } from 'element-plus'

View File

@@ -50,7 +50,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="webFilling">
import { getCopyright, setCopyright } from '@/api/setting/website'
import feedback from '@/utils/feedback'
// 表单数据

View File

@@ -59,7 +59,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="webInformation">
import { getWebsite, setWebsite } from '@/api/setting/website'
import useAppStore from '@/stores/modules/app'
import feedback from '@/utils/feedback'

View File

@@ -30,7 +30,7 @@
</footer-btns>
</template>
<script setup lang="ts">
<script setup lang="ts" naem="webProtocol">
import { getProtocol, setProtocol } from '@/api/setting/website'
import feedback from '@/utils/feedback'

View File

@@ -65,7 +65,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts" name="userSetting">
import { setUserInfo } from '@/api/user'
import useUserStore from '@/stores/modules/user'
import feedback from '@/utils/feedback'

View File

@@ -130,7 +130,7 @@
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup name="workbench">
import { getWorkbench } from '@/api/app'
import vCharts from 'vue-echarts'
import menu_admin from './image/menu_admin.png'