mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	Merge branch 'main' into gitee
This commit is contained in:
		
						commit
						97cb48e726
					
				
							
								
								
									
										36
									
								
								src/layout/components/sidebar/linkItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/layout/components/sidebar/linkItem.vue
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { computed } from "vue";
 | 
				
			||||||
 | 
					import { isUrl } from "@pureadmin/utils";
 | 
				
			||||||
 | 
					import { menuType } from "@/layout/types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defineOptions({
 | 
				
			||||||
 | 
					  name: "LinkItem"
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const props = defineProps<{
 | 
				
			||||||
 | 
					  to: menuType;
 | 
				
			||||||
 | 
					}>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const isExternalLink = computed(() => isUrl(props.to.name));
 | 
				
			||||||
 | 
					const getLinkProps = (item: menuType) => {
 | 
				
			||||||
 | 
					  if (isExternalLink.value) {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      href: item.name,
 | 
				
			||||||
 | 
					      target: "_blank",
 | 
				
			||||||
 | 
					      rel: "noopener"
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    to: item
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <component
 | 
				
			||||||
 | 
					    :is="isExternalLink ? 'a' : 'router-link'"
 | 
				
			||||||
 | 
					    v-bind="getLinkProps(to)"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
 | 
					    <slot />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
@ -48,6 +48,7 @@ const { title, getLogo } = useNav();
 | 
				
			|||||||
    flex-wrap: nowrap;
 | 
					    flex-wrap: nowrap;
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    height: 100%;
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    padding-left: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    img {
 | 
					    img {
 | 
				
			||||||
      display: inline-block;
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +1,28 @@
 | 
				
			|||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import path from "path";
 | 
					import path from "path";
 | 
				
			||||||
import { getConfig } from "@/config";
 | 
					import { getConfig } from "@/config";
 | 
				
			||||||
 | 
					import LinkItem from "./linkItem.vue";
 | 
				
			||||||
import { menuType } from "../../types";
 | 
					import { menuType } from "../../types";
 | 
				
			||||||
import extraIcon from "./extraIcon.vue";
 | 
					import extraIcon from "./extraIcon.vue";
 | 
				
			||||||
import { ReText } from "@/components/ReText";
 | 
					import { ReText } from "@/components/ReText";
 | 
				
			||||||
import { useNav } from "@/layout/hooks/useNav";
 | 
					import { useNav } from "@/layout/hooks/useNav";
 | 
				
			||||||
import { transformI18n } from "@/plugins/i18n";
 | 
					import { transformI18n } from "@/plugins/i18n";
 | 
				
			||||||
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
					import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 | 
				
			||||||
import { type CSSProperties, type PropType, computed, ref, toRaw } from "vue";
 | 
					import {
 | 
				
			||||||
 | 
					  type PropType,
 | 
				
			||||||
 | 
					  type CSSProperties,
 | 
				
			||||||
 | 
					  ref,
 | 
				
			||||||
 | 
					  toRaw,
 | 
				
			||||||
 | 
					  computed,
 | 
				
			||||||
 | 
					  useAttrs
 | 
				
			||||||
 | 
					} from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
 | 
					import ArrowUp from "@iconify-icons/ep/arrow-up-bold";
 | 
				
			||||||
import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
 | 
					import EpArrowDown from "@iconify-icons/ep/arrow-down-bold";
 | 
				
			||||||
import ArrowLeft from "@iconify-icons/ep/arrow-left-bold";
 | 
					import ArrowLeft from "@iconify-icons/ep/arrow-left-bold";
 | 
				
			||||||
import ArrowRight from "@iconify-icons/ep/arrow-right-bold";
 | 
					import ArrowRight from "@iconify-icons/ep/arrow-right-bold";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const attrs = useAttrs();
 | 
				
			||||||
const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
 | 
					const { layout, isCollapse, tooltipEffect, getDivStyle } = useNav();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
@ -32,6 +41,7 @@ const props = defineProps({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const getNoDropdownStyle = computed((): CSSProperties => {
 | 
					const getNoDropdownStyle = computed((): CSSProperties => {
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
 | 
					    width: "100%",
 | 
				
			||||||
    display: "flex",
 | 
					    display: "flex",
 | 
				
			||||||
    alignItems: "center"
 | 
					    alignItems: "center"
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -96,61 +106,66 @@ function resolvePath(routePath) {
 | 
				
			|||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <el-menu-item
 | 
					  <link-item
 | 
				
			||||||
    v-if="
 | 
					    v-if="
 | 
				
			||||||
      hasOneShowingChild(props.item.children, props.item) &&
 | 
					      hasOneShowingChild(props.item.children, props.item) &&
 | 
				
			||||||
      (!onlyOneChild.children || onlyOneChild.noShowingChildren)
 | 
					      (!onlyOneChild.children || onlyOneChild.noShowingChildren)
 | 
				
			||||||
    "
 | 
					    "
 | 
				
			||||||
    :index="resolvePath(onlyOneChild.path)"
 | 
					    :to="item"
 | 
				
			||||||
    :class="{ 'submenu-title-noDropdown': !isNest }"
 | 
					 | 
				
			||||||
    :style="getNoDropdownStyle"
 | 
					 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <div
 | 
					    <el-menu-item
 | 
				
			||||||
      v-if="toRaw(props.item.meta.icon)"
 | 
					      :index="resolvePath(onlyOneChild.path)"
 | 
				
			||||||
      class="sub-menu-icon"
 | 
					      :class="{ 'submenu-title-noDropdown': !isNest }"
 | 
				
			||||||
      :style="getSubMenuIconStyle"
 | 
					      :style="getNoDropdownStyle"
 | 
				
			||||||
 | 
					      v-bind="attrs"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <component
 | 
					      <div
 | 
				
			||||||
        :is="
 | 
					        v-if="toRaw(props.item.meta.icon)"
 | 
				
			||||||
          useRenderIcon(
 | 
					        class="sub-menu-icon"
 | 
				
			||||||
            toRaw(onlyOneChild.meta.icon) ||
 | 
					        :style="getSubMenuIconStyle"
 | 
				
			||||||
              (props.item.meta && toRaw(props.item.meta.icon))
 | 
					      >
 | 
				
			||||||
          )
 | 
					        <component
 | 
				
			||||||
        "
 | 
					          :is="
 | 
				
			||||||
      />
 | 
					            useRenderIcon(
 | 
				
			||||||
    </div>
 | 
					              toRaw(onlyOneChild.meta.icon) ||
 | 
				
			||||||
    <el-text
 | 
					                (props.item.meta && toRaw(props.item.meta.icon))
 | 
				
			||||||
      v-if="
 | 
					            )
 | 
				
			||||||
        (!props.item?.meta.icon &&
 | 
					          "
 | 
				
			||||||
          isCollapse &&
 | 
					        />
 | 
				
			||||||
          layout === 'vertical' &&
 | 
					 | 
				
			||||||
          props.item?.pathList?.length === 1) ||
 | 
					 | 
				
			||||||
        (!onlyOneChild.meta.icon &&
 | 
					 | 
				
			||||||
          isCollapse &&
 | 
					 | 
				
			||||||
          layout === 'mix' &&
 | 
					 | 
				
			||||||
          props.item?.pathList?.length === 2)
 | 
					 | 
				
			||||||
      "
 | 
					 | 
				
			||||||
      truncated
 | 
					 | 
				
			||||||
      class="!px-4 !text-inherit"
 | 
					 | 
				
			||||||
    >
 | 
					 | 
				
			||||||
      {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					 | 
				
			||||||
    </el-text>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <template #title>
 | 
					 | 
				
			||||||
      <div :style="getDivStyle">
 | 
					 | 
				
			||||||
        <ReText
 | 
					 | 
				
			||||||
          :tippyProps="{
 | 
					 | 
				
			||||||
            offset: [0, -10],
 | 
					 | 
				
			||||||
            theme: tooltipEffect
 | 
					 | 
				
			||||||
          }"
 | 
					 | 
				
			||||||
          class="!text-inherit"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          {{ transformI18n(onlyOneChild.meta.title) }}
 | 
					 | 
				
			||||||
        </ReText>
 | 
					 | 
				
			||||||
        <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					      <el-text
 | 
				
			||||||
  </el-menu-item>
 | 
					        v-if="
 | 
				
			||||||
 | 
					          (!props.item?.meta.icon &&
 | 
				
			||||||
 | 
					            isCollapse &&
 | 
				
			||||||
 | 
					            layout === 'vertical' &&
 | 
				
			||||||
 | 
					            props.item?.pathList?.length === 1) ||
 | 
				
			||||||
 | 
					          (!onlyOneChild.meta.icon &&
 | 
				
			||||||
 | 
					            isCollapse &&
 | 
				
			||||||
 | 
					            layout === 'mix' &&
 | 
				
			||||||
 | 
					            props.item?.pathList?.length === 2)
 | 
				
			||||||
 | 
					        "
 | 
				
			||||||
 | 
					        truncated
 | 
				
			||||||
 | 
					        class="!px-4 !text-inherit"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {{ transformI18n(onlyOneChild.meta.title) }}
 | 
				
			||||||
 | 
					      </el-text>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <template #title>
 | 
				
			||||||
 | 
					        <div :style="getDivStyle">
 | 
				
			||||||
 | 
					          <ReText
 | 
				
			||||||
 | 
					            :tippyProps="{
 | 
				
			||||||
 | 
					              offset: [0, -10],
 | 
				
			||||||
 | 
					              theme: tooltipEffect
 | 
				
			||||||
 | 
					            }"
 | 
				
			||||||
 | 
					            class="!text-inherit"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {{ transformI18n(onlyOneChild.meta.title) }}
 | 
				
			||||||
 | 
					          </ReText>
 | 
				
			||||||
 | 
					          <extraIcon :extraIcon="onlyOneChild.meta.extraIcon" />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </template>
 | 
				
			||||||
 | 
					    </el-menu-item>
 | 
				
			||||||
 | 
					  </link-item>
 | 
				
			||||||
  <el-sub-menu
 | 
					  <el-sub-menu
 | 
				
			||||||
    v-else
 | 
					    v-else
 | 
				
			||||||
    ref="subMenu"
 | 
					    ref="subMenu"
 | 
				
			||||||
 | 
				
			|||||||
@ -62,6 +62,7 @@ export interface setType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export type menuType = {
 | 
					export type menuType = {
 | 
				
			||||||
  id?: number;
 | 
					  id?: number;
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
  path?: string;
 | 
					  path?: string;
 | 
				
			||||||
  noShowingChildren?: boolean;
 | 
					  noShowingChildren?: boolean;
 | 
				
			||||||
  children?: menuType[];
 | 
					  children?: menuType[];
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,11 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* 修复 windows 下双滚动条问题 https://github.com/pure-admin/vue-pure-admin/pull/936#issuecomment-1968125992 */
 | 
				
			||||||
 | 
					  .el-popper.pure-scrollbar {
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* popper menu 超出内容区可滚动 */
 | 
					  /* popper menu 超出内容区可滚动 */
 | 
				
			||||||
  .pure-scrollbar {
 | 
					  .pure-scrollbar {
 | 
				
			||||||
    max-height: calc(100vh - calc(50px * 2.5));
 | 
					    max-height: calc(100vh - calc(50px * 2.5));
 | 
				
			||||||
@ -130,11 +135,9 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    a {
 | 
					    a {
 | 
				
			||||||
      display: inline-block;
 | 
					 | 
				
			||||||
      display: flex;
 | 
					      display: flex;
 | 
				
			||||||
      flex-wrap: wrap;
 | 
					      flex-wrap: wrap;
 | 
				
			||||||
      width: 100%;
 | 
					      width: 100%;
 | 
				
			||||||
      padding-left: 10px;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .el-menu {
 | 
					    .el-menu {
 | 
				
			||||||
@ -332,9 +335,18 @@
 | 
				
			|||||||
      margin-top: 0;
 | 
					      margin-top: 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 无子菜单时激活 border-bottom */
 | 
				
			||||||
 | 
					    a > .is-active.submenu-title-noDropdown {
 | 
				
			||||||
 | 
					      border-bottom: 2px solid var(--el-menu-active-color);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .el-menu--popup {
 | 
					    .el-menu--popup {
 | 
				
			||||||
      background-color: $subMenuBg !important;
 | 
					      background-color: $subMenuBg !important;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      a > .is-active.submenu-title-noDropdown {
 | 
				
			||||||
 | 
					        border-bottom: none;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      .el-menu-item {
 | 
					      .el-menu-item {
 | 
				
			||||||
        color: $menuText;
 | 
					        color: $menuText;
 | 
				
			||||||
        background-color: $subMenuBg;
 | 
					        background-color: $subMenuBg;
 | 
				
			||||||
@ -349,12 +361,6 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* 无子菜单时激活 border-bottom */
 | 
					 | 
				
			||||||
    .router-link-exact-active > .submenu-title-noDropdown {
 | 
					 | 
				
			||||||
      height: 60px;
 | 
					 | 
				
			||||||
      border-bottom: 2px solid var(--el-menu-active-color);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* 子菜单中还有子菜单 */
 | 
					    /* 子菜单中还有子菜单 */
 | 
				
			||||||
    .el-menu .el-sub-menu__title {
 | 
					    .el-menu .el-sub-menu__title {
 | 
				
			||||||
      min-width: $sideBarWidth !important;
 | 
					      min-width: $sideBarWidth !important;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user