|
@@ -2,26 +2,90 @@
|
|
|
<div class="_tagList">
|
|
|
<div class="tag-view">
|
|
|
<ul>
|
|
|
- <li v-for="(item, index) in visitedViews" :key="index">
|
|
|
- <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-if="index == 0">
|
|
|
- <div class="homeBox" @click="navigate">
|
|
|
- <Icon :icon="item.meta.icon || ''" />
|
|
|
- <p>{{ item.meta.title }}</p>
|
|
|
- </div>
|
|
|
- </router-link>
|
|
|
- <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-else>
|
|
|
- <div class="fhomeBox" @click="navigate">
|
|
|
- <div>
|
|
|
+ <ContextMenu
|
|
|
+ :ref="itemRefs.set"
|
|
|
+ :schema="[
|
|
|
+ {
|
|
|
+ icon: 'ep:refresh',
|
|
|
+ label: t('common.reload'),
|
|
|
+ disabled: selectedTag?.fullPath !== item.fullPath,
|
|
|
+ command: () => {
|
|
|
+ refreshSelectedTag(item)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: 'ep:close',
|
|
|
+ label: t('common.closeTab'),
|
|
|
+ disabled: !!visitedViews?.length && selectedTag?.meta.affix,
|
|
|
+ command: () => {
|
|
|
+ closeSelectedTag(item)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ divided: true,
|
|
|
+ icon: 'ep:d-arrow-left',
|
|
|
+ label: t('common.closeTheLeftTab'),
|
|
|
+ disabled:
|
|
|
+ !!visitedViews?.length &&
|
|
|
+ (item.fullPath === visitedViews[0].fullPath ||
|
|
|
+ selectedTag?.fullPath !== item.fullPath),
|
|
|
+ command: () => {
|
|
|
+ closeLeftTags()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: 'ep:d-arrow-right',
|
|
|
+ label: t('common.closeTheRightTab'),
|
|
|
+ disabled:
|
|
|
+ !!visitedViews?.length &&
|
|
|
+ (item.fullPath === visitedViews[visitedViews.length - 1].fullPath ||
|
|
|
+ selectedTag?.fullPath !== item.fullPath),
|
|
|
+ command: () => {
|
|
|
+ closeRightTags()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ divided: true,
|
|
|
+ icon: 'ep:discount',
|
|
|
+ label: t('common.closeOther'),
|
|
|
+ disabled: selectedTag?.fullPath !== item.fullPath,
|
|
|
+ command: () => {
|
|
|
+ closeOthersTags()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]"
|
|
|
+ v-for="(item, index) in visitedViews"
|
|
|
+ :key="index"
|
|
|
+ :tag-item="item"
|
|
|
+ :class="[
|
|
|
+ `${prefixCls}__item`,
|
|
|
+ item?.meta?.affix ? `${prefixCls}__item--affix` : '',
|
|
|
+ {
|
|
|
+ 'is-active': isActive(item)
|
|
|
+ }
|
|
|
+ ]"
|
|
|
+ @visible-change="visibleChange"
|
|
|
+ >
|
|
|
+ <li>
|
|
|
+ <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-if="index == 0">
|
|
|
+ <div class="homeBox" @click="navigate">
|
|
|
<Icon :icon="item.meta.icon || ''" />
|
|
|
<p>{{ item.meta.title }}</p>
|
|
|
</div>
|
|
|
- <img
|
|
|
- @click.stop.prevent="closeSelectedTag(item)"
|
|
|
- src="@/assets/imgs/OA/layout/close.png"
|
|
|
- />
|
|
|
- </div>
|
|
|
- </router-link>
|
|
|
- </li>
|
|
|
+ </router-link>
|
|
|
+ <router-link :to="{ ...item }" exact v-slot="{ navigate }" v-else>
|
|
|
+ <div class="fhomeBox" @click="navigate">
|
|
|
+ <div>
|
|
|
+ <p>{{ item.meta.title }}</p>
|
|
|
+ </div>
|
|
|
+ <img
|
|
|
+ @click.stop.prevent="closeSelectedTag(item)"
|
|
|
+ src="@/assets/imgs/OA/layout/close.png"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </router-link>
|
|
|
+ </li>
|
|
|
+ </ContextMenu>
|
|
|
</ul>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -33,13 +97,21 @@ import { useRouter } from 'vue-router'
|
|
|
import { usePermissionStore } from '@/store/modules/permission'
|
|
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
|
import { filterAffixTags } from './helper'
|
|
|
+import { useTemplateRefsList } from '@vueuse/core'
|
|
|
+import { ContextMenu, ContextMenuExpose } from '@/layout/components/ContextMenu'
|
|
|
+import { useI18n } from '@/hooks/web/useI18n'
|
|
|
+import { useDesign } from '@/hooks/web/useDesign'
|
|
|
+const { getPrefixCls } = useDesign()
|
|
|
+const prefixCls = getPrefixCls('tags-view')
|
|
|
+const { t } = useI18n()
|
|
|
const selectedTag = ref<RouteLocationNormalizedLoaded>()
|
|
|
const { currentRoute, push, replace } = useRouter()
|
|
|
const permissionStore = usePermissionStore()
|
|
|
const routers = computed(() => permissionStore.getRouters)
|
|
|
const tagsViewStore = useTagsViewStore()
|
|
|
const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
|
|
|
-
|
|
|
+// 所有右键菜单组件的元素
|
|
|
+const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
|
|
|
const visitedViews = computed(() => tagsViewStore.getVisitedViews)
|
|
|
// 初始化tag
|
|
|
const initTags = () => {
|
|
@@ -52,6 +124,44 @@ const initTags = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 右键菜单装填改变的时候
|
|
|
+const visibleChange = (visible: boolean, tagItem: RouteLocationNormalizedLoaded) => {
|
|
|
+ if (visible) {
|
|
|
+ for (const v of unref(itemRefs)) {
|
|
|
+ const elDropdownMenuRef = v.elDropdownMenuRef
|
|
|
+ if (tagItem.fullPath !== v.tagItem.fullPath) {
|
|
|
+ elDropdownMenuRef?.handleClose()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+// 关闭其它
|
|
|
+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
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭左侧
|
|
|
+const closeLeftTags = () => {
|
|
|
+ tagsViewStore.delLeftViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭右侧
|
|
|
+const closeRightTags = () => {
|
|
|
+ tagsViewStore.delRightViews(unref(selectedTag) as RouteLocationNormalizedLoaded)
|
|
|
+}
|
|
|
+
|
|
|
// 新增tag
|
|
|
const addTags = () => {
|
|
|
const { name } = unref(currentRoute)
|
|
@@ -102,6 +212,8 @@ watch(
|
|
|
)
|
|
|
/** 初始化 **/
|
|
|
onMounted(() => {
|
|
|
+ console.log(selectedTag)
|
|
|
+
|
|
|
initTags()
|
|
|
addTags()
|
|
|
})
|
|
@@ -188,4 +300,8 @@ li {
|
|
|
border: 2px solid #2e77e6;
|
|
|
padding: 0px !important;
|
|
|
}
|
|
|
+
|
|
|
+.el-dropdown {
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
</style>
|