You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/src/layout/components/Sidebar/index.vue

724 lines
26 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
* @Author: qinzhenpen qzp1807@126.com
* @Date: 2024-08-09 17:36:23
* @LastEditors: qinzhenpen qzp1807@126.com
* @LastEditTime: 2025-05-21 17:19:46
* @FilePath: \vue3\src\layout\components\Sidebar\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<template>
<div :class="[{ 'has-logo': showLogo }, { 'student-sidebar-shell': isCourseStyleSidebar }, { 'is-student-nav': isStudentRole }, { 'is-collapse': isCollapse }]" :style="sidebarStyle">
<!-- <logo v-if="showLogo" :collapse="isCollapse" /> -->
<template v-if="isCourseStyleSidebar">
<!-- 右缘折叠把手:贴侧边栏右缘垂直居中,点击收起/展开
常驻显示 —— 此前按「教师角色 + 学生实训页路由」做条件渲染,
学生端切到非实训页(首页 / AI 智能助手 / 学情分析 / 考试 / 实验报告 / BI 等)时
按钮会凭空消失,同一角色在不同页面表现不一致,这里去掉条件固定常显 -->
<button
class="course-sidebar-toggle"
type="button"
:aria-label="isCollapse ? '展开导航' : '收起导航'"
:title="isCollapse ? '展开导航' : '收起导航'"
@click.stop="toggleCourseSidebar"
>
<el-icon class="toggle-arrow toggle-arrow--left"><ArrowLeftBold /></el-icon>
<el-icon class="toggle-arrow toggle-arrow--right"><ArrowRightBold /></el-icon>
</button>
<!-- 学生端:el-menu / el-sub-menu,分组默认展开、可折叠 -->
<el-scrollbar v-if="isStudentRole" class="student-sidebar-scroll" wrap-class="scrollbar-wrapper">
<el-menu
:key="`${studentMenuKey}-${isCollapse ? 'collapsed' : 'expanded'}`"
class="student-course-menu"
mode="vertical"
:default-active="activeMenu"
:default-openeds="studentDefaultOpens"
:collapse="isCollapse"
:collapse-transition="false"
:unique-opened="false"
background-color="#ffffff"
text-color="#374151"
@select="handleStudentMenuSelect"
>
<template v-for="section in currentCourseNav" :key="section.path || section.title">
<!-- 一级直跳项 -->
<el-menu-item v-if="section.path" :index="section.path">
<el-icon class="student-menu-icon">
<component :is="getStudentNavIcon(section)" />
</el-icon>
<template #title>{{ getCourseNavTitle(section) }}</template>
</el-menu-item>
<!-- 可折叠分组 -->
<el-sub-menu
v-else
:index="getStudentGroupKey(section)"
popper-class="student-menu-popper"
>
<template #title>
<el-icon class="student-menu-icon">
<component :is="getStudentNavIcon(section)" />
</el-icon>
<span>{{ getCourseNavTitle(section) }}</span>
</template>
<el-menu-item
v-for="child in section.children"
:key="child.path || child.title"
:index="child.path || getStudentGroupKey(section) + '-' + child.title"
:disabled="!child.path"
>
<el-icon class="student-menu-icon">
<component :is="getStudentNavIcon(child)" />
</el-icon>
<template #title>{{ getCourseNavTitle(child) }}</template>
</el-menu-item>
</el-sub-menu>
</template>
</el-menu>
</el-scrollbar>
<!-- 教师端:保持原有手写导航结构 -->
<el-scrollbar v-else class="theme-dark student-sidebar-scroll" wrap-class="scrollbar-wrapper">
<nav class="student-course-nav">
<template v-for="section in currentCourseNav" :key="section.path || section.title">
<button v-if="section.path" type="button" :class="['student-course-heading', { active: isStudentNavActive(section) }]" :title="getCourseNavTitle(section)" @click="goStudentNav(section.path)">
<span class="student-course-icon student-course-icon--heading">
<component :is="getStudentNavIcon(section)" />
</span>
<span class="student-course-text">{{ getCourseNavTitle(section) }}</span>
</button>
<div v-else class="student-course-heading" :title="getCourseNavTitle(section)">
<span class="student-course-icon student-course-icon--heading">
<component :is="getStudentNavIcon(section)" />
</span>
<span class="student-course-text">{{ getCourseNavTitle(section) }}</span>
</div>
<div v-if="section.children?.length" class="student-course-list">
<template v-for="child in section.children" :key="child.path || child.title">
<button v-if="child.path" type="button" :class="['student-course-link', { active: isStudentNavActive(child) }]" :title="getCourseNavTitle(child)" @click="goStudentNav(child.path)">
<span class="student-course-icon">
<component :is="getStudentNavIcon(child)" />
</span>
<span class="student-course-text">{{ getCourseNavTitle(child) }}</span>
</button>
<div v-else class="student-course-link disabled" :title="getCourseNavTitle(child)">
<span class="student-course-icon">
<component :is="getStudentNavIcon(child)" />
</span>
<span class="student-course-text">{{ getCourseNavTitle(child) }}</span>
</div>
</template>
</div>
</template>
</nav>
</el-scrollbar>
</template>
<el-scrollbar v-else :class="sideTheme" wrap-class="scrollbar-wrapper">
<el-menu :key="sidebarMenuKey" :default-openeds="['/demand/demand', '/product/product', '/test/test', '/channel/channel', '/assessment/assessment']" :default-active="activeMenu" :collapse="isCollapse" :background-color="sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground" :text-color="sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor" :unique-opened="false" :active-text-color="theme" :collapse-transition="false" mode="vertical">
<sidebar-item v-for="(route, index) in visibleSidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script setup>
import Logo from "./Logo";
import SidebarItem from "./SidebarItem";
import variables from "@/assets/styles/variables.module.scss";
import useAppStore from "@/store/modules/app";
import * as indexApi from "@/api/teacher";
import useSettingsStore from "@/store/modules/settings";
import usePermissionStore from "@/store/modules/permission";
import { constantRoutes, dynamicRoutes, teacherRoutes, platformAdminRoutes, schoolAdminRoutes } from "@/router/index.js";
import useUserStore from "@/store/modules/user";
import { getCachedStudentTrainingTasks, loadStudentTrainingTasks } from "@/api/trainingTask";
import { buildStudentTaskSections } from "@/utils/studentTrainingNavigation";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const appStore = useAppStore();
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore();
const sidebarRouters = ref([...constantRoutes]);
const visibleSidebarRouters = computed(() => filterRoutesByOrganizationMode(sidebarRouters.value));
const sidebarMenuKey = computed(() => visibleSidebarRouters.value.map((route) => route.path).join("|"));
const routerStatus = {
行业需求分析: [
{
id: "9f413263-e6ff-4ee5-984a-7a231cad6818",
module: "行业需求分析-蛋糕指数",
sort: 1,
status: 0,
parentDisabled: true,
},
],
竞争环境分析: [
{
id: "ae274ec6-971a-4a33-aa63-2e449f146487",
module: "竞争环境分析-赫芬达尔指数",
sort: 2,
status: 0,
},
],
消费人群分析: [
{
id: "b91026aa-275c-4779-8602-61051a931d3a",
module: "消费人群分析-波士顿矩阵分析",
sort: 3,
status: 1,
},
{
id: "191026aa-275c-4779-8602-61051a931d3a",
classId: "1",
schoolId: "1",
module: "消费人群分析-RFM分析",
status: 0,
sort: 3,
},
],
用户数据分析: [
{
id: "4b4a685a-b9a3-4edc-9a68-a670d8c84c94",
module: "用户数据分析-描述性统计",
sort: 4,
status: 0,
},
{
id: "1c6099e7-fc8a-4485-b828-8d1aef8e34b4",
module: "用户数据分析-聚类分析",
sort: 5,
status: 1,
},
],
数据化选品: [
{
id: "fc9f19cb-8f77-4810-a538-eec97f840c0a",
module: "数据化选品-线性预测法-销售预测",
sort: 6,
status: 0,
},
],
产品定价: [
{
id: "b95af20c-6242-42cd-a7c2-ddec7b9a0957",
module: "产品定价-PSM模型",
sort: 7,
status: 0,
},
],
产品差异化定位: [
{
id: "4ca53e70-c168-455a-8dbd-f7d6475c5903",
module: "产品差异化定位-SPAN模型",
sort: 8,
status: 0,
},
],
产品结构规划: [
{
id: "31f289b7-04a7-4b8b-b5b4-6333f7c3d76e",
module: "产品结构规划",
sort: 9,
status: 0,
},
],
发布渠道评估: [
{
id: "b58ef210-624b-43f2-bbac-f788c8d96cc8",
module: "发布渠道评估-指标评估法-熵值法",
sort: 10,
status: 0,
},
],
产品推广测试: [
{
id: "de9206fe-1e95-454f-912c-54dbd0a383cc",
module: "产品推广测试-A/B测试",
sort: 11,
status: 0,
},
],
渠道表现分析: [
{
id: "2063efde-f8ba-4f69-be9b-1d87586044f6",
module: "渠道表现分析-转化分析-漏斗模型",
sort: 12,
status: 0,
},
],
产品营销定位: [
{
id: "e99dee9f-a7a9-4e8c-a77b-8db6dfbc64d7",
module: "产品营销定位-四象限法则",
sort: 13,
status: 0,
},
],
采购需求预测: [
{
id: "c8835d65-db31-4952-9d8d-5d07bf4a9c90",
module: "采购需求预测-季节指数预测法",
sort: 14,
status: 0,
},
],
采购产品定位: [
{
id: "acd195cf-5e43-4c5e-8ec9-e5ad85612063",
module: "采购产品定位-卡拉杰克模型",
sort: 15,
status: 0,
},
],
供应商评估与选择: [
{
id: "206e5b9a-95a0-41d7-b2f2-19f5cf10331a",
module: "供应商评估与选择-线性权重法",
sort: 16,
status: 0,
},
],
产品表现分析: [
{
id: "0aca8b42-c665-4759-b1b4-b35a0daf2e80",
module: "产品表现分析-功效系数法",
sort: 17,
status: 0,
},
],
产品问题诊断: [
{
id: "55a0ffd4-9863-40d8-bc4c-7830c731eaa7",
module: "产品问题诊断-五维四率法",
sort: 18,
status: 1,
},
{
id: "205f28ce-31d8-449a-8053-7d6f85e98a68",
module: "产品问题诊断-KANO模型",
sort: 19,
status: 0,
},
{
id: "2768d846-dfe8-42c1-b31f-f4deef85f34d",
module: "产品问题诊断-市场机会矩阵",
sort: 20,
status: 0,
},
{
id: "d0fc3cb4-2cde-401f-b243-33bdb5ef1094",
module: "产品问题诊断-流量数据分析法",
sort: 21,
status: 0,
},
{
id: "25896e1a-b099-4778-bd87-3b92aa8845da",
module: "产品问题诊断-用户评论分析",
sort: 22,
status: 0,
},
],
品类结构优化: [
{
id: "6bbeebf1-662a-46d6-aa4a-e5e8c4c3d5f1",
module: "品类结构优化-帕累托/ABC分析",
sort: 23,
status: 1,
},
{
id: "90212d7c-d8b5-4455-bc7a-693ded4b3f8f",
module: "品类结构优化-购物篮分析",
sort: 24,
status: 0,
},
],
};
const showLogo = computed(() => settingsStore.sidebarLogo);
const sideTheme = computed(() => settingsStore.sideTheme);
const theme = computed(() => settingsStore.theme);
const isCollapse = computed(() => !appStore.sidebar.opened);
const isTeacherRole = computed(() => Number(userStore.userInfo.roleId) === 3);
const isStudentRole = computed(() => ![1, 2, 3].includes(Number(userStore.userInfo.roleId)));
const isCourseStyleSidebar = computed(() => isStudentRole.value || isTeacherRole.value);
function toggleCourseSidebar() {
appStore.toggleSideBar(false);
}
const sidebarStyle = computed(() => {
if (isCourseStyleSidebar.value) return {};
return {
backgroundColor: sideTheme.value === "theme-dark" ? variables.menuBackground : variables.menuLightBackground,
};
});
const studentCourseNav = [
{ title: "AI智能助手", path: "/assistant/index", activePrefix: "/assistant" },
{
title: "互联网产品开发基础",
children: [
{ title: "新产品调查与分析", path: "/foundation/new-product-survey" },
{ title: "产品开发关键因素", path: "/foundation/product-development-factors" },
{ title: "产品开发主要流程", path: "/foundation/product-development-process" },
],
},
{
title: "市场洞察与需求分析",
children: [
{ title: "行业需求分析", path: "/demand/index" },
{ title: "竞争环境分析", path: "/demand/environment" },
{ title: "市场机会识别与选品", path: "/product/index" },
{ title: "商业可行性论证", path: "/demand/business-feasibility" },
{ title: "目标用户画像", path: "/demand/people" },
{ title: "消费者需求与行为", path: "/demand/consumer-behavior" },
{ title: "消费场景解构", path: "/demand/consumer-scenario" },
{ title: "需求转化为功能", path: "/demand/feature-conversion" },
{ title: "产品价值主张及定位", path: "/product/differentiation" },
],
},
{
title: "产品规划与设计",
children: [
{ title: "产品架构设计", path: "/product/structure" },
{ title: "售后服务流程设计", path: "/product/after-sales-service" },
{ title: "产品需求说明书", path: "/product/requirements-doc" },
],
},
{
title: "产品开发与测试验证",
children: [
{ title: "智能硬件成本估算", path: "/product/hardware-cost" },
{ title: "供应渠道评估", path: "/channel/supplier" },
{ title: "采购需求预测", path: "/channel/index" },
{ title: "产品定价", path: "/product/price" },
],
},
{
title: "产品上线与运营推广",
children: [
{ title: "品类结构优化", path: "/assessment/optimization" },
{ title: "产品发布渠道评估", path: "/test/index" },
{ title: "投放效果评估与优化", path: "/test/promotion" },
{ title: "产品问题诊断与迭代", path: "/assessment/diagnosis" },
],
},
{
title: "综合实训",
children: [
{ title: "综合案例实训", path: "/comprehensive/index" },
],
},
];
const teacherManageNav = [
{
title: "教学管理",
children: [
{ title: "院系管理", path: "/school/index", requiresFacultyManagement: true },
{ title: "专业管理", path: "/major/index", requiresMajorManagement: true },
{ title: "班级管理", path: "/class/index" },
{ title: "教师管理", path: "/teacher/index" },
{ title: "学生管理", path: "/student/index" },
{ title: "实训任务管理", path: "/training-task/index" },
{ title: "任务分配", path: "/task/index" },
{ title: "任务评阅", path: "/task-review/index" },
{ title: "成绩中心", path: "/score/index" },
{ title: "综合考核", path: "/exam/index" },
],
},
];
const trainingTaskKeyByPath = {
"/comprehensive/index": "comprehensive-case-training",
"/foundation/new-product-survey": "new-product-survey",
"/foundation/product-development-factors": "product-development-factors",
"/foundation/product-development-process": "product-development-process",
"/demand/index": "industry-demand-analysis",
"/demand/environment": "competitive-environment-analysis",
"/product/index": "market-opportunity-selection",
"/demand/business-feasibility": "business-feasibility",
"/demand/people": "target-user-profile",
"/demand/consumer-behavior": "consumer-behavior",
"/demand/consumer-scenario": "consumer-scenario",
"/demand/feature-conversion": "feature-conversion",
"/product/differentiation": "product-value-positioning",
"/product/structure": "product-structure",
"/product/after-sales-service": "after-sales-service",
"/product/requirements-doc": "requirements-doc",
"/product/hardware-cost": "hardware-cost",
"/channel/supplier": "supplier-evaluation",
"/channel/index": "purchase-demand-forecast",
"/product/price": "product-pricing",
"/assessment/optimization": "category-optimization",
"/test/index": "release-channel-evaluation",
"/test/promotion": "promotion-effect-optimization",
"/assessment/diagnosis": "product-diagnosis-iteration",
};
const studentCourseBaseNav = [
{ title: "AI智能助手", path: "/assistant/index", activePrefix: "/assistant" },
];
const studentTaskSections = ref([]);
const currentCourseNav = computed(() => (isTeacherRole.value
? filterTeacherManageNavigation(teacherManageNav)
: [...studentCourseBaseNav, ...studentTaskSections.value]));
const studentIconByPath = {
"/assistant/index": "MagicStick",
"/comprehensive/index": "School",
"/foundation/new-product-survey": "Search",
"/foundation/product-development-factors": "SetUp",
"/foundation/product-development-process": "Guide",
"/demand/index": "DataAnalysis",
"/demand/environment": "TrendCharts",
"/product/index": "Opportunity",
"/demand/business-feasibility": "Histogram",
"/demand/people": "UserFilled",
"/demand/consumer-behavior": "ShoppingCart",
"/demand/consumer-scenario": "MapLocation",
"/demand/feature-conversion": "Connection",
"/product/differentiation": "PriceTag",
"/product/structure": "Box",
"/product/after-sales-service": "Service",
"/product/requirements-doc": "Document",
"/product/hardware-cost": "Cpu",
"/channel/supplier": "Ship",
"/channel/index": "ShoppingBag",
"/product/price": "Money",
"/assessment/optimization": "CollectionTag",
"/test/index": "Promotion",
"/test/promotion": "DataLine",
"/assessment/diagnosis": "Tools",
"/report/index": "DocumentChecked",
"/school/index": "OfficeBuilding",
"/major/index": "Collection",
"/class/index": "Flag",
"/teacher/index": "UserFilled",
"/student/index": "Avatar",
"/training-task/index": "Files",
"/task/index": "Management",
"/task-review/index": "EditPen",
"/score/index": "Trophy",
"/exam/index": "Stopwatch",
};
const studentIconBySectionStart = [
{ path: "/training/", icon: "Document" },
{ path: "/foundation/", icon: "Collection" },
{ path: "/demand/", icon: "Search" },
{ path: "/product/", icon: "Goods" },
{ path: "/channel/", icon: "Connection" },
{ path: "/assessment/", icon: "DataBoard" },
{ path: "/test/", icon: "Finished" },
{ path: "/school/", icon: "OfficeBuilding" },
{ path: "/major/", icon: "Collection" },
{ path: "/class/", icon: "Flag" },
{ path: "/teacher/", icon: "UserFilled" },
{ path: "/student/", icon: "Avatar" },
{ path: "/training-task/", icon: "Files" },
{ path: "/task/", icon: "Management" },
{ path: "/score/", icon: "Trophy" },
];
function getStudentNavIcon(item) {
const path = item.path || item.children?.[0]?.path || "";
const exactIcon = studentIconByPath[path];
const sectionIcon = studentIconBySectionStart.find((section) => path.startsWith(section.path))?.icon;
return ElementPlusIconsVue[exactIcon || sectionIcon] || ElementPlusIconsVue.Menu;
}
const activeMenu = computed(() => {
const { meta, path } = route;
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu;
}
return path;
});
function isStudentNavActive(item) {
if (item.activePrefix) {
return route.path.startsWith(item.activePrefix);
}
return route.path === item.path;
}
function goStudentNav(path) {
if (!path || route.path === path) return;
router.push(path);
}
/* ===== 学生端 el-menu:默认展开全部分组,分组可折叠 ===== */
function getStudentGroupKey(section) {
return section.title || section.path || "";
}
// 所有可折叠分组默认展开(default-openeds 仅在菜单挂载时初始化)
const studentDefaultOpens = computed(() =>
currentCourseNav.value
.filter((section) => !section.path && section.children?.length)
.map((section) => getStudentGroupKey(section))
);
// 异步加载分组后重建菜单,使新分组按 default-openeds 展开
const studentMenuKey = ref(0);
function bumpStudentMenu() {
studentMenuKey.value += 1;
}
function handleStudentMenuSelect(index) {
goStudentNav(index);
}
function getCourseNavTitle(item) {
return item?.title || "";
}
async function loadStudentTaskNavigation() {
if (!isStudentRole.value) {
studentTaskSections.value = [];
return;
}
const cachedTasks = getCachedStudentTrainingTasks();
if (cachedTasks.length) {
studentTaskSections.value = buildStudentTaskSections(cachedTasks);
bumpStudentMenu();
}
try {
const res = await loadStudentTrainingTasks();
studentTaskSections.value = buildStudentTaskSections(res.data || []);
bumpStudentMenu();
} catch (error) {
if (!cachedTasks.length) {
studentTaskSections.value = [];
}
}
}
function groupAndSortModules(modules) {
const grouped = modules.reduce((acc, item) => {
const prefix = item.module.split("-")[0].trim();
if (!acc[prefix]) {
acc[prefix] = [];
}
acc[prefix].push({
id: item.id,
module: item.module,
sort: item.sort,
status: item.disabledStatus,
});
return acc;
}, {});
// 对每个分组按sort排序
Object.keys(grouped).forEach((key) => {
grouped[key].sort((a, b) => a.sort - b.sort);
});
return grouped;
}
function processModuleStatus(groupedData) {
const result = {
data: JSON.parse(JSON.stringify(groupedData)), // 原始数据副本
disabledParents: [], // 被禁用的父模块列表(所有子模块都禁用)
activeParents: [], // 活跃的父模块列表
disabledChildren: [], // 被禁用的子模块(仅当父模块有多个子模块时)
parentStatus: {}, // 每个父模块的详细状态
};
// 分析每个父模块状态
for (const [parentModule, children] of Object.entries(result.data)) {
const disabledCount = children.filter((child) => child.status === 1).length;
const totalCount = children.length;
result.parentStatus[parentModule] = {
disabledCount,
totalCount,
isDisabled: disabledCount === totalCount && totalCount > 0,
};
// 只有当父模块有多个子模块时,才收集被禁用的子模块
if (totalCount > 1) {
children.forEach((child) => {
if (child.status === 1) {
result.disabledChildren.push({
parentModule,
...child,
module: child.module.split("-")[1].trim(),
});
}
});
}
if (result.parentStatus[parentModule].isDisabled) {
result.disabledParents.push(parentModule);
children.forEach((child) => {
child.parentDisabled = true; // 标记父模块禁用状态
});
} else {
result.activeParents.push(parentModule);
}
}
return result;
}
/**
* 过滤掉 children 中 meta.title 在排除列表里的路由
* @param {Array} routes 原始路由数组
* @param {Array} excludeTitles 要排除的 meta.title 列表
* @returns {Array} 新的路由数组
*/
function excludeRoutesByMetaTitle(routes, excludeTitles) {
return routes.reduce((result, route) => {
if (Array.isArray(route.children)) {
const filteredChildren = route.children.filter((child) => !excludeTitles.includes(child.meta?.title));
if (filteredChildren.length > 0) {
result.push({ ...route, children: filteredChildren });
}
} else {
result.push(route); // 没有 children 的保留原样
}
return result;
}, []);
}
const getTaskList = async () => {
if (userStore.userInfo.roleId == 1) {
sidebarRouters.value = [...constantRoutes, ...platformAdminRoutes];
} else if (userStore.userInfo.roleId == 2) {
await userStore.ensureSchoolProductConfig().catch(() => null);
sidebarRouters.value = [...constantRoutes, ...filterRoutesByOrganizationMode(schoolAdminRoutes)];
} else if (userStore.userInfo.roleId != 3) {
await loadStudentTaskNavigation();
sidebarRouters.value = [...constantRoutes, ...dynamicRoutes];
} else {
await userStore.ensureSchoolProductConfig().catch(() => null);
sidebarRouters.value = [...constantRoutes, ...filterRoutesByOrganizationMode(teacherRoutes)];
}
};
function isSchoolNavigationVisible(item) {
const config = userStore.schoolProductConfig;
const facultyEnabled = config?.facultyManagementEnabled === true;
const majorEnabled = config?.majorManagementEnabled === true;
const adminClassEnabled = config?.adminClassManagementEnabled === true;
const capability = item.meta || item;
if (capability.requiresManagerTeacher && userStore.userInfo.teacherAdmin !== true) return false;
if (capability.requiresFacultyManagement && !facultyEnabled) return false;
if (capability.requiresMajorManagement && !majorEnabled) return false;
if (capability.requiresAdminClass && !adminClassEnabled) return false;
return true;
}
function filterRoutesByOrganizationMode(routes) {
return routes.filter(isSchoolNavigationVisible);
}
function filterTeacherManageNavigation(sections) {
return sections
.map((section) => {
if (!section.children) return section;
return {
...section,
children: section.children.filter(isSchoolNavigationVisible),
};
})
.filter((section) => (section.children ? section.children.length > 0 : isSchoolNavigationVisible(section)));
}
watch(
() => userStore.schoolProductConfig?.organizationMode,
(organizationMode, previousOrganizationMode) => {
if (organizationMode === previousOrganizationMode) return;
if ([2, 3].includes(Number(userStore.userInfo.roleId))) {
getTaskList();
}
}
);
onMounted(() => {
getTaskList();
});
</script>