chore: 整理项目资源和配置
This commit is contained in:
@@ -49,10 +49,8 @@
|
||||
</span>
|
||||
<!-- 内容全屏 -->
|
||||
<span class="tags-actions__btn" @click="appStore.toggleContentFullscreen()">
|
||||
<el-icon :size="16">
|
||||
<FullScreen v-if="!appStore.contentFullscreen" />
|
||||
<Close v-else />
|
||||
</el-icon>
|
||||
<div v-if="!appStore.contentFullscreen" class="i-svg:fullscreen icon-16" />
|
||||
<div v-else class="i-svg:fullscreen-exit icon-16" />
|
||||
</span>
|
||||
<!-- 下拉菜单 -->
|
||||
<el-dropdown trigger="click" @command="handleActionCommand">
|
||||
@@ -62,39 +60,27 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="refresh">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Refresh />
|
||||
</el-icon>
|
||||
<el-icon :size="14" class="icon-14"><Refresh /></el-icon>
|
||||
<span>刷新当前</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="currentTag && !currentTag.affix" command="closeCurrent">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Close />
|
||||
</el-icon>
|
||||
<div class="i-svg:close icon-14" />
|
||||
<span>关闭当前</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="closeOthers">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
<el-dropdown-item divided command="closeOtherTags">
|
||||
<div class="i-svg:close_other icon-14" />
|
||||
<span>关闭其它</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="closeLeft">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<DArrowLeft />
|
||||
</el-icon>
|
||||
<el-dropdown-item command="closeLeftTags">
|
||||
<div class="i-svg:close_left icon-14" />
|
||||
<span>关闭左侧</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="closeRight">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<DArrowRight />
|
||||
</el-icon>
|
||||
<el-dropdown-item command="closeRightTags">
|
||||
<div class="i-svg:close_right icon-14" />
|
||||
<span>关闭右侧</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="closeAll">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
<el-dropdown-item divided command="closeAllTags">
|
||||
<div class="i-svg:close_all icon-14" />
|
||||
<span>关闭所有</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -114,25 +100,25 @@
|
||||
class="contextmenu__danger"
|
||||
@click="closeSelectedTag(selectedTag)"
|
||||
>
|
||||
<el-icon :size="16" class="contextmenu__icon"><Close /></el-icon>
|
||||
<div class="i-svg:close contextmenu__icon" />
|
||||
<span>关闭</span>
|
||||
</li>
|
||||
<li class="contextmenu__divider" />
|
||||
<li @click="closeOtherTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><Remove /></el-icon>
|
||||
<div class="i-svg:close_other contextmenu__icon" />
|
||||
<span>关闭其它</span>
|
||||
</li>
|
||||
<li v-if="!isFirstView" @click="closeLeftTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><DArrowLeft /></el-icon>
|
||||
<div class="i-svg:close_left contextmenu__icon" />
|
||||
<span>关闭左侧</span>
|
||||
</li>
|
||||
<li v-if="!isLastView" @click="closeRightTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><DArrowRight /></el-icon>
|
||||
<div class="i-svg:close_right contextmenu__icon" />
|
||||
<span>关闭右侧</span>
|
||||
</li>
|
||||
<li class="contextmenu__divider" />
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
<el-icon :size="16" class="contextmenu__icon"><CircleClose /></el-icon>
|
||||
<div class="i-svg:close_all contextmenu__icon" />
|
||||
<span>关闭所有</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -212,16 +198,16 @@ const handleActionCommand = (command: string) => {
|
||||
case "closeCurrent":
|
||||
closeSelectedTag(currentTag.value);
|
||||
break;
|
||||
case "closeOthers":
|
||||
case "closeOtherTags":
|
||||
closeOtherTagsForActive();
|
||||
break;
|
||||
case "closeLeft":
|
||||
case "closeLeftTags":
|
||||
closeLeftTagsForActive();
|
||||
break;
|
||||
case "closeRight":
|
||||
case "closeRightTags":
|
||||
closeRightTagsForActive();
|
||||
break;
|
||||
case "closeAll":
|
||||
case "closeAllTags":
|
||||
closeAllTags(currentTag.value);
|
||||
break;
|
||||
}
|
||||
@@ -379,9 +365,7 @@ const closeSelectedTag = (tag: TagView | null) => {
|
||||
});
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 批量关闭标签(左/右/其它方向) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
// 批量关闭标签(左/右/其它方向)
|
||||
|
||||
/**
|
||||
* 按方向批量关闭标签的通用执行器。
|
||||
@@ -407,7 +391,9 @@ function closeDirectional(
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭当前激活标签之外的其它标签 */
|
||||
/**
|
||||
* 关闭当前激活标签之外的其它标签。
|
||||
*/
|
||||
const closeOtherTagsForActive = () => {
|
||||
if (!currentTag.value) return;
|
||||
tagsViewStore.delOtherViews(currentTag.value).then(() => {
|
||||
@@ -646,19 +632,33 @@ useContextMenuManager();
|
||||
background-color: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
:deep(.el-icon) {
|
||||
:deep(.el-icon),
|
||||
:deep(div) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
&:hover :deep(.el-icon) {
|
||||
&:hover :deep(.el-icon),
|
||||
&:hover :deep(div) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown-icon {
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
opacity: 0.55;
|
||||
.icon-16 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.icon-14 {
|
||||
flex-shrink: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 6px;
|
||||
opacity: 0.55;
|
||||
|
||||
&.el-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,6 +697,8 @@ useContextMenuManager();
|
||||
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
/**
|
||||
* 混合布局菜单逻辑
|
||||
*
|
||||
* 从 MixLayout.vue 提取,负责:
|
||||
* - 顶部菜单项扁平化(单子菜单向上合并 title/icon)
|
||||
* - 侧边菜单路径解析与激活判定
|
||||
* - 菜单切换导航(自动跳转到第一个可访问子菜单)
|
||||
* - 路由变化时同步顶部菜单激活态与侧边菜单数据
|
||||
*
|
||||
* 模板只绑定返回值,无需关心内部实现。
|
||||
*/
|
||||
import type { LocationQueryRaw, RouteRecordRaw } from "vue-router";
|
||||
import { useLayout } from "../useLayout";
|
||||
@@ -15,10 +7,6 @@ import { useAppStore, usePermissionStore, useSettingsStore } from "@/stores";
|
||||
import { isExternal } from "@/utils/index";
|
||||
import { ElIcon } from "element-plus";
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* MenuIcon — 菜单图标渲染组件(Element Plus / SVG 双模式) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const MenuIcon = defineComponent({
|
||||
props: { icon: String },
|
||||
setup(props) {
|
||||
@@ -39,9 +27,6 @@ const MenuIcon = defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* useMixMenu */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export function useMixMenu() {
|
||||
const route = useRoute();
|
||||
@@ -53,7 +38,6 @@ export function useMixMenu() {
|
||||
|
||||
const { activeTopMenuPath, sideMenuRoutes } = useLayout();
|
||||
|
||||
/* ------ 顶部菜单 ------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* 顶部菜单项。
|
||||
@@ -84,9 +68,12 @@ export function useMixMenu() {
|
||||
});
|
||||
});
|
||||
|
||||
/* ------ 侧边菜单 ------------------------------------------------- */
|
||||
|
||||
/** 当前路由对应的侧边菜单激活路径(优先取 meta.activeMenu) */
|
||||
/**
|
||||
* 当前路由对应的侧边菜单激活路径。
|
||||
*
|
||||
* 优先取 meta.activeMenu,否则使用当前路由路径。
|
||||
*/
|
||||
const activeSideMenuPath = computed(() => {
|
||||
const { meta, path } = route;
|
||||
return typeof meta?.activeMenu === "string" ? meta.activeMenu : path;
|
||||
@@ -105,8 +92,6 @@ export function useMixMenu() {
|
||||
return `${activeTopMenuPath.value}/${routePath}`;
|
||||
}
|
||||
|
||||
/* ------ 路径工具 ------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* 从完整路径中提取第一段作为顶级菜单路径。
|
||||
*
|
||||
@@ -114,14 +99,15 @@ export function useMixMenu() {
|
||||
* "/dashboard" → "/"
|
||||
*/
|
||||
function extractTopMenuPath(path: string): string {
|
||||
return path.split("/").filter(Boolean).length > 1
|
||||
? path.match(/^\/[^/]+/)?.[0] || "/"
|
||||
: "/";
|
||||
return path.split("/").filter(Boolean).length > 1 ? path.match(/^\/[^/]+/)?.[0] || "/" : "/";
|
||||
}
|
||||
|
||||
/* ------ 菜单切换 ------------------------------------------------- */
|
||||
|
||||
/** 顶部菜单点击:切换侧边菜单数据,并导航到第一个可访问叶子菜单 */
|
||||
/**
|
||||
* 顶部菜单点击。
|
||||
*
|
||||
* 切换侧边菜单数据,并导航到第一个可访问叶子菜单。
|
||||
*/
|
||||
function handleTopMenuSelect(menuPath: string) {
|
||||
if (menuPath === activeTopMenuPath.value) return;
|
||||
|
||||
@@ -153,7 +139,7 @@ export function useMixMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
/* ------ 路由同步 ------------------------------------------------- */
|
||||
// 路由同步
|
||||
|
||||
/**
|
||||
* 监听路由变化,保持顶部菜单激活态和侧边菜单数据同步。
|
||||
|
||||
@@ -58,16 +58,30 @@ export function useLayout() {
|
||||
// 菜单数据
|
||||
// ============================================
|
||||
|
||||
/** 路由列表(左侧/顶部菜单) */
|
||||
/**
|
||||
* 路由列表。
|
||||
*
|
||||
* 左侧/顶部菜单共用,由权限 store 生成。
|
||||
*/
|
||||
const routes = computed(() => permissionStore.routes);
|
||||
|
||||
/** 混合布局侧边菜单 */
|
||||
/**
|
||||
* 混合布局侧边菜单。
|
||||
*
|
||||
* 根据当前激活的顶部菜单路径动态计算。
|
||||
*/
|
||||
const sideMenuRoutes = computed(() => permissionStore.mixLayoutSideMenus);
|
||||
|
||||
/** 顶部菜单激活路径 */
|
||||
/**
|
||||
* 顶部菜单激活路径。
|
||||
*/
|
||||
const activeTopMenuPath = computed(() => appStore.activeTopMenuPath);
|
||||
|
||||
/** 当前激活菜单 */
|
||||
/**
|
||||
* 当前激活菜单。
|
||||
*
|
||||
* 优先取路由 meta.activeMenu,否则取当前路径。
|
||||
*/
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
return meta?.activeMenu || path;
|
||||
|
||||
Reference in New Issue
Block a user