refactor: 自动导入修改和项目重构优化
Former-commit-id: 100ab2e0092d96b17146163759aef897e5c14fbd
This commit is contained in:
@@ -1,16 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
|
||||
import Hamburger from '@/components/Hamburger/index.vue';
|
||||
import Breadcrumb from '@/components/Breadcrumb/index.vue';
|
||||
import Screenfull from '@/components/Screenfull/index.vue';
|
||||
import SizeSelect from '@/components/SizeSelect/index.vue';
|
||||
import LangSelect from '@/components/LangSelect/index.vue';
|
||||
import MixNav from './Sidebar/MixNav.vue';
|
||||
import { CaretBottom } from '@element-plus/icons-vue';
|
||||
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
@@ -24,12 +14,14 @@ const settingsStore = useSettingsStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const device = computed(() => appStore.device);
|
||||
const { device } = storeToRefs(appStore); // 设备类型:desktop-宽屏设备 || mobile-窄屏设备
|
||||
const { layout } = storeToRefs(settingsStore); // 布局模式:left-左侧模式||top-顶部模式||mix-混合模式
|
||||
|
||||
function toggleSideBar() {
|
||||
appStore.toggleSidebar(true);
|
||||
}
|
||||
|
||||
// 注销
|
||||
function logout() {
|
||||
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
@@ -52,7 +44,7 @@ function logout() {
|
||||
<div class="navbar">
|
||||
<div
|
||||
class="flex justify-start"
|
||||
v-if="device === 'mobile' || settingsStore.layout === 'left'"
|
||||
v-if="device === 'mobile' || layout === 'left'"
|
||||
>
|
||||
<hamburger
|
||||
:is-active="appStore.sidebar.opened"
|
||||
@@ -62,13 +54,24 @@ function logout() {
|
||||
<breadcrumb />
|
||||
</div>
|
||||
|
||||
<mix-nav v-if="device !== 'mobile' && settingsStore.layout === 'mix'" />
|
||||
<mix-nav v-if="device !== 'mobile' && layout === 'mix'" />
|
||||
|
||||
<!-- 宽屏或左侧模式显示 -->
|
||||
<div
|
||||
v-if="device === 'mobile' || settingsStore.layout === 'left'"
|
||||
v-if="device === 'desktop' || layout === 'left'"
|
||||
class="flex justify-start"
|
||||
>
|
||||
<!-- 左侧窄屏不显示 -->
|
||||
<div v-if="device !== 'mobile'" class="flex justify-center items-center">
|
||||
<i-ep-add-location />
|
||||
<i-ep-aim />
|
||||
<div i-ep-check />
|
||||
|
||||
<el-button>
|
||||
<template #icon><i-ep-circle-check-filled /></template>
|
||||
Hello world
|
||||
</el-button>
|
||||
|
||||
<!--全屏 -->
|
||||
<screenfull id="screenfull" />
|
||||
|
||||
@@ -80,14 +83,14 @@ function logout() {
|
||||
<!--语言选择-->
|
||||
<lang-select />
|
||||
</div>
|
||||
|
||||
<!-- 头像 -->
|
||||
<el-dropdown trigger="click">
|
||||
<div class="flex justify-center items-center pr-[20px]">
|
||||
<img
|
||||
:src="userStore.avatar + '?imageView2/1/w/80/h/80'"
|
||||
class="w-[40px] h-[40px] rounded-lg"
|
||||
/>
|
||||
<CaretBottom class="w-3 h-3" />
|
||||
<i-ep-caret-bottom class="w-3 h-3" />
|
||||
</div>
|
||||
|
||||
<template #dropdown>
|
||||
@@ -115,15 +118,12 @@ function logout() {
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-dropdown {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: #fff;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 0px 2px rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 0 1px #0003;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { computed } from 'vue';
|
||||
import { isExternal } from '@/utils/validate';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { DeviceType, useAppStore } from '@/store/modules/app';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
const appStore = useAppStore();
|
||||
|
||||
const sidebar = computed(() => appStore.sidebar);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted } from 'vue';
|
||||
import { RouterLink, useRoute, useRouter, RouteRecordRaw } from 'vue-router';
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router';
|
||||
import {
|
||||
ElDropdown,
|
||||
ElDropdownItem,
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'path-browserify';
|
||||
import { isExternal } from '@/utils/validate';
|
||||
import AppLink from './Link.vue';
|
||||
|
||||
import { generateTitle } from '@/utils/i18n';
|
||||
import { translateRouteTitleI18n } from '@/utils/i18n';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -78,10 +78,10 @@ function resolvePath(routePath: string) {
|
||||
>
|
||||
<svg-icon
|
||||
v-if="onlyOneChild.meta && onlyOneChild.meta.icon"
|
||||
:icon-class="onlyOneChild.meta.icon"
|
||||
:icon-name="onlyOneChild.meta.icon"
|
||||
/>
|
||||
<template #title>
|
||||
{{ generateTitle(onlyOneChild.meta.title) }}
|
||||
{{ translateRouteTitleI18n(onlyOneChild.meta.title) }}
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
@@ -92,10 +92,10 @@ function resolvePath(routePath: string) {
|
||||
<template #title>
|
||||
<svg-icon
|
||||
v-if="item.meta && item.meta.icon"
|
||||
:icon-class="item.meta.icon"
|
||||
:icon-name="item.meta.icon"
|
||||
/>
|
||||
<span v-if="item.meta && item.meta.title">{{
|
||||
generateTitle(item.meta.title)
|
||||
translateRouteTitleI18n(item.meta.title)
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
getCurrentInstance
|
||||
} from 'vue';
|
||||
import { useTagsViewStore, TagView } from '@/store/modules/tagsView';
|
||||
|
||||
const tagAndTagSpacing = ref(4);
|
||||
@@ -102,8 +95,8 @@ defineExpose({
|
||||
<template>
|
||||
<el-scrollbar
|
||||
ref="scrollContainer"
|
||||
:vertical="false"
|
||||
class="scroll-container"
|
||||
:vertical="false"
|
||||
@wheel.prevent="handleScroll"
|
||||
>
|
||||
<slot />
|
||||
|
||||
@@ -7,26 +7,27 @@ import {
|
||||
onMounted,
|
||||
ComponentInternalInstance
|
||||
} from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import path from 'path-browserify';
|
||||
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import ScrollPane from './ScrollPane.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { generateTitle } from '@/utils/i18n';
|
||||
import { translateRouteTitleI18n } from '@/utils/i18n';
|
||||
|
||||
import { usePermissionStore } from '@/store/modules/permission';
|
||||
import { useTagsViewStore, TagView } from '@/store/modules/tagsView';
|
||||
|
||||
const permissionStore = usePermissionStore();
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
import ScrollPane from './ScrollPane.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const visible = ref(false);
|
||||
const permissionStore = usePermissionStore();
|
||||
const tagsViewStore = useTagsViewStore();
|
||||
|
||||
const { visitedViews } = storeToRefs(tagsViewStore);
|
||||
|
||||
const selectedTag = ref({});
|
||||
const scrollPaneRef = ref();
|
||||
const left = ref(0);
|
||||
@@ -45,11 +46,12 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
watch(visible, value => {
|
||||
const tagMenuVisible = ref(false); // 标签操作菜单显示状态
|
||||
watch(tagMenuVisible, value => {
|
||||
if (value) {
|
||||
document.body.addEventListener('click', closeMenu);
|
||||
document.body.addEventListener('click', closeTagMenu);
|
||||
} else {
|
||||
document.body.removeEventListener('click', closeMenu);
|
||||
document.body.removeEventListener('click', closeTagMenu);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -78,11 +80,11 @@ function filterAffixTags(routes: any[], basePath = '/') {
|
||||
}
|
||||
|
||||
function initTags() {
|
||||
const tags = filterAffixTags(permissionStore.routes);
|
||||
const tags: TagView[] = filterAffixTags(permissionStore.routes);
|
||||
affixTags.value = tags;
|
||||
for (const tag of tags) {
|
||||
// Must have tag name
|
||||
if ((tag as TagView).name) {
|
||||
if (tag.name) {
|
||||
tagsViewStore.addVisitedView(tag);
|
||||
}
|
||||
}
|
||||
@@ -205,7 +207,7 @@ function closeAllTags(view: TagView) {
|
||||
});
|
||||
}
|
||||
|
||||
function openMenu(tag: TagView, e: MouseEvent) {
|
||||
function openTagMenu(tag: TagView, e: MouseEvent) {
|
||||
const menuMinWidth = 105;
|
||||
const offsetLeft = proxy?.$el.getBoundingClientRect().left; // container margin left
|
||||
const offsetWidth = proxy?.$el.offsetWidth; // container width
|
||||
@@ -219,16 +221,16 @@ function openMenu(tag: TagView, e: MouseEvent) {
|
||||
}
|
||||
|
||||
top.value = e.clientY;
|
||||
visible.value = true;
|
||||
tagMenuVisible.value = true;
|
||||
selectedTag.value = tag;
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
visible.value = false;
|
||||
function closeTagMenu() {
|
||||
tagMenuVisible.value = false;
|
||||
}
|
||||
|
||||
function handleScroll() {
|
||||
closeMenu();
|
||||
closeTagMenu();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@@ -237,71 +239,71 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="h-[34px] w-full border-b-[1px] border-gray-200 shadow-lg shadow-[rgba(0, 21, 41, 0.08)]"
|
||||
<scroll-pane
|
||||
class="tags-container"
|
||||
ref="scrollPaneRef"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<scroll-pane
|
||||
ref="scrollPaneRef"
|
||||
class="tags-container"
|
||||
@scroll="handleScroll"
|
||||
<router-link
|
||||
:class="'tags-item ' + (isActive(tag) ? 'active' : '')"
|
||||
v-for="tag in visitedViews"
|
||||
:key="tag.path"
|
||||
:data-path="tag.path"
|
||||
:to="{ path: tag.path, query: tag.query }"
|
||||
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||
@contextmenu.prevent="openTagMenu(tag, $event)"
|
||||
>
|
||||
<router-link
|
||||
v-for="tag in tagsViewStore.visitedViews"
|
||||
:key="tag.path"
|
||||
:data-path="tag.path"
|
||||
:class="isActive(tag) ? 'active' : ''"
|
||||
:to="{ path: tag.path, query: tag.query }"
|
||||
class="tags-item"
|
||||
@click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''"
|
||||
@contextmenu.prevent="openMenu(tag, $event)"
|
||||
{{ translateRouteTitleI18n(tag.meta?.title) }}
|
||||
<span
|
||||
v-if="!isAffix(tag)"
|
||||
class="rounded-[60%] hover:bg-gray-300"
|
||||
@click.prevent.stop="closeSelectedTag(tag)"
|
||||
>
|
||||
{{ generateTitle(tag.meta?.title) }}
|
||||
<i-ep-close class="text-[10px]" />
|
||||
</span>
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
|
||||
<span
|
||||
v-if="!isAffix(tag)"
|
||||
class="tags-item-remove"
|
||||
@click.prevent.stop="closeSelectedTag(tag)"
|
||||
>
|
||||
<svg-icon icon-class="close" />
|
||||
</span>
|
||||
</router-link>
|
||||
</scroll-pane>
|
||||
|
||||
<ul
|
||||
v-show="visible"
|
||||
:style="{ left: left + 'px', top: top + 'px' }"
|
||||
class="tags-item-menu"
|
||||
>
|
||||
<li @click="refreshSelectedTag(selectedTag)">
|
||||
<svg-icon icon-class="refresh" />
|
||||
刷新
|
||||
</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
||||
<svg-icon icon-class="close" />
|
||||
关闭
|
||||
</li>
|
||||
<li @click="closeOtherTags">
|
||||
<svg-icon icon-class="close_other" />
|
||||
关闭其它
|
||||
</li>
|
||||
<li v-if="!isFirstView()" @click="closeLeftTags">
|
||||
<svg-icon icon-class="close_left" />
|
||||
关闭左侧
|
||||
</li>
|
||||
<li v-if="!isLastView()" @click="closeRightTags">
|
||||
<svg-icon icon-class="close_right" />
|
||||
关闭右侧
|
||||
</li>
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
<svg-icon icon-class="close_all" />
|
||||
关闭所有
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- tag标签操作菜单 -->
|
||||
<ul
|
||||
v-show="tagMenuVisible"
|
||||
class="tag-menu"
|
||||
:style="{ left: left + 'px', top: top + 'px' }"
|
||||
>
|
||||
<li @click="refreshSelectedTag(selectedTag)">
|
||||
<svg-icon icon-name="refresh" />
|
||||
刷新
|
||||
</li>
|
||||
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
|
||||
<svg-icon icon-name="close" />
|
||||
关闭
|
||||
</li>
|
||||
<li @click="closeOtherTags">
|
||||
<svg-icon icon-name="close_other" />
|
||||
关闭其它
|
||||
</li>
|
||||
<li v-if="!isFirstView()" @click="closeLeftTags">
|
||||
<svg-icon icon-name="close_left" />
|
||||
关闭左侧
|
||||
</li>
|
||||
<li v-if="!isLastView()" @click="closeRightTags">
|
||||
<svg-icon icon-name="close_right" />
|
||||
关闭右侧
|
||||
</li>
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
<svg-icon icon-name="close_all" />
|
||||
关闭所有
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tags-container {
|
||||
height: 34px;
|
||||
width: 100%;
|
||||
border: 1px solid #eee;
|
||||
box-shadow: 0px 1px 1px #eee;
|
||||
|
||||
.tags-item {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
@@ -324,7 +326,7 @@ onMounted(() => {
|
||||
|
||||
&.active {
|
||||
background-color: var(--el-color-primary);
|
||||
color: var(--el-color-primary-light-9);
|
||||
color: #fff;
|
||||
border-color: var(--el-color-primary);
|
||||
&::before {
|
||||
content: '';
|
||||
@@ -333,22 +335,13 @@ onMounted(() => {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&-remove {
|
||||
border-radius: 50%;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tags-item-menu {
|
||||
.tag-menu {
|
||||
background: #fff;
|
||||
z-index: 99;
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user