1316 lines
33 KiB
Vue
1316 lines
33 KiB
Vue
<template>
|
||
<div class="admin-dashboard">
|
||
<!-- 顶部图片 -->
|
||
<div class="top-image-container" v-if="showTopImage">
|
||
<img src="/images/teacher/顶部.png" alt="顶部图片" class="top-image">
|
||
<button class="close-button" @click="handleClose">关闭</button>
|
||
</div>
|
||
|
||
<div class="main-content">
|
||
<!-- 侧边栏 -->
|
||
<div class="sidebar-container" v-if="!hideSidebar">
|
||
<!-- 头像 -->
|
||
<div class="avatar-container">
|
||
<img :src="userStore.user?.avatar"
|
||
:alt="userStore.user?.profile?.realName || userStore.user?.nickname || userStore.user?.username"
|
||
class="avatar">
|
||
<div class="avatar-text">
|
||
{{ userStore.user?.profile?.realName || userStore.user?.nickname || userStore.user?.username }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 导航栏 -->
|
||
<div class="nav-container">
|
||
<!-- 动态菜单渲染 -->
|
||
<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 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>
|
||
|
||
<!-- 没有子菜单的直接链接 -->
|
||
<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助教 - 已注释 -->
|
||
<!-- <div class="ai-container">
|
||
<router-link to="/teacher/ai-assistant" class="ai-tab" @mouseenter="isAiHovered = true"
|
||
@mouseleave="isAiHovered = false">
|
||
<img :src="(isAiActive || isAiHovered) ? '/images/aiAssistant/AI助教1.png' : '/images/aiAssistant/AI助教2.png'"
|
||
alt="ai" />
|
||
<span>AI助教</span>
|
||
</router-link>
|
||
</div> -->
|
||
|
||
<!-- 智能体编排 - 可展开菜单 - 已注释 -->
|
||
<!-- <div class="nav-container orchestration-nav">
|
||
<div class="nav-item" :class="{ active: activeNavItem === 6 }" @click="toggleOrchestrationMenu">
|
||
<img :src="activeNavItem === 6 ? '/images/aiAssistant/AI助教1.png' : '/images/aiAssistant/AI助教2.png'" alt="">
|
||
<span>智能体编排</span>
|
||
<n-icon class="expand-icon" :class="{ expanded: orchestrationMenuExpanded }">
|
||
<ChevronDownOutline />
|
||
</n-icon>
|
||
</div>
|
||
|
||
<div class="submenu-container" :class="{ expanded: orchestrationMenuExpanded }">
|
||
<router-link to="/teacher/airag/aiapp" class="submenu-item"
|
||
:class="{ active: activeSubNavItem === 'app-management' }" @click="setActiveSubNavItem('app-management')">
|
||
<span>AI应用管理</span>
|
||
</router-link>
|
||
<router-link to="/teacher/airag/aiknowledge" class="submenu-item"
|
||
:class="{ active: activeSubNavItem === 'knowledge-base' }" @click="setActiveSubNavItem('knowledge-base')">
|
||
<span>AI知识库</span>
|
||
</router-link>
|
||
<router-link to="/teacher/airag/aiflow" class="submenu-item"
|
||
:class="{ active: activeSubNavItem === 'process-design' }" @click="setActiveSubNavItem('process-design')">
|
||
<span>AI流程设计</span>
|
||
</router-link>
|
||
<router-link to="/teacher/airag/aimodel" class="submenu-item"
|
||
:class="{ active: activeSubNavItem === 'model-config' }" @click="setActiveSubNavItem('model-config')">
|
||
<span>AI模型配置</span>
|
||
</router-link>
|
||
<router-link to="/teacher/airag/ocr" class="submenu-item"
|
||
:class="{ active: activeSubNavItem === 'ocr-recognition' }"
|
||
@click="setActiveSubNavItem('ocr-recognition')">
|
||
<span>OCR识别</span>
|
||
</router-link>
|
||
</div>
|
||
</div> -->
|
||
</div>
|
||
|
||
<!-- 右侧路由视图 -->
|
||
<div class="router-view-container" :class="{ 'full-width': hideSidebar }">
|
||
<!-- 面包屑 -->
|
||
<div class="breadcrumb" v-if="breadcrumbDisplay">
|
||
<span class="breadcrumb-side"></span>
|
||
<div class="custom-breadcrumb">
|
||
<!-- 左侧课程管理 -->
|
||
<div class="breadcrumb-item clickable first-item" v-if="isCourseEditor">
|
||
<n-button text @click="handleBreadcrumbClick('/teacher/course-management')">
|
||
<template #icon>
|
||
<n-icon>
|
||
<ChevronBackSharp />
|
||
</n-icon>
|
||
</template>
|
||
课程管理
|
||
</n-button>
|
||
</div>
|
||
<!-- <span class="breadcrumb-item clickable first-item"
|
||
@click="handleBreadcrumbClick('/teacher/course-management')" v-else>课程管理</span> -->
|
||
|
||
<!-- 右侧路径 -->
|
||
<div class="breadcrumb-path">
|
||
<span v-for="(item, index) in breadcrumbPathItems" :key="index" class="breadcrumb-item" :class="{
|
||
'clickable': index < breadcrumbPathItems.length - 1,
|
||
'last-item': index === breadcrumbPathItems.length - 1
|
||
}" @click="index < breadcrumbPathItems.length - 1 ? handleBreadcrumbClick(item.path) : null">
|
||
{{ item.title }}
|
||
<span v-if="index < breadcrumbPathItems.length - 1" class="breadcrumb-separator"> > </span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<router-view></router-view>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
// @ts-nocheck
|
||
import { ref, onMounted, computed, watch, nextTick } from 'vue'
|
||
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()
|
||
|
||
|
||
const width = window.innerWidth;
|
||
const height = window.innerHeight;
|
||
console.log(`当前屏幕宽度: ${width}px, 高度: ${height}px`);
|
||
|
||
// 添加导航项激活状态管理
|
||
const activeNavItem = ref(''); // 当前激活的菜单ID
|
||
const activeSubNavItem = ref(''); // 子菜单激活状态
|
||
const expandedMenus = ref(new Set()); // 展开的菜单ID集合
|
||
const showTopImage = ref(false); // 控制顶部图片显示/隐藏
|
||
|
||
// 需要隐藏顶部图片的路由路径数组
|
||
const hideTopImageRoutes = [
|
||
'teacher/chapter-editor-teacher',
|
||
'teacher/course-editor'
|
||
// 可以在这里添加更多需要隐藏顶部图片的路由
|
||
];
|
||
|
||
const route = useRoute();
|
||
const router = useRouter();
|
||
// const isAiHovered = ref(false); // AI助教悬停状态 - 已注释
|
||
// const isAiActive = computed(() => route.path.includes('/teacher/ai-assistant')); // AI助教激活状态 - 已注释
|
||
const breadcrumbDisplay = computed(() => {
|
||
const currentPath = route.path;
|
||
let arr = ['certificate/new']; // 移除 'ai-assistant', 'airag' - 已注释
|
||
let found = arr.find(item => currentPath.includes(item));
|
||
if (found) {
|
||
return false;
|
||
}
|
||
return true;
|
||
});
|
||
|
||
const isCourseEditor = computed(() => route.path.includes('course-editor') || route.path.includes('chapter-editor-teacher'));
|
||
|
||
// 检查菜单是否展开
|
||
const isMenuExpanded = (menuId) => {
|
||
return expandedMenus.value.has(menuId)
|
||
}
|
||
|
||
// 切换菜单展开状态
|
||
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)
|
||
}
|
||
}
|
||
|
||
// 设置当前菜单为激活状态
|
||
activeNavItem.value = menu.id
|
||
|
||
// 如果有路径且没有子菜单,则导航
|
||
if (menu.path && (!menu.children || menu.children.length === 0)) {
|
||
router.push(menu.path)
|
||
}
|
||
}
|
||
|
||
// 处理子菜单点击
|
||
const handleSubMenuClick = (subMenu, parentMenu) => {
|
||
activeSubNavItem.value = subMenu.id
|
||
activeNavItem.value = parentMenu.id
|
||
if (subMenu.path) {
|
||
router.push(subMenu.path)
|
||
}
|
||
}
|
||
|
||
// 获取菜单图标,处理激活状态
|
||
const getMenuIcon = (menu) => {
|
||
if (!menu.icon) return null
|
||
|
||
// 如果是激活状态且有对应的激活图标
|
||
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)
|
||
}
|
||
|
||
// 处理面包屑点击
|
||
const handleBreadcrumbClick = (path: string) => {
|
||
console.log('面包屑点击,跳转到:', path);
|
||
router.push(path);
|
||
}
|
||
|
||
// 处理关闭按钮点击
|
||
const handleClose = () => {
|
||
console.log('关闭按钮被点击');
|
||
showTopImage.value = false; // 隐藏顶部图片容器
|
||
|
||
// 动态更新CSS变量,让侧边栏占满全高
|
||
nextTick(() => {
|
||
document.documentElement.style.setProperty('--top-height', '0px');
|
||
});
|
||
}
|
||
|
||
// 判断是否隐藏左侧侧边栏
|
||
const hideSidebar = computed(() => {
|
||
const currentPath = route.path
|
||
// 当进入课程管理相关页面或章节编辑页面时隐藏侧边栏
|
||
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;
|
||
|
||
// 证书管理模块的面包屑逻辑(优先处理)
|
||
if (currentPath.includes('certificate')) {
|
||
console.log('证书页面路径:', currentPath);
|
||
let breadcrumbs: Array<{ title: string, path: string }> = [];
|
||
// 从路径中提取课程ID,如果路径包含course-editor
|
||
const courseIdMatch = currentPath.match(/\/course-editor\/(\d+)/);
|
||
const courseId = courseIdMatch ? courseIdMatch[1] : '1';
|
||
|
||
if (currentPath.includes('/certificate/detail/')) {
|
||
console.log('匹配到证书详情页面');
|
||
// 证书详细页面:课程管理 > 证书 > 证书详情
|
||
breadcrumbs = [
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '证书管理',
|
||
path: `/teacher/course-editor/${courseId}/certificate`
|
||
},
|
||
{
|
||
title: '证书详情',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.includes('/certificate/add')) {
|
||
console.log('匹配到添加证书页面');
|
||
// 添加证书页面:课程管理 > 证书 > 添加证书
|
||
breadcrumbs = [
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '证书管理',
|
||
path: `/teacher/course-editor/${courseId}/certificate`
|
||
},
|
||
{
|
||
title: '添加证书',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.endsWith('/certificate')) {
|
||
console.log('匹配到证书管理页面');
|
||
// 证书管理页面:课程管理 > 证书
|
||
breadcrumbs = [
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '证书',
|
||
path: `/teacher/course-editor/${courseId}/certificate`
|
||
}
|
||
];
|
||
} else {
|
||
console.log('证书页面但未匹配到具体条件');
|
||
}
|
||
console.log('证书页面面包屑:', breadcrumbs);
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 如果在课程编辑器相关页面
|
||
if (currentPath.includes('course-editor')) {
|
||
// 从路径中提取课程ID
|
||
const courseIdMatch = currentPath.match(/\/course-editor\/(\d+)/);
|
||
const courseId = courseIdMatch ? courseIdMatch[1] : '未知';
|
||
|
||
let breadcrumbs: Array<{ title: string, path: string }> = [];
|
||
|
||
// 根据当前路径添加子页面标题
|
||
if (currentPath.includes('courseware')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课件管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('question-bank')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '题库管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('add-question')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '题库管理',
|
||
path: currentPath.replace('/add-question', '/question-bank')
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
},
|
||
{
|
||
title: '新增试题',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else if (currentPath.includes('chapters')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '章节管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('template-import')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
},
|
||
{
|
||
title: '作业管理',
|
||
path: `/teacher/course-editor/${courseId}/homework`
|
||
},
|
||
{
|
||
title: '导入',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else if (currentPath.includes('homework')) {
|
||
// 检查是否是批阅作业详情页面
|
||
if (currentPath.includes('review/') && currentPath.split('/').length > 6) {
|
||
// 批阅作业详情页面:课程管理 > 课程名称 > 批阅作业 > 批阅
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
},
|
||
{
|
||
title: '批阅作业',
|
||
path: `/teacher/course-editor/${courseId}/homework/review`
|
||
},
|
||
{
|
||
title: '批阅',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else {
|
||
// 普通作业页面:作业管理
|
||
breadcrumbs.push(
|
||
{
|
||
title: '作业管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
}
|
||
} else if (currentPath.includes('practice/exam')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '考试管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('practice/review')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '阅卷中心',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
|
||
} else if (currentPath.includes('certificate')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '证书管理',
|
||
path: '/teacher/course-editor/1/certificate'
|
||
},
|
||
{
|
||
title: '证书名称详情',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else if (currentPath.includes('discussion/add')) {
|
||
// 添加讨论页面:课程管理 > 讨论 > 添加讨论
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '讨论',
|
||
path: `/teacher/course-editor/${courseId}/discussion`
|
||
},
|
||
{
|
||
title: '添加讨论',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else if (currentPath.includes('discussion')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '讨论管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('comment/')) {
|
||
// 查看评论页面:课程管理 > 讨论 > 查看讨论
|
||
breadcrumbs.push(
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: '讨论',
|
||
path: `/teacher/course-editor/${courseId}/discussion`
|
||
},
|
||
{
|
||
title: '查看讨论',
|
||
path: currentPath
|
||
}
|
||
);
|
||
} else if (currentPath.includes('statistics')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '统计管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('notification')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '通知管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
} else if (currentPath.includes('management')) {
|
||
breadcrumbs.push(
|
||
{
|
||
title: '综合管理',
|
||
path: currentPath
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
}
|
||
);
|
||
}
|
||
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 如果在章节编辑页面,显示课程管理>课程名称>新建/编辑章节
|
||
if (currentPath.includes('chapter-editor-teacher')) {
|
||
const courseId = route.params.courseId;
|
||
let breadcrumbs = [
|
||
{
|
||
title: '课程管理',
|
||
path: '/teacher/course-management'
|
||
},
|
||
{
|
||
title: `课程${courseId}`,
|
||
path: `/teacher/course-editor/${courseId}`
|
||
},
|
||
{
|
||
title: route.query.mode === 'add' ? '新建章节' : '编辑章节',
|
||
path: `/teacher/course-editor/${courseId}/chapters`
|
||
},
|
||
];
|
||
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 学员管理模块的面包屑逻辑
|
||
if (currentPath.includes('student-management')) {
|
||
let breadcrumbs: Array<{ title: string, path: string }> = [];
|
||
|
||
if (currentPath.includes('student-library')) {
|
||
console.log('匹配到学员库页面');
|
||
breadcrumbs = [
|
||
{
|
||
title: '学员中心',
|
||
path: '/teacher/student-management'
|
||
},
|
||
{
|
||
title: '学员库',
|
||
path: '/teacher/student-management/student-library'
|
||
}
|
||
];
|
||
} else if (currentPath.includes('class-management')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '学员中心',
|
||
path: '/teacher/student-management'
|
||
},
|
||
{
|
||
title: '班级管理',
|
||
path: '/teacher/student-management/class-management'
|
||
}
|
||
];
|
||
} else if (currentPath.endsWith('/student-management')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '学员中心',
|
||
path: '/teacher/student-management'
|
||
}
|
||
];
|
||
}
|
||
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 回收站页面的面包屑逻辑
|
||
if (currentPath.includes('recycle-bin')) {
|
||
const breadcrumbs = [
|
||
{
|
||
title: '我的资源',
|
||
path: '/teacher/my-resources'
|
||
},
|
||
{
|
||
title: '回收站',
|
||
path: currentPath
|
||
}
|
||
]
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 智能体编排模块的面包屑逻辑
|
||
if (currentPath.includes('airag')) {
|
||
console.log('智能体编排页面路径:', currentPath);
|
||
let breadcrumbs: Array<{ title: string, path: string }> = [];
|
||
|
||
// 根据具体页面添加子页面标题
|
||
if (currentPath.includes('aiapp')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: '/teacher/airag'
|
||
},
|
||
{
|
||
title: 'AI应用管理',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.includes('aiknowledge')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: '/teacher/airag'
|
||
},
|
||
{
|
||
title: 'AI知识库',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.includes('aiflow')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: '/teacher/airag'
|
||
},
|
||
{
|
||
title: 'AI流程设计',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.includes('aimodel')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: '/teacher/airag'
|
||
},
|
||
{
|
||
title: 'AI模型配置',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else if (currentPath.includes('ocr')) {
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: '/teacher/airag'
|
||
},
|
||
{
|
||
title: 'OCR识别',
|
||
path: currentPath
|
||
}
|
||
];
|
||
} else {
|
||
// 智能体编排主页面
|
||
breadcrumbs = [
|
||
{
|
||
title: '智能体编排',
|
||
path: currentPath
|
||
}
|
||
];
|
||
}
|
||
|
||
console.log('智能体编排页面面包屑:', breadcrumbs);
|
||
return breadcrumbs;
|
||
}
|
||
|
||
// 其他页面的面包屑逻辑
|
||
const matchedRoutes = route.matched;
|
||
let breadcrumbs = matchedRoutes
|
||
.filter((item: any) => item.meta.title !== '管理后台')
|
||
.map((item: any) => ({
|
||
title: item.meta.title || '未知页面',
|
||
path: item.path
|
||
}));
|
||
|
||
console.log('其他页面面包屑:', breadcrumbs);
|
||
return breadcrumbs;
|
||
});
|
||
|
||
// 监听路由变化,更新激活的导航项
|
||
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();
|
||
|
||
// 确保广告默认隐藏
|
||
showTopImage.value = false;
|
||
|
||
// 初始化CSS变量
|
||
if (showTopImage.value) {
|
||
document.documentElement.style.setProperty('--top-height', '130px');
|
||
} else {
|
||
document.documentElement.style.setProperty('--top-height', '0px');
|
||
}
|
||
updateTopImageVisibility();
|
||
});
|
||
|
||
// 使用watch监听路由变化
|
||
watch(route, () => {
|
||
updateActiveNavItem();
|
||
updateTopImageVisibility();
|
||
});
|
||
|
||
// 更新顶部图片显示状态
|
||
const updateTopImageVisibility = () => {
|
||
const currentPath = route.path;
|
||
console.log('检查路径是否需要隐藏顶部图片:', currentPath);
|
||
|
||
// 检查当前路径是否包含需要隐藏顶部图片的路由
|
||
const shouldHideTopImage = hideTopImageRoutes.some(routePath =>
|
||
currentPath.includes(routePath)
|
||
);
|
||
|
||
// 默认隐藏广告,只在特定路由下显示(如果需要的话)
|
||
showTopImage.value = false; // 默认隐藏
|
||
console.log('顶部图片显示状态:', showTopImage.value);
|
||
};
|
||
|
||
</script>
|
||
|
||
<style scoped>
|
||
.admin-dashboard {
|
||
position: relative;
|
||
}
|
||
|
||
.top-image-container {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 130px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 关闭按钮样式 */
|
||
.close-button {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 15px;
|
||
width: 30px;
|
||
height: 20px;
|
||
background-color: #7192DC;
|
||
color: white;
|
||
border: none;
|
||
font-size: 10px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10;
|
||
transition: background-color 0.3s ease;
|
||
}
|
||
|
||
.close-button:hover {
|
||
background-color: #999999;
|
||
}
|
||
|
||
/* 展开图标样式 */
|
||
.expand-icon {
|
||
margin-left: auto;
|
||
margin-right: 20px;
|
||
transition: transform 0.3s ease;
|
||
color: #666;
|
||
}
|
||
|
||
.expand-icon.expanded {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
/* 子菜单容器 */
|
||
.submenu-container {
|
||
overflow: hidden;
|
||
max-height: 0;
|
||
transition: max-height 0.3s ease-out;
|
||
margin-left: 20px;
|
||
}
|
||
|
||
.submenu-container.expanded {
|
||
max-height: 200px;
|
||
}
|
||
|
||
/* 子菜单项样式 */
|
||
.submenu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 40px;
|
||
margin-bottom: 8px;
|
||
margin-left: 10px;
|
||
margin-right: 10px;
|
||
padding-left: 40px;
|
||
border-radius: 8px;
|
||
transition: all 0.3s ease;
|
||
text-decoration: none;
|
||
color: #666;
|
||
font-size: 16px;
|
||
position: relative;
|
||
}
|
||
|
||
.submenu-item:hover {
|
||
background: rgba(102, 183, 227, 0.05);
|
||
}
|
||
|
||
.submenu-item.active {
|
||
background: rgba(102, 183, 227, 0.1);
|
||
color: #0C99DA;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media screen and (max-width: 768px) {
|
||
.top-image-container {
|
||
height: 100px;
|
||
}
|
||
}
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.top-image-container {
|
||
height: 80px;
|
||
}
|
||
}
|
||
|
||
.top-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: absolute;
|
||
left: 0px;
|
||
top: 0px;
|
||
opacity: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.main-content {
|
||
display: flex;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.main-content {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.sidebar-container {
|
||
width: 100%;
|
||
height: auto;
|
||
min-height: 300px;
|
||
}
|
||
|
||
.router-view-container {
|
||
height: auto;
|
||
min-height: calc(100vh - var(--top-height, 100px) - 300px);
|
||
}
|
||
}
|
||
|
||
.sidebar-container {
|
||
width: 240px;
|
||
height: calc(100vh - var(--top-height, 130px) - 64px);
|
||
background: #FFFFFF;
|
||
overflow-y: auto;
|
||
/* 隐藏滚动条但保持滚动功能 */
|
||
scrollbar-width: none;
|
||
/* Firefox */
|
||
-ms-overflow-style: none;
|
||
/* IE and Edge */
|
||
}
|
||
|
||
/* 隐藏Webkit浏览器的滚动条 */
|
||
.sidebar-container::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.sidebar-container {
|
||
--top-height: 100px;
|
||
}
|
||
}
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.sidebar-container {
|
||
--top-height: 80px;
|
||
width: 200px;
|
||
}
|
||
}
|
||
|
||
.avatar-container {
|
||
position: relative;
|
||
padding: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
/* 移除原来的边框 */
|
||
}
|
||
|
||
/* 添加带间距的横线 */
|
||
.avatar-container::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 15px;
|
||
right: 15px;
|
||
height: 1px;
|
||
background-color: #E6E6E6;
|
||
}
|
||
|
||
.avatar-container img {
|
||
width: 80px;
|
||
height: 80px;
|
||
/* 圆角 */
|
||
border-radius: 50%;
|
||
margin-top: 30px;
|
||
}
|
||
|
||
.avatar-text {
|
||
height: 31px;
|
||
font-family: AppleSystemUIFont;
|
||
font-size: 20px;
|
||
color: #000000;
|
||
line-height: 26px;
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.avatar-container {
|
||
height: 180px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.avatar-container img {
|
||
margin: 0 0 15px 0;
|
||
}
|
||
|
||
.avatar-text {
|
||
margin: 0;
|
||
text-align: center;
|
||
}
|
||
}
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.avatar-container {
|
||
height: 150px;
|
||
}
|
||
|
||
.avatar-container img {
|
||
width: 80px;
|
||
height: 80px;
|
||
}
|
||
|
||
.avatar-text {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
|
||
.nav-container {
|
||
margin-top: 30px;
|
||
/* 鼠标变小手 */
|
||
cursor: pointer;
|
||
|
||
}
|
||
|
||
/* 智能体编排菜单移除顶部外边距 */
|
||
.orchestration-nav {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.nav-container .nav-item {
|
||
margin-left: 15px;
|
||
width: 210px;
|
||
height: 50px;
|
||
margin-bottom: 15px;
|
||
/* 圆角 */
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
transition: all 0.3s ease;
|
||
gap: 8px;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.nav-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.nav-container .nav-item {
|
||
width: 200px;
|
||
margin: 0 10px 15px;
|
||
}
|
||
|
||
.submenu-container {
|
||
width: 200px;
|
||
}
|
||
}
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.nav-container .nav-item {
|
||
width: 150px;
|
||
height: 45px;
|
||
margin: 0 5px 10px;
|
||
}
|
||
|
||
.nav-container .nav-item img {
|
||
margin-left: 20px;
|
||
}
|
||
}
|
||
|
||
.nav-container .nav-item:hover {
|
||
background: rgba(102, 183, 227, 0.05);
|
||
}
|
||
|
||
/* 添加激活状态样式 */
|
||
.nav-container .nav-item.active {
|
||
background: rgba(102, 183, 227, 0.1);
|
||
}
|
||
|
||
.nav-container .nav-item.active span {
|
||
color: #0C99DA;
|
||
}
|
||
|
||
.nav-container .nav-item img {
|
||
height: 18px;
|
||
margin-left: 40px;
|
||
margin-top: 0;
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.nav-container .nav-item span {
|
||
height: 26px;
|
||
font-family: AppleSystemUIFont;
|
||
font-size: 18px;
|
||
color: #666666;
|
||
line-height: 23px;
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
.ai-container {
|
||
margin: 0 20px;
|
||
border-top: 1.5px solid #E6E6E6;
|
||
padding-top: 30px;
|
||
}
|
||
|
||
.ai-tab {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
height: 54px;
|
||
padding-left: 16px;
|
||
color: #666666;
|
||
background: transparent;
|
||
border-radius: 8px;
|
||
text-decoration: none;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.ai-tab.router-link-active,
|
||
.ai-tab.router-link-exact-active {
|
||
background: #E2F5FF;
|
||
color: #0088D1;
|
||
}
|
||
|
||
.ai-tab:hover {
|
||
background: rgba(2, 136, 209, 0.06);
|
||
color: #0088D1;
|
||
}
|
||
|
||
.ai-tab img {
|
||
margin-left: 30px;
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
|
||
.router-view-container {
|
||
flex: 1;
|
||
padding: 10px 25px;
|
||
background: #F5F7FA;
|
||
height: calc(100vh - var(--top-height, 130px) - 64px);
|
||
overflow-y: hidden;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 全宽显示(隐藏侧边栏时) */
|
||
.router-view-container.full-width {
|
||
width: 100%;
|
||
margin-left: 0;
|
||
}
|
||
|
||
@media screen and (max-width: 768px) {
|
||
.router-view-container {
|
||
--top-height: 100px;
|
||
padding: 15px;
|
||
}
|
||
}
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.router-view-container {
|
||
--top-height: 80px;
|
||
padding: 10px;
|
||
}
|
||
}
|
||
|
||
.breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.breadcrumb-side {
|
||
width: 4px;
|
||
height: 17px;
|
||
background-color: #0288D1;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
|
||
@media screen and (max-width: 480px) {
|
||
.nav-container .nav-item {
|
||
width: 150px;
|
||
height: 45px;
|
||
margin: 0 5px 10px;
|
||
}
|
||
|
||
.nav-container .nav-item img {
|
||
margin-left: 20px;
|
||
}
|
||
|
||
.submenu-container {
|
||
width: 150px;
|
||
}
|
||
}
|
||
|
||
/* 面包屑样式 */
|
||
.custom-breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.breadcrumb-path {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 4px 0;
|
||
}
|
||
|
||
.breadcrumb-item {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 14px;
|
||
color: #000;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.breadcrumb-item.clickable:hover {
|
||
color: #0C99DA;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.breadcrumb-item.last-item {
|
||
color: #999;
|
||
cursor: default;
|
||
}
|
||
|
||
.breadcrumb-item.last-item:hover {
|
||
color: #999;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.breadcrumb-item.first-item {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
color: #666;
|
||
margin: 0 4px;
|
||
font-weight: normal;
|
||
}
|
||
</style>
|