Bläddra i källkod

增加头部导航栏标签

wxy 4 månader sedan
förälder
incheckning
602219c0c4

+ 53 - 61
src/components/Layout/components/layout/blendLeft.vue

@@ -1,7 +1,7 @@
 <template>
   <a-layout style="min-height: 100vh">
     <a-layout-sider theme="dark" :width="140" :collapsed-width="48" collapsible :trigger="null"
-      @collapse="evMenuSecondLongShow" v-model:collapsed="menuSecondLongShow">
+      v-model:collapsed="menuSecondLongShow">
       <div class="logo-layout">
         <div class="logo">
           <img src="@/assets/images/logo.png" style="height: 26px; width: 26px;" />
@@ -9,9 +9,8 @@
         </div>
       </div>
 
-      <a-menu v-model:selectedKeys="menuTabSate" theme="dark" mode="inline" @mouseleave="evMouseleaveMenu">
-        <a-menu-item v-for="routeItem in routesData" :key="routeItem.name"
-          @mouseenter="evMenuGetFn(routeItem, 'mouseenter')" @click="changeRoutesItems(routeItem)">
+      <a-menu v-model:selectedKeys="menuTabSate" theme="dark" mode="inline">
+        <a-menu-item v-for="routeItem in routesData" :key="routeItem.name" @click="changeRoutesItems(routeItem)">
           <template #icon>
             <svg-icon :icon="routeItem.meta.icon"></svg-icon>
           </template>
@@ -26,23 +25,23 @@
       </a-layout-header>
       <a-layout>
         <a-layout-sider id="layout-sider" :collapsed="false" :width="menuSecondData &&
-          menuSecondData.children &&
-          menuSecondData.children.length > 0
+          menuSecondData &&
+          menuSecondData.length > 0
           ? 160
           : 0
-          " @mouseleave="evMouseLeavesSubMenu">
+          ">
           <a-menu :selectedKeys="routeItemSelectedKeys" id="layout-sider" theme="light" mode="vertical"
             :collapsed="false" :auto-open="true">
-            <template v-for="routeItem in menuSecondData?.children || []">
+            <template v-for="routeItem in menuSecondData || []">
               <!-- {{ routeItem }} -->
-              <a-menu-item v-if="!routeItem.children || routeItem.children.length === 0"
-                :key="routeItem.name?.toString()" @click="evGoPage(routeItem)">
+              <a-menu-item v-if="menuSecondData.length !== 0" :key="routeItem.name?.toString()"
+                @click="evGoPage(routeItem)">
                 <span class="menu-level-font">{{ routeItem.meta.title }}</span>
               </a-menu-item>
-
-              <template v-else-if="routeItem.children && routeItem.children.length > 0">
+              <!-- 
+              <template v-else-if="menuSecondData && menuSecondData.length > 0">
                 <sub-menu :key="routeItem.name" :menu-info="routeItem" @go="evGoPage" />
-              </template>
+              </template> -->
             </template>
           </a-menu>
         </a-layout-sider>
@@ -62,7 +61,7 @@ import { useRoute, useRouter } from "vue-router";
 import { useSystemStore } from "@/store/modules/systemStore";
 import LayoutHeader from "@/components/Layout/components/layoutHeader/index.vue";
 import subMenu from "@/components/Layout/components/subMenu/index.vue";
-import {RouterTagData} from '@/store/modules/routerTag.js'
+import { RouterTagData } from '@/store/modules/routerTag.js'
 
 // 标签页仓库
 const settingStore = RouterTagData()
@@ -76,37 +75,11 @@ const menuSecondLongShow = ref(systemStore.menuSecondLongShow);
 // 主菜单
 const routesData = router.options.routes[0]?.children || [];
 
-const menuTabSate = ref([systemStore.getMenuTabSate || routesData[0].name]);
+const menuTabSate = ref();
 //子菜单
-const menuSecondData = ref(systemStore.getRouteItem);
-// 选中的状态路由列表
-const menuSecondSelectedStatusData = ref(systemStore.getRouteItem);
+const menuSecondData = ref();
 const routeItemSelectedKeys = ref();
 
