mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	perf: layout (#50)
This commit is contained in:
		
							parent
							
								
									77b7abcbc3
								
							
						
					
					
						commit
						6b16a04229
					
				
							
								
								
									
										1
									
								
								src/assets/svg/globalization.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/assets/svg/globalization.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="globalization" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z" fill="currentColor"></path><path d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z" fill="currentColor"></path></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 965 B  | 
@ -1 +0,0 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconinternationality" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 512 512"><path d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z" fill="currentColor"></path><path d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z" fill="currentColor"></path></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 972 B  | 
@ -1,10 +0,0 @@
 | 
			
		||||
import { App } from "vue";
 | 
			
		||||
import reBreadCrumb from "./src/index.vue";
 | 
			
		||||
 | 
			
		||||
export const ReBreadCrumb = Object.assign(reBreadCrumb, {
 | 
			
		||||
  install(app: App) {
 | 
			
		||||
    app.component(reBreadCrumb.name, reBreadCrumb);
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default ReBreadCrumb;
 | 
			
		||||
@ -1,3 +1,14 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
const lists = ref<ForDataType<undefined>>([
 | 
			
		||||
  { type: "", label: "善良" },
 | 
			
		||||
  { type: "success", label: "好学" },
 | 
			
		||||
  { type: "info", label: "幽默" },
 | 
			
		||||
  { type: "danger", label: "旅游" },
 | 
			
		||||
  { type: "warning", label: "追剧" }
 | 
			
		||||
]);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <el-descriptions
 | 
			
		||||
    class="margin-top"
 | 
			
		||||
@ -75,17 +86,6 @@
 | 
			
		||||
  </el-descriptions>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
const lists = ref<ForDataType<undefined>>([
 | 
			
		||||
  { type: "", label: "善良" },
 | 
			
		||||
  { type: "success", label: "好学" },
 | 
			
		||||
  { type: "info", label: "幽默" },
 | 
			
		||||
  { type: "danger", label: "旅游" },
 | 
			
		||||
  { type: "warning", label: "追剧" }
 | 
			
		||||
]);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.el-tag--mini {
 | 
			
		||||
  margin-right: 10px !important;
 | 
			
		||||
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
import { App } from "vue";
 | 
			
		||||
import reHamBurger from "./src/index.vue";
 | 
			
		||||
 | 
			
		||||
export const ReHamBurger = Object.assign(reHamBurger, {
 | 
			
		||||
  install(app: App) {
 | 
			
		||||
    app.component(reHamBurger.name, reHamBurger);
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default ReHamBurger;
 | 
			
		||||
@ -1,3 +1,59 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import Hamburger from "./sidebar/hamBurger.vue";
 | 
			
		||||
import { useRouter, useRoute } from "vue-router";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import Breadcrumb from "./sidebar/breadCrumb.vue";
 | 
			
		||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
			
		||||
import { unref, watch, getCurrentInstance } from "vue";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import screenfull from "../components/screenfull/index.vue";
 | 
			
		||||
import globalization from "/@/assets/svg/globalization.svg";
 | 
			
		||||
 | 
			
		||||
const instance =
 | 
			
		||||
  getCurrentInstance().appContext.config.globalProperties.$storage;
 | 
			
		||||
const pureApp = useAppStoreHook();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
let usename = storageSession.getItem("info")?.username;
 | 
			
		||||
const { locale, t } = useI18n();
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => locale.value,
 | 
			
		||||
  () => {
 | 
			
		||||
    //@ts-ignore
 | 
			
		||||
    document.title = t(unref(route.meta.title)); // 动态title
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 退出登录
 | 
			
		||||
const logout = (): void => {
 | 
			
		||||
  storageSession.removeItem("info");
 | 
			
		||||
  router.push("/login");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function onPanel() {
 | 
			
		||||
  emitter.emit("openPanel");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function toggleSideBar() {
 | 
			
		||||
  pureApp.toggleSideBar();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 简体中文
 | 
			
		||||
function translationCh() {
 | 
			
		||||
  instance.locale = { locale: "zh" };
 | 
			
		||||
  locale.value = "zh";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// English
 | 
			
		||||
function translationEn() {
 | 
			
		||||
  instance.locale = { locale: "en" };
 | 
			
		||||
  locale.value = "en";
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="navbar">
 | 
			
		||||
    <Hamburger
 | 
			
		||||
@ -13,7 +69,7 @@
 | 
			
		||||
      <screenfull v-show="!deviceDetection()" />
 | 
			
		||||
      <!-- 国际化 -->
 | 
			
		||||
      <el-dropdown trigger="click">
 | 
			
		||||
        <iconinternationality />
 | 
			
		||||
        <globalization />
 | 
			
		||||
        <template #dropdown>
 | 
			
		||||
          <el-dropdown-menu class="translation">
 | 
			
		||||
            <el-dropdown-item
 | 
			
		||||
@ -60,99 +116,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, unref, watch, getCurrentInstance } from "vue";
 | 
			
		||||
import Breadcrumb from "/@/components/ReBreadCrumb";
 | 
			
		||||
import Hamburger from "/@/components/ReHamBurger";
 | 
			
		||||
import screenfull from "../components/screenfull/index.vue";
 | 
			
		||||
import { useRouter, useRoute } from "vue-router";
 | 
			
		||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import favicon from "/favicon.ico";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
import iconinternationality from "/@/assets/svg/iconinternationality.svg";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Navbar",
 | 
			
		||||
  components: {
 | 
			
		||||
    Breadcrumb,
 | 
			
		||||
    Hamburger,
 | 
			
		||||
    screenfull,
 | 
			
		||||
    iconinternationality
 | 
			
		||||
  },
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  computed: {
 | 
			
		||||
    // eslint-disable-next-line vue/return-in-computed-property
 | 
			
		||||
    currentLocale() {
 | 
			
		||||
      switch (this.$storage.locale?.locale) {
 | 
			
		||||
        case "zh":
 | 
			
		||||
          return true;
 | 
			
		||||
        case "en":
 | 
			
		||||
          return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const instance =
 | 
			
		||||
      getCurrentInstance().appContext.config.globalProperties.$storage;
 | 
			
		||||
    const pureApp = useAppStoreHook();
 | 
			
		||||
    const router = useRouter();
 | 
			
		||||
    const route = useRoute();
 | 
			
		||||
    let usename = storageSession.getItem("info")?.username;
 | 
			
		||||
    const { locale, t } = useI18n();
 | 
			
		||||
 | 
			
		||||
    watch(
 | 
			
		||||
      () => locale.value,
 | 
			
		||||
      () => {
 | 
			
		||||
        //@ts-ignore
 | 
			
		||||
        document.title = t(unref(route.meta.title)); // 动态title
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // 退出登录
 | 
			
		||||
    const logout = (): void => {
 | 
			
		||||
      storageSession.removeItem("info");
 | 
			
		||||
      router.push("/login");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function onPanel() {
 | 
			
		||||
      emitter.emit("openPanel");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function toggleSideBar() {
 | 
			
		||||
      pureApp.toggleSideBar();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 简体中文
 | 
			
		||||
    function translationCh() {
 | 
			
		||||
      instance.locale = { locale: "zh" };
 | 
			
		||||
      locale.value = "zh";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // English
 | 
			
		||||
    function translationEn() {
 | 
			
		||||
      instance.locale = { locale: "en" };
 | 
			
		||||
      locale.value = "en";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      locale,
 | 
			
		||||
      usename,
 | 
			
		||||
      pureApp,
 | 
			
		||||
      favicon,
 | 
			
		||||
      logout,
 | 
			
		||||
      onPanel,
 | 
			
		||||
      translationCh,
 | 
			
		||||
      translationEn,
 | 
			
		||||
      toggleSideBar,
 | 
			
		||||
      deviceDetection
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.navbar {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
@ -190,7 +153,7 @@ export default defineComponent({
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .iconinternationality {
 | 
			
		||||
    .globalization {
 | 
			
		||||
      height: 48px;
 | 
			
		||||
      width: 40px;
 | 
			
		||||
      padding: 11px;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,114 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import {
 | 
			
		||||
  computed,
 | 
			
		||||
  unref,
 | 
			
		||||
  watch,
 | 
			
		||||
  nextTick,
 | 
			
		||||
  onMounted,
 | 
			
		||||
  getCurrentInstance
 | 
			
		||||
} from "vue";
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
import settings from "/@/settings";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import SidebarItem from "./sidebarItem.vue";
 | 
			
		||||
import { algorithm } from "/@/utils/algorithm";
 | 
			
		||||
import screenfull from "../screenfull/index.vue";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import globalization from "/@/assets/svg/globalization.svg";
 | 
			
		||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
			
		||||
 | 
			
		||||
const instance =
 | 
			
		||||
  getCurrentInstance().appContext.config.globalProperties.$storage;
 | 
			
		||||
const menuRef = templateRef<ElRef | null>("menu", null);
 | 
			
		||||
const routeStore = usePermissionStoreHook();
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const routers = useRouter().options.routes;
 | 
			
		||||
let usename = storageSession.getItem("info")?.username;
 | 
			
		||||
const { locale, t } = useI18n();
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => locale.value,
 | 
			
		||||
  () => {
 | 
			
		||||
    //@ts-ignore
 | 
			
		||||
    // 动态title
 | 
			
		||||
    document.title = t(unref(route.meta.title));
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 退出登录
 | 
			
		||||
const logout = (): void => {
 | 
			
		||||
  storageSession.removeItem("info");
 | 
			
		||||
  router.push("/login");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function onPanel() {
 | 
			
		||||
  emitter.emit("openPanel");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const activeMenu = computed(() => {
 | 
			
		||||
  const { meta, path } = route;
 | 
			
		||||
  if (meta.activeMenu) {
 | 
			
		||||
    return meta.activeMenu;
 | 
			
		||||
  }
 | 
			
		||||
  return path;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const menuSelect = (indexPath: string): void => {
 | 
			
		||||
  let parentPath = "";
 | 
			
		||||
  let parentPathIndex = indexPath.lastIndexOf("/");
 | 
			
		||||
  if (parentPathIndex > 0) {
 | 
			
		||||
    parentPath = indexPath.slice(0, parentPathIndex);
 | 
			
		||||
  }
 | 
			
		||||
  // 找到当前路由的信息
 | 
			
		||||
  function findCurrentRoute(routes) {
 | 
			
		||||
    return routes.map(item => {
 | 
			
		||||
      if (item.path === indexPath) {
 | 
			
		||||
        // 切换左侧菜单 通知标签页
 | 
			
		||||
        emitter.emit("changLayoutRoute", {
 | 
			
		||||
          indexPath,
 | 
			
		||||
          parentPath
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        if (item.children) findCurrentRoute(item.children);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  findCurrentRoute(algorithm.increaseIndexes(routers));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function backHome() {
 | 
			
		||||
  router.push("/welcome");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleResize() {
 | 
			
		||||
  menuRef.value.handleResize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 简体中文
 | 
			
		||||
function translationCh() {
 | 
			
		||||
  instance.locale = { locale: "zh" };
 | 
			
		||||
  locale.value = "zh";
 | 
			
		||||
  handleResize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// English
 | 
			
		||||
function translationEn() {
 | 
			
		||||
  instance.locale = { locale: "en" };
 | 
			
		||||
  locale.value = "en";
 | 
			
		||||
  handleResize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    handleResize();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="horizontal-header">
 | 
			
		||||
    <div class="horizontal-header-left" @click="backHome">
 | 
			
		||||
@ -25,7 +136,7 @@
 | 
			
		||||
      <screenfull v-show="!deviceDetection()" />
 | 
			
		||||
      <!-- 国际化 -->
 | 
			
		||||
      <el-dropdown trigger="click">
 | 
			
		||||
        <iconinternationality />
 | 
			
		||||
        <globalization />
 | 
			
		||||
        <template #dropdown>
 | 
			
		||||
          <el-dropdown-menu class="translation">
 | 
			
		||||
            <el-dropdown-item
 | 
			
		||||
@ -72,177 +183,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import {
 | 
			
		||||
  computed,
 | 
			
		||||
  defineComponent,
 | 
			
		||||
  unref,
 | 
			
		||||
  watch,
 | 
			
		||||
  nextTick,
 | 
			
		||||
  onMounted,
 | 
			
		||||
  getCurrentInstance
 | 
			
		||||
} from "vue";
 | 
			
		||||
import { useI18n } from "vue-i18n";
 | 
			
		||||
import settings from "/@/settings";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import SidebarItem from "./sidebarItem.vue";
 | 
			
		||||
import { algorithm } from "/@/utils/algorithm";
 | 
			
		||||
import screenfull from "../screenfull/index.vue";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
			
		||||
import iconinternationality from "/@/assets/svg/iconinternationality.svg";
 | 
			
		||||
 | 
			
		||||
let routerArrays: Array<object> = [
 | 
			
		||||
  {
 | 
			
		||||
    path: "/welcome",
 | 
			
		||||
    parentPath: "/",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "message.hshome",
 | 
			
		||||
      icon: "el-icon-s-home",
 | 
			
		||||
      showLink: true,
 | 
			
		||||
      savedPosition: false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "sidebar",
 | 
			
		||||
  components: { SidebarItem, screenfull, iconinternationality },
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  computed: {
 | 
			
		||||
    // eslint-disable-next-line vue/return-in-computed-property
 | 
			
		||||
    currentLocale() {
 | 
			
		||||
      if (
 | 
			
		||||
        !this.$storage.routesInStorage ||
 | 
			
		||||
        this.$storage.routesInStorage.length === 0
 | 
			
		||||
      ) {
 | 
			
		||||
        // eslint-disable-next-line vue/no-side-effects-in-computed-properties
 | 
			
		||||
        this.$storage.routesInStorage = routerArrays;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!this.$storage.locale) {
 | 
			
		||||
        // eslint-disable-next-line
 | 
			
		||||
        this.$storage.locale = { locale: "zh" };
 | 
			
		||||
        useI18n().locale.value = "zh";
 | 
			
		||||
      }
 | 
			
		||||
      switch (this.$storage.locale?.locale) {
 | 
			
		||||
        case "zh":
 | 
			
		||||
          return true;
 | 
			
		||||
        case "en":
 | 
			
		||||
          return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const instance =
 | 
			
		||||
      getCurrentInstance().appContext.config.globalProperties.$storage;
 | 
			
		||||
    const menuRef = templateRef<ElRef | null>("menu", null);
 | 
			
		||||
 | 
			
		||||
    const routeStore = usePermissionStoreHook();
 | 
			
		||||
    const route = useRoute();
 | 
			
		||||
    const router = useRouter();
 | 
			
		||||
    const routers = useRouter().options.routes;
 | 
			
		||||
    let usename = storageSession.getItem("info")?.username;
 | 
			
		||||
    const { locale, t } = useI18n();
 | 
			
		||||
 | 
			
		||||
    watch(
 | 
			
		||||
      () => locale.value,
 | 
			
		||||
      () => {
 | 
			
		||||
        //@ts-ignore
 | 
			
		||||
        // 动态title
 | 
			
		||||
        document.title = t(unref(route.meta.title));
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // 退出登录
 | 
			
		||||
    const logout = (): void => {
 | 
			
		||||
      storageSession.removeItem("info");
 | 
			
		||||
      router.push("/login");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function onPanel() {
 | 
			
		||||
      emitter.emit("openPanel");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const activeMenu = computed(() => {
 | 
			
		||||
      const { meta, path } = route;
 | 
			
		||||
      if (meta.activeMenu) {
 | 
			
		||||
        return meta.activeMenu;
 | 
			
		||||
      }
 | 
			
		||||
      return path;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const menuSelect = (indexPath: string): void => {
 | 
			
		||||
      let parentPath = "";
 | 
			
		||||
      let parentPathIndex = indexPath.lastIndexOf("/");
 | 
			
		||||
      if (parentPathIndex > 0) {
 | 
			
		||||
        parentPath = indexPath.slice(0, parentPathIndex);
 | 
			
		||||
      }
 | 
			
		||||
      // 找到当前路由的信息
 | 
			
		||||
      function findCurrentRoute(routes) {
 | 
			
		||||
        return routes.map(item => {
 | 
			
		||||
          if (item.path === indexPath) {
 | 
			
		||||
            // 切换左侧菜单 通知标签页
 | 
			
		||||
            emitter.emit("changLayoutRoute", {
 | 
			
		||||
              indexPath,
 | 
			
		||||
              parentPath
 | 
			
		||||
            });
 | 
			
		||||
          } else {
 | 
			
		||||
            if (item.children) findCurrentRoute(item.children);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      findCurrentRoute(algorithm.increaseIndexes(routers));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function backHome() {
 | 
			
		||||
      router.push("/welcome");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function handleResize() {
 | 
			
		||||
      menuRef.value.handleResize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 简体中文
 | 
			
		||||
    function translationCh() {
 | 
			
		||||
      instance.locale = { locale: "zh" };
 | 
			
		||||
      locale.value = "zh";
 | 
			
		||||
      handleResize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // English
 | 
			
		||||
    function translationEn() {
 | 
			
		||||
      instance.locale = { locale: "en" };
 | 
			
		||||
      locale.value = "en";
 | 
			
		||||
      handleResize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        handleResize();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      locale,
 | 
			
		||||
      usename,
 | 
			
		||||
      settings,
 | 
			
		||||
      routeStore,
 | 
			
		||||
      activeMenu,
 | 
			
		||||
      logout,
 | 
			
		||||
      onPanel,
 | 
			
		||||
      backHome,
 | 
			
		||||
      menuSelect,
 | 
			
		||||
      translationCh,
 | 
			
		||||
      translationEn,
 | 
			
		||||
      deviceDetection
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.translation {
 | 
			
		||||
  .el-dropdown-menu__item {
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,61 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import Logo from "./logo.vue";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import SidebarItem from "./sidebarItem.vue";
 | 
			
		||||
import { algorithm } from "/@/utils/algorithm";
 | 
			
		||||
import { storageLocal } from "/@/utils/storage";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { computed, ref, onBeforeMount } from "vue";
 | 
			
		||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
			
		||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const pureApp = useAppStoreHook();
 | 
			
		||||
const router = useRouter().options.routes;
 | 
			
		||||
const routeStore = usePermissionStoreHook();
 | 
			
		||||
const showLogo = ref(storageLocal.getItem("logoVal") || "1");
 | 
			
		||||
const isCollapse = computed(() => {
 | 
			
		||||
  return !pureApp.getSidebarStatus;
 | 
			
		||||
});
 | 
			
		||||
const activeMenu = computed(() => {
 | 
			
		||||
  const { meta, path } = route;
 | 
			
		||||
  if (meta.activeMenu) {
 | 
			
		||||
    return meta.activeMenu;
 | 
			
		||||
  }
 | 
			
		||||
  return path;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const menuSelect = (indexPath: string): void => {
 | 
			
		||||
  let parentPath = "";
 | 
			
		||||
  let parentPathIndex = indexPath.lastIndexOf("/");
 | 
			
		||||
  if (parentPathIndex > 0) {
 | 
			
		||||
    parentPath = indexPath.slice(0, parentPathIndex);
 | 
			
		||||
  }
 | 
			
		||||
  // 找到当前路由的信息
 | 
			
		||||
  // eslint-disable-next-line no-inner-declarations
 | 
			
		||||
  function findCurrentRoute(routes) {
 | 
			
		||||
    return routes.map(item => {
 | 
			
		||||
      if (item.path === indexPath) {
 | 
			
		||||
        // 切换左侧菜单 通知标签页
 | 
			
		||||
        emitter.emit("changLayoutRoute", {
 | 
			
		||||
          indexPath,
 | 
			
		||||
          parentPath
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        if (item.children) findCurrentRoute(item.children);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  findCurrentRoute(algorithm.increaseIndexes(router));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onBeforeMount(() => {
 | 
			
		||||
  emitter.on("logoChange", key => {
 | 
			
		||||
    showLogo.value = key;
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div :class="['sidebar-container', showLogo ? 'has-logo' : '']">
 | 
			
		||||
    <Logo v-if="showLogo === '1'" :collapse="isCollapse" />
 | 
			
		||||
@ -21,77 +79,3 @@
 | 
			
		||||
    </el-scrollbar>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Logo from "./logo.vue";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import SidebarItem from "./sidebarItem.vue";
 | 
			
		||||
import { algorithm } from "/@/utils/algorithm";
 | 
			
		||||
import { storageLocal } from "/@/utils/storage";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { useAppStoreHook } from "/@/store/modules/app";
 | 
			
		||||
import { computed, defineComponent, ref, onBeforeMount } from "vue";
 | 
			
		||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "sidebar",
 | 
			
		||||
  components: { SidebarItem, Logo },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const routeStore = usePermissionStoreHook();
 | 
			
		||||
 | 
			
		||||
    const router = useRouter().options.routes;
 | 
			
		||||
 | 
			
		||||
    const pureApp = useAppStoreHook();
 | 
			
		||||
 | 
			
		||||
    const route = useRoute();
 | 
			
		||||
 | 
			
		||||
    const showLogo = ref(storageLocal.getItem("logoVal") || "1");
 | 
			
		||||
 | 
			
		||||
    const activeMenu = computed(() => {
 | 
			
		||||
      const { meta, path } = route;
 | 
			
		||||
      if (meta.activeMenu) {
 | 
			
		||||
        return meta.activeMenu;
 | 
			
		||||
      }
 | 
			
		||||
      return path;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const menuSelect = (indexPath: string): void => {
 | 
			
		||||
      let parentPath = "";
 | 
			
		||||
      let parentPathIndex = indexPath.lastIndexOf("/");
 | 
			
		||||
      if (parentPathIndex > 0) {
 | 
			
		||||
        parentPath = indexPath.slice(0, parentPathIndex);
 | 
			
		||||
      }
 | 
			
		||||
      // 找到当前路由的信息
 | 
			
		||||
      // eslint-disable-next-line no-inner-declarations
 | 
			
		||||
      function findCurrentRoute(routes) {
 | 
			
		||||
        return routes.map(item => {
 | 
			
		||||
          if (item.path === indexPath) {
 | 
			
		||||
            // 切换左侧菜单 通知标签页
 | 
			
		||||
            emitter.emit("changLayoutRoute", {
 | 
			
		||||
              indexPath,
 | 
			
		||||
              parentPath
 | 
			
		||||
            });
 | 
			
		||||
          } else {
 | 
			
		||||
            if (item.children) findCurrentRoute(item.children);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      findCurrentRoute(algorithm.increaseIndexes(router));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onBeforeMount(() => {
 | 
			
		||||
      emitter.on("logoChange", key => {
 | 
			
		||||
        showLogo.value = key;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      activeMenu,
 | 
			
		||||
      isCollapse: computed(() => !pureApp.getSidebarStatus),
 | 
			
		||||
      menuSelect,
 | 
			
		||||
      showLogo,
 | 
			
		||||
      routeStore
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,442 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
export default {
 | 
			
		||||
  computed: {
 | 
			
		||||
    dynamicTagList() {
 | 
			
		||||
      return this.$storage.routesInStorage;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import {
 | 
			
		||||
  ref,
 | 
			
		||||
  watch,
 | 
			
		||||
  onBeforeMount,
 | 
			
		||||
  unref,
 | 
			
		||||
  nextTick,
 | 
			
		||||
  getCurrentInstance
 | 
			
		||||
} from "vue";
 | 
			
		||||
import { RouteConfigs } from "../../types";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import { storageLocal } from "/@/utils/storage";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
 | 
			
		||||
 | 
			
		||||
import close from "/@/assets/svg/close.svg";
 | 
			
		||||
import refresh from "/@/assets/svg/refresh.svg";
 | 
			
		||||
import closeAll from "/@/assets/svg/close_all.svg";
 | 
			
		||||
import closeLeft from "/@/assets/svg/close_left.svg";
 | 
			
		||||
import closeOther from "/@/assets/svg/close_other.svg";
 | 
			
		||||
import closeRight from "/@/assets/svg/close_right.svg";
 | 
			
		||||
 | 
			
		||||
let refreshButton = "refresh-button";
 | 
			
		||||
const instance = getCurrentInstance();
 | 
			
		||||
let st: any;
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const showTags = ref(storageLocal.getItem("tagsVal") || false);
 | 
			
		||||
const containerDom = templateRef<HTMLElement | null>("containerDom", null);
 | 
			
		||||
const activeIndex = ref(-1);
 | 
			
		||||
let routerArrays: Array<RouteConfigs> = [
 | 
			
		||||
  {
 | 
			
		||||
    path: "/welcome",
 | 
			
		||||
    parentPath: "/",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "message.hshome",
 | 
			
		||||
      icon: "el-icon-s-home",
 | 
			
		||||
      showLink: true,
 | 
			
		||||
      savedPosition: false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
const tagsViews = ref<ForDataType<undefined>>([
 | 
			
		||||
  {
 | 
			
		||||
    icon: refresh,
 | 
			
		||||
    text: "重新加载",
 | 
			
		||||
    divided: false,
 | 
			
		||||
    disabled: false,
 | 
			
		||||
    show: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: close,
 | 
			
		||||
    text: "关闭当前标签页",
 | 
			
		||||
    divided: false,
 | 
			
		||||
    disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
    show: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: closeLeft,
 | 
			
		||||
    text: "关闭左侧标签页",
 | 
			
		||||
    divided: true,
 | 
			
		||||
    disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
    show: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: closeRight,
 | 
			
		||||
    text: "关闭右侧标签页",
 | 
			
		||||
    divided: false,
 | 
			
		||||
    disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
    show: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: closeOther,
 | 
			
		||||
    text: "关闭其他标签页",
 | 
			
		||||
    divided: true,
 | 
			
		||||
    disabled: routerArrays.length > 2 ? false : true,
 | 
			
		||||
    show: true
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    icon: closeAll,
 | 
			
		||||
    text: "关闭全部标签页",
 | 
			
		||||
    divided: false,
 | 
			
		||||
    disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
    show: true
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
// 显示模式,默认灵动模式显示
 | 
			
		||||
const showModel = ref(storageLocal.getItem("showModel") || "smart");
 | 
			
		||||
if (!showModel.value) {
 | 
			
		||||
  storageLocal.setItem("showModel", "card");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let visible = ref(false);
 | 
			
		||||
let buttonLeft = ref(0);
 | 
			
		||||
let buttonTop = ref(0);
 | 
			
		||||
 | 
			
		||||
// 当前右键选中的路由信息
 | 
			
		||||
let currentSelect = ref({});
 | 
			
		||||
 | 
			
		||||
function dynamicRouteTag(value: string, parentPath: string): void {
 | 
			
		||||
  const hasValue = st.routesInStorage.some((item: any) => {
 | 
			
		||||
    return item.path === value;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function concatPath(arr: object[], value: string, parentPath: string) {
 | 
			
		||||
    if (!hasValue) {
 | 
			
		||||
      arr.forEach((arrItem: any) => {
 | 
			
		||||
        let pathConcat = parentPath + arrItem.path;
 | 
			
		||||
        if (arrItem.path === value || pathConcat === value) {
 | 
			
		||||
          routerArrays.push({
 | 
			
		||||
            path: value,
 | 
			
		||||
            parentPath: `/${parentPath.split("/")[1]}`,
 | 
			
		||||
            meta: arrItem.meta
 | 
			
		||||
          });
 | 
			
		||||
          st.routesInStorage = routerArrays;
 | 
			
		||||
        } else {
 | 
			
		||||
          if (arrItem.children && arrItem.children.length > 0) {
 | 
			
		||||
            concatPath(arrItem.children, value, parentPath);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  concatPath(router.options.routes, value, parentPath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 重新加载
 | 
			
		||||
function onFresh() {
 | 
			
		||||
  toggleClass(true, refreshButton, document.querySelector(".rotate"));
 | 
			
		||||
  const { fullPath } = unref(route);
 | 
			
		||||
  router.replace({
 | 
			
		||||
    path: "/redirect" + fullPath
 | 
			
		||||
  });
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    removeClass(document.querySelector(".rotate"), refreshButton);
 | 
			
		||||
  }, 600);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteDynamicTag(obj: any, current: any, tag?: string) {
 | 
			
		||||
  let valueIndex: number = routerArrays.findIndex((item: any) => {
 | 
			
		||||
    return item.path === obj.path;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const spliceRoute = (start?: number, end?: number, other?: boolean): void => {
 | 
			
		||||
    if (other) {
 | 
			
		||||
      st.routesInStorage = [
 | 
			
		||||
        {
 | 
			
		||||
          path: "/welcome",
 | 
			
		||||
          parentPath: "/",
 | 
			
		||||
          meta: {
 | 
			
		||||
            title: "message.hshome",
 | 
			
		||||
            icon: "el-icon-s-home",
 | 
			
		||||
            showLink: true,
 | 
			
		||||
            savedPosition: false
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        obj
 | 
			
		||||
      ];
 | 
			
		||||
      routerArrays = st.routesInStorage;
 | 
			
		||||
    } else {
 | 
			
		||||
      routerArrays.splice(start, end);
 | 
			
		||||
      st.routesInStorage = routerArrays;
 | 
			
		||||
    }
 | 
			
		||||
    router.push(obj.path);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (tag === "other") {
 | 
			
		||||
    spliceRoute(1, 1, true);
 | 
			
		||||
  } else if (tag === "left") {
 | 
			
		||||
    spliceRoute(1, valueIndex - 1);
 | 
			
		||||
  } else if (tag === "right") {
 | 
			
		||||
    spliceRoute(valueIndex + 1, routerArrays.length);
 | 
			
		||||
  } else {
 | 
			
		||||
    // 从当前匹配到的路径中删除
 | 
			
		||||
    spliceRoute(valueIndex, 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (current === obj.path) {
 | 
			
		||||
    // 如果删除当前激活tag就自动切换到最后一个tag
 | 
			
		||||
    let newRoute: any = routerArrays.slice(-1);
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      router.push({
 | 
			
		||||
        path: newRoute[0].path
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deleteMenu(item, tag?: string) {
 | 
			
		||||
  deleteDynamicTag(item, item.path, tag);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onClickDrop(key, item, selectRoute?: RouteConfigs) {
 | 
			
		||||
  if (item && item.disabled) return;
 | 
			
		||||
  // 当前路由信息
 | 
			
		||||
  switch (key) {
 | 
			
		||||
    case 0:
 | 
			
		||||
      // 重新加载
 | 
			
		||||
      onFresh();
 | 
			
		||||
      break;
 | 
			
		||||
    case 1:
 | 
			
		||||
      // 关闭当前标签页
 | 
			
		||||
      selectRoute
 | 
			
		||||
        ? deleteMenu({ path: selectRoute.path, meta: selectRoute.meta })
 | 
			
		||||
        : deleteMenu({ path: route.path, meta: route.meta });
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:
 | 
			
		||||
      // 关闭左侧标签页
 | 
			
		||||
      selectRoute
 | 
			
		||||
        ? deleteMenu(
 | 
			
		||||
            {
 | 
			
		||||
              path: selectRoute.path,
 | 
			
		||||
              meta: selectRoute.meta
 | 
			
		||||
            },
 | 
			
		||||
            "left"
 | 
			
		||||
          )
 | 
			
		||||
        : deleteMenu({ path: route.path, meta: route.meta }, "left");
 | 
			
		||||
      break;
 | 
			
		||||
    case 3:
 | 
			
		||||
      // 关闭右侧标签页
 | 
			
		||||
      selectRoute
 | 
			
		||||
        ? deleteMenu(
 | 
			
		||||
            {
 | 
			
		||||
              path: selectRoute.path,
 | 
			
		||||
              meta: selectRoute.meta
 | 
			
		||||
            },
 | 
			
		||||
            "right"
 | 
			
		||||
          )
 | 
			
		||||
        : deleteMenu({ path: route.path, meta: route.meta }, "right");
 | 
			
		||||
      break;
 | 
			
		||||
    case 4:
 | 
			
		||||
      // 关闭其他标签页
 | 
			
		||||
      selectRoute
 | 
			
		||||
        ? deleteMenu(
 | 
			
		||||
            {
 | 
			
		||||
              path: selectRoute.path,
 | 
			
		||||
              meta: selectRoute.meta
 | 
			
		||||
            },
 | 
			
		||||
            "other"
 | 
			
		||||
          )
 | 
			
		||||
        : deleteMenu({ path: route.path, meta: route.meta }, "other");
 | 
			
		||||
      break;
 | 
			
		||||
    case 5:
 | 
			
		||||
      // 关闭全部标签页
 | 
			
		||||
      routerArrays.splice(1, routerArrays.length);
 | 
			
		||||
      st.routesInStorage = routerArrays;
 | 
			
		||||
      router.push("/welcome");
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    showMenuModel(route.fullPath);
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 触发右键中菜单的点击事件
 | 
			
		||||
function selectTag(key, item) {
 | 
			
		||||
  onClickDrop(key, item, currentSelect.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function closeMenu() {
 | 
			
		||||
  visible.value = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showMenus(value: Boolean) {
 | 
			
		||||
  Array.of(1, 2, 3, 4, 5).forEach(v => {
 | 
			
		||||
    tagsViews.value[v].show = value;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function disabledMenus(value: Boolean) {
 | 
			
		||||
  Array.of(1, 2, 3, 4, 5).forEach(v => {
 | 
			
		||||
    tagsViews.value[v].disabled = value;
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 检查当前右键的菜单两边是否存在别的菜单,如果左侧的菜单是首页,则不显示关闭左侧标签页,如果右侧没有菜单,则不显示关闭右侧标签页
 | 
			
		||||
function showMenuModel(currentPath: string, refresh = false) {
 | 
			
		||||
  let allRoute = unref(st.routesInStorage);
 | 
			
		||||
  let routeLength = unref(st.routesInStorage).length;
 | 
			
		||||
  // currentIndex为1时,左侧的菜单是首页,则不显示关闭左侧标签页
 | 
			
		||||
  let currentIndex = allRoute.findIndex(v => v.path === currentPath);
 | 
			
		||||
  // 如果currentIndex等于routeLength-1,右侧没有菜单,则不显示关闭右侧标签页
 | 
			
		||||
  showMenus(true);
 | 
			
		||||
 | 
			
		||||
  if (refresh) {
 | 
			
		||||
    tagsViews.value[0].show = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (currentIndex === 1 && routeLength !== 2) {
 | 
			
		||||
    // 左侧的菜单是首页,右侧存在别的菜单
 | 
			
		||||
    tagsViews.value[2].show = false;
 | 
			
		||||
    Array.of(1, 3, 4, 5).forEach(v => {
 | 
			
		||||
      tagsViews.value[v].disabled = false;
 | 
			
		||||
    });
 | 
			
		||||
    tagsViews.value[2].disabled = true;
 | 
			
		||||
  } else if (currentIndex === 1 && routeLength === 2) {
 | 
			
		||||
    disabledMenus(false);
 | 
			
		||||
    // 左侧的菜单是首页,右侧不存在别的菜单
 | 
			
		||||
    Array.of(2, 3, 4).forEach(v => {
 | 
			
		||||
      tagsViews.value[v].show = false;
 | 
			
		||||
      tagsViews.value[v].disabled = true;
 | 
			
		||||
    });
 | 
			
		||||
  } else if (routeLength - 1 === currentIndex && currentIndex !== 0) {
 | 
			
		||||
    // 当前路由是所有路由中的最后一个
 | 
			
		||||
    tagsViews.value[3].show = false;
 | 
			
		||||
    Array.of(1, 2, 4, 5).forEach(v => {
 | 
			
		||||
      tagsViews.value[v].disabled = false;
 | 
			
		||||
    });
 | 
			
		||||
    tagsViews.value[3].disabled = true;
 | 
			
		||||
  } else if (currentIndex === 0) {
 | 
			
		||||
    // 当前路由为首页
 | 
			
		||||
    disabledMenus(true);
 | 
			
		||||
  } else {
 | 
			
		||||
    disabledMenus(false);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function openMenu(tag, e) {
 | 
			
		||||
  closeMenu();
 | 
			
		||||
  if (tag.path === "/welcome") {
 | 
			
		||||
    // 右键菜单为首页,只显示刷新
 | 
			
		||||
    showMenus(false);
 | 
			
		||||
    tagsViews.value[0].show = true;
 | 
			
		||||
  } else if (route.path !== tag.path) {
 | 
			
		||||
    // 右键菜单不匹配当前路由,隐藏刷新
 | 
			
		||||
    tagsViews.value[0].show = false;
 | 
			
		||||
    showMenuModel(tag.path);
 | 
			
		||||
    // eslint-disable-next-line no-dupe-else-if
 | 
			
		||||
  } else if (st.routesInStorage.length === 2 && route.path !== tag.path) {
 | 
			
		||||
    showMenus(true);
 | 
			
		||||
    // 只有两个标签时不显示关闭其他标签页
 | 
			
		||||
    tagsViews.value[4].show = false;
 | 
			
		||||
  } else if (route.path === tag.path) {
 | 
			
		||||
    // 右键当前激活的菜单
 | 
			
		||||
    showMenuModel(tag.path, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  currentSelect.value = tag;
 | 
			
		||||
  const menuMinWidth = 105;
 | 
			
		||||
  const offsetLeft = unref(containerDom).getBoundingClientRect().left;
 | 
			
		||||
  const offsetWidth = unref(containerDom).offsetWidth;
 | 
			
		||||
  const maxLeft = offsetWidth - menuMinWidth;
 | 
			
		||||
  const left = e.clientX - offsetLeft + 5;
 | 
			
		||||
  if (left > maxLeft) {
 | 
			
		||||
    buttonLeft.value = maxLeft;
 | 
			
		||||
  } else {
 | 
			
		||||
    buttonLeft.value = left;
 | 
			
		||||
  }
 | 
			
		||||
  buttonTop.value = e.clientY + 10;
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    visible.value = true;
 | 
			
		||||
  }, 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 触发tags标签切换
 | 
			
		||||
function tagOnClick(item) {
 | 
			
		||||
  showMenuModel(item.path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 鼠标移入
 | 
			
		||||
function onMouseenter(item, index) {
 | 
			
		||||
  if (index) activeIndex.value = index;
 | 
			
		||||
  if (unref(showModel) === "smart") {
 | 
			
		||||
    if (hasClass(instance.refs["schedule" + index], "schedule-active")) return;
 | 
			
		||||
    toggleClass(true, "schedule-in", instance.refs["schedule" + index]);
 | 
			
		||||
    toggleClass(false, "schedule-out", instance.refs["schedule" + index]);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (hasClass(instance.refs["dynamic" + index], "card-active")) return;
 | 
			
		||||
    toggleClass(true, "card-in", instance.refs["dynamic" + index]);
 | 
			
		||||
    toggleClass(false, "card-out", instance.refs["dynamic" + index]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 鼠标移出
 | 
			
		||||
function onMouseleave(item, index) {
 | 
			
		||||
  activeIndex.value = -1;
 | 
			
		||||
  if (unref(showModel) === "smart") {
 | 
			
		||||
    if (hasClass(instance.refs["schedule" + index], "schedule-active")) return;
 | 
			
		||||
    toggleClass(false, "schedule-in", instance.refs["schedule" + index]);
 | 
			
		||||
    toggleClass(true, "schedule-out", instance.refs["schedule" + index]);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (hasClass(instance.refs["dynamic" + index], "card-active")) return;
 | 
			
		||||
    toggleClass(false, "card-in", instance.refs["dynamic" + index]);
 | 
			
		||||
    toggleClass(true, "card-out", instance.refs["dynamic" + index]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => visible.value,
 | 
			
		||||
  val => {
 | 
			
		||||
    if (val) {
 | 
			
		||||
      document.body.addEventListener("click", closeMenu);
 | 
			
		||||
    } else {
 | 
			
		||||
      document.body.removeEventListener("click", closeMenu);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
onBeforeMount(() => {
 | 
			
		||||
  if (!instance) return;
 | 
			
		||||
  st = instance.appContext.app.config.globalProperties.$storage;
 | 
			
		||||
  routerArrays = st.routesInStorage ?? routerArrays;
 | 
			
		||||
 | 
			
		||||
  // 根据当前路由初始化操作标签页的禁用状态
 | 
			
		||||
  showMenuModel(route.fullPath);
 | 
			
		||||
 | 
			
		||||
  // 触发隐藏标签页
 | 
			
		||||
  emitter.on("tagViewsChange", key => {
 | 
			
		||||
    if (unref(showTags) === key) return;
 | 
			
		||||
    showTags.value = key;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 改变标签风格
 | 
			
		||||
  emitter.on("tagViewsShowModel", key => {
 | 
			
		||||
    showModel.value = key;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  //  接收侧边栏切换传递过来的参数
 | 
			
		||||
  emitter.on("changLayoutRoute", ({ indexPath, parentPath }) => {
 | 
			
		||||
    dynamicRouteTag(indexPath, parentPath);
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      showMenuModel(indexPath);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div ref="containerDom" class="tags-view" v-if="!showTags">
 | 
			
		||||
    <el-scrollbar wrap-class="scrollbar-wrapper" class="scroll-container">
 | 
			
		||||
@ -87,479 +526,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import {
 | 
			
		||||
  ref,
 | 
			
		||||
  watch,
 | 
			
		||||
  onBeforeMount,
 | 
			
		||||
  unref,
 | 
			
		||||
  nextTick,
 | 
			
		||||
  getCurrentInstance
 | 
			
		||||
} from "vue";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { storageLocal } from "/@/utils/storage";
 | 
			
		||||
import { emitter } from "/@/utils/mitt";
 | 
			
		||||
import { toggleClass, removeClass, hasClass } from "/@/utils/operate";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import closeOther from "/@/assets/svg/close_other.svg";
 | 
			
		||||
import closeLeft from "/@/assets/svg/close_left.svg";
 | 
			
		||||
import closeRight from "/@/assets/svg/close_right.svg";
 | 
			
		||||
import close from "/@/assets/svg/close.svg";
 | 
			
		||||
import refresh from "/@/assets/svg/refresh.svg";
 | 
			
		||||
import closeAll from "/@/assets/svg/close_all.svg";
 | 
			
		||||
 | 
			
		||||
let refreshButton = "refresh-button";
 | 
			
		||||
let routerArrays: Array<object> = [
 | 
			
		||||
  {
 | 
			
		||||
    path: "/welcome",
 | 
			
		||||
    parentPath: "/",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "message.hshome",
 | 
			
		||||
      icon: "el-icon-s-home",
 | 
			
		||||
      showLink: true,
 | 
			
		||||
      savedPosition: false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "tag",
 | 
			
		||||
  components: {
 | 
			
		||||
    closeOther,
 | 
			
		||||
    closeLeft,
 | 
			
		||||
    closeRight,
 | 
			
		||||
    close,
 | 
			
		||||
    refresh,
 | 
			
		||||
    closeAll
 | 
			
		||||
  },
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  computed: {
 | 
			
		||||
    dynamicTagList() {
 | 
			
		||||
      return this.$storage.routesInStorage;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const instance = getCurrentInstance();
 | 
			
		||||
    let st: any;
 | 
			
		||||
    const route = useRoute();
 | 
			
		||||
    const router = useRouter();
 | 
			
		||||
    const showTags = ref(storageLocal.getItem("tagsVal") || false);
 | 
			
		||||
    const containerDom = templateRef<HTMLElement | null>("containerDom", null);
 | 
			
		||||
    const activeIndex = ref(-1);
 | 
			
		||||
    const tagsViews = ref([
 | 
			
		||||
      {
 | 
			
		||||
        icon: "refresh",
 | 
			
		||||
        text: "重新加载",
 | 
			
		||||
        divided: false,
 | 
			
		||||
        disabled: false,
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        icon: "close",
 | 
			
		||||
        text: "关闭当前标签页",
 | 
			
		||||
        divided: false,
 | 
			
		||||
        disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        icon: "closeLeft",
 | 
			
		||||
        text: "关闭左侧标签页",
 | 
			
		||||
        divided: true,
 | 
			
		||||
        disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        icon: "closeRight",
 | 
			
		||||
        text: "关闭右侧标签页",
 | 
			
		||||
        divided: false,
 | 
			
		||||
        disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        icon: "closeOther",
 | 
			
		||||
        text: "关闭其他标签页",
 | 
			
		||||
        divided: true,
 | 
			
		||||
        disabled: routerArrays.length > 2 ? false : true,
 | 
			
		||||
        show: true
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        icon: "closeAll",
 | 
			
		||||
        text: "关闭全部标签页",
 | 
			
		||||
        divided: false,
 | 
			
		||||
        disabled: routerArrays.length > 1 ? false : true,
 | 
			
		||||
        show: true
 | 
			
		||||
      }
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // 显示模式,默认灵动模式显示
 | 
			
		||||
    const showModel = ref(storageLocal.getItem("showModel") || "smart");
 | 
			
		||||
    if (!showModel.value) {
 | 
			
		||||
      storageLocal.setItem("showModel", "card");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let visible = ref(false);
 | 
			
		||||
    let buttonLeft = ref(0);
 | 
			
		||||
    let buttonTop = ref(0);
 | 
			
		||||
 | 
			
		||||
    // 当前右键选中的路由信息
 | 
			
		||||
    let currentSelect = ref({});
 | 
			
		||||
 | 
			
		||||
    function dynamicRouteTag(value: string, parentPath: string): void {
 | 
			
		||||
      const hasValue = st.routesInStorage.some((item: any) => {
 | 
			
		||||
        return item.path === value;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      function concatPath(arr: object[], value: string, parentPath: string) {
 | 
			
		||||
        if (!hasValue) {
 | 
			
		||||
          arr.forEach((arrItem: any) => {
 | 
			
		||||
            let pathConcat = parentPath + arrItem.path;
 | 
			
		||||
            if (arrItem.path === value || pathConcat === value) {
 | 
			
		||||
              routerArrays.push({
 | 
			
		||||
                path: value,
 | 
			
		||||
                parentPath: `/${parentPath.split("/")[1]}`,
 | 
			
		||||
                meta: arrItem.meta
 | 
			
		||||
              });
 | 
			
		||||
              st.routesInStorage = routerArrays;
 | 
			
		||||
            } else {
 | 
			
		||||
              if (arrItem.children && arrItem.children.length > 0) {
 | 
			
		||||
                concatPath(arrItem.children, value, parentPath);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      concatPath(router.options.routes, value, parentPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 重新加载
 | 
			
		||||
    function onFresh() {
 | 
			
		||||
      toggleClass(true, refreshButton, document.querySelector(".rotate"));
 | 
			
		||||
      const { fullPath } = unref(route);
 | 
			
		||||
      router.replace({
 | 
			
		||||
        path: "/redirect" + fullPath
 | 
			
		||||
      });
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        removeClass(document.querySelector(".rotate"), refreshButton);
 | 
			
		||||
      }, 600);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function deleteDynamicTag(obj: any, current: any, tag?: string) {
 | 
			
		||||
      let valueIndex: number = routerArrays.findIndex((item: any) => {
 | 
			
		||||
        return item.path === obj.path;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const spliceRoute = (
 | 
			
		||||
        start?: number,
 | 
			
		||||
        end?: number,
 | 
			
		||||
        other?: boolean
 | 
			
		||||
      ): void => {
 | 
			
		||||
        if (other) {
 | 
			
		||||
          st.routesInStorage = routerArrays = [
 | 
			
		||||
            {
 | 
			
		||||
              path: "/welcome",
 | 
			
		||||
              parentPath: "/",
 | 
			
		||||
              meta: {
 | 
			
		||||
                title: "message.hshome",
 | 
			
		||||
                icon: "el-icon-s-home",
 | 
			
		||||
                showLink: true,
 | 
			
		||||
                savedPosition: false
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            obj
 | 
			
		||||
          ];
 | 
			
		||||
        } else {
 | 
			
		||||
          routerArrays.splice(start, end);
 | 
			
		||||
          st.routesInStorage = routerArrays;
 | 
			
		||||
        }
 | 
			
		||||
        router.push(obj.path);
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (tag === "other") {
 | 
			
		||||
        spliceRoute(1, 1, true);
 | 
			
		||||
      } else if (tag === "left") {
 | 
			
		||||
        spliceRoute(1, valueIndex - 1);
 | 
			
		||||
      } else if (tag === "right") {
 | 
			
		||||
        spliceRoute(valueIndex + 1, routerArrays.length);
 | 
			
		||||
      } else {
 | 
			
		||||
        // 从当前匹配到的路径中删除
 | 
			
		||||
        spliceRoute(valueIndex, 1);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (current === obj.path) {
 | 
			
		||||
        // 如果删除当前激活tag就自动切换到最后一个tag
 | 
			
		||||
        let newRoute: any = routerArrays.slice(-1);
 | 
			
		||||
        nextTick(() => {
 | 
			
		||||
          router.push({
 | 
			
		||||
            path: newRoute[0].path
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function deleteMenu(item, tag?: string) {
 | 
			
		||||
      deleteDynamicTag(item, item.path, tag);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onClickDrop(key, item, selectRoute) {
 | 
			
		||||
      if (item && item.disabled) return;
 | 
			
		||||
      // 当前路由信息
 | 
			
		||||
      switch (key) {
 | 
			
		||||
        case 0:
 | 
			
		||||
          // 重新加载
 | 
			
		||||
          onFresh();
 | 
			
		||||
          break;
 | 
			
		||||
        case 1:
 | 
			
		||||
          // 关闭当前标签页
 | 
			
		||||
          selectRoute
 | 
			
		||||
            ? deleteMenu({ path: selectRoute.path, meta: selectRoute.meta })
 | 
			
		||||
            : deleteMenu({ path: route.path, meta: route.meta });
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          // 关闭左侧标签页
 | 
			
		||||
          selectRoute
 | 
			
		||||
            ? deleteMenu(
 | 
			
		||||
                {
 | 
			
		||||
                  path: selectRoute.path,
 | 
			
		||||
                  meta: selectRoute.meta
 | 
			
		||||
                },
 | 
			
		||||
                "left"
 | 
			
		||||
              )
 | 
			
		||||
            : deleteMenu({ path: route.path, meta: route.meta }, "left");
 | 
			
		||||
          break;
 | 
			
		||||
        case 3:
 | 
			
		||||
          // 关闭右侧标签页
 | 
			
		||||
          selectRoute
 | 
			
		||||
            ? deleteMenu(
 | 
			
		||||
                {
 | 
			
		||||
                  path: selectRoute.path,
 | 
			
		||||
                  meta: selectRoute.meta
 | 
			
		||||
                },
 | 
			
		||||
                "right"
 | 
			
		||||
              )
 | 
			
		||||
            : deleteMenu({ path: route.path, meta: route.meta }, "right");
 | 
			
		||||
          break;
 | 
			
		||||
        case 4:
 | 
			
		||||
          // 关闭其他标签页
 | 
			
		||||
          selectRoute
 | 
			
		||||
            ? deleteMenu(
 | 
			
		||||
                {
 | 
			
		||||
                  path: selectRoute.path,
 | 
			
		||||
                  meta: selectRoute.meta
 | 
			
		||||
                },
 | 
			
		||||
                "other"
 | 
			
		||||
              )
 | 
			
		||||
            : deleteMenu({ path: route.path, meta: route.meta }, "other");
 | 
			
		||||
          break;
 | 
			
		||||
        case 5:
 | 
			
		||||
          // 关闭全部标签页
 | 
			
		||||
          routerArrays.splice(1, routerArrays.length);
 | 
			
		||||
          st.routesInStorage = routerArrays;
 | 
			
		||||
          router.push("/welcome");
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        showMenuModel(route.fullPath);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 触发右键中菜单的点击事件
 | 
			
		||||
    function selectTag(key, item) {
 | 
			
		||||
      onClickDrop(key, item, currentSelect.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function closeMenu() {
 | 
			
		||||
      visible.value = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function showMenus(value: Boolean) {
 | 
			
		||||
      Array.of(1, 2, 3, 4, 5).forEach(v => {
 | 
			
		||||
        tagsViews.value[v].show = value;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function disabledMenus(value: Boolean) {
 | 
			
		||||
      Array.of(1, 2, 3, 4, 5).forEach(v => {
 | 
			
		||||
        tagsViews.value[v].disabled = value;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 检查当前右键的菜单两边是否存在别的菜单,如果左侧的菜单是首页,则不显示关闭左侧标签页,如果右侧没有菜单,则不显示关闭右侧标签页
 | 
			
		||||
    function showMenuModel(currentPath: string, refresh = false) {
 | 
			
		||||
      let allRoute = unref(st.routesInStorage);
 | 
			
		||||
      let routeLength = unref(st.routesInStorage).length;
 | 
			
		||||
      // currentIndex为1时,左侧的菜单是首页,则不显示关闭左侧标签页
 | 
			
		||||
      let currentIndex = allRoute.findIndex(v => v.path === currentPath);
 | 
			
		||||
      // 如果currentIndex等于routeLength-1,右侧没有菜单,则不显示关闭右侧标签页
 | 
			
		||||
      showMenus(true);
 | 
			
		||||
 | 
			
		||||
      if (refresh) {
 | 
			
		||||
        tagsViews.value[0].show = true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (currentIndex === 1 && routeLength !== 2) {
 | 
			
		||||
        // 左侧的菜单是首页,右侧存在别的菜单
 | 
			
		||||
        tagsViews.value[2].show = false;
 | 
			
		||||
        Array.of(1, 3, 4, 5).forEach(v => {
 | 
			
		||||
          tagsViews.value[v].disabled = false;
 | 
			
		||||
        });
 | 
			
		||||
        tagsViews.value[2].disabled = true;
 | 
			
		||||
      } else if (currentIndex === 1 && routeLength === 2) {
 | 
			
		||||
        disabledMenus(false);
 | 
			
		||||
        // 左侧的菜单是首页,右侧不存在别的菜单
 | 
			
		||||
        Array.of(2, 3, 4).forEach(v => {
 | 
			
		||||
          tagsViews.value[v].show = false;
 | 
			
		||||
          tagsViews.value[v].disabled = true;
 | 
			
		||||
        });
 | 
			
		||||
      } else if (routeLength - 1 === currentIndex && currentIndex !== 0) {
 | 
			
		||||
        // 当前路由是所有路由中的最后一个
 | 
			
		||||
        tagsViews.value[3].show = false;
 | 
			
		||||
        Array.of(1, 2, 4, 5).forEach(v => {
 | 
			
		||||
          tagsViews.value[v].disabled = false;
 | 
			
		||||
        });
 | 
			
		||||
        tagsViews.value[3].disabled = true;
 | 
			
		||||
      } else if (currentIndex === 0) {
 | 
			
		||||
        // 当前路由为首页
 | 
			
		||||
        disabledMenus(true);
 | 
			
		||||
      } else {
 | 
			
		||||
        disabledMenus(false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function openMenu(tag, e) {
 | 
			
		||||
      closeMenu();
 | 
			
		||||
      if (tag.path === "/welcome") {
 | 
			
		||||
        // 右键菜单为首页,只显示刷新
 | 
			
		||||
        showMenus(false);
 | 
			
		||||
        tagsViews.value[0].show = true;
 | 
			
		||||
      } else if (route.path !== tag.path) {
 | 
			
		||||
        // 右键菜单不匹配当前路由,隐藏刷新
 | 
			
		||||
        tagsViews.value[0].show = false;
 | 
			
		||||
        showMenuModel(tag.path);
 | 
			
		||||
        // eslint-disable-next-line no-dupe-else-if
 | 
			
		||||
      } else if (st.routesInStorage.length === 2 && route.path !== tag.path) {
 | 
			
		||||
        showMenus(true);
 | 
			
		||||
        // 只有两个标签时不显示关闭其他标签页
 | 
			
		||||
        tagsViews.value[4].show = false;
 | 
			
		||||
      } else if (route.path === tag.path) {
 | 
			
		||||
        // 右键当前激活的菜单
 | 
			
		||||
        showMenuModel(tag.path, true);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      currentSelect.value = tag;
 | 
			
		||||
      const menuMinWidth = 105;
 | 
			
		||||
      const offsetLeft = unref(containerDom).getBoundingClientRect().left;
 | 
			
		||||
      const offsetWidth = unref(containerDom).offsetWidth;
 | 
			
		||||
      const maxLeft = offsetWidth - menuMinWidth;
 | 
			
		||||
      const left = e.clientX - offsetLeft + 5;
 | 
			
		||||
      if (left > maxLeft) {
 | 
			
		||||
        buttonLeft.value = maxLeft;
 | 
			
		||||
      } else {
 | 
			
		||||
        buttonLeft.value = left;
 | 
			
		||||
      }
 | 
			
		||||
      buttonTop.value = e.clientY + 10;
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        visible.value = true;
 | 
			
		||||
      }, 10);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 触发tags标签切换
 | 
			
		||||
    function tagOnClick(item) {
 | 
			
		||||
      showMenuModel(item.path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 鼠标移入
 | 
			
		||||
    function onMouseenter(item, index) {
 | 
			
		||||
      if (index) activeIndex.value = index;
 | 
			
		||||
      if (unref(showModel) === "smart") {
 | 
			
		||||
        if (hasClass(instance.refs["schedule" + index], "schedule-active"))
 | 
			
		||||
          return;
 | 
			
		||||
        toggleClass(true, "schedule-in", instance.refs["schedule" + index]);
 | 
			
		||||
        toggleClass(false, "schedule-out", instance.refs["schedule" + index]);
 | 
			
		||||
      } else {
 | 
			
		||||
        if (hasClass(instance.refs["dynamic" + index], "card-active")) return;
 | 
			
		||||
        toggleClass(true, "card-in", instance.refs["dynamic" + index]);
 | 
			
		||||
        toggleClass(false, "card-out", instance.refs["dynamic" + index]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 鼠标移出
 | 
			
		||||
    function onMouseleave(item, index) {
 | 
			
		||||
      activeIndex.value = -1;
 | 
			
		||||
      if (unref(showModel) === "smart") {
 | 
			
		||||
        if (hasClass(instance.refs["schedule" + index], "schedule-active"))
 | 
			
		||||
          return;
 | 
			
		||||
        toggleClass(false, "schedule-in", instance.refs["schedule" + index]);
 | 
			
		||||
        toggleClass(true, "schedule-out", instance.refs["schedule" + index]);
 | 
			
		||||
      } else {
 | 
			
		||||
        if (hasClass(instance.refs["dynamic" + index], "card-active")) return;
 | 
			
		||||
        toggleClass(false, "card-in", instance.refs["dynamic" + index]);
 | 
			
		||||
        toggleClass(true, "card-out", instance.refs["dynamic" + index]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    watch(
 | 
			
		||||
      () => visible.value,
 | 
			
		||||
      val => {
 | 
			
		||||
        if (val) {
 | 
			
		||||
          document.body.addEventListener("click", closeMenu);
 | 
			
		||||
        } else {
 | 
			
		||||
          document.body.removeEventListener("click", closeMenu);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    onBeforeMount(() => {
 | 
			
		||||
      if (!instance) return;
 | 
			
		||||
      st = instance.appContext.app.config.globalProperties.$storage;
 | 
			
		||||
      routerArrays = st.routesInStorage ?? routerArrays;
 | 
			
		||||
 | 
			
		||||
      // 根据当前路由初始化操作标签页的禁用状态
 | 
			
		||||
      showMenuModel(route.fullPath);
 | 
			
		||||
 | 
			
		||||
      // 触发隐藏标签页
 | 
			
		||||
      emitter.on("tagViewsChange", key => {
 | 
			
		||||
        if (unref(showTags) === key) return;
 | 
			
		||||
        showTags.value = key;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // 改变标签风格
 | 
			
		||||
      emitter.on("tagViewsShowModel", key => {
 | 
			
		||||
        showModel.value = key;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      //  接收侧边栏切换传递过来的参数
 | 
			
		||||
      emitter.on("changLayoutRoute", ({ indexPath, parentPath }) => {
 | 
			
		||||
        dynamicRouteTag(indexPath, parentPath);
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          showMenuModel(indexPath);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      deleteMenu,
 | 
			
		||||
      showTags,
 | 
			
		||||
      onFresh,
 | 
			
		||||
      tagsViews,
 | 
			
		||||
      onClickDrop,
 | 
			
		||||
      visible,
 | 
			
		||||
      buttonLeft,
 | 
			
		||||
      buttonTop,
 | 
			
		||||
      openMenu,
 | 
			
		||||
      closeMenu,
 | 
			
		||||
      selectTag,
 | 
			
		||||
      currentSelect,
 | 
			
		||||
      onMouseenter,
 | 
			
		||||
      onMouseleave,
 | 
			
		||||
      tagOnClick,
 | 
			
		||||
      activeIndex,
 | 
			
		||||
      showModel,
 | 
			
		||||
      showMenuModel
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
@keyframes scheduleInWidth {
 | 
			
		||||
  from {
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,5 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
let routerArrays: Array<object> = [
 | 
			
		||||
  {
 | 
			
		||||
    path: "/welcome",
 | 
			
		||||
    parentPath: "/",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "message.hshome",
 | 
			
		||||
      icon: "el-icon-s-home",
 | 
			
		||||
      showLink: true,
 | 
			
		||||
      savedPosition: false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
import { routerArrays } from "./types";
 | 
			
		||||
export default {
 | 
			
		||||
  computed: {
 | 
			
		||||
    layout() {
 | 
			
		||||
@ -204,7 +193,6 @@ onBeforeMount(() => {
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
$sideBarWidth: 210px;
 | 
			
		||||
@mixin clearfix {
 | 
			
		||||
  &::after {
 | 
			
		||||
    content: "";
 | 
			
		||||
@ -241,7 +229,7 @@ $sideBarWidth: 210px;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  z-index: 9;
 | 
			
		||||
  width: calc(100% - #{$sideBarWidth});
 | 
			
		||||
  width: calc(100% - 210px);
 | 
			
		||||
  transition: width 0.28s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								src/layout/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/layout/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
export type RouteConfigs = {
 | 
			
		||||
  path?: string;
 | 
			
		||||
  parentPath?: string;
 | 
			
		||||
  meta?: {
 | 
			
		||||
    title?: string;
 | 
			
		||||
    icon?: string;
 | 
			
		||||
    showLink?: boolean;
 | 
			
		||||
    savedPosition?: boolean;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const routerArrays: Array<RouteConfigs> = [
 | 
			
		||||
  {
 | 
			
		||||
    path: "/welcome",
 | 
			
		||||
    parentPath: "/",
 | 
			
		||||
    meta: {
 | 
			
		||||
      title: "message.hshome",
 | 
			
		||||
      icon: "el-icon-s-home",
 | 
			
		||||
      showLink: true,
 | 
			
		||||
      savedPosition: false
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
@ -179,7 +179,7 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .iconinternationality {
 | 
			
		||||
      .globalization {
 | 
			
		||||
        height: 62px;
 | 
			
		||||
        width: 40px;
 | 
			
		||||
        padding: 11px;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user