소스 검색

完成页面布局的切换

xiaochan 1 년 전
부모
커밋
9a4b2e7b0b

+ 13 - 18
src/layout/HeaderV2/Logo.vue

@@ -1,29 +1,26 @@
 <template>
-  <div class="box">
-    <div class="logo-container" v-if="showLogo">
-      <img alt="" src="@/assets/csthyylogoplain.png"/>
-      <h1>
-        {{ systemTitle }}
-        <br/>
-        <span style="font-size: 12px">编码:{{ systemStore.hospitalCode }} </span>
-      </h1>
-    </div>
-
-    <CollapseIcon/>
-
+  <div class="logo-container">
+    <img alt="logo" src="@/assets/csthyylogoplain.png"/>
+    <h1 v-if="showText">
+      {{ systemTitle }}
+      <br/>
+      <span style="font-size: 12px">编码:{{ systemStore.hospitalCode }} </span>
+    </h1>
   </div>
 </template>
 
 <script setup lang="ts">
 import {systemTitle} from '@/config'
 import {useSystemStore} from "@/pinia/system-store";
-import CollapseIcon from "@/layout/compoents/CollapseIcon.vue";
 
-defineProps<{
-  showLogo: boolean
-}>()
+withDefaults(defineProps<{
+  showText?: boolean;
+}>(), {
+  showText: true
+})
 
 const systemStore = useSystemStore()
+
 </script>
 
 <style lang="scss" scoped>
@@ -32,7 +29,6 @@ const systemStore = useSystemStore()
   justify-content: center;
   align-items: center;
   height: 40px;
-  padding: 10px;
   background-color: white;
 }
 
@@ -41,7 +37,6 @@ const systemStore = useSystemStore()
   align-items: center;
   width: 100%;
   background-color: white;
