| | |
| | | <template> |
| | | <!-- <div v-if="!item.hidden">--> |
| | | <!-- <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">--> |
| | | <!-- <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">--> |
| | | <!-- <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">--> |
| | | <!-- <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"/>--> |
| | | <!-- <template #title><span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span></template>--> |
| | | <!-- </el-menu-item>--> |
| | | <!-- </app-link>--> |
| | | <!-- </template>--> |
| | | |
| | | <!-- <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>--> |
| | | <!-- <template v-if="item.meta" #title>--> |
| | | <!-- <svg-icon :icon-class="item.meta && item.meta.icon" />--> |
| | | <!-- <span class="menu-title" :title="hasTitle(item.meta.title)">{{ item.meta.title }}</span>--> |
| | | <!-- </template>--> |
| | | |
| | | <!-- <sidebar-item--> |
| | | <!-- v-for="child in item.children"--> |
| | | <!-- :key="child.path"--> |
| | | <!-- :is-nest="true"--> |
| | | <!-- :item="child"--> |
| | | <!-- :base-path="resolvePath(child.path)"--> |
| | | <!-- class="nest-menu"--> |
| | | <!-- />--> |
| | | <!-- </el-sub-menu>--> |
| | | <!-- </div>--> |
| | | <div v-if="!item.hidden"> |
| | | <template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow"> |
| | | <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)"> |
| | | <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }"> |
| | | <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)"/> |
| | | <template #title><span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span></template> |
| | | <!-- 优化条件:优先判定【仅有1个可见子菜单】,直接走一级菜单渲染 --> |
| | | <template v-if="calcSingleChild(item) && item.path != '/system'"> |
| | | <app-link v-if="onlyOneChild?.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)"> |
| | | <el-menu-item |
| | | :index="resolvePath(onlyOneChild.path)" |
| | | :class="{ 'submenu-title-noDropdown': !isNest }" |
| | | > |
| | | <svg-icon :icon-class="item.meta?.icon || onlyOneChild.meta?.icon"/> |
| | | <template #title> |
| | | <span class="menu-title" :title="hasTitle(item.meta?.title || onlyOneChild.meta?.title)"> |
| | | {{ item.meta?.title || onlyOneChild.meta?.title }} |
| | | </span> |
| | | </template> |
| | | </el-menu-item> |
| | | </app-link> |
| | | </template> |
| | | |
| | | <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> |
| | | <!-- 多个子菜单 / 强制目录:正常展开二级菜单 --> |
| | | <el-sub-menu |
| | | v-else |
| | | ref="subMenu" |
| | | :index="resolvePath(item.path)" |
| | | popper-append-to-body |
| | | > |
| | | <template v-if="item.meta" #title> |
| | | <svg-icon :icon-class="item.meta && item.meta.icon" /> |
| | | <span class="menu-title" :title="hasTitle(item.meta.title)">{{ item.meta.title }}</span> |
| | | </template> |
| | | |
| | | <sidebar-item |
| | | v-for="child in item.children" |
| | | :key="child.path" |
| | | :is-nest="true" |
| | | :item="child" |
| | | :base-path="resolvePath(child.path)" |
| | | class="nest-menu" |
| | | v-for="child in item.children" |
| | | :key="child.path" |
| | | :is-nest="true" |
| | | :item="child" |
| | | :base-path="resolvePath(child.path)" |
| | | class="nest-menu" |
| | | /> |
| | | </el-sub-menu> |
| | | </div> |
| | | </template> |
| | | |
| | | <!--<script setup>--> |
| | | <!--import { isExternal } from '@/utils/validate'--> |
| | | <!--import AppLink from './Link'--> |
| | | <!--import { getNormalPath } from '@/utils/ruoyi'--> |
| | | |
| | | <!--const props = defineProps({--> |
| | | <!-- // route object--> |
| | | <!-- item: {--> |
| | | <!-- type: Object,--> |
| | | <!-- required: true--> |
| | | <!-- },--> |
| | | <!-- isNest: {--> |
| | | <!-- type: Boolean,--> |
| | | <!-- default: false--> |
| | | <!-- },--> |
| | | <!-- basePath: {--> |
| | | <!-- type: String,--> |
| | | <!-- default: ''--> |
| | | <!-- }--> |
| | | <!--})--> |
| | | |
| | | <!--const onlyOneChild = ref({});--> |
| | | |
| | | <!--function hasOneShowingChild(children = [], parent) {--> |
| | | <!-- if (!children) {--> |
| | | <!-- children = [];--> |
| | | <!-- }--> |
| | | <!-- const showingChildren = children.filter(item => {--> |
| | | <!-- if (item.hidden) {--> |
| | | <!-- return false--> |
| | | <!-- } else {--> |
| | | <!-- // Temp set(will be used if only has one showing child)--> |
| | | <!-- onlyOneChild.value = item--> |
| | | <!-- return true--> |
| | | <!-- }--> |
| | | <!-- })--> |
| | | |
| | | <!-- // When there is only one child router, the child router is displayed by default--> |
| | | <!-- if (showingChildren.length === 1) {--> |
| | | <!-- return true--> |
| | | <!-- }--> |
| | | |
| | | <!-- // Show parent if there are no child router to display--> |
| | | <!-- if (showingChildren.length === 0) {--> |
| | | <!-- onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }--> |
| | | <!-- return true--> |
| | | <!-- }--> |
| | | |
| | | <!-- return false--> |
| | | <!--};--> |
| | | |
| | | <!--function resolvePath(routePath, routeQuery) {--> |
| | | <!-- if (isExternal(routePath)) {--> |
| | | <!-- return routePath--> |
| | | <!-- }--> |
| | | <!-- if (isExternal(props.basePath)) {--> |
| | | <!-- return props.basePath--> |
| | | <!-- }--> |
| | | <!-- if (routeQuery) {--> |
| | | <!-- let query = JSON.parse(routeQuery);--> |
| | | <!-- return { path: getNormalPath(props.basePath + '/' + routePath), query: query }--> |
| | | <!-- }--> |
| | | <!-- return getNormalPath(props.basePath + '/' + routePath)--> |
| | | <!--}--> |
| | | |
| | | <!--function hasTitle(title){--> |
| | | <!-- if (title.length > 5) {--> |
| | | <!-- return title;--> |
| | | <!-- } else {--> |
| | | <!-- return "";--> |
| | | <!-- }--> |
| | | <!--}--> |
| | | <!--</script>--> |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import { isExternal } from '@/utils/validate' |
| | | import AppLink from './Link' |
| | | import { getNormalPath } from '@/utils/ruoyi' |
| | |
| | | } |
| | | }) |
| | | |
| | | const onlyOneChild = ref({}); |
| | | // 修复:初始化为 null,而非空对象 |
| | | const onlyOneChild = ref(null); |
| | | |
| | | /** |
| | | * 修复版:判断是否只有一个可见子菜单(核心改动) |
| | | */ |
| | | function hasOneShowingChild(children = [], parent) { |
| | | if (!children) { |
| | | children = []; |
| | | } |
| | | const showingChildren = children.filter(item => { |
| | | if (item.hidden) { |
| | | return false |
| | | } else { |
| | | // Temp set(will be used if only has one showing child) |
| | | onlyOneChild.value = item |
| | | return true |
| | | } |
| | | }) |
| | | if (!children) children = [] |
| | | |
| | | // When there is only one child router, the child router is displayed by default |
| | | // 1. 先统一过滤出【未隐藏】的子菜单 |
| | | const showingChildren = children.filter(item => !item.hidden) |
| | | |
| | | // 2. 仅有 1 个可见子菜单:赋值 + 标记无下级,适配原有判断 |
| | | if (showingChildren.length === 1) { |
| | | const child = showingChildren[0] |
| | | // 标记:当前子菜单没有可展示的下级(关键,适配原模板逻辑) |
| | | onlyOneChild.value = { ...child, noShowingChildren: true } |
| | | return true |
| | | } |
| | | |
| | | // Show parent if there are no child router to display |
| | | // 3. 没有可见子菜单 |
| | | if (showingChildren.length === 0) { |
| | | onlyOneChild.value = { ...parent, path: '', noShowingChildren: true } |
| | | return true |
| | | } |
| | | |
| | | // 4. 多个子菜单 |
| | | onlyOneChild.value = null |
| | | return false |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * 新增统一判断方法:简化模板条件,命中「单菜单合并逻辑」 |
| | | */ |
| | | function calcSingleChild(item) { |
| | | // 存在子菜单 且 仅有一个可见子菜单 |
| | | return hasOneShowingChild(item.children, item) |
| | | } |
| | | |
| | | function resolvePath(routePath, routeQuery) { |
| | | if (isExternal(routePath)) { |
| | |
| | | } |
| | | |
| | | function hasTitle(title){ |
| | | if (title.length > 5) { |
| | | if (title && title.length > 5) { |
| | | return title; |
| | | } else { |
| | | return ""; |