feat: 初始化提交
笑笑 authored at 2025-05-13 21:25:06
2.62 KiB
cube-front
<script setup lang="ts">
import { computed } from 'vue';
import { type TreeMenuItem } from 'cube-front/core/stores/menu';
import SecondCascaderMenu from './components/SecondCascaderMenu.vue';
import { isChildMenu, hasChildren } from 'cube-front/core/utils/menuHelpers';

/**
 * 层叠菜单组件Props接口定义
 */
interface CascaderMenuProps {
  /** 菜单项 */
  menu: TreeMenuItem;
  /** 激活菜单项 */
  activeMenu?: TreeMenuItem;
  /** 当前鼠标悬浮菜单项 */
  currentMenu?: TreeMenuItem;
  /** 菜单点击回调函数 */
  onMenuClick: (menu: TreeMenuItem) => void;
}

const props = defineProps<CascaderMenuProps>();

/** 一行显示菜单项数量 */
const menuItemColumns = 3;
/** 子菜单宽度 */
const subMenuWidth = 225;
/** 层叠菜单宽度 */
const subWidth = `${subMenuWidth * menuItemColumns}px`;
/** 导航栏宽度 */
const navWidth = '200px';
/** 是否折叠 */
const collapsed = false;

/**
 * 计算处理后的子菜单列表
 * 将没有子菜单的项目归类到一起,有子菜单的单独列出
 */
const children = computed(() => {
  /**  无子菜单的菜单项  */
  const noChildrenList = props.menu.children?.filter((item) => !hasChildren(item));

  /** 有子菜单的菜单项 */
  const childrenList: TreeMenuItem[] =
    noChildrenList && noChildrenList.length > 0
      ? [
          {
            ...props.menu,
            children: noChildrenList,
          },
        ]
      : [];

  props.menu.children?.forEach((item) => {
    if (noChildrenList?.includes(item)) return;
    childrenList.push(item);
  });

  return childrenList;
});
</script>

<template>
  <div
    :class="[
      'menu-cascader',
      {
        'menu-cascader-current': currentMenu && isChildMenu(currentMenu, menu),
      },
    ]"
    :style="{
      maxWidth: collapsed ? 'calc(100vw - 50px)' : `calc(100vw - ${navWidth})`,
    }"
  >
    <SecondCascaderMenu
      v-for="second in children"
      :key="second.id"
      :menu="second"
      :width="subWidth"
      :menuItemColumns="menuItemColumns"
      :active-menu="activeMenu"
      :on-menu-click="onMenuClick"
    />
  </div>
</template>

<style lang="scss" scoped>
.menu-cascader {
  position: relative;
  box-sizing: border-box;
  display: none;
  height: 100%;
  width: 675px;
  max-width: calc(100vw - 200px);
  overflow: hidden auto;
  padding: 32px 16px 0;
  z-index: 1100;
  background: #fff;
  border-left: 1px solid #f0f0f0;

  /* 完全隐藏滚动条,但保留滚动功能 */
  scrollbar-width: none;
  -ms-overflow-style: none;

  &::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
  }
}

.menu-cascader-current {
  display: block;
}
</style>