-  padding-left: 5px;
 
   img {
     width: 28px

+ 0 - 19
src/layout/HeaderV2/tabs-hook.ts

@@ -1,19 +0,0 @@
-import {clone} from "xe-utils";
-
-const tabsHook = {
-    setItem: function (arr: any) {
-        localStorage.setItem('tabs', JSON.stringify(arr))
-    },
-    getItem: function (): any[] {
-        return clone(JSON.parse(localStorage.getItem('tabs') || '[]'))
-    },
-    getItemKey: function (): any[] {
-        let data = this.getItem()
-        let temp = []
-        for (let i = 0; i < data.length; i++) {
-            temp.push(JSON.stringify(data[i]))
-        }
-        return temp
-    }
-}
-export default tabsHook

+ 5 - 0
src/layout/MenuV2/MenuItemV2.vue

@@ -14,6 +14,7 @@
                   v-for="item in data?.children"/>
   </el-sub-menu>
   <el-menu-item v-else
+                :class="{'menu-item-padding': data.children === null}"
                 @click="(value) => menuItem(value , data)"
                 :index="data?.completePath"
                 :id="data.name"
@@ -90,4 +91,8 @@ a {
   outline: none;
   color: #000;
 }
+
+.menu-item-padding {
+  padding: 0 16px;
+}
 </style>

+ 14 - 13
src/layout/MenuV2/MenuV2.vue

@@ -1,16 +1,15 @@
 <template>
   <div class="floating">
-    <div>
-      <Logo :show-logo="!isCollapse"/>
-      <div style="height: 30px; padding: 0 8px 8px 8px" @click="expandMenu" id="tutorial_search_menu">
-        <el-input
-            ref="searchRef"
-            v-model="menuText"
-            prefix-icon="Search"
-            clearable
-            @input="searchInput"
-            placeholder="菜单太难找?在这里搜索。"/>
-      </div>
+    <div
+        style="height: 30px; padding: 0 8px 8px 8px"
+        @click="expandMenu">
+      <el-input
+          ref="searchRef"
+          v-model="menuText"
+          prefix-icon="Search"
+          clearable
+          @input="searchInput"
+          placeholder="菜单太难找?在这里搜索。"/>
     </div>
 
     <div class="layout_flex_1-y">
@@ -30,7 +29,6 @@
         </el-menu>
       </el-scrollbar>
     </div>
-
   </div>
 </template>
 
@@ -38,7 +36,6 @@
 import MenuItemV2 from "./MenuItemV2.vue";
 import {computed, nextTick, onMounted, Ref, ref, watch} from "vue";
 import {useRoute} from "vue-router";
-import Logo from '../HeaderV2/Logo.vue'
 import XEUtils from "xe-utils";
 import router, {routerMenus} from '@/router'
 import sleep from "@/utils/sleep";
@@ -48,6 +45,10 @@ import {ElMenu} from "element-plus";
 import {useSystemStore} from "@/pinia/system-store";
 import {stringNotBlank} from "@/utils/blank-utils";
 
+defineProps<{
+  type: 'default' | 'fillet'
+}>()
+
 const menuText: Ref<string> = ref('')
 const menuRef = useCompRef(ElMenu)
 const menuData = computed(() => {

+ 1 - 6
src/layout/compoents/CollapseIcon.vue

@@ -21,12 +21,7 @@ const switchCollapse = () => {
 
 <style lang="scss">
 .collapse-icon {
-  margin-right: 5px;
   font-size: 26px;
-
-  &:hover {
-    background: lightgray;
-    cursor: pointer;
-  }
+  cursor: pointer;
 }
 </style>

+ 151 - 0
src/layout/default-layout/DefaultTabs.vue

@@ -0,0 +1,151 @@
+<script setup lang="tsx">
+import {useTab} from "@/pinia/use-tabs";
+import {useCyNamespace} from "@/utils/xiaochan-element-plus";
+import {Close} from "@element-plus/icons-vue";
+import RightClickMenu from "@/components/menu-item/RightClickMenu.vue";
+import router from "@/router";
+import {ref, watch} from "vue";
+
+const ns = useCyNamespace('default-tabs')
+const tagRef = ref<HTMLElement | null>(null)
+const opt = [
+  {
+    name: '关闭', click: (data, index) => {
+      useTab.removeByIndex(index)
+    }
+  },
+  {
+    name: '关闭其他选项卡', click: (data, index: number) => {
+      router.push(data.path)
+      useTab.closeOther(index)
+    }
+  },
+  {
+    name: '关闭所有选项卡', click: (data, index) => {
+      useTab.closeAll()
+    }
+  },
+  {
+    name: '关闭左侧选项卡', click: (data, index) => {
+      useTab.closeLeft(index)
+    }
+  },
+  {
+    name: '关闭右侧选项卡', click: (data, index) => {
+      useTab.closeRight(index)
+    }
+  }
+]
+const mousePosition = ref()
+const contextmenuItem = (item, index, event) => {
+  mousePosition.value = {
+    event,
+    data: item,
+    index
+  }
+}
+
+async function handleScrolling() {
+  await nextTick()
+  const name = router.currentRoute.value.name
+  const key = `#router_tabs-${name}`
+  const item = tagRef.value!.querySelector(key)
+  item.scrollIntoView({
+    block: 'center',
+    inline: 'nearest',
+    behavior: 'smooth'
+  })
+}
+
+watch(() => useTab.tabs.value, () => {
+  nextTick(() => {
+    handleScrolling()
+  })
+}, {deep: true})
+
+watch(() => router.currentRoute.value, () => {
+  useTab.tabsAdd(router.currentRoute.value)
+  handleScrolling()
+}, {deep: true, immediate: true})
+</script>
+
+<template>
+  <right-click-menu
+      :mouse-position="mousePosition"
+      :config="opt"/>
+  <el-scrollbar>
+    <div
+        ref="tagRef"
+        :class="[ns.b('tagsview')]"
+    >
+      <div
+          :id="`router_tabs-${item.name}`"
+          v-for="(item,index) in useTab.tabs.value"
+          @click="useTab.routerPush(index)"
+          @contextmenu.prevent="contextmenuItem(item,index,$event)"
+          :class="[
+              ns.is('active' , useTab.isActive(item.name)),
+              ns.b('item')
+          ]"
+          class="layout-tabs_item">
+        <span>
+          {{ item.title }}
+        </span>
+        <el-icon
+            @click.stop.prevent="useTab.removeByIndex(index)"
+            style="margin-left: 5px">
+          <Close/>
+        </el-icon>
+      </div>
+    </div>
+  </el-scrollbar>
+</template>
+
+<style lang="scss">
+.tags-style-five-svg {
+  -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxwYXRoIHRyYW5zZm9ybT0icm90YXRlKC0wLjEzMzUwNiA1MC4xMTkyIDUwKSIgaWQ9InN2Z18xIiBkPSJtMTAwLjExOTE5LDEwMGMtNTUuMjI4LDAgLTEwMCwtNDQuNzcyIC0xMDAsLTEwMGwwLDEwMGwxMDAsMHoiIG9wYWNpdHk9InVuZGVmaW5lZCIgc3Ryb2tlPSJudWxsIiBmaWxsPSIjRjhFQUU3Ii8+CiAgPHBhdGggZD0ibS0wLjYzNzY2LDcuMzEyMjhjMC4xMTkxOSwwIDAuMjE3MzcsMC4wNTc5NiAwLjQ3Njc2LDAuMTE5MTljMC4yMzIsMC4wNTQ3NyAwLjI3MzI5LDAuMDM0OTEgMC4zNTc1NywwLjExOTE5YzAuMDg0MjgsMC4wODQyOCAwLjM1NzU3LDAgMC40NzY3NiwwbDAuMTE5MTksMGwwLjIzODM4LDAiIGlkPSJzdmdfMiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHBhdGggZD0ibTI4LjkyMTM0LDY5LjA1MjQ0YzAsMC4xMTkxOSAwLDAuMjM4MzggMCwwLjM1NzU3bDAsMC4xMTkxOWwwLDAuMTE5MTkiIGlkPSJzdmdfMyIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z180IiBoZWlnaHQ9IjAiIHdpZHRoPSIxLjMxMTA4IiB5PSI2LjgzNTUyIiB4PSItMC4wNDE3MSIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z181IiBoZWlnaHQ9IjEuNzg3ODQiIHdpZHRoPSIwLjExOTE5IiB5PSI2OC40NTY1IiB4PSIyOC45MjEzNCIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z182IiBoZWlnaHQ9IjQuODg2NzciIHdpZHRoPSIxOS4wNzAzMiIgeT0iNTEuMjkzMjEiIHg9IjM2LjY2ODY2IiBzdHJva2U9Im51bGwiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+'),
+  url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTg5Ljc2MjQgNy4zMzAxNCA1NS4xMjUyKSIgc3Ryb2tlPSJudWxsIiBpZD0ic3ZnXzEiIGZpbGw9IiNGOEVBRTciIGQ9Im02Mi41NzQ0OSwxMTcuNTIwODZjLTU1LjIyOCwwIC0xMDAsLTQ0Ljc3MiAtMTAwLC0xMDBsMCwxMDBsMTAwLDB6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPgogIDxwYXRoIGQ9Im0tMC42Mzc2Niw3LjMxMjI4YzAuMTE5MTksMCAwLjIxNzM3LDAuMDU3OTYgMC40NzY3NiwwLjExOTE5YzAuMjMyLDAuMDU0NzcgMC4yNzMyOSwwLjAzNDkxIDAuMzU3NTcsMC4xMTkxOWMwLjA4NDI4LDAuMDg0MjggMC4zNTc1NywwIDAuNDc2NzYsMGwwLjExOTE5LDBsMC4yMzgzOCwwIiBpZD0ic3ZnXzIiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxwYXRoIGQ9Im0yOC45MjEzNCw2OS4wNTI0NGMwLDAuMTE5MTkgMCwwLjIzODM4IDAsMC4zNTc1N2wwLDAuMTE5MTlsMCwwLjExOTE5IiBpZD0ic3ZnXzMiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNCIgaGVpZ2h0PSIwIiB3aWR0aD0iMS4zMTEwOCIgeT0iNi44MzU1MiIgeD0iLTAuMDQxNzEiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNSIgaGVpZ2h0PSIxLjc4Nzg0IiB3aWR0aD0iMC4xMTkxOSIgeT0iNjguNDU2NSIgeD0iMjguOTIxMzQiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNiIgaGVpZ2h0PSI0Ljg4Njc3IiB3aWR0aD0iMTkuMDcwMzIiIHk9IjUxLjI5MzIxIiB4PSIzNi42Njg2NiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiA8L2c+Cjwvc3ZnPg=='),
+  url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect rx='8' width='100%' height='100%' fill='%23F8EAE7'/></svg>");
+  -webkit-mask-size: 18px 30px, 20px 30px, calc(100%) calc(100% + 27px);
+  -webkit-mask-position: right bottom, left bottom, center top;
+  -webkit-mask-repeat: no-repeat;
+}
+
+.cy-default-tabs-tagsview {
+  background-color: var(--el-color-white);
+  border-bottom: 1px solid var(--next-border-color-light);
+  width: 100%;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  padding: 0 15px;
+
+  .cy-default-tabs-item {
+    border-style: solid;
+    border-color: transparent;
+    height: 28px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    padding: 0 15px;
+    white-space: nowrap;
+
+    .el-icon :hover {
+      color: white;
+      background: var(--el-color-primary);
+    }
+
+    &:hover {
+      @extend .tags-style-five-svg ;
+      @extend .is-active
+    }
+
+    &.is-active {
+      @extend .tags-style-five-svg ;
+      background: var(--el-color-primary-light-9);
+      color: var(--el-color-primary);
+      z-index: 1;
+    }
+  }
+}
+</style>

+ 122 - 7
src/layout/default-layout/index.vue

@@ -1,14 +1,39 @@
 <template>
-
   <div class="layout_container layout-horizontal">
-    <aside style="width: 220px">
-      asdsad
+    <aside
+        :style="{width: isCollapse ? '50px': '220px'}"
+        class="layout-default_aside"
+    >
+      <div class="layout-default_logo">
+        <Logo :show-text="!isCollapse"/>
+      </div>
+      <div class="layout_flex_1-y">
+        <MenuV2 type="default"/>
+      </div>
     </aside>
     <div class="layout_main layout_container ">
-      <header style="height: 50px">
-
+      <header class="layout-default_header">
+        <div class="layout-display-center">
+          <CollapseIcon class="layout-display-center"/>
+          <div style="margin-left: 5px">
+            <el-breadcrumb>
+              <el-breadcrumb-item to="/dashboard">
+                首页
+              </el-breadcrumb-item>
+              <el-breadcrumb-item v-for="item in routerPathName">
+                {{ item }}
+              </el-breadcrumb-item>
+            </el-breadcrumb>
+          </div>
+        </div>
+        <div class="layout-display-center">
+          <ToolInfoBar/>
+        </div>
       </header>
-      <div class="layout_main">
+      <div>
+        <DefaultTabs/>
+      </div>
+      <div class="layout_main layout-default_main">
         <router-view v-slot="{ Component }">
           <transition name="fade-transform" mode="out-in">
             <keep-alive>
@@ -20,5 +45,95 @@
     </div>
   </div>
 </template>
-<script setup>
+<script setup lang="ts">
+import {computed} from "vue";
+import {useSystemStore} from "@/pinia/system-store";
+import MenuV2 from "@/layout/MenuV2/MenuV2.vue";
+import Logo from "@/layout/HeaderV2/Logo.vue";
+import CollapseIcon from "@/layout/compoents/CollapseIcon.vue";
+import ToolInfoBar from "@/layout/fillet-layout/ToolInfoBar.vue";
+import DefaultTabs from "@/layout/default-layout/DefaultTabs.vue";
+import router, {routerMenus} from "@/router";
+import {find, toTreeArray} from "xe-utils";
+
+const systemStore = useSystemStore()
+const isCollapse = computed<boolean>(() => systemStore.getCollapse)
+
+const menuData = computed(() => {
+  return routerMenus.value
+})
+const data = toTreeArray(menuData.value)
+const routerPathName = ref([])
+
+function findBreadcrumb() {
+  for (let i = 0; i < data.length; i++) {
+    const item = data[i]
+    if (item.name === router.currentRoute.value.name) {
+      if (item.cascaders === null && item.cascaders.length < 0) {
+        break
+      }
+      const tmp = []
+      item.cascaders?.forEach(c => {
+        const findName = find(data, (item) => {
+          return item.id === c
+        })
+        tmp.push(findName.metaTitle)
+      })
+      routerPathName.value = tmp
+      break;
+    }
+  }
+  routerPathName.value.push(router.currentRoute.value.meta.title)
+}
+
+watch(() => router.currentRoute.value, () => {
+  findBreadcrumb()
+}, {deep: true, immediate: true})
+
 </script>
+
+<style lang="scss">
+.layout-default_aside {
+  transition: width .3s ease;
+  margin: 0 !important;
+  display: flex;
+  flex-direction: column;
+  background: white;
+}
+
+.layout-default_logo {
+  margin: 5px 10px 0 10px;
+}
+
+.layout-default_header {
+  height: 40px;
+  display: flex;
+  align-items: center;
+  padding: 0 10px;
+  margin: 0 !important;
+  background: white;
+  border-bottom: 1px solid #f1f2f3;
+  justify-content: space-between;
+}
+
+.layout-default_main {
+  background: #F5F5F5;
+  padding: 5px 5px 6px;
+}
+
+.layout-display-center {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.layout-default_user {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.layout-default_header-left {
+  @extend .layout-default_user
+}
+</style>

+ 55 - 0
src/layout/fillet-layout/FilletAside.vue

@@ -0,0 +1,55 @@
+<template>
+  <div class="floating">
+    <div class="layout_fillet-logo">
+      <Logo v-if="!isCollapse"/>
+      <CollapseIcon/>
+    </div>
+
+    <div class="layout_flex_1-y">
+      <MenuV2 type="fillet"/>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {computed} from "vue";
+import Logo from '../HeaderV2/Logo.vue'
+import {useSystemStore} from "@/pinia/system-store";
+import MenuV2 from "@/layout/MenuV2/MenuV2.vue";
+import CollapseIcon from "@/layout/compoents/CollapseIcon.vue";
+
+
+const systemStore = useSystemStore()
+const isCollapse = computed<boolean>(() => systemStore.getCollapse)
+
+</script>
+
+<style lang="scss">
+.floating {
+  height: 100%;
+  width: 100%;
+  background-color: var(--el-menu-bg-color);
+  display: flex;
+  flex-direction: column;
+
+  .el-menu {
+    border-right: 0 !important;
+    position: relative;
+  }
+
+  .menu {
+    overflow: auto;
+  }
+}
+
+.layout_fillet-logo {
+  display: flex;
+  padding: 5px 10px 0 10px;
+  align-items: center;
+  justify-content: space-between;
+}
+
+:deep(.el-sub-menu__title) {
+  padding: 0 16px;
+}
+</style>

+ 1 - 1
src/layout/HeaderV2/HeaderV2.vue → src/layout/fillet-layout/HeaderV2.vue

@@ -8,7 +8,7 @@
 </template>
 
 <script setup name='HeaderV2' lang="ts">
-import RouteNavigation from "@/layout/HeaderV2/router-tabs/RouteNavigation.vue";
+import RouteNavigation from "@/layout/fillet-layout/RouteNavigation.vue";
 import ToolInfoBar from "./ToolInfoBar.vue";
 
 </script>

+ 9 - 1
src/layout/HeaderV2/router-tabs/RouteNavigation.vue → src/layout/fillet-layout/RouteNavigation.vue

@@ -89,9 +89,17 @@ async function handleScrolling() {
   tagRef.value!.scrollTo({top: 0, left: scroll, behavior: 'smooth'})
 }
 
+watch(() => useTab.tabs.value, () => {
+  nextTick(() => {
+    handleScrolling()
+  })
+}, {deep: true})
+
 watch(() => router.currentRoute.value, () => {
   useTab.tabsAdd(router.currentRoute.value)
-  handleScrolling()
+  nextTick(() => {
+    handleScrolling()
+  })
 }, {deep: true, immediate: true})
 </script>
 

+ 6 - 7
src/layout/HeaderV2/ToolInfoBar.vue → src/layout/fillet-layout/ToolInfoBar.vue

@@ -1,7 +1,6 @@
 <template>
   <div class="tool_info_bar">
     <div class="function-list">
-
       <div class="function-list-item" style="width:max-content">
         <scroll-notifications/>
       </div>
@@ -25,12 +24,12 @@
 </template>
 
 <script setup lang="ts">
-import Download from './function-list/Download.vue'
-import Message from './function-list/Message.vue'
-import FullScreen from './function-list/Fullscreen.vue'
-import UserInfo from "./function-list/UserInfo.vue";
-import ScrollNotifications from "./ScrollNotifications.vue";
-import Theme from "./function-list/Theme.vue";
+import Download from '@/layout/function-list/Download.vue'
+import Message from '@/layout/function-list/Message.vue'
+import FullScreen from '@/layout/function-list/Fullscreen.vue'
+import UserInfo from "@/layout/function-list/UserInfo.vue";
+import ScrollNotifications from "../HeaderV2/ScrollNotifications.vue";
+import Theme from "@/layout/function-list/Theme.vue";
 import changePassword from "@/components/system/password-layer";
 import router from "@/router";
 

+ 5 - 5
src/layout/fillet-layout/index.vue

@@ -5,7 +5,7 @@
               class="layout_aside"
               :class="isCollapse ? 'hide-aside' : 'show-side'"
     >
-      <menu-v2/>
+      <FilletAside/>
     </el-aside>
     <el-container style="height: 100vh">
       <el-header style="height: 50px; display: block">
@@ -24,12 +24,13 @@
   </el-container>
 </template>
 
-<script setup>
+<script setup lang="ts">
 import {computed} from 'vue'
-import MenuV2 from "@/layout/MenuV2/MenuV2";
-import HeaderV2 from "@/layout/HeaderV2/HeaderV2";
+import HeaderV2 from "@/layout/fillet-layout/HeaderV2.vue";
 import {useSystemStore} from "@/pinia/system-store";
 import {useUserStore} from "@/pinia/user-store";
+import FilletAside from "@/layout/fillet-layout/FilletAside.vue";
+
 
 const systemStore = useSystemStore()
 const userStore = useUserStore()
@@ -45,7 +46,6 @@ const hideMenu = () => {
 
 .layout_aside {
   margin: 7px 4px 6px 6px;
-  //height: calc(100vh - 32px);
   box-shadow: 0 0 12px rgba(0, 0, 0, .12);;
   border-radius: 4px;
   overflow: hidden;

+ 0 - 0
src/layout/HeaderV2/function-list/Download.vue → src/layout/function-list/Download.vue


+ 0 - 0
src/layout/HeaderV2/function-list/Fullscreen.vue → src/layout/function-list/Fullscreen.vue


+ 1 - 1
src/layout/HeaderV2/function-list/Message.vue → src/layout/function-list/Message.vue

@@ -69,7 +69,7 @@
 
 <script>
 import {computed, defineComponent, onMounted, ref, reactive} from 'vue'
-import {onPageRefresh, fetchAllSenders, fetchAllMessages} from '../../../api/messages'
+import {onPageRefresh, fetchAllSenders, fetchAllMessages} from '../../api/messages'
 import {useSystemStore} from "@/pinia/system-store";
 
 export default defineComponent({

+ 16 - 0
src/layout/HeaderV2/function-list/Theme.vue → src/layout/function-list/Theme.vue

@@ -5,7 +5,16 @@
     </div>
 
     <el-drawer v-model="drawer" title="系统设置" class="herder_height">
+      <el-switch
+          active-text="圆角布局"
+          inactive-text="常见布局"
+          active-value="filletLayout"
+          inactive-value="defaultLayout"
+          @change="pageNameChange"
+          v-model="pageName"
+      />
       <el-collapse v-model="activeNames">
+
         <el-collapse-item title="菜单配置" name="0">
           <el-form>
             <el-form-item label="侧边菜单栏背景色">
@@ -69,6 +78,13 @@ watch(() => theme.value, () => {
   tabsHook.setItem(theme.value)
 }, {deep: true})
 
+
+const pageName = ref(localStorage.pageName)
+
+function pageNameChange(val) {
+  localStorage.pageName = val
+}
+
 onMounted(() => {
   const el = document.documentElement
   for (let key in theme.value) {

+ 1 - 1
src/layout/HeaderV2/function-list/UserInfo.vue → src/layout/function-list/UserInfo.vue

@@ -45,7 +45,7 @@
 
 <script setup name='UserInfo' lang="ts">
 import {genTextPortrait} from '@/utils/portrait'
-import UserInfoDisplay from "@/layout/HeaderV2/function-list/UserInfoDisplay.vue";
+import UserInfoDisplay from "@/layout/function-list/UserInfoDisplay.vue";
 import {useUserStore} from "@/pinia/user-store";
 import {stringNotBlank} from "@/utils/blank-utils";
 import LUpload from "@/views/settings/permissions/LUpload.vue";

+ 0 - 0
src/layout/HeaderV2/function-list/UserInfoDisplay.vue → src/layout/function-list/UserInfoDisplay.vue


+ 2 - 1
src/layout/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <component :is="layouts['filletLayout']"/>
+  <component :is="layouts[pageName]"/>
 </template>
 
 <script setup lang="ts">
@@ -17,6 +17,7 @@ const layouts: any = {
   defaultLayout: defineAsyncComponent(() => import('./default-layout/index.vue'))
 }
 
+const pageName = localStorage.pageName ?? 'filletLayout'
 const userStore = useUserStore()
 const router = useRouter()
 

+ 23 - 14
src/pinia/use-tabs.ts

@@ -1,4 +1,4 @@
-import {Ref, computed, watch} from "vue";
+import {computed} from "vue";
 import {useLocalStorage} from "@vueuse/core";
 import router from "@/router";
 import XEUtils from "xe-utils";
@@ -13,30 +13,34 @@ export interface Tab {
     query: any;
     title: string;
     path: string
+    params: string | null
 }
 
 // 导出tabs对象
 export const tabs = useLocalStorage<Tab[]>("tabs", [])
 
-function useTabs() {
-
-    const tabsKeys = computed(() => {
-        return eachAndReturnList(tabs, (item) => {
-            return item.name
-        })
+export const tabsKeys = computed(() => {
+    return eachAndReturnList(tabs, (item) => {
+        return item.name
     })
+})
+
+function useTabs() {
 
     function routerPush(index: number) {
         if (XEUtils.has(tabs.value, index)) {
             const pushInfo = tabs.value[index]
             router.push({
                 name: pushInfo.name,
-                query: pushInfo.query
+                query: pushInfo.query,
+                params: pushInfo.params
             }).then(r => {
 
             })
         } else {
-            router.push("/").then(() => {
+            router.push({
+                name: 'dashboard'
+            }).then(() => {
             })
         }
     }
@@ -57,11 +61,12 @@ function useTabs() {
     function tabsAdd(info: RouteLocationNormalizedLoaded) {
         const hasIndex = tabsKeys.value.indexOf(info.name)
 
-        const tmp = {
+        const tmp: Tab = {
             path: info.path,
             name: info.name,
             query: info.query,
             title: info.meta.title,
+            params: info.params
         }
 
         if (XEUtils.get(info, 'meta.hideTabs', true)) {
@@ -73,9 +78,9 @@ function useTabs() {
         }
 
         if (hasIndex > -1) {
-            tabs.value[hasIndex] = <Tab>tmp
+            tabs.value[hasIndex] = tmp
         } else {
-            tabs.value.push(<Tab>tmp)
+            tabs.value.push(tmp)
         }
     }
 
@@ -90,7 +95,10 @@ function useTabs() {
     }
 
     function closeAll() {
-        router.push("/").then(() => {})
+        router.push({
+            name: 'dashboard'
+        }).then(() => {
+        })
         tabs.value = []
     }
 
@@ -99,7 +107,8 @@ function useTabs() {
     }
 
     function closeOther(index: number) {
-        tabs.value = []
+        routerPush(index)
+        tabs.value = tabs.value.splice(index, 1)
     }
 
     return {

+ 2 - 2
src/views/settings/menu-settings/MenuSettings.vue

@@ -53,14 +53,14 @@ function addRouterClick(row: IntergrationMenu | null = null) {
     mainOverflowAuto: false,
     metaHideTabs: false,
     metaPassRule: false,
-    metaShowMenu: false,
+    metaShowMenu: true,
     metaTitle: "",
     name: "",
     parentId: row?.id,
     path: "",
     pathParams: "",
     redirect: "",
-    sort: 0,
+    sort: 9999,
     type: 0
   });
 }

+ 1 - 1
src/views/system/login.vue

@@ -85,7 +85,7 @@ const checkForm = () => {
 const userStore = useUserStore()
 const submit = () => {
   checkForm()
-  let params = {
+  const params = {
     codeRs: form.codeRs,
     password: form.password,
   }