You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
13 KiB
472 lines
13 KiB
<!-- @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>
|