-const evMenuSecondLongShow = () => {
-  systemStore.setStateValue({
-    key: "menuSecondLongShow",
-    value: menuSecondLongShow.value ? 1 : 0,
-    localStorage: true,
-  });
-};
-const evMouseleaveMenu = (e) => {
-  if (
-    e.relatedTarget?.offsetParent?.id &&
-    e.relatedTarget?.offsetParent?.id == "layout-sider"
-  )
-    return;
-  menuSecondData.value = menuSecondSelectedStatusData.value;
-};
-// 子菜单
-const evMouseLeavesSubMenu = () => {
-  menuSecondData.value = menuSecondSelectedStatusData.value;
-};
-// 鼠标滑动上去更新菜单栏 目前先屏蔽
-const evMenuGetFn = (routeItem, type) => {
-  // menuSecondData.value = routeItem;
-  // console.log(routeItem);
-};
 
 // 查找最下级
 const findPath = (data) => {
@@ -119,43 +92,62 @@ const findPath = (data) => {
 
 // 主路由 状态
 const changeRoutesItems = (e) => {
-  const item = findPath(e);
-  evGoPage(item);
+  evGoPage(e);
 };
 
 // 跳转路由
 const evGoPage = async (routeItem) => {
-  // settingStore.tagsPushData(routeItem);
-  await router.push({
-    name: routeItem.name,
-  });
-  menuTabSate.value = [route.matched[1].name];
+  // 主路由跳转
+  if (routeItem.children) {
+    menuSecondData.value = routeItem.children
+    await router.push({
+      name: routeItem.children[0].name,
+    });
+    routeItemSelectedKeys.value = routeItem.children[0].name
+  } else {
+    await router.push({
+      name: routeItem.name,
+    });
+    routeItemSelectedKeys.value = routeItem.name
+  }
   systemStore.setStateValue({
     key: "menuTabSate",
-    value: menuTabSate.value[0] || "",
+    value: routeItem.children?routeItem.children[0].name:routeItem.name,
     localStorage: true,
   });
+  settingStore.getDefault(routeItem.children?routeItem.children[0].name:routeItem.name)
 
-  menuSecondSelectedStatusData.value = routesData.find(
-    (item) => item.name == menuTabSate.value
-  );
-  menuSecondData.value = menuSecondSelectedStatusData.value;
-  systemStore.setStateValue({
-    key: "routeItem",
-    value: JSON.stringify(menuSecondData.value),
-    localStorage: true,
-  });
+  settingStore.tagsPushData(routeItem.children?routeItem.children[0]:routeItem)
 };
 
 watch(
   route,
   (val) => {
     if (val.name) {
-      routeItemSelectedKeys.value = [val.name];
+      routesData.forEach(item => {
+        item.children.forEach(res => {
+          if (res.name == val.name) {
+            menuSecondData.value = item.children
+          }
+        })
+      })
     }
   },
-  { immediate: true }
+  { immediate: true, deep: true }
 );
+
+watch(() => settingStore.getMenuTabSate, val => {
+  if (val) {
+    routeItemSelectedKeys.value = [val]
+    menuTabSate.value = routesData.map(item => {
+      const found = item.children.find(res => res.name === val);
+      return found ? item.name : null; 
+    }).filter(name => name !== null); 
+  } else {
+    routeItemSelectedKeys.value = [routesData[0].children?.name]
+    menuTabSate.value = [routesData[0].name]
+  }
+}, { immediate: true })
 </script>
 <style scoped lang="less">
 .layout-header {

+ 89 - 47
src/components/Layout/components/layoutHeader/index.vue

@@ -2,74 +2,67 @@
   <div class="header">
     <!--    标签-->
     <div class="flex-left-tag">
-<!--      <a-space wrap>-->
-<!--        <a-tag-->
-<!--            v-for="(tag, index) in tags"-->
-<!--            :key="tag.name"-->
-<!--            :closable="index !== 0"-->
-<!--            @close="settingStore.handleRemove(tag)"-->
-<!--        >-->
-<!--          {{ tag.meta.title }}-->
-<!--        </a-tag>-->
-<!--      </a-space>-->
+      <a-space wrap>
+        <a-tag v-for="(tag, index) in tags" :key="tag.name" :closable="tag.name !== route.name"
+          @close="routerTagData.handleRemove(tag)" @click="tabsRouter(tag)" class="tags" color="arcoblue">
+          {{ tag.meta.title }}
+        </a-tag>
+      </a-space>
+      <div class="setting" v-if="tags.length !== 0">
+        <a-button type="outline" @click="ClearNavigation">清空导航</a-button>
+      </div>
     </div>
     <!--    个人信息和操作-->
     <div class="flex-right-user">
-      <a-select :style="{width:'100px'}" v-model="langStore.lang" :bordered="false" @change="toggleLang">
-        <a-option v-for="item in langList" :key="item.key" :value="item.key">{{ item.label }}</a-option>
-      </a-select>
-
-      <div class="toggle-theme-box">
-        <icon-sun-fill v-if="designStore.getDarkTheme" @click="toggleTheme(false)" :size="18"/>
-        <icon-moon-fill v-else @click="toggleTheme(true)" :size="18"/>
-      </div>
-
       <a-dropdown trigger="click">
         <a-avatar :size="38" class="avatar-body">
-          <img
-              class="avatar-image"
-              alt="avatar"
-              src="https://avatars.githubusercontent.com/u/39849555?v=4"
-          />
+          <img class="avatar-image" alt="avatar" src="https://avatars.githubusercontent.com/u/39849555?v=4" />
         </a-avatar>
+        <div class="userName">{{ userInform?.username }}</div>
         <template #content>
           <a-doption>
             <a-space @click="evHandleLogout">
-              <icon-export/>
+              <icon-export />
               <span>{{ $t('global.logOut') }}</span>
             </a-space>
           </a-doption>
         </template>
       </a-dropdown>
+
+      <div class="toggle-theme-box">
+        <icon-sun-fill v-if="designStore.getDarkTheme" @click="toggleTheme(false)" :size="18" />
+        <icon-moon-fill v-else @click="toggleTheme(true)" :size="18" />
+      </div>
+      <a-select :style="{ width: '100px' }" v-model="langStore.lang" :bordered="false" @change="toggleLang">
+        <a-option v-for="item in langList" :key="item.key" :value="item.key">{{ item.label }}</a-option>
+      </a-select>
     </div>
   </div>
 </template>
 
 <script setup>
-import {ref, inject, onMounted, watch, reactive} from 'vue'
-import {useRouter} from 'vue-router'
-import {useSystemStore} from '@/store/modules/systemStore'
-import {Notification} from '@arco-design/web-vue'
-import {useDesignStore} from '@/store/modules/designStore'
-import {useLangStore} from '@/store/modules/langStore'
-import {useI18n} from 'vue-i18n'
-import {langList} from '@/i18n'
-import {fn_logout} from '@/utils'
-import {RouterTagData} from '@/store/modules/routerTag.js'
-import { setLocalStorage, getLocalStorage } from "@/utils";
-// 标签页仓库
-const settingStore = RouterTagData()
-import {updateRouteByMenu} from "@/router/router.update.js"
-
+import { onMounted, ref, watch } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
+import { useSystemStore } from '@/store/modules/systemStore'
+import { Notification } from '@arco-design/web-vue'
+import { useDesignStore } from '@/store/modules/designStore'
+import { useLangStore } from '@/store/modules/langStore'
+import { useI18n } from 'vue-i18n'
+import { langList } from '@/i18n'
+import { fn_logout } from '@/utils'
+import { RouterTagData } from '@/store/modules/routerTag.js'
+import { updateRouteByMenu } from "@/router/router.update.js"
+import { Modal } from '@arco-design/web-vue';
 
 const router = useRouter()
-const {locale} = useI18n()
+const route = useRoute()
+const { locale } = useI18n()
 const systemStore = useSystemStore()
 const designStore = useDesignStore()
 const langStore = useLangStore()
-
-
-// const reload  = inject('reloadRoutePage')
+const userInform = ref()
+const routerTagData = RouterTagData()
+const tags = ref([])
 
 const toggleTheme = (e) => {
   designStore.changeTheme(e)
@@ -83,21 +76,49 @@ const toggleLang = async (e) => {
 }
 
 const evHandleLogout = () => {
-
   Notification.success({
     content: '退出成功!',
     duration: 1000,
   })
   // 清除缓存数据
   fn_logout()
-
   router.push({
     name: "login",
   })
 }
 
+watch(
+  () => routerTagData.tagData,
+  (val) => {
+    // 更新 tags
+    tags.value = val;
+  },
+  { deep: true }
+);
+
+const tabsRouter = (data) => {
+  router.push(data.name)
+  localStorage.setItem('menuTabSate', data.name)
+  routerTagData.getDefault(data.name)
+}
 
+// 清空导航
+const ClearNavigation = () => {
+  Modal.warning({
+    title: '确定要清空当前导航栏吗',
+    closable:true,
+    onOk:()=>{
+      routerTagData.tagData = []
+      localStorage.removeItem('RouterTagData')
+    }
+  });
+}
 
+onMounted(() => {
+  userInform.value = JSON.parse(localStorage.getItem("user_login_information")) || ''
+  const tagList = localStorage.getItem('RouterTagData') || []
+  routerTagData.tagsPushFilter(tagList)
+})
 </script>
 
 <style scoped lang="less">
@@ -109,10 +130,23 @@ const evHandleLogout = () => {
   padding: 0 10px;
 }
 
+.flex-left-tag {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  justify-content: space-between;
+
+  :deep(.arco-space-item) {
+    margin-bottom: 0 !important;
+  }
+
+}
+
 .flex-right-user {
   width: auto;
   display: flex;
   align-items: center;
+  margin-left: 3rem;
 }
 
 .avatar-body {
@@ -130,10 +164,18 @@ const evHandleLogout = () => {
 }
 
 .toggle-theme-box {
-  margin-right: 0.8rem;
+  margin-left: 0.8rem;
 }
 
 :deep(.arco-select-view-suffix) {
   padding: 0;
 }
+
+.userName {
+  margin-left: 0.8rem;
+}
+
+.tags {
+  cursor: pointer;
+}
 </style>

+ 38 - 11
src/store/modules/routerTag.js

@@ -1,14 +1,41 @@
-import { defineStore } from 'pinia'
+import { defineStore } from "pinia";
 import { setLocalStorage, getLocalStorage } from "@/utils";
-
 export const RouterTagData = defineStore({
-    id: 'RouterTagData',
-    state: () => ({
-        tagData:  []
-    }),
-    getters: {
-
+  id: "RouterTagData",
+  state: () => ({
+    tagData: [],
+    getMenuTabSate:localStorage.getItem('menuTabSate') || ''
+  }),
+  getters: {},
+  actions: {
+    tagsPushData(data) {
+      // 先将已有的相同 name 的标签移除
+      this.tagData = this.tagData.filter((res) => res.name !== data.name);
+      // 再将新的标签加入
+      this.tagData.push(data);
+      this.localStorageTagsData(this.tagData);
+    },
+    // 初始化标签
+    tagsPushFilter(data) {
+      if (data.length !== 0) {
+        this.tagData = JSON.parse(data);
+      } else {
+        this.tagData = data;
+      }
+    },
+    // 删除标签
+    handleRemove(data) {
+      // 去重
+      this.tagData = this.tagData.filter((item) => item.name !== data.name);
+      this.localStorageTagsData(this.tagData);
     },
-    actions: {
-    }
-})
+    localStorageTagsData(data) {
+      localStorage.setItem("RouterTagData", JSON.stringify(data));
+    },
+    // 默认选中菜单
+    getDefault(data){
+        this.getMenuTabSate = data
+    },
+
+  },
+});