feat:教师端菜单栏替换为接口获取动态渲染
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 490 B After Width: | Height: | Size: 490 B |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 712 B |
@ -127,6 +127,23 @@ export interface QueryCourseSectionParams {
|
||||
*/
|
||||
export class TeachCourseApi {
|
||||
|
||||
|
||||
/**
|
||||
* 菜单列表接口
|
||||
*/
|
||||
static async getTeacherMenuList(): Promise<ApiResponse<any>> {
|
||||
try{
|
||||
const response = await ApiRequest.get<any>('/aiol/aiolMenu/getTeacherMenus')
|
||||
console.log('📝 获取教师菜单响应:', response);
|
||||
|
||||
return response
|
||||
} catch(error) {
|
||||
console.error('❌ 获取教师菜单失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新建课程
|
||||
*/
|
||||
|
@ -21,79 +21,44 @@
|
||||
|
||||
<!-- 导航栏 -->
|
||||
<div class="nav-container">
|
||||
<router-link to="/teacher/course-management" class="nav-item" :class="{ active: activeNavItem === 0 }"
|
||||
@click="setActiveNavItem(0)">
|
||||
<img :src="activeNavItem === 0 ? '/images/teacher/课程管理(选中).png' : '/images/teacher/课程管理.png'" alt="">
|
||||
<span>课程管理</span>
|
||||
</router-link>
|
||||
|
||||
<!-- 考试管理 - 可展开菜单 -->
|
||||
<div class="nav-item" :class="{ active: activeNavItem === 4 }" @click="toggleExamMenu">
|
||||
<img
|
||||
:src="activeNavItem === 4 ? '/images/teacher/examination-active.png' : '/images/teacher/examination.png'"
|
||||
alt="">
|
||||
<span>考试管理</span>
|
||||
<n-icon class="expand-icon" :class="{ expanded: examMenuExpanded }">
|
||||
<!-- 动态菜单渲染 -->
|
||||
<template v-for="menu in menuList" :key="menu.id">
|
||||
<!-- 有子菜单的父级菜单 -->
|
||||
<div v-if="menu.children && menu.children.length > 0"
|
||||
class="nav-item"
|
||||
:class="{ active: activeNavItem === menu.id }"
|
||||
@click="toggleMenu(menu)">
|
||||
<img :src="getMenuIcon(menu)" :alt="menu.name" v-if="menu.icon">
|
||||
<span>{{ menu.name }}</span>
|
||||
<n-icon class="expand-icon" :class="{ expanded: isMenuExpanded(menu.id) }">
|
||||
<ChevronDownOutline />
|
||||
</n-icon>
|
||||
</div>
|
||||
|
||||
<!-- 考试管理子菜单 -->
|
||||
<div class="submenu-container" :class="{ expanded: examMenuExpanded }">
|
||||
<router-link to="/teacher/exam-management/question-bank" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'question-bank' }" @click="setActiveSubNavItem('question-bank')">
|
||||
<span>题库管理</span>
|
||||
</router-link>
|
||||
<router-link to="/teacher/exam-management/exam-library" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'exam-library' }" @click="setActiveSubNavItem('exam-library')">
|
||||
<span>试卷管理</span>
|
||||
</router-link>
|
||||
<router-link to="/teacher/exam-management/marking-center/list" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'marking-center' }" @click="setActiveSubNavItem('marking-center')">
|
||||
<span>阅卷中心</span>
|
||||
<!-- 子菜单容器 -->
|
||||
<div v-if="menu.children && menu.children.length > 0"
|
||||
class="submenu-container"
|
||||
:class="{ expanded: isMenuExpanded(menu.id) }">
|
||||
<router-link v-for="subMenu in menu.children"
|
||||
:key="subMenu.id"
|
||||
:to="subMenu.path"
|
||||
class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === subMenu.id }"
|
||||
@click="handleSubMenuClick(subMenu, menu)">
|
||||
<span>{{ subMenu.name }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 学员中心 - 可展开菜单 -->
|
||||
<div class="nav-item" :class="{ active: activeNavItem === 1 }"
|
||||
@click="toggleStudentMenu('/teacher/student-management/student-library')">
|
||||
<img :src="activeNavItem === 1 ? '/images/teacher/学院管理(选中).png' : '/images/teacher/学员管理.png'" alt="">
|
||||
<span>学员中心</span>
|
||||
<n-icon class="expand-icon" :class="{ expanded: studentMenuExpanded }">
|
||||
<ChevronDownOutline />
|
||||
</n-icon>
|
||||
</div>
|
||||
|
||||
<!-- 学员中心子菜单 -->
|
||||
<div class="submenu-container" :class="{ expanded: studentMenuExpanded }">
|
||||
<router-link to="/teacher/student-management/student-library" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'student-library' }"
|
||||
@click="setActiveSubNavItem('student-library')">
|
||||
<span>学员库</span>
|
||||
</router-link>
|
||||
<router-link to="/teacher/student-management/class-management" class="submenu-item"
|
||||
:class="{ active: activeSubNavItem === 'class-management' }"
|
||||
@click="setActiveSubNavItem('class-management')">
|
||||
<span>班级管理</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<!-- <router-link to="/teacher/my-resources" class="nav-item" :class="{ active: activeNavItem === 2 }"
|
||||
@click="setActiveNavItem(2)">
|
||||
<img :src="activeNavItem === 2 ? '/images/teacher/我的资源(选中).png' : '/images/teacher/我的资源.png'" alt="">
|
||||
<span>我的资源</span>
|
||||
</router-link> -->
|
||||
<router-link to="/teacher/message-center" class="nav-item" :class="{ active: activeNavItem === 5 }"
|
||||
@click="setActiveNavItem(5)">
|
||||
<img :src="activeNavItem === 5 ? '/images/profile/message-active.png' : '/images/profile/message.png'"
|
||||
alt="">
|
||||
<span>消息中心</span>
|
||||
</router-link>
|
||||
<router-link to="/teacher/personal-center" class="nav-item" :class="{ active: activeNavItem === 3 }"
|
||||
@click="setActiveNavItem(3)">
|
||||
<img :src="activeNavItem === 3 ? '/images/teacher/个人中心(选中).png' : '/images/teacher/个人中心.png'" alt="">
|
||||
<span>个人中心</span>
|
||||
<!-- 没有子菜单的直接链接 -->
|
||||
<router-link v-else
|
||||
:to="menu.path"
|
||||
class="nav-item"
|
||||
:class="{ active: activeNavItem === menu.id }"
|
||||
@click="toggleMenu(menu)">
|
||||
<img :src="getMenuIcon(menu)" :alt="menu.name" v-if="menu.icon">
|
||||
<span>{{ menu.name }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- ai助教 - 已注释 -->
|
||||
@ -188,6 +153,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { ChevronDownOutline } from '@vicons/ionicons5'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { ChevronBackSharp } from '@vicons/ionicons5'
|
||||
import { TeachCourseApi } from '@/api/modules/teachCourse'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
@ -197,11 +163,9 @@ const height = window.innerHeight;
|
||||
console.log(`当前屏幕宽度: ${width}px, 高度: ${height}px`);
|
||||
|
||||
// 添加导航项激活状态管理
|
||||
const activeNavItem = ref(0); // 0: 课程管理, 1: 学员管理, 2: 我的资源, 3: 个人中心, 4: 考试管理, 5: 消息中心 (6: 智能体编排 - 已注释)
|
||||
const activeNavItem = ref(''); // 当前激活的菜单ID
|
||||
const activeSubNavItem = ref(''); // 子菜单激活状态
|
||||
const examMenuExpanded = ref(false); // 考试管理菜单展开状态
|
||||
const studentMenuExpanded = ref(false); // 学员中心菜单展开状态
|
||||
// const orchestrationMenuExpanded = ref(false); // 智能体编排菜单展开状态 - 已注释
|
||||
const expandedMenus = ref(new Set()); // 展开的菜单ID集合
|
||||
const showTopImage = ref(false); // 控制顶部图片显示/隐藏
|
||||
|
||||
// 需要隐藏顶部图片的路由路径数组
|
||||
@ -227,88 +191,77 @@ const breadcrumbDisplay = computed(() => {
|
||||
|
||||
const isCourseEditor = computed(() => route.path.includes('course-editor') || route.path.includes('chapter-editor-teacher'));
|
||||
|
||||
const setActiveNavItem = (index: number) => {
|
||||
activeNavItem.value = index;
|
||||
// 如果不是考试管理,关闭考试管理子菜单
|
||||
if (index !== 4) {
|
||||
examMenuExpanded.value = false;
|
||||
// 检查菜单是否展开
|
||||
const isMenuExpanded = (menuId) => {
|
||||
return expandedMenus.value.has(menuId)
|
||||
}
|
||||
// 如果不是学员中心,关闭学员中心子菜单
|
||||
if (index !== 1) {
|
||||
studentMenuExpanded.value = false;
|
||||
}
|
||||
// 如果不是智能体编排,关闭智能体编排子菜单 - 已注释
|
||||
// if (index !== 6) {
|
||||
// orchestrationMenuExpanded.value = false;
|
||||
// }
|
||||
// 如果切换到其他菜单,清空子菜单选中状态
|
||||
if (index !== 4 && index !== 1) { // 移除 index !== 6 条件
|
||||
activeSubNavItem.value = '';
|
||||
|
||||
// 切换菜单展开状态
|
||||
const toggleMenu = (menu) => {
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
if (expandedMenus.value.has(menu.id)) {
|
||||
expandedMenus.value.delete(menu.id)
|
||||
} else {
|
||||
expandedMenus.value.add(menu.id)
|
||||
}
|
||||
}
|
||||
|
||||
// 考试管理菜单切换
|
||||
const toggleExamMenu = () => {
|
||||
// 如果当前菜单要展开,先关闭其他菜单
|
||||
if (!examMenuExpanded.value) {
|
||||
studentMenuExpanded.value = false;
|
||||
}
|
||||
// 设置当前菜单为激活状态
|
||||
activeNavItem.value = menu.id
|
||||
|
||||
examMenuExpanded.value = !examMenuExpanded.value;
|
||||
activeNavItem.value = 4;
|
||||
|
||||
// 如果展开且没有选中子菜单,默认选中第一个
|
||||
if (examMenuExpanded.value && !activeSubNavItem.value) {
|
||||
activeSubNavItem.value = 'question-management';
|
||||
// 如果有路径且没有子菜单,则导航
|
||||
if (menu.path && (!menu.children || menu.children.length === 0)) {
|
||||
router.push(menu.path)
|
||||
}
|
||||
}
|
||||
|
||||
// 学员中心菜单切换
|
||||
const toggleStudentMenu = (path: string) => {
|
||||
// 如果当前菜单要展开,先关闭其他菜单
|
||||
if (!studentMenuExpanded.value) {
|
||||
examMenuExpanded.value = false;
|
||||
}
|
||||
|
||||
studentMenuExpanded.value = !studentMenuExpanded.value;
|
||||
activeNavItem.value = 1;
|
||||
|
||||
// 如果展开且没有选中子菜单,默认选中第一个
|
||||
if (studentMenuExpanded.value && !activeSubNavItem.value) {
|
||||
activeSubNavItem.value = 'student-library';
|
||||
router.push(path);
|
||||
// 处理子菜单点击
|
||||
const handleSubMenuClick = (subMenu, parentMenu) => {
|
||||
activeSubNavItem.value = subMenu.id
|
||||
activeNavItem.value = parentMenu.id
|
||||
if (subMenu.path) {
|
||||
router.push(subMenu.path)
|
||||
}
|
||||
}
|
||||
|
||||
// 智能体编排菜单切换 - 已注释
|
||||
// const toggleOrchestrationMenu = () => {
|
||||
// orchestrationMenuExpanded.value = !orchestrationMenuExpanded.value;
|
||||
// activeNavItem.value = 6;
|
||||
// 获取菜单图标,处理激活状态
|
||||
const getMenuIcon = (menu) => {
|
||||
if (!menu.icon) return null
|
||||
|
||||
// // 如果展开且没有选中子菜单,默认选中第一个
|
||||
// if (orchestrationMenuExpanded.value && !activeSubNavItem.value) {
|
||||
// activeSubNavItem.value = 'app-management';
|
||||
// }
|
||||
// }
|
||||
|
||||
// 设置子菜单激活状态
|
||||
const setActiveSubNavItem = (subItem: string) => {
|
||||
activeSubNavItem.value = subItem;
|
||||
|
||||
// 根据子菜单项判断属于哪个主菜单
|
||||
if (subItem === 'question-bank' || subItem === 'exam-library' || subItem === 'marking-center') {
|
||||
// 考试管理子菜单
|
||||
activeNavItem.value = 4;
|
||||
examMenuExpanded.value = true;
|
||||
} else if (subItem === 'student-library' || subItem === 'class-management') {
|
||||
// 学员中心子菜单
|
||||
activeNavItem.value = 1;
|
||||
studentMenuExpanded.value = true;
|
||||
} else if (subItem === 'app-management' || subItem === 'knowledge-base' || subItem === 'process-design' || subItem === 'model-config' || subItem === 'ocr-recognition') {
|
||||
// 智能体编排子菜单
|
||||
activeNavItem.value = 6;
|
||||
orchestrationMenuExpanded.value = true;
|
||||
// 如果是激活状态且有对应的激活图标
|
||||
if (activeNavItem.value === menu.id) {
|
||||
return menu.icon.replace('.png', '-active.png')
|
||||
}
|
||||
|
||||
return menu.icon
|
||||
}
|
||||
|
||||
// 更新激活的导航项
|
||||
const updateActiveNavItem = () => {
|
||||
const path = route.path;
|
||||
console.log('当前路径:', path);
|
||||
|
||||
// 遍历菜单找到匹配的路径
|
||||
const findActiveMenu = (menus, parentId = null) => {
|
||||
for (const menu of menus) {
|
||||
if (menu.path && path.includes(menu.path.replace('/teacher/', ''))) {
|
||||
activeNavItem.value = parentId || menu.id
|
||||
if (parentId) {
|
||||
activeSubNavItem.value = menu.id
|
||||
expandedMenus.value.add(parentId)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (menu.children && menu.children.length > 0) {
|
||||
if (findActiveMenu(menu.children, menu.id)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
findActiveMenu(menuList.value)
|
||||
}
|
||||
|
||||
// 处理面包屑点击
|
||||
@ -335,6 +288,50 @@ const hideSidebar = computed(() => {
|
||||
return currentPath.includes('course-editor') || currentPath.includes('chapter-editor-teacher') || currentPath.includes('certificate')
|
||||
})
|
||||
|
||||
// 定义菜单数据
|
||||
const menuList = ref([])
|
||||
|
||||
// 处理菜单数据,构建层级关系
|
||||
const processMenuData = (menuData) => {
|
||||
const menuMap = new Map()
|
||||
const rootMenus = []
|
||||
|
||||
// 先创建所有菜单项的映射
|
||||
menuData.forEach(menu => {
|
||||
menuMap.set(menu.id, {
|
||||
...menu,
|
||||
children: []
|
||||
})
|
||||
})
|
||||
|
||||
// 构建层级关系
|
||||
menuData.forEach(menu => {
|
||||
if (menu.parentId === null) {
|
||||
// 根级菜单
|
||||
rootMenus.push(menuMap.get(menu.id))
|
||||
} else {
|
||||
// 子菜单
|
||||
const parent = menuMap.get(menu.parentId)
|
||||
if (parent) {
|
||||
parent.children.push(menuMap.get(menu.id))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 按sortOrder排序
|
||||
const sortMenus = (menus) => {
|
||||
menus.sort((a, b) => b.sortOrder - a.sortOrder)
|
||||
menus.forEach(menu => {
|
||||
if (menu.children.length > 0) {
|
||||
sortMenus(menu.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
sortMenus(rootMenus)
|
||||
return rootMenus
|
||||
}
|
||||
|
||||
// 动态生成面包屑路径项(右侧部分)
|
||||
const breadcrumbPathItems = computed(() => {
|
||||
const currentPath = route.path;
|
||||
@ -795,7 +792,20 @@ const breadcrumbPathItems = computed(() => {
|
||||
});
|
||||
|
||||
// 监听路由变化,更新激活的导航项
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// 获取菜单数据
|
||||
const menuResponse = await TeachCourseApi.getTeacherMenuList()
|
||||
const rawMenuData = menuResponse.data.result
|
||||
console.log('原始菜单数据:', rawMenuData);
|
||||
|
||||
// 处理菜单数据
|
||||
menuList.value = processMenuData(rawMenuData)
|
||||
console.log('处理后的菜单数据:', menuList.value);
|
||||
} catch (error) {
|
||||
console.error('获取菜单数据失败:', error)
|
||||
}
|
||||
|
||||
// 初始设置
|
||||
updateActiveNavItem();
|
||||
|
||||
@ -832,62 +842,6 @@ const updateTopImageVisibility = () => {
|
||||
console.log('顶部图片显示状态:', showTopImage.value);
|
||||
};
|
||||
|
||||
// 更新激活的导航项
|
||||
const updateActiveNavItem = () => {
|
||||
const path = route.path;
|
||||
console.log('当前路径:', path); // 添加调试信息
|
||||
if (path.includes('course-management')) {
|
||||
activeNavItem.value = 0; // 课程管理
|
||||
} else if (path.includes('student-management')) {
|
||||
activeNavItem.value = 1; // 学员管理
|
||||
studentMenuExpanded.value = true;
|
||||
|
||||
// 根据路径设置子菜单激活状态
|
||||
if (path.includes('student-library')) {
|
||||
activeSubNavItem.value = 'student-library';
|
||||
} else if (path.includes('class-management')) {
|
||||
activeSubNavItem.value = 'class-management';
|
||||
}
|
||||
} else if (path.includes('my-resources')) {
|
||||
activeNavItem.value = 2; // 我的资源
|
||||
} else if (path.includes('personal-center')) {
|
||||
activeNavItem.value = 3; // 个人中心
|
||||
} else if (path.includes('exam-management')) {
|
||||
activeNavItem.value = 4; // 考试管理
|
||||
examMenuExpanded.value = true;
|
||||
|
||||
const arr = ['question-bank', 'exam-library', 'marking-center'];
|
||||
const found = arr.find(item => path.includes(item));
|
||||
activeSubNavItem.value = found || '';
|
||||
} else if (path.includes('message-center')) {
|
||||
activeNavItem.value = 5; // 消息中心
|
||||
// } else if (path.includes('ai-assistant')) {
|
||||
// // AI助教页面,清空所有导航项选中状态 - 已注释
|
||||
// console.log('检测到AI助教页面,清空导航选中状态');
|
||||
// activeNavItem.value = -1;
|
||||
// activeSubNavItem.value = '';
|
||||
// examMenuExpanded.value = false;
|
||||
// studentMenuExpanded.value = false;
|
||||
// } else if (path.includes('airag')) {
|
||||
// // 智能体编排相关页面 - 已注释
|
||||
// activeNavItem.value = 6; // 智能体编排
|
||||
// orchestrationMenuExpanded.value = true;
|
||||
|
||||
// // 根据路径设置子菜单激活状态
|
||||
// if (path.includes('aiapp')) {
|
||||
// activeSubNavItem.value = 'app-management';
|
||||
// } else if (path.includes('aiknowledge')) {
|
||||
// activeSubNavItem.value = 'knowledge-base';
|
||||
// } else if (path.includes('aiflow')) {
|
||||
// activeSubNavItem.value = 'process-design';
|
||||
// } else if (path.includes('aimodel')) {
|
||||
// activeSubNavItem.value = 'model-config';
|
||||
// } else if (path.includes('ocr')) {
|
||||
// activeSubNavItem.value = 'ocr-recognition';
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|