|
|
<!-- @format -->
<template> <el-container style="min-height: 100vh"> <el-aside class="sidebar" v-if="!$route.meta.hiddenSidebar"> <!-- 侧边栏头部 --> <div class="sidebar-header"> <img src="../assets/images/deepChart.png" class="sidebar-logo" /> <span class="sidebar-title">DeepChart</span> </div>
<!-- 侧边栏菜单 --> <el-menu class="sidebar-menu" background-color="transparent" router :default-active="lastActivePath"> <!-- 第一层循环:遍历父路由 (如: 用户权限管理、活动管理) --> <el-sub-menu v-for="parentRoute in filteredSidebarRoutes" :key="parentRoute.name" :index="`/${parentRoute.path}`"> <!-- 父目录 --> <template #title> <el-icon> <component :is="parentRoute.meta.icon" /> </el-icon> <span class="sidebar-parent-text">{{ parentRoute.meta.title }}</span> </template> <!-- 第二层循环:遍历子路由 --> <template v-for="childRoute in parentRoute.filteredChildren" :key="childRoute.name"> <!-- 如果有孙子菜单(如:新年幸运签),渲染为【子目录 el-sub-menu】 --> <el-sub-menu v-if="childRoute.children && childRoute.children.length > 0" :index="`/${parentRoute.path}/${childRoute.path}`"> <template #title> <el-icon class="sidebar-child-icon" /> <span class="sidebar-child-text">{{ childRoute.meta.title }}</span> </template>
<!-- 第三层循环:遍历孙子路由 (如: 历史记录、内容配置) --> <el-menu-item v-for="grandChild in childRoute.children" :key="grandChild.name" :index="`/${parentRoute.path}/${childRoute.path}/${grandChild.path}`" class="sidebar-grandchild-container"> <span class="sidebar-grandchild-text">{{ grandChild.meta.title }}</span> </el-menu-item> </el-sub-menu>
<!-- 如果没有子菜单(如:行情期限),渲染为【点击项 el-menu-item】 --> <el-menu-item v-else :index="`/${parentRoute.path}/${childRoute.path}`" class="sidebar-child-container"> <el-icon class="sidebar-child-icon" /> <span class="sidebar-child-text">{{ childRoute.meta.title }}</span> </el-menu-item> </template> </el-sub-menu> </el-menu>
<div class="sidebar-logout" @click="handleLogout"> <el-icon style="bottom: -3px"><SwitchButton /></el-icon> 退出登录 </div> <div class="sidebar-set" @click="handleSet" v-if="permission == '2'"> <el-icon style="bottom: -3px"><Setting /></el-icon> 设置 </div> </el-aside>
<!-- 首页刷新时间弹窗 --> <el-dialog v-model="setValue" title="设置" width="500"> <div class="refresh-time-container"> <el-button type="danger">首页刷新时间</el-button> <el-form-item label="刷新时间" style="margin-top: 20px; margin-bottom: 40px"> <el-input-number v-model="refreshTime" :step="1" placeholder="请输入刷新时间" style="width: 200px"> <template #suffix> <span>s</span> </template> </el-input-number> </el-form-item> <el-button type="danger">Android下载链接配置</el-button> <el-form-item label="编辑链接" style="margin-top: 20px; margin-bottom: 40px"> <el-input v-model="Androidurl" style="width: 300px" placeholder="请输入最新Android下载链接" /> </el-form-item> </div> <template #footer> <div class="dialog-footer"> <el-button @click="setValue = false">取消</el-button> <el-button type="danger" @click="setEnv">确认修改</el-button> </div> </template> </el-dialog>
<!-- 主页面 --> <el-main class="main-content"> <router-view /> </el-main> </el-container></template>
<script setup>import { computed, ref, watch, onMounted } from "vue";import { useRouter, useRoute } from "vue-router";import { ElMessage } from "element-plus";import { getEnvApi, setEnvApi } from "../api/userPermissions";import { usePermissionStore } from "../store/permission";const permissionStore = usePermissionStore();
const router = useRouter();const route = useRoute();
// token
const token = localStorage.getItem("token");//permission
const permission = ref("-1");// 递归收集父路由
const collectParentRoutes = (routes) => { let parentRoutes = []; routes.forEach((route) => { if (route.meta?.isParentNav === true && route.meta?.showSidebar === true) { parentRoutes.push(route); } if (route.children && route.children.length > 0) { parentRoutes = [...parentRoutes, ...collectParentRoutes(route.children)]; } }); return parentRoutes;};
const getPermission = async () => { const result = await getPermissionApi({ token: token }); console.log("result", result); permission.value = result.permission_level;};
// 过滤侧边栏路由
const filteredSidebarRoutes = computed(() => { const allParentRoutes = collectParentRoutes(router.options.routes);
return allParentRoutes .map((parentRoute) => { // 先获取 children,如果为空则设为 []
const rawChildren = parentRoute.children || [];
const filteredChildren = rawChildren .map((childRoute) => { // 浅拷贝 childRoute,避免直接修改原始路由对象
const newChild = { ...childRoute }; if (newChild.children && newChild.children.length > 0) { newChild.children = newChild.children.filter( (grandChild) => grandChild.meta?.showSidebar === true ); } return newChild; }) .filter((childRoute) => { // 必须标记为显示侧边栏
if (childRoute.meta?.showSidebar !== true) return false;
// 权限判断
if (permission.value == "2") { // 权限为2可以看到全部
return true; } else if (permission.value == "1") { // 权限为1只可以看到查看被邀请用户
return childRoute.name === "invitedLook"; }
// 默认情况(如未登录或无权限字段),根据实际需求处理,这里暂时隐藏
return false; }); return { ...parentRoute, filteredChildren }; }) .filter((parentRoute) => parentRoute.filteredChildren.length > 0);});
// 计算所有侧边栏有效菜单集合
const validMenuIndexes = computed(() => { const indexes = []; filteredSidebarRoutes.value.forEach((parentRoute) => { // 收集父菜单
indexes.push(`/${parentRoute.path}`); // 收集子菜单
parentRoute.filteredChildren.forEach((childRoute) => { indexes.push(`/${parentRoute.path}/${childRoute.path}`); // 收集孙子菜单
if (childRoute.children && childRoute.children.length > 0) { childRoute.children.forEach((grandChild) => { // 收集三级菜单路径 (确保拼接正确)
indexes.push(`/${parentRoute.path}/${childRoute.path}/${grandChild.path}`); }); } }); }); return indexes;});
// 存储最后一次选中的「有效侧边栏路径」
const lastActivePath = ref("");
// 初始化+监听路由变化,更新最后有效路径
watch( [() => route.path, validMenuIndexes], ([newPath, newIndexes]) => { // 如果新路由是侧边栏有效路径,更新,否则不跟新
if (newIndexes.includes(newPath)) { lastActivePath.value = newPath; } }, { immediate: true } // 初始化时立即执行一次
);
// 退出登录
const handleLogout = () => { try { localStorage.removeItem("token"); router.push("/login"); ElMessage.success("退出登录成功"); } catch (error) { ElMessage.error("退出登录失败,请重试"); }};
// 设置弹窗开关
const setValue = ref(false);
// 首页刷新时间
const refreshTime = ref("");
// 安卓最新安装包
const Androidurl = ref("");
// 设置按钮
const handleSet = async () => { const data1 = await getEnvApi({ token: token, key: "SYNC_INTERVAL", });
const data2 = await getEnvApi({ token: token, key: "DOWNLOAD_URL", });
refreshTime.value = data1; Androidurl.value = data2; setValue.value = true;};
// 确认修改按钮
const setEnv = async () => { try { await setEnvApi({ token: token, key: "SYNC_INTERVAL", value: refreshTime.value, });
await setEnvApi({ token: token, key: "DOWNLOAD_URL", value: Androidurl.value, });
ElMessage.success("修改成功"); setValue.value = false; } catch (error) { ElMessage.error("修改失败"); setValue.value = false; }};
onMounted(async () => { permission.value = await permissionStore.getPermission();});</script>
<style scoped>/* 侧边栏核心样式 */.sidebar { position: fixed; left: 24px; top: 10px; width: 336px; height: calc(100vh - 20px); flex-shrink: 0; border-radius: 8px; background: #fee6e6; box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25); overflow: hidden; position: relative;}
/* 侧边栏头部样式 */.sidebar-header { position: absolute; left: 45px; top: 59px; display: flex; align-items: center;}
.sidebar-logo { height: 40px; width: auto; object-fit: contain;}
.sidebar-title { margin-left: 10px; color: #000000; font-family: "PingFang SC", sans-serif; font-size: 32px; font-style: normal; font-weight: 700; line-height: 33.1px; white-space: nowrap;}
/* 侧边栏菜单容器 */.sidebar-menu { margin-left: 20px; margin-top: 169px; width: calc(100% - 20px); border-right: none; height: 70%; overflow-y: auto; overflow-x: hidden;}
/* 主内容区样式 */.main-content { padding: 20px; background-color: #fee6e6; height: calc(100vh - 20px); margin-left: 50px; margin-right: 24px; margin-top: 10px; box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25);}
/* 父目录文字样式 */.sidebar-parent-text { height: 33.1px; flex: 1 0 0; overflow: hidden; color: #1f0303; text-overflow: ellipsis; white-space: nowrap; font-family: "PingFang SC", sans-serif; font-size: 21.06px; font-style: normal; font-weight: 700; line-height: 33.1px; display: inline-flex; align-items: center;}
/* 子目录核心样式 */.sidebar-child-container { width: 300px !important; height: 60px !important; margin-left: 2px !important; background: #fee6e6 !important; position: relative; padding: 0 !important; border-radius: 6.02px !important; box-sizing: border-box !important;}
/* 子目录图标样式 */.sidebar-child-icon { position: absolute; left: 48px; top: 50%; transform: translateY(-50%); font-size: 18px !important; color: inherit;}
/* 子目录文字样式(未选中) */.sidebar-child-text { position: absolute; left: 58px; top: 20px; height: 33.1px; overflow: hidden; color: #03071f; text-overflow: ellipsis; white-space: nowrap; font-family: "PingFang SC", sans-serif; font-size: 18px; font-style: normal; font-weight: 400; line-height: 22px;}
.sidebar-grandchild-text { position: absolute; left: 78px; top: 15px; height: 33px; overflow: hidden; color: #03071f; text-overflow: ellipsis; white-space: nowrap; font-family: "PingFang SC", sans-serif; font-size: 16px; font-style: normal; font-weight: 400; line-height: 22px;}
/* 子目录选中态样式 */.sidebar-child-container.is-active,.sidebar-grandchild-container.is-active { background: #ffffff !important; /* 选中后容器变为白色 */}
/* 选中态文字样式 */.sidebar-child-container.is-active .sidebar-child-text,.sidebar-grandchild-container.is-active .sidebar-grandchild-text { color: #ff0000 !important; /* 选中后文字红色 */ font-weight: 500;}
/* 覆盖Element Plus默认样式 */.el-sub-menu__title { height: 33.1px !important; line-height: 33.1px !important; padding: 0 !important;}.el-menu-item { border: none !important;}.el-menu--vertical .el-menu-item { width: 300px !important;}
/* 退出登录 */.sidebar-logout { position: absolute; bottom: 30px; left: 10%;
color: #1f0303; font-family: "PingFang SC", sans-serif; font-size: 21.06px; font-style: normal; font-weight: 700; line-height: 33.1px;
cursor: pointer; user-select: none; transition: color 0.2s ease;}
/* 退出登录hover效果 */.sidebar-logout:hover { color: #ff0000;}
/* 设置 */.sidebar-set { position: absolute; bottom: 30px; left: 60%;
color: #1f0303; font-family: "PingFang SC", sans-serif; font-size: 21.06px; font-style: normal; font-weight: 700; line-height: 33.1px;
cursor: pointer; user-select: none; transition: color 0.2s ease;}
/* 设置hover效果 */.sidebar-set:hover { color: #ff0000;}</style>
|