feat:学员中心菜单对接接口;教师端菜单添加一个显示的判断
This commit is contained in:
parent
49a55c6c26
commit
949d5f439d
@ -1,6 +1,6 @@
|
|||||||
// 菜单相关API
|
// 菜单相关API
|
||||||
import { ApiRequest } from '../request'
|
import { ApiRequest } from '../request'
|
||||||
import type { ApiResponse } from '../types'
|
import type { ApiResponse, ApiResponseWithResult } from '../types'
|
||||||
|
|
||||||
// 菜单项接口定义
|
// 菜单项接口定义
|
||||||
export interface MenuItem {
|
export interface MenuItem {
|
||||||
@ -27,7 +27,7 @@ export class MenuApi {
|
|||||||
/**
|
/**
|
||||||
* 获取学生菜单
|
* 获取学生菜单
|
||||||
*/
|
*/
|
||||||
static async getStudentMenus(): Promise<ApiResponse<MenuItem[]>> {
|
static async getStudentMenus(): Promise<ApiResponseWithResult<MenuItem[]>> {
|
||||||
return await ApiRequest.get('/aiol/aiolMenu/getStudentMenus')
|
return await ApiRequest.get('/aiol/aiolMenu/getStudentMenus')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ export interface ApiResponseWithResult<T = any> {
|
|||||||
code: number
|
code: number
|
||||||
message: string
|
message: string
|
||||||
data: {
|
data: {
|
||||||
|
code: number
|
||||||
result: T
|
result: T
|
||||||
}
|
}
|
||||||
timestamp?: string
|
timestamp?: string
|
||||||
|
@ -3406,6 +3406,9 @@ onUnmounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 40px 20px;
|
padding: 40px 20px;
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-text {
|
.loading-text {
|
||||||
|
@ -23,70 +23,27 @@
|
|||||||
<!-- 分割线 -->
|
<!-- 分割线 -->
|
||||||
<div class="menu-divider"></div>
|
<div class="menu-divider"></div>
|
||||||
|
|
||||||
<!-- 我的课程 -->
|
<!-- 动态菜单 -->
|
||||||
<div :class="['image-text_19', { active: activeTab === 'courses' }]" @click="handleMenuSelect('courses')">
|
<div
|
||||||
<img class="image_8 default-icon" referrerpolicy="no-referrer" src="/images/profile/course.png" />
|
v-for="(menu, index) in visibleMenuItems"
|
||||||
<img class="image_8 hover-icon" referrerpolicy="no-referrer" src="/images/profile/course-active.png" />
|
:key="menu.id"
|
||||||
<span class="text-group_19">我的课程</span>
|
:class="[`menu-item-${index}`, { active: activeTab === getMenuTabKey(menu.path) }]"
|
||||||
|
@click="handleMenuSelect(getMenuTabKey(menu.path))"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="menu-icon default-icon"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
:src="menu.icon"
|
||||||
|
:alt="`${menu.name}图标`"
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
class="menu-icon hover-icon"
|
||||||
|
referrerpolicy="no-referrer"
|
||||||
|
:src="getActiveIcon(menu.icon)"
|
||||||
|
:alt="`${menu.name}激活图标`"
|
||||||
|
/>
|
||||||
|
<span class="menu-text">{{ menu.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 我的作业 -->
|
|
||||||
<div :class="['image-text_20', { active: activeTab === 'homework' }]" @click="handleMenuSelect('homework')">
|
|
||||||
<img class="label_4 default-icon" referrerpolicy="no-referrer" src="/images/profile/grade.png" />
|
|
||||||
<img class="label_4 hover-icon" referrerpolicy="no-referrer" src="/images/profile/grade-active.png" />
|
|
||||||
<span class="text-group_20">我的作业</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的考试 -->
|
|
||||||
<div :class="['image-text_21', { active: activeTab === 'exam' }]" @click="handleMenuSelect('exam')">
|
|
||||||
<img class="label_5 default-icon" referrerpolicy="no-referrer" src="/images/profile/checklist.png" />
|
|
||||||
<img class="label_5 hover-icon" referrerpolicy="no-referrer" src="/images/profile/checklist-active.png" />
|
|
||||||
<span class="text-group_21">我的考试</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的练习 -->
|
|
||||||
<div :class="['image-text_22', { active: activeTab === 'practice' }]" @click="handleMenuSelect('practice')">
|
|
||||||
<img class="label_6 default-icon" referrerpolicy="no-referrer" src="/images/profile/bookmark.png" />
|
|
||||||
<img class="label_6 hover-icon" referrerpolicy="no-referrer" src="/images/profile/bookmark-active.png" />
|
|
||||||
<span class="text-group_22">我的练习</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的活动 -->
|
|
||||||
<div :class="['image-text_23', { active: activeTab === 'activity' }]" @click="handleMenuSelect('activity')">
|
|
||||||
<img class="thumbnail_40 default-icon" referrerpolicy="no-referrer" src="/images/profile/gift.png" />
|
|
||||||
<img class="thumbnail_40 hover-icon" referrerpolicy="no-referrer" src="/images/profile/gift-active.png" />
|
|
||||||
<span class="text-group_23">我的活动</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的关注 -->
|
|
||||||
<div :class="['image-text_27', { active: activeTab === 'follows' }]" @click="handleMenuSelect('follows')">
|
|
||||||
<img class="thumbnail_42 default-icon" referrerpolicy="no-referrer" src="/images/profile/concern.png" />
|
|
||||||
<img class="thumbnail_42 hover-icon" referrerpolicy="no-referrer"
|
|
||||||
src="/images/profile/concern-active.png" />
|
|
||||||
<span class="text-group_27">我的关注</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的消息 -->
|
|
||||||
<div :class="['image-text_24', { active: activeTab === 'message' }]" @click="handleMenuSelect('message')">
|
|
||||||
<img class="label_7 default-icon" referrerpolicy="no-referrer" src="/images/profile/message.png" />
|
|
||||||
<img class="label_7 hover-icon" referrerpolicy="no-referrer" src="/images/profile/message-active.png" />
|
|
||||||
<span class="text-group_24">我的消息</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的资料 -->
|
|
||||||
<div :class="['image-text_25', { active: activeTab === 'materials' }]" @click="handleMenuSelect('materials')">
|
|
||||||
<img class="image_9 default-icon" referrerpolicy="no-referrer" src="/images/profile/profile.png" />
|
|
||||||
<img class="image_9 hover-icon" referrerpolicy="no-referrer" src="/images/profile/profile-active.png" />
|
|
||||||
<span class="text-group_25">我的资料</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 我的下载 -->
|
|
||||||
<!-- <div :class="['image-text_26', { active: activeTab === 'download' }]" @click="handleMenuSelect('download')">
|
|
||||||
<img class="thumbnail_41 default-icon" referrerpolicy="no-referrer" src="/images/profile/download.png" />
|
|
||||||
<img class="thumbnail_41 hover-icon" referrerpolicy="no-referrer"
|
|
||||||
src="/images/profile/download-active.png" />
|
|
||||||
<span class="text-group_26">我的下载</span>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1042,6 +999,7 @@ import QuillEditor from '@/components/common/QuillEditor.vue'
|
|||||||
import InstantMessage from '@/components/InstantMessage.vue'
|
import InstantMessage from '@/components/InstantMessage.vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { MessageApi, type BackendMessageItem } from '@/api'
|
import { MessageApi, type BackendMessageItem } from '@/api'
|
||||||
|
import MenuApi from '@/api/modules/menu'
|
||||||
import CourseContent from '@/components/profile/CourseContent.vue'
|
import CourseContent from '@/components/profile/CourseContent.vue'
|
||||||
import PracticeContent from '@/components/profile/PracticeContent.vue'
|
import PracticeContent from '@/components/profile/PracticeContent.vue'
|
||||||
import ActivityContent from '@/components/profile/ActivityContent.vue'
|
import ActivityContent from '@/components/profile/ActivityContent.vue'
|
||||||
@ -3394,7 +3352,47 @@ const submitAssignment = () => {
|
|||||||
closeUploadModal()
|
closeUploadModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
const menuItems = ref<any[]>([])
|
||||||
|
const getMenu = async () => {
|
||||||
|
try {
|
||||||
|
const response = await MenuApi.getStudentMenus()
|
||||||
|
if (response.data && response.data.code === 200) {
|
||||||
|
menuItems.value = response.data.result
|
||||||
|
console.log('✅ 获取菜单成功:', menuItems.value)
|
||||||
|
} else {
|
||||||
|
menuItems.value = []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 获取菜单失败:', error)
|
||||||
|
menuItems.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算可见的菜单项
|
||||||
|
const visibleMenuItems = computed(() => {
|
||||||
|
return menuItems.value
|
||||||
|
.filter(menu => menu.izVisible === 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 从路径获取菜单tab key
|
||||||
|
const getMenuTabKey = (path: string): TabType => {
|
||||||
|
const pathMatch = path.match(/\/profile\/(.+)/)
|
||||||
|
return pathMatch ? pathMatch[1] as TabType : 'courses'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取激活状态的图标
|
||||||
|
const getActiveIcon = (iconPath: string) => {
|
||||||
|
if (!iconPath) return iconPath
|
||||||
|
|
||||||
|
const lastDotIndex = iconPath.lastIndexOf('.')
|
||||||
|
if (lastDotIndex === -1) return iconPath + '-active'
|
||||||
|
|
||||||
|
const fileName = iconPath.substring(0, lastDotIndex)
|
||||||
|
const extension = iconPath.substring(lastDotIndex)
|
||||||
|
return fileName + '-active' + extension
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
// 初始化
|
// 初始化
|
||||||
// 检查是否需要刷新
|
// 检查是否需要刷新
|
||||||
const shouldRefresh = sessionStorage.getItem('refreshProfile')
|
const shouldRefresh = sessionStorage.getItem('refreshProfile')
|
||||||
@ -3408,6 +3406,9 @@ onMounted(() => {
|
|||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取菜单
|
||||||
|
await getMenu()
|
||||||
|
|
||||||
const tabKey = <TabType>route.params.tabKey || 'courses'
|
const tabKey = <TabType>route.params.tabKey || 'courses'
|
||||||
handleMenuSelect(tabKey)
|
handleMenuSelect(tabKey)
|
||||||
|
|
||||||
@ -9269,4 +9270,97 @@ onActivated(() => {
|
|||||||
.form-input::placeholder {
|
.form-input::placeholder {
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 动态菜单样式 */
|
||||||
|
[class^="menu-item-"] {
|
||||||
|
width: 11vw;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 1.5vh 0 1.5vh 1.8vw;
|
||||||
|
border-radius: 0.31vw;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"]:hover {
|
||||||
|
background: #eff7fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"].active {
|
||||||
|
background: #eff7fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动态菜单图标 */
|
||||||
|
[class^="menu-item-"] .menu-icon {
|
||||||
|
width: 1.04vw;
|
||||||
|
height: 1.04vw;
|
||||||
|
margin-right: 0.78vw;
|
||||||
|
object-fit: contain;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动态菜单文字 */
|
||||||
|
[class^="menu-item-"] .menu-text {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(102, 102, 102, 1);
|
||||||
|
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 1.46vh;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 激活状态的菜单文字颜色 */
|
||||||
|
[class^="menu-item-"].active .menu-text {
|
||||||
|
color: rgba(2, 134, 206, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 悬停状态的菜单文字颜色 */
|
||||||
|
[class^="menu-item-"]:hover .menu-text {
|
||||||
|
color: rgba(2, 134, 206, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 动态菜单图标悬停效果 */
|
||||||
|
[class^="menu-item-"] .hover-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"]:hover .default-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"]:hover .hover-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 激活状态的图标显示 */
|
||||||
|
[class^="menu-item-"].active .default-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"].active .hover-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端适配 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
[class^="menu-item-"] {
|
||||||
|
width: 80%;
|
||||||
|
margin: 1.5vh 0;
|
||||||
|
padding: 2vh 0 2vh 3vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"] .menu-icon {
|
||||||
|
width: 6vw;
|
||||||
|
height: 6vw;
|
||||||
|
margin-right: 4vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class^="menu-item-"] .menu-text {
|
||||||
|
font-size: 4.5vw;
|
||||||
|
line-height: 3vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -296,8 +296,11 @@ const processMenuData = (menuData) => {
|
|||||||
const menuMap = new Map()
|
const menuMap = new Map()
|
||||||
const rootMenus = []
|
const rootMenus = []
|
||||||
|
|
||||||
|
// 过滤只显示 izVisible 为 1 的菜单项
|
||||||
|
const visibleMenuData = menuData.filter(menu => menu.izVisible === 1)
|
||||||
|
|
||||||
// 先创建所有菜单项的映射
|
// 先创建所有菜单项的映射
|
||||||
menuData.forEach(menu => {
|
visibleMenuData.forEach(menu => {
|
||||||
menuMap.set(menu.id, {
|
menuMap.set(menu.id, {
|
||||||
...menu,
|
...menu,
|
||||||
children: []
|
children: []
|
||||||
@ -305,7 +308,7 @@ const processMenuData = (menuData) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 构建层级关系
|
// 构建层级关系
|
||||||
menuData.forEach(menu => {
|
visibleMenuData.forEach(menu => {
|
||||||
if (menu.parentId === null) {
|
if (menu.parentId === null) {
|
||||||
// 根级菜单
|
// 根级菜单
|
||||||
rootMenus.push(menuMap.get(menu.id))
|
rootMenus.push(menuMap.get(menu.id))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user