|
@@ -1,72 +1,82 @@
|
|
|
<template>
|
|
|
<div class="_tagList">
|
|
|
<div class="tag-view">
|
|
|
- <ul>
|
|
|
- <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()
|
|
|
+ <draggable
|
|
|
+ class="tags-draggable-list"
|
|
|
+ v-model="visitedViews"
|
|
|
+ item-key="fullPath"
|
|
|
+ ghost-class="draggable-ghost"
|
|
|
+ filter=".unDrag"
|
|
|
+ @end="
|
|
|
+ (event) => {
|
|
|
+ // todo 不允许拖拽到第一项或最后一项之外
|
|
|
+ console.log('draged: ', event)
|
|
|
+ }
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <template #item="{ element: item, index }">
|
|
|
+ <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) || index === 0,
|
|
|
+ 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()
|
|
|
+ }
|
|
|
}
|
|
|
- },
|
|
|
- {
|
|
|
- divided: true,
|
|
|
- icon: 'ep:discount',
|
|
|
- label: t('common.closeOther'),
|
|
|
- disabled: selectedTag?.fullPath !== item.fullPath,
|
|
|
- command: () => {
|
|
|
- closeOthersTags()
|
|
|
+ ]"
|
|
|
+ :tag-item="item"
|
|
|
+ :class="[
|
|
|
+ `${prefixCls}__item`,
|
|
|
+ item?.meta?.affix ? `${prefixCls}__item--affix unDrag` : '',
|
|
|
+ {
|
|
|
+ 'is-route-tag-active': isActive(item)
|
|
|
}
|
|
|
- }
|
|
|
- ]"
|
|
|
- v-for="(item, index) in visitedViews"
|
|
|
- :key="index"
|
|
|
- :tag-item="item"
|
|
|
- :class="[
|
|
|
- `${prefixCls}__item`,
|
|
|
- item?.meta?.affix ? `${prefixCls}__item--affix` : '',
|
|
|
- {
|
|
|
- 'is-route-tag-active': isActive(item)
|
|
|
- }
|
|
|
- ]"
|
|
|
- @visible-change="visibleChange"
|
|
|
- >
|
|
|
- <li>
|
|
|
+ ]"
|
|
|
+ @visible-change="visibleChange"
|
|
|
+ >
|
|
|
<router-link :to="{ ...item }" exact v-slot="{ navigate }" v-if="index === 0">
|
|
|
<div class="homeBox" @click="navigate">
|
|
|
<Icon :icon="item.meta.icon || ''" />
|
|
@@ -76,24 +86,32 @@
|
|
|
<router-link :to="{ ...item }" exact v-slot="{ navigate }" v-else>
|
|
|
<div class="fhomeBox" @click="navigate">
|
|
|
<div class="pBox">
|
|
|
- <p>
|
|
|
- {{ item.meta.title }}
|
|
|
- <!-- 用于多开页面的区分展示(例如详情页)-->
|
|
|
- {{ (item?.query?.name ?? '') !== '' ? `(${item?.query?.name})` : '' }}
|
|
|
- </p>
|
|
|
+ <el-tooltip
|
|
|
+ class="box-item"
|
|
|
+ effect="dark"
|
|
|
+ :content="`${item.meta.title}${(item?.query?.name ?? '') !== '' ? `( ${item?.query?.name} )` : ''}`"
|
|
|
+ placement="top-start"
|
|
|
+ >
|
|
|
+ <p>
|
|
|
+ {{ item.meta.title }}
|
|
|
+ <!-- 用于多开页面的区分展示(例如详情页)-->
|
|
|
+ {{ (item?.query?.name ?? '') !== '' ? `(${item?.query?.name})` : '' }}
|
|
|
+ </p>
|
|
|
+ </el-tooltip>
|
|
|
</div>
|
|
|
<div @click.stop.prevent="closeSelectedTag(item)" class="close">
|
|
|
<span>×</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</router-link>
|
|
|
- </li>
|
|
|
- </ContextMenu>
|
|
|
- </ul>
|
|
|
+ </ContextMenu>
|
|
|
+ </template>
|
|
|
+ </draggable>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
+import 'vuedraggable'
|
|
|
import { computed, onMounted, nextTick, ref, watch } from 'vue'
|
|
|
import { Icon } from '@/components/Icon'
|
|
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
|
@@ -105,6 +123,7 @@ import { useTemplateRefsList } from '@vueuse/core'
|
|
|
import { ContextMenu, ContextMenuExpose } from '@/layout/components/ContextMenu'
|
|
|
import { useI18n } from '@/hooks/web/useI18n'
|
|
|
import { useDesign } from '@/hooks/web/useDesign'
|
|
|
+import draggable from 'vuedraggable'
|
|
|
|
|
|
const { getPrefixCls } = useDesign()
|
|
|
const prefixCls = getPrefixCls('tags-view')
|
|
@@ -117,7 +136,12 @@ const tagsViewStore = useTagsViewStore()
|
|
|
const affixTagArr = ref<RouteLocationNormalizedLoaded[]>([])
|
|
|
// 所有右键菜单组件的元素
|
|
|
const itemRefs = useTemplateRefsList<ComponentRef<typeof ContextMenu & ContextMenuExpose>>()
|
|
|
-const visitedViews = computed(() => tagsViewStore.getVisitedViews)
|
|
|
+const visitedViews = computed({
|
|
|
+ get: () => tagsViewStore.getVisitedViews,
|
|
|
+ set: (views) => tagsViewStore.allResetView(views)
|
|
|
+})
|
|
|
+
|
|
|
+console.log('visitedViews: ', visitedViews)
|
|
|
|
|
|
// 初始化tag
|
|
|
const initTags = () => {
|
|
@@ -223,19 +247,6 @@ onMounted(() => {
|
|
|
})
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
-div,
|
|
|
-h1,
|
|
|
-h2,
|
|
|
-h3,
|
|
|
-h4,
|
|
|
-h5,
|
|
|
-h6,
|
|
|
-p,
|
|
|
-ul,
|
|
|
-li {
|
|
|
- box-sizing: border-box;
|
|
|
-}
|
|
|
-
|
|
|
._tagList {
|
|
|
width: 100%;
|
|
|
height: 36px;
|
|
@@ -248,86 +259,80 @@ li {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
|
|
|
- ul {
|
|
|
+ .tags-draggable-list {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
|
|
|
- li {
|
|
|
+ a {
|
|
|
width: 100%;
|
|
|
+ display: block;
|
|
|
height: 100%;
|
|
|
- cursor: pointer;
|
|
|
+ border-radius: 10px;
|
|
|
+ color: inherit;
|
|
|
+ text-decoration: none;
|
|
|
+ padding: 2px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
|
|
|
- a {
|
|
|
- width: 100%;
|
|
|
- display: block;
|
|
|
- height: 100%;
|
|
|
- border-radius: 10px;
|
|
|
- color: inherit;
|
|
|
- text-decoration: none;
|
|
|
- padding: 2px;
|
|
|
- box-sizing: border-box;
|
|
|
+ .homeBox {
|
|
|
+ width: 70px;
|
|
|
+ height: 16px;
|
|
|
+ opacity: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin-left: 5px;
|
|
|
+ font-size: 16px;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ .fhomeBox {
|
|
|
+ width: 100%;
|
|
|
+ height: 16px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 0 10px;
|
|
|
+ border-right: 2px solid rgb(209, 197, 197);
|
|
|
|
|
|
- .homeBox {
|
|
|
- width: 70px;
|
|
|
- height: 16px;
|
|
|
- opacity: 1;
|
|
|
+ .pBox {
|
|
|
+ width: calc(100% - 17px);
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
|
|
|
p {
|
|
|
- margin-left: 5px;
|
|
|
+ overflow: hidden;
|
|
|
font-size: 16px;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- .fhomeBox {
|
|
|
- width: 100%;
|
|
|
- height: 16px;
|
|
|
+ .close {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- padding: 0 10px;
|
|
|
- border-right: 2px solid rgb(209, 197, 197);
|
|
|
-
|
|
|
- .pBox {
|
|
|
- width: calc(100% - 17px);
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-
|
|
|
- p {
|
|
|
- overflow: hidden;
|
|
|
- font-size: 16px;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .close {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- flex-shrink: 0;
|
|
|
- width: 12px;
|
|
|
- height: 12px;
|
|
|
- background-color: #878b91;
|
|
|
- border-radius: 50%;
|
|
|
- margin-left: 5px;
|
|
|
+ justify-content: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 12px;
|
|
|
+ height: 12px;
|
|
|
+ background-color: #878b91;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-left: 5px;
|
|
|
|
|
|
- span {
|
|
|
- color: #fff;
|
|
|
- }
|
|
|
+ span {
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- img {
|
|
|
- cursor: pointer;
|
|
|
- margin-top: 4px;
|
|
|
- display: block;
|
|
|
- }
|
|
|
+ img {
|
|
|
+ cursor: pointer;
|
|
|
+ margin-top: 4px;
|
|
|
+ display: block;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -365,18 +370,22 @@ li {
|
|
|
}
|
|
|
|
|
|
.tag-view {
|
|
|
- ul {
|
|
|
- .el-dropdown:nth-child(2) {
|
|
|
- .fhomeBox {
|
|
|
- border-left: 2px solid rgb(209, 197, 197);
|
|
|
- }
|
|
|
+ .el-dropdown:nth-child(2) {
|
|
|
+ .fhomeBox {
|
|
|
+ border-left: 2px solid rgb(209, 197, 197);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- .el-dropdown:last-child {
|
|
|
- .fhomeBox {
|
|
|
- border-right: 0;
|
|
|
- }
|
|
|
+ .el-dropdown:last-child {
|
|
|
+ .fhomeBox {
|
|
|
+ border-right: 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.draggable-ghost {
|
|
|
+ background: #f7fafc;
|
|
|
+ border: 1px solid #4299e1;
|
|
|
+ opacity: 0.5;
|
|
|
+}
|
|
|
</style>
|