8739 lines
211 KiB
Vue
8739 lines
211 KiB
Vue
<template>
|
||
<div class="profile-page">
|
||
<!-- 刷新遮罩 -->
|
||
<div v-if="isRefreshing" class="refresh-mask">
|
||
<div class="refresh-content">
|
||
<div class="refresh-spinner"></div>
|
||
<p>正在刷新...</p>
|
||
</div>
|
||
</div>
|
||
<!-- 主要内容区域 -->
|
||
<div class="profile-content flex-row">
|
||
<!-- 左侧侧边栏 -->
|
||
<div class="block_14">
|
||
<!-- 用户头像和姓名 -->
|
||
<SafeAvatar class="image_7" :src="userStore.user?.avatar"
|
||
:name="userStore.user?.profile?.realName || userStore.user?.nickname || userStore.user?.username || '用户'"
|
||
:size="96" alt="用户头像" />
|
||
<span class="text_72">{{ userStore.user?.profile?.realName || userStore.user?.nickname ||
|
||
userStore.user?.username || '用户名' }}</span>
|
||
|
||
<!-- 菜单项容器 -->
|
||
<div class="box_22">
|
||
<!-- 分割线 -->
|
||
<div class="menu-divider"></div>
|
||
|
||
<!-- 动态菜单 -->
|
||
<div
|
||
v-for="(menu, index) in visibleMenuItems"
|
||
:key="menu.id"
|
||
: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>
|
||
|
||
<!-- 右侧内容区域 -->
|
||
<div class="group_5 flex-col">
|
||
<!-- 课程内容 -->
|
||
<!-- <div>
|
||
<div class="text-wrapper_1 flex-row">
|
||
<span class="text_12" :class="{ active: activeCourseTab === 'all' }"
|
||
@click="handleCourseTabChange('all')">全部课程</span>
|
||
<span class="text_13" :class="{ active: activeCourseTab === 'learning' }"
|
||
@click="handleCourseTabChange('learning')">学习中</span>
|
||
<span class="text_14" :class="{ active: activeCourseTab === 'completed' }"
|
||
@click="handleCourseTabChange('completed')">已完结</span>
|
||
</div>
|
||
|
||
<div class="course-divider"></div>
|
||
|
||
<div class="course-list">
|
||
<div v-for="course in filteredCourses" :key="course.id" class="box_2 flex-row justify-between">
|
||
<div class="block_4 flex-col">
|
||
<div class="box_3 flex-row justify-between">
|
||
<div class="status-image-container">
|
||
<img class="status-image" referrerpolicy="no-referrer"
|
||
:src="course.status === 'learning' ? '/images/icon/learning.png' : '/images/icon/finish.png'"
|
||
alt="{{ getStatusText(course.status) }}" />
|
||
</div>
|
||
<img class="thumbnail_4" referrerpolicy="no-referrer" :src="bannerImage" :alt="bannerAlt" />
|
||
<span :class="['status-text', course.status]">{{ getStatusText(course.status) }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="block_5 flex-col">
|
||
<div class="group_6 flex-row">
|
||
<span class="text_16">{{ course.title }}</span>
|
||
<img class="thumbnail_5" referrerpolicy="no-referrer"
|
||
src="https://lanhu-oss-2537-2.lanhuapp.com/SketchPnge131c44858bb817d4885b81fdd8ddff8507f62cd51f1025cee826849e6a52c65" />
|
||
<span class="text_17">{{ course.rating || 541 }}</span>
|
||
</div>
|
||
<span class="text_18">讲师:{{ course.instructor }}</span>
|
||
<span class="text_19">{{ course.description }}</span>
|
||
|
||
<div class="group_7 flex-row">
|
||
<img class="thumbnail_6" referrerpolicy="no-referrer" src="/images/profile/11.png" />
|
||
<span class="text_20">共{{ course.chapters || 9 }}章{{ course.lessons || 54 }}节</span>
|
||
<img class="thumbnail_7" referrerpolicy="no-referrer" src="/images/profile/22.png" />
|
||
<span class="text_21">{{ course.duration || '12小时43分钟' }}</span>
|
||
<img class="thumbnail_8" referrerpolicy="no-referrer"
|
||
:src="course.status === 'learning' ? '/images/profile/33.png' : '/images/profile/33.png'" />
|
||
<span class="text_22">已看{{ course.watchedTime || '10小时20分钟' }}</span>
|
||
<div class="text-wrapper_2 flex-col" @click="goToCourse(course.id)">
|
||
<span class="text_23">{{ course.status === 'learning' ? '去学习' : '去复习' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="pagination-wrapper" v-if="totalPages > 1">
|
||
<div class="pagination">
|
||
<span class="pagination-item nav-button" :class="{ disabled: currentPage === 1 }"
|
||
@click="goToPage('first')">
|
||
首页
|
||
</span>
|
||
<span class="pagination-item nav-button" :class="{ disabled: currentPage === 1 }"
|
||
@click="goToPage('prev')">
|
||
上一页
|
||
</span>
|
||
|
||
<span v-for="page in totalPages" :key="page" class="pagination-item page-number"
|
||
:class="{ active: page === currentPage }" @click="goToPage(page)">
|
||
{{ page }}
|
||
</span>
|
||
|
||
<span class="pagination-item nav-button" :class="{ disabled: currentPage === totalPages }"
|
||
@click="goToPage('next')">
|
||
下一页
|
||
</span>
|
||
<span class="pagination-item nav-button" :class="{ disabled: currentPage === totalPages }"
|
||
@click="goToPage('last')">
|
||
尾页
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div> -->
|
||
|
||
<CourseContent v-if="isCoursesTab"></CourseContent>
|
||
|
||
|
||
<!-- 作业内容 -->
|
||
<div v-else-if="isHomeworkTab" class="homework-content">
|
||
<!-- 作业筛选标签 -->
|
||
<div v-if="!showDraftBoxView" class="text-wrapper_1 flex-row">
|
||
<span class="text_12" :class="{ active: activeHomeworkTab === 'all' }"
|
||
@click="handleHomeworkTabChange('all')">全部作业</span>
|
||
<span class="text_13" :class="{ active: activeHomeworkTab === 'pending' }"
|
||
@click="handleHomeworkTabChange('pending')">未完成</span>
|
||
<span class="text_14" :class="{ active: activeHomeworkTab === 'completed' }"
|
||
@click="handleHomeworkTabChange('completed')">已完成</span>
|
||
<span class="draftbox" @click="showDraftBox">
|
||
<img src="/images/auth/mti.png" alt="">
|
||
<span>草稿箱</span>
|
||
</span>
|
||
</div>
|
||
<!-- 分割线 -->
|
||
<div v-if="!showDraftBoxView" class="course-divider"></div>
|
||
|
||
<!-- 面包屑 -->
|
||
<!-- <div class="breadcrumb-wrapper flex-row">
|
||
<span class="text_15">全部作业</span>
|
||
<span class="text_15">></span>
|
||
<span class="text_15 homework">作业名称</span>
|
||
</div> -->
|
||
|
||
<!-- 作业详情视图 -->
|
||
<div v-if="showDetailView && detailAssignment">
|
||
<!-- <div class="detail-header">
|
||
<div class="breadcrumb-nav">
|
||
<span class="breadcrumb-item" @click="backToAssignmentList">全部作业</span>
|
||
<span class="breadcrumb-separator">></span>
|
||
<span class="breadcrumb-current">作业名称</span>
|
||
</div>
|
||
</div> -->
|
||
|
||
<div class="group_11">
|
||
<!-- 头部信息 -->
|
||
<div class="box_5">
|
||
<div class="image-text_2">
|
||
<div class="avatar-line"></div>
|
||
<img :src="detailAssignment.teacherAvatar" alt="教师头像" class="image_22" />
|
||
<div class="text-group_3">
|
||
<span class="text_30">{{ detailAssignment.teacherName }}</span>
|
||
<span class="text_31">{{ detailAssignment.assignTime }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<span class="text_32">
|
||
<img v-if="detailAssignment.status === '已提交'" src="/images/profile/55.png" alt="">
|
||
<span :style="{
|
||
color: detailAssignment.status === '未完成' || detailAssignment.status === '待提交' ? '#FF560C' : '#999999',
|
||
fontSize: '14px'
|
||
}">
|
||
{{ detailAssignment.status === '未完成' || detailAssignment.status === '待提交' ? '未完成' :
|
||
(detailAssignment.status === '已完成' ? '已完成' : '541人已完成') }}
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 作业内容 -->
|
||
<div class="text-group_4">
|
||
<div class="course-divider"></div>
|
||
<span class="text_33">{{ detailAssignment.title }}</span>
|
||
<div class="description-container">
|
||
<span class="text_34 description-full-view">
|
||
{{ detailAssignment.description }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业附件区域 -->
|
||
<div class="box_6">
|
||
<div class="attachment-images">
|
||
<img v-for="(_, index) in detailAssignment.attachments.slice(0, 5)" :key="index"
|
||
src="/images/traings/traing1.png" :class="['image_' + (24 + index)]" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="files-container">
|
||
<div class="file-items">
|
||
<img src="/images/auth/file.png" alt="" class="files-icon">
|
||
<span>文件名称.PDF</span>
|
||
<img src="/images/auth/download.png" alt="" class="files-icon">
|
||
</div>
|
||
<div class="file-items">
|
||
<img src="/images/auth/file.png" alt="" class="files-icon">
|
||
<span>文件名称.PDF</span>
|
||
<img src="/images/auth/download.png" alt="" class="files-icon">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="course-name">这里是课程名称!!! <span>查看详情></span></div>
|
||
|
||
|
||
<!-- 作业按钮区域 -->
|
||
<div class="assignment-buttons">
|
||
<template v-if="detailAssignment.status === '未完成' || detailAssignment.status === '待提交'">
|
||
<div class="text-wrapper_8 submit-button" @click="showUploadFromDetail">
|
||
<span class="">上传作业</span>
|
||
</div>
|
||
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 草稿箱视图 -->
|
||
<div v-if="showDraftBoxView && draftAssignment">
|
||
<div class="detail-header">
|
||
<div class="breadcrumb-nav">
|
||
<span class="breadcrumb-item" @click="backFromDraftBox">全部作业</span>
|
||
<span class="breadcrumb-separator">></span>
|
||
<span class="breadcrumb-current">草稿箱</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="group_11">
|
||
<!-- 头部信息 -->
|
||
<div class="box_5">
|
||
<div class="image-text_2">
|
||
<div class="avatar-line"></div>
|
||
<img :src="draftAssignment.teacherAvatar" alt="教师头像" class="image_22" />
|
||
<div class="text-group_3">
|
||
<span class="text_30">{{ draftAssignment.teacherName }}</span>
|
||
<span class="text_31">{{ draftAssignment.assignTime }}</span>
|
||
</div>
|
||
</div>
|
||
<span class="text_32">
|
||
<img v-if="draftAssignment.status === '已提交'" src="/images/profile/55.png" alt="">
|
||
<span :style="{
|
||
color: draftAssignment.status === '未完成' || draftAssignment.status === '待提交' ? '#FF560C' : '#999999',
|
||
fontSize: '14px'
|
||
}">
|
||
{{ draftAssignment.status === '未完成' || draftAssignment.status === '待提交' ? '未完成' :
|
||
(draftAssignment.status === '已完成' ? '已完成' : '541人已完成') }}
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 作业内容 -->
|
||
<div class="text-group_4">
|
||
<span class="text_33">{{ draftAssignment.title }}</span>
|
||
<div class="description-container">
|
||
<span class="text_34 description-full-view">
|
||
{{ draftAssignment.description }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业附件区域 -->
|
||
<div class="box_6">
|
||
<div class="attachment-images">
|
||
<img v-for="(_, index) in draftAssignment.attachments.slice(0, 5)" :key="index"
|
||
src="/images/traings/traing1.png" :class="['image_' + (24 + index)]" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="files-container">
|
||
<div class="file-items">
|
||
<img src="/images/auth/file.png" alt="" class="files-icon">
|
||
<span>文件名称.PDF</span>
|
||
<img src="/images/auth/download.png" alt="" class="files-icon">
|
||
</div>
|
||
<div class="file-items">
|
||
<img src="/images/auth/file.png" alt="" class="files-icon">
|
||
<span>文件名称.PDF</span>
|
||
<img src="/images/auth/download.png" alt="" class="files-icon">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="course-name">这里是课程名称!!! <span>查看详情></span></div>
|
||
|
||
<!-- 作业按钮区域 -->
|
||
<div class="assignment-buttons">
|
||
<div class="text-wrapper_8 submit-button" @click="showUploadModal(draftAssignment)">
|
||
<span class="text_36">上传作业</span>
|
||
</div>
|
||
<div class="text-wrapper_8 anew-button" @click="reEditDraft">
|
||
<span class="text_36">重新编辑</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业列表 -->
|
||
<div v-else-if="!showDetailView && !showDraftBoxView">
|
||
<div v-for="assignment in filteredAssignments" :key="assignment.id" class="group_11">
|
||
<!-- 作业头部信息 -->
|
||
<div class="box_5">
|
||
<div class="image-text_2">
|
||
<div class="avatar-line"></div>
|
||
<img src="/images/traings/traing1.png" class="image_22" />
|
||
<div class="text-group_3">
|
||
<span class="text_30">{{ assignment.teacherName }}</span>
|
||
<span class="text_31">{{ assignment.assignTime }}</span>
|
||
</div>
|
||
</div>
|
||
<span class="text_32">
|
||
<span :style="{
|
||
color: assignment.status === '未完成' || assignment.status === '待提交' ? '#FF560C' : '#999999',
|
||
fontSize: '14px'
|
||
}">
|
||
{{ assignment.status === '未完成' || assignment.status === '待提交' ? '未完成' : '已完成' }}
|
||
</span>
|
||
</span>
|
||
</div>
|
||
|
||
|
||
<!-- 作业内容 -->
|
||
<div class="text-group_4">
|
||
<!-- 分割线 -->
|
||
<div class="course-divider"></div>
|
||
|
||
<span class="text_33">{{ assignment.title }}</span>
|
||
<div class="description-container">
|
||
<span class="text_34 text-truncated">
|
||
{{ assignment.description }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 作业附件区域 -->
|
||
<div class="box_6">
|
||
|
||
|
||
<!-- 附件图片列表 -->
|
||
<div class="attachment-images">
|
||
<img v-for="(_, index) in assignment.attachments.slice(0, 5)" :key="index"
|
||
src="/images/traings/traing1.png" :class="['image_' + (24 + index)]" />
|
||
</div>
|
||
|
||
<div class="attachment-images attachment-number-container">
|
||
<img src="/images/profile/55.png" alt="" class="attachment-number-icon">
|
||
<span class="attachment-number-text">541人已完成</span>
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
<!-- 作业按钮区域 -->
|
||
<div class="assignment-buttons">
|
||
<!-- 未完成状态显示两个按钮 -->
|
||
<template v-if="assignment.status === '未完成' || assignment.status === '待提交'">
|
||
<div class="text-wrapper_8 view-button" @click="showUploadModal(assignment)">
|
||
<span class="text_36 text-view">上传作业</span>
|
||
</div>
|
||
<!-- 查看详细 -->
|
||
<div class="text-wrapper_8 details-button" @click="viewAssignmentDetail(assignment)">
|
||
<span class="text_36">查看详情</span>
|
||
</div>
|
||
</template>
|
||
<!-- 已完成状态只显示一个按钮 -->
|
||
<template v-else>
|
||
<div class="text-wrapper_8 details-button" @click="viewAssignmentDetail(assignment)">
|
||
<span class="text_36">查看详情</span>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 考试内容 -->
|
||
<div v-else-if="isExamTab" class="exam-content">
|
||
<!-- 考试筛选标签 -->
|
||
<div class="text-wrapper_1 flex-row">
|
||
<span class="text_12" :class="{ active: activeExamTab === 'all' }"
|
||
@click="handleExamTabChange('all')">全部考试</span>
|
||
<span class="text_13" :class="{ active: activeExamTab === 'upcoming' }"
|
||
@click="handleExamTabChange('upcoming')">未开始</span>
|
||
<span class="text_14" :class="{ active: activeExamTab === 'ongoing' }"
|
||
@click="handleExamTabChange('ongoing')">进行中</span>
|
||
<span class="text_15" :class="{ active: activeExamTab === 'finished' }"
|
||
@click="handleExamTabChange('finished')">已结束</span>
|
||
</div>
|
||
|
||
<!-- 分割线 -->
|
||
<div class="course-divider"></div>
|
||
|
||
<!-- 考试列表 -->
|
||
<div class="exam-grid">
|
||
<div v-for="exam in filteredExams" :key="exam.id" class="exam-card">
|
||
<!-- 考试标题 -->
|
||
<div class="exam-title">{{ exam.title }}</div>
|
||
|
||
<!-- 分数显示 -->
|
||
<div class="exam-score-badge" v-if="exam.score !== null">
|
||
<span class="score-text">{{ exam.score }}<span>分</span></span>
|
||
</div>
|
||
|
||
<!-- 考试信息 -->
|
||
<div class="exam-details">
|
||
<div class="exam-meta-item">
|
||
<span class="meta-label">考试日期:</span>
|
||
<span class="meta-value">{{ exam.examDate }}</span>
|
||
</div>
|
||
<div class="exam-meta-item">
|
||
<span class="meta-label">考试时间:</span>
|
||
<span class="meta-value">{{ exam.duration }}分钟</span>
|
||
</div>
|
||
<div class="exam-meta-item">
|
||
<span class="meta-label">考试题量:</span>
|
||
<span class="meta-value">{{ exam.questionCount }}题</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 考试描述 -->
|
||
<div class="exam-description">
|
||
{{ exam.description }}
|
||
</div>
|
||
|
||
<!-- 底部操作区域 -->
|
||
<div class="exam-footer">
|
||
<div class="exam-action-right">
|
||
<button v-if="exam.status === 'upcoming'" class="action-btn upcoming-btn" @click="startExam(exam.id)">
|
||
未开始
|
||
</button>
|
||
<button v-else-if="exam.status === 'ongoing'" class="action-btn ongoing-btn"
|
||
@click="continueExam(exam.id)">
|
||
开始考试
|
||
</button>
|
||
<button v-else-if="exam.status === 'finished'" class="action-btn finished-btn"
|
||
@click="viewExamResult(exam.id)">
|
||
查看详情
|
||
</button>
|
||
</div>
|
||
<div class="exam-status-left">
|
||
<span class="exam-status-text">{{ getExamStatusText(exam.status) }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 练习内容 -->
|
||
<PracticeContent v-else-if="isPracticeTab"></PracticeContent>
|
||
|
||
|
||
<!-- 活动内容 -->
|
||
<ActivityContent v-else-if="isActivityTab"></ActivityContent>
|
||
|
||
|
||
<!-- 关注内容 -->
|
||
<div v-else-if="isFollowsTab" class="follows-content">
|
||
<!-- 关注筛选标签 -->
|
||
<div class="text-wrapper_1 flex-row">
|
||
<span class="text_12" :class="{ active: activeFollowsTab === 'all' }"
|
||
@click="handleFollowsTabChange('all')">全部关注</span>
|
||
<span class="text_13" :class="{ active: activeFollowsTab === 'recent' }"
|
||
@click="handleFollowsTabChange('recent')">最近关注</span>
|
||
<span class="text_14" :class="{ active: activeFollowsTab === 'frequent' }"
|
||
@click="handleFollowsTabChange('frequent')">最常访问</span>
|
||
</div>
|
||
|
||
<!-- 关注分割线 -->
|
||
<div class="course-divider"></div>
|
||
|
||
<!-- 关注列表 -->
|
||
<div class="follows-list">
|
||
<div v-for="follow in filteredFollows" :key="follow.id" class="follow-item">
|
||
<!-- 用户头像 -->
|
||
<div class="follow-avatar">
|
||
<img :src="follow.avatar" :alt="follow.name" class="avatar-image" />
|
||
</div>
|
||
|
||
<!-- 右侧信息区域 -->
|
||
<div class="follow-right-content">
|
||
<!-- 用户信息 -->
|
||
<div class="follow-info">
|
||
<div class="follow-name">{{ follow.name }}</div>
|
||
<div class="follow-description">{{ follow.description }}</div>
|
||
</div>
|
||
|
||
<!-- 关注操作 -->
|
||
<div class="follow-actions">
|
||
<button class="follow-btn"
|
||
:class="{ 'following': follow.isFollowing, 'not-following': !follow.isFollowing }"
|
||
@click="toggleFollow(follow.id)">
|
||
{{ follow.isFollowing ? '已关注' : '取消关注' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消息内容 -->
|
||
<div v-else-if="isMessageTab" class="message-content">
|
||
<!-- 消息筛选标签 -->
|
||
<div class="message-header">
|
||
<div class="message-tabs">
|
||
<span class="message-tab-item" :class="{ active: activeMessageTab === 'instant' }"
|
||
@click="handleMessageTabChange('instant')">
|
||
即时消息
|
||
<span v-if="instantMessageCount > 0" class="message-count">{{ instantMessageCount }}</span>
|
||
</span>
|
||
<span class="message-tab-item" :class="{ active: activeMessageTab === 'comment' }"
|
||
@click="handleMessageTabChange('comment')">
|
||
评论和@
|
||
<span v-if="commentMessageCount > 0" class="message-count">{{ commentMessageCount }}</span>
|
||
</span>
|
||
<span class="message-tab-item" :class="{ active: activeMessageTab === 'like' }"
|
||
@click="handleMessageTabChange('like')">
|
||
点赞
|
||
<span v-if="likeMessageCount > 0" class="message-count">{{ likeMessageCount }}</span>
|
||
</span>
|
||
<span class="message-tab-item" :class="{ active: activeMessageTab === 'system' }"
|
||
@click="handleMessageTabChange('system')">
|
||
系统消息
|
||
<span v-if="systemMessageCount > 0" class="message-count">{{ systemMessageCount }}</span>
|
||
</span>
|
||
</div>
|
||
<div class="message-actions">
|
||
<span class="action-link" :class="{ disabled: markingAllAsRead }" @click="markAllAsRead">
|
||
<img src="/images/profile/read.png" alt="全部已读" class="action-icon">
|
||
{{ markingAllAsRead ? '标记中...' : '全部已读' }}
|
||
</span>
|
||
<span class="action-link" :class="{ active: sortByTime !== 'none' }" @click="toggleSortByTime">
|
||
<img src="/images/profile/time.png" alt="按时间" class="action-icon">
|
||
{{ getSortText() }}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消息列表 -->
|
||
<div class="message-list">
|
||
<!-- 即时消息 -->
|
||
<div v-if="activeMessageTab === 'instant'" class="instant-message-container">
|
||
<InstantMessage />
|
||
</div>
|
||
|
||
<!-- 评论和@消息 -->
|
||
<div v-else-if="activeMessageTab === 'comment'">
|
||
<!-- 加载状态 -->
|
||
<div v-if="commentMessagesLoading" class="loading-container">
|
||
<div class="loading-text">正在加载评论和@消息...</div>
|
||
</div>
|
||
|
||
<!-- 评论和@消息列表 -->
|
||
<div v-else-if="filteredMessages.length > 0" class="message-list-container">
|
||
<div v-for="msg in filteredMessages" :key="msg.id" class="message-item">
|
||
<!-- 未读标识 - 移到右上角 -->
|
||
<div v-if="!msg.isRead" class="unread-indicator-top-right"></div>
|
||
|
||
<!-- 消息内容 -->
|
||
<div class="message-main">
|
||
<!-- 用户头像和信息 -->
|
||
<div class="message-user">
|
||
<img :src="msg.senderAvatar" class="image_22" />
|
||
<div class="user-info">
|
||
<div class="user-content">
|
||
<span class="user-name">{{ msg.senderName }}</span>
|
||
<span class="action-type">{{ getActionText(msg.type) }}:</span>
|
||
<span class="message-content">{{ msg.content }}</span>
|
||
</div>
|
||
<div class="course-info-container">
|
||
<span class="course-label">回复了我的课程:</span>
|
||
<span class="course-name">《{{ msg.courseName }}》</span>
|
||
</div>
|
||
</div>
|
||
<div class="message-time">{{ msg.date }}</div>
|
||
</div>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div class="message-actions-row">
|
||
<button class="message-action-btn reply-btn" @click="startReply(msg.id)">
|
||
<img src="/images/profile/reply.png" alt="回复" class="action-icon">
|
||
回复
|
||
</button>
|
||
<button class="message-action-btn delete-btn">
|
||
<img src="/images/profile/del.png" alt="删除" class="action-icon">
|
||
删除
|
||
</button>
|
||
<button class="message-action-btn report-btn">
|
||
<img src="/images/profile/report.png" alt="举报" class="action-icon">
|
||
举报
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 回复区域 -->
|
||
<div v-if="replyingMessageId === msg.id" class="reply-section">
|
||
<div class="reply-input-container">
|
||
<n-input v-model:value="replyContent" type="textarea" placeholder="回复该评论:" :rows="3"
|
||
class="reply-input" />
|
||
<div class="reply-actions">
|
||
<button class="send-btn" @click="sendReply(msg.id)">发送</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 已有回复显示 -->
|
||
<div v-if="msg.hasReply && msg.replyContent" class="existing-reply">
|
||
<div class="reply-content">{{ msg.replyContent }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div v-else class="empty-state">
|
||
<div class="empty-text">暂无评论和@消息</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 点赞消息 -->
|
||
<div v-else-if="activeMessageTab === 'like'">
|
||
<!-- 加载状态 -->
|
||
<div v-if="likeMessagesLoading" class="loading-container">
|
||
<div class="loading-text">正在加载点赞消息...</div>
|
||
</div>
|
||
|
||
<!-- 点赞消息列表 -->
|
||
<div v-else-if="filteredLikeMessages.length > 0">
|
||
<div v-for="like in filteredLikeMessages" :key="'like-' + like.id" class="like-message-item">
|
||
<!-- 未读标识 -->
|
||
<div v-if="!like.isRead" class="unread-indicator-top-right"></div>
|
||
|
||
<!-- 点赞消息内容 -->
|
||
<div class="like-message-main">
|
||
<div class="like-message-user">
|
||
<img :src="like.userAvatar" class="image_22" />
|
||
<div class="like-info">
|
||
<div class="user-content">
|
||
<span class="user-name">{{ like.userName }}</span>
|
||
<span class="action-type">{{ getLikeActionText(like.type) }}:</span>
|
||
<span class="message-content" v-if="like.content">{{ like.content }}</span>
|
||
</div>
|
||
<div class="course-info-container" v-if="like.courseName">
|
||
<span class="course-label">课程:</span>
|
||
<span class="course-name">《{{ like.courseName }}》</span>
|
||
</div>
|
||
</div>
|
||
<div class="message-time">{{ like.date }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div v-else class="empty-state">
|
||
<div class="empty-text">暂无点赞消息</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 系统消息 -->
|
||
<div v-else-if="activeMessageTab === 'system'">
|
||
<!-- 加载状态 -->
|
||
<div v-if="systemMessagesLoading" class="loading-container">
|
||
<div class="loading-text">正在加载系统消息...</div>
|
||
</div>
|
||
|
||
<!-- 系统消息列表 -->
|
||
<div v-else-if="filteredSystemMessages.length > 0 && !showMessageDetail">
|
||
<div v-for="sysMsg in filteredSystemMessages" :key="'sys-' + sysMsg.id" class="system-message-item">
|
||
<!-- 系统消息内容 -->
|
||
<div class="system-message-main">
|
||
<!-- 系统图标和信息 -->
|
||
<div class="system-message-user">
|
||
<div class="system-icon"></div>
|
||
<div class="system-info">
|
||
<div class="system-title">{{ sysMsg.title }}</div>
|
||
<div class="system-subtitle-row">
|
||
<span class="system-subtitle">{{ sysMsg.subtitle }}</span>
|
||
<span class="system-detail-link" @click="goToSystemMessageDetail(sysMsg)">查看详情></span>
|
||
</div>
|
||
</div>
|
||
<div class="system-time">{{ sysMsg.date }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 消息详情 -->
|
||
<div v-else-if="showMessageDetail && selectedMessage" class="message-detail-container">
|
||
<div class="message-detail-header">
|
||
<button class="back-btn" @click="closeMessageDetail">← 返回</button>
|
||
<h3 class="detail-title">系统消息详情</h3>
|
||
</div>
|
||
|
||
<div class="message-detail-content">
|
||
<div class="message-detail-info">
|
||
<div class="message-detail-icon">
|
||
<div class="system-icon"></div>
|
||
</div>
|
||
<div class="message-detail-text">
|
||
<h4 class="message-detail-title">{{ selectedMessage.title }}</h4>
|
||
<div class="message-detail-time">{{ selectedMessage.date }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="message-detail-body">
|
||
<div class="message-detail-subtitle">{{ selectedMessage.subtitle }}</div>
|
||
</div>
|
||
|
||
<div class="message-detail-actions">
|
||
<button class="action-btn mark-read-btn" :disabled="selectedMessage.isRead || markingAsRead"
|
||
@click="markMessageAsRead(selectedMessage.id)">
|
||
{{ selectedMessage.isRead ? '已读' : (markingAsRead ? '标记中...' : '标记为已读') }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div v-else class="empty-state">
|
||
<div class="empty-text">暂无系统消息</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 我的资料页面 -->
|
||
<MaterialsContent v-else-if="activeTab === 'materials'"></MaterialsContent>
|
||
|
||
<!-- 我的下载页面 -->
|
||
<div v-else-if="activeTab === 'download'" class="download-content"
|
||
:class="{ 'in-subdirectory': isInSubDirectory }">
|
||
<!-- 下载页面标签页 -->
|
||
<div class="download-header">
|
||
<div class="download-tabs">
|
||
<span class="download-tab-item" :class="{ active: activeDownloadTab === 'courseware' }"
|
||
@click="handleDownloadTabChange('courseware')">
|
||
课件
|
||
</span>
|
||
<span class="download-tab-item" :class="{ active: activeDownloadTab === 'certificate' }"
|
||
@click="handleDownloadTabChange('certificate')">
|
||
证书
|
||
</span>
|
||
<span class="download-tab-item" :class="{ active: activeDownloadTab === 'resources' }"
|
||
@click="handleDownloadTabChange('resources')">
|
||
资源库
|
||
</span>
|
||
<span class="download-tab-item" :class="{ active: activeDownloadTab === 'homework' }"
|
||
@click="handleDownloadTabChange('homework')">
|
||
作业
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 面包屑导航或筛选和操作区域 -->
|
||
<div v-if="isInSubDirectory" class="breadcrumb-controls">
|
||
<div class="breadcrumb-nav">
|
||
<span class="breadcrumb-text" @click="goBack">{{ currentPath.join(' > ') }} ></span>
|
||
<span class="breadcrumb-current">{{ currentPath[currentPath.length - 1] || '文件夹' }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 筛选和操作区域 -->
|
||
<div v-else-if="activeDownloadTab === 'courseware'" class="download-controls">
|
||
<div class="download-filters">
|
||
<div class="filter-group">
|
||
<label class="filter-label">类型:</label>
|
||
<select v-model="downloadFilter.type" class="filter-select">
|
||
<option value="all">全部</option>
|
||
<option value="folder">文件夹</option>
|
||
<option value="file">文件</option>
|
||
</select>
|
||
</div>
|
||
<div class="search-group">
|
||
<label class="search-label">搜索:</label>
|
||
<div class="search-input-container">
|
||
<input v-model="downloadFilter.keyword" type="text" class="search-input" placeholder="请输入文件名称" />
|
||
<button class="search-btn">
|
||
<img src="/images/profile/search.png" alt="搜索图标" class="search-icon" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="download-actions">
|
||
<span class="file-count">已全部加载,共17个文件</span>
|
||
<button class="new-folder-btn" @click="createNewFolder">
|
||
+ 新建文件夹
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 文件网格 -->
|
||
<div class="files-grid"
|
||
:class="{ 'subdirectory-grid': isInSubDirectory, 'certificate-grid': activeDownloadTab === 'certificate', 'homework-grid': activeDownloadTab === 'homework' }">
|
||
<div v-for="file in filteredDownloadFiles" :key="file.id" class="file-item"
|
||
:class="{ 'subdirectory-item': isInSubDirectory }" @dblclick="handleFolderDoubleClick(file)"
|
||
@click="handleFileClick(file)">
|
||
<div class="file-menu">
|
||
<button class="file-menu-btn" @click.stop="toggleFileMenu(file.id)">
|
||
<img src="/images/profile/more.png" alt="更多操作" class="more-icon" />
|
||
</button>
|
||
<div v-if="activeFileMenu === file.id" class="file-menu-dropdown">
|
||
<div class="menu-item" @click.stop="renameFile(file.id)">
|
||
<img src="/images/profile/edit.png" alt="编辑图标" class="menu-icon" />
|
||
<span>编辑</span>
|
||
</div>
|
||
<div class="menu-item" @click.stop="deleteFile(file.id)">
|
||
<img src="/images/profile/del.png" alt="删除图标" class="menu-icon" />
|
||
<span>删除</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="file-icon">
|
||
<img :src="getFileIcon(file.id)" alt="文件图标" class="folder-icon" />
|
||
</div>
|
||
<div class="file-name">{{ file.name }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 其他内容的占位符 -->
|
||
<div v-else class="other-content">
|
||
<h2>{{ getTabTitle(activeTab) }}</h2>
|
||
<p>{{ activeTab }}功能开发中...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 上传作业弹窗 -->
|
||
<div v-if="showModal" class="custom-modal-overlay" @click="closeUploadModal">
|
||
<div class="custom-modal" @click.stop>
|
||
<div v-if="currentAssignment" class="modal-content">
|
||
<n-form>
|
||
<div class="form-item">
|
||
<label class="form-label">标题名称 <span class="required">*</span></label>
|
||
<input v-model="uploadForm.title" type="text" class="form-input" placeholder="" />
|
||
</div>
|
||
<n-form-item label="编辑内容" required>
|
||
<QuillEditor v-model="uploadForm.content" placeholder="请输入内容" height="400px" />
|
||
</n-form-item>
|
||
<!-- <n-form-item label="上传文件" required>
|
||
<n-upload multiple directory-dnd :custom-request="customRequest" :default-upload="false">
|
||
<n-button>选择文件</n-button>
|
||
</n-upload>
|
||
<div class="file-list" v-if="uploadForm.files.length > 0">
|
||
<div v-for="(file, index) in uploadForm.files" :key="index" class="file-item">
|
||
<div class="file-icon">
|
||
<img src="/images/auth/file.png" alt="文件图标" />
|
||
</div>
|
||
<div class="file-info">
|
||
<div class="file-name">{{ file.name }}</div>
|
||
<div class="file-size">{{ (file.size / 1024).toFixed(2) }}KB</div>
|
||
</div>
|
||
<button class="file-delete" @click="removeFile(index)">🗑️</button>
|
||
</div>
|
||
</div>
|
||
</n-form-item> -->
|
||
</n-form>
|
||
<div class="modal-footer">
|
||
<button type="primary" @click="submitAssignment" style="margin-left: 12px;">确认</button>
|
||
<button @click="closeUploadModal" class="cancel">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 考试详情页面 -->
|
||
|
||
|
||
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onMounted, onActivated, reactive } from 'vue'
|
||
import { useMessage, NInput, NForm, NFormItem } from 'naive-ui'
|
||
// import { useI18n } from 'vue-i18n'
|
||
import { useUserStore } from '@/stores/user'
|
||
import SafeAvatar from '@/components/common/SafeAvatar.vue'
|
||
import QuillEditor from '@/components/common/QuillEditor.vue'
|
||
import InstantMessage from '@/components/InstantMessage.vue'
|
||
import { useRouter, useRoute } from 'vue-router'
|
||
import { MessageApi, type BackendMessageItem } from '@/api'
|
||
import MenuApi from '@/api/modules/menu'
|
||
import CourseContent from '@/components/profile/CourseContent.vue'
|
||
import PracticeContent from '@/components/profile/PracticeContent.vue'
|
||
import ActivityContent from '@/components/profile/ActivityContent.vue'
|
||
import MaterialsContent from '@/components/profile/MaterialsContent.vue'
|
||
|
||
// const { t, locale } = useI18n()
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
// 轮播图根据语言动态切换
|
||
// const bannerImage = computed(() => {
|
||
// return locale.value === 'zh' ? '/banners/banner8.png' : '/banners/banner1-en.png'
|
||
// })
|
||
|
||
// const bannerAlt = computed(() => {
|
||
// return t('home.banner.alt')
|
||
// })
|
||
|
||
// 定义课程接口
|
||
// interface Course {
|
||
// id: number
|
||
// title: string
|
||
// instructor: string
|
||
// description: string
|
||
// thumbnail: string
|
||
// status: 'learning' | 'completed'
|
||
// rating?: number
|
||
// chapters?: number
|
||
// lessons?: number
|
||
// duration?: string
|
||
// watchedTime?: string
|
||
// progress?: number
|
||
// }
|
||
|
||
// 定义作业接口
|
||
interface Assignment {
|
||
id: number
|
||
teacherName: string
|
||
teacherAvatar: string
|
||
assignTime: string
|
||
status: string
|
||
title: string
|
||
description: string
|
||
attachments: Array<{
|
||
icon: string
|
||
name: string
|
||
}>
|
||
mainImage: string
|
||
}
|
||
|
||
// 定义考试接口
|
||
interface Exam {
|
||
id: number
|
||
title: string
|
||
examDate: string
|
||
duration: number
|
||
questionCount: number
|
||
description: string
|
||
status: 'upcoming' | 'ongoing' | 'finished'
|
||
score: number | null
|
||
}
|
||
|
||
// 考试题目选项接口
|
||
// interface ExamOption {
|
||
// id: string
|
||
// text: string
|
||
// image?: string
|
||
// }
|
||
|
||
// 考试题目接口
|
||
// interface ExamQuestion {
|
||
// id: number
|
||
// type: 'single' | 'multiple'
|
||
// title: string
|
||
// content: string
|
||
// options: ExamOption[]
|
||
// correctAnswers: string[]
|
||
// userAnswers: string[]
|
||
// isCorrect: boolean
|
||
// }
|
||
|
||
// 考试详情接口
|
||
// interface ExamDetail {
|
||
// id: number
|
||
// title: string
|
||
// examDate: string
|
||
// duration: number
|
||
// totalQuestions: number
|
||
// correctCount: number
|
||
// wrongCount: number
|
||
// score: number
|
||
// questions: ExamQuestion[]
|
||
// }
|
||
|
||
// 练习接口
|
||
// interface Practice {
|
||
// id: number
|
||
// title: string
|
||
// practiceDate: string
|
||
// duration: number
|
||
// questionCount: number
|
||
// description: string
|
||
// status: 'ongoing' | 'finished'
|
||
// score: number | null
|
||
// correctCount: number
|
||
// wrongCount: number
|
||
// }
|
||
|
||
// 练习详情接口(复用考试题目结构)
|
||
// interface PracticeDetail {
|
||
// id: number
|
||
// title: string
|
||
// practiceDate: string
|
||
// duration: number
|
||
// totalQuestions: number
|
||
// correctCount: number
|
||
// wrongCount: number
|
||
// score: number
|
||
// questions: ExamQuestion[]
|
||
// }
|
||
|
||
// 活动接口
|
||
// interface Activity {
|
||
// id: number
|
||
// title: string
|
||
// subtitle: string
|
||
// courseTitle: string
|
||
// activityDate: string
|
||
// duration: number
|
||
// activityType: string
|
||
// registeredCount: string
|
||
// description: string
|
||
// status: 'ongoing' | 'finished'
|
||
// score: number | null
|
||
// }
|
||
|
||
// 消息接口
|
||
interface Message {
|
||
id: string
|
||
senderName: string
|
||
senderAvatar: string
|
||
content: string
|
||
courseName: string
|
||
date: string
|
||
isRead: boolean
|
||
hasReply: boolean
|
||
replyContent?: string
|
||
type: 'comment' | 'mention' | 'reply'
|
||
}
|
||
|
||
// 系统消息接口
|
||
interface SystemMessage {
|
||
id: string
|
||
title: string
|
||
subtitle: string
|
||
date: string
|
||
isRead: boolean
|
||
}
|
||
|
||
// 点赞消息接口
|
||
interface LikeMessage {
|
||
id: string
|
||
userName: string
|
||
userAvatar: string
|
||
type: 'comment' | 'course'
|
||
courseName?: string
|
||
content?: string
|
||
date: string
|
||
isRead: boolean
|
||
}
|
||
|
||
|
||
|
||
const message = useMessage()
|
||
const userStore = useUserStore()
|
||
|
||
// 定义标签页类型
|
||
type TabType = 'courses' | 'homework' | 'exam' | 'practice' | 'activity' | 'follows' | 'message' | 'materials' | 'download'
|
||
|
||
const activeTab = ref<TabType>('courses')
|
||
// const activeCourseTab = ref('all')
|
||
|
||
// 作业筛选状态
|
||
const activeHomeworkTab = ref('all')
|
||
|
||
// 考试筛选状态
|
||
const activeExamTab = ref('all')
|
||
|
||
// 练习筛选状态
|
||
// const activePracticeTab = ref('all')
|
||
|
||
// 活动筛选状态
|
||
// const activeActivityTab = ref('all')
|
||
|
||
// 关注筛选状态
|
||
const activeFollowsTab = ref('all')
|
||
|
||
// 消息相关状态
|
||
const activeMessageTab = ref('instant')
|
||
const replyingMessageId = ref<string | null>(null)
|
||
const replyContent = ref('')
|
||
|
||
// 系统消息相关状态
|
||
const systemMessages = ref<SystemMessage[]>([])
|
||
const systemMessagesLoading = ref(false)
|
||
const systemMessagesTotal = ref(0)
|
||
const systemMessagesPageSize = ref(10)
|
||
const systemMessagesCurrentPage = ref(1)
|
||
|
||
// 点赞消息相关状态
|
||
const likeMessages = ref<LikeMessage[]>([])
|
||
const likeMessagesLoading = ref(false)
|
||
const likeMessagesTotal = ref(0)
|
||
const likeMessagesPageSize = ref(10)
|
||
const likeMessagesCurrentPage = ref(1)
|
||
|
||
// 评论和@消息相关状态
|
||
const commentMessages = ref<Message[]>([])
|
||
const commentMessagesLoading = ref(false)
|
||
const commentMessagesTotal = ref(0)
|
||
const commentMessagesPageSize = ref(10)
|
||
const commentMessagesCurrentPage = ref(1)
|
||
|
||
// 消息详情状态
|
||
const showMessageDetail = ref(false)
|
||
const selectedMessage = ref<SystemMessage | null>(null)
|
||
const markingAsRead = ref(false)
|
||
const markingAllAsRead = ref(false)
|
||
|
||
// 排序状态
|
||
const sortByTime = ref<'asc' | 'desc' | 'none'>('none') // 'asc': 升序, 'desc': 降序, 'none': 不排序
|
||
|
||
// 消息数量统计
|
||
const instantMessageCount = ref(0)
|
||
const commentMessageCount = ref(0)
|
||
const likeMessageCount = ref(0)
|
||
const systemMessageCount = ref(0)
|
||
const messageCountsLoading = ref(false)
|
||
|
||
// 下载相关状态
|
||
const activeDownloadTab = ref('courseware')
|
||
const activeFileMenu = ref<number | null>(null)
|
||
const currentPath = ref<string[]>([]) // 当前路径,用于面包屑
|
||
const isInSubDirectory = ref(false) // 是否在子目录中
|
||
const isRefreshing = ref(false) // 是否正在刷新
|
||
|
||
// 下载筛选条件
|
||
const downloadFilter = reactive({
|
||
type: 'all',
|
||
keyword: ''
|
||
})
|
||
|
||
// 下载文件数据
|
||
const downloadFiles = reactive([
|
||
{ id: 1, name: '图片', type: 'folder', category: 'courseware' },
|
||
{ id: 2, name: '文档', type: 'folder', category: 'courseware' },
|
||
{ id: 3, name: '视频', type: 'folder', category: 'courseware' },
|
||
{ id: 4, name: '样子', type: 'folder', category: 'courseware' },
|
||
{ id: 5, name: '音频', type: 'folder', category: 'courseware' },
|
||
{ id: 6, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 7, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 8, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 9, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 10, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 11, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 12, name: '文件名称', type: 'folder', category: 'courseware' },
|
||
{ id: 13, name: '证书文件1', type: 'folder', category: 'certificate' },
|
||
{ id: 14, name: '证书文件2', type: 'folder', category: 'certificate' },
|
||
{ id: 16, name: '证书文件2', type: 'folder', category: 'certificate' },
|
||
{ id: 17, name: '证书文件2', type: 'folder', category: 'certificate' },
|
||
{ id: 18, name: '证书文件2', type: 'folder', category: 'certificate' },
|
||
{ id: 15, name: '资源文件1', type: 'folder', category: 'resources' },
|
||
{ id: 19, name: '作业文件1', type: 'folder', category: 'homework' },
|
||
{ id: 20, name: '作业文件2', type: 'folder', category: 'homework' },
|
||
{ id: 21, name: '作业文件3', type: 'folder', category: 'homework' },
|
||
{ id: 22, name: '作业文件4', type: 'folder', category: 'homework' },
|
||
{ id: 23, name: '作业文件5', type: 'folder', category: 'homework' },
|
||
{ id: 24, name: '作业文件6', type: 'folder', category: 'homework' }
|
||
|
||
])
|
||
|
||
// 分页相关状态
|
||
// const currentPage = ref(1)
|
||
// const pageSize = ref(5) // 每页显示5个课程
|
||
|
||
// 模拟课程数据(基于蓝湖UI设计)
|
||
// const mockCourses: Course[] = [
|
||
// {
|
||
// id: 1,
|
||
// title: '教育心理学的起源',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPngd0745b9ee85d1fd2251cde7df5f13cdc38cfb57ba7f1ca467638a1196af0a4fc',
|
||
// status: 'learning',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '10小时20分钟',
|
||
// progress: 75
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// title: '现代教育技术应用',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'completed',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '10小时20分钟',
|
||
// progress: 100
|
||
// },
|
||
// {
|
||
// id: 3,
|
||
// title: '课程设计与开发',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'completed',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '10小时20分钟',
|
||
// progress: 100
|
||
// },
|
||
// {
|
||
// id: 4,
|
||
// title: '现代教育技术应用',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'learning',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '8小时15分钟',
|
||
// progress: 65
|
||
// },
|
||
// {
|
||
// id: 5,
|
||
// title: '数字化教学设计',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'learning',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '5小时30分钟',
|
||
// progress: 45
|
||
// },
|
||
// {
|
||
// id: 6,
|
||
// title: '在线教育平台运营',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'completed',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '12小时43分钟',
|
||
// progress: 100
|
||
// },
|
||
// {
|
||
// id: 7,
|
||
// title: '教学评估与反馈',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'learning',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '3小时20分钟',
|
||
// progress: 25
|
||
// },
|
||
// {
|
||
// id: 8,
|
||
// title: '智能教育工具应用',
|
||
// instructor: '代方枚 史雯',
|
||
// description: '本课程紧跟风向,让每一位教师了解并学习使用DeepSeek,结合办公自动化职业岗位标准,以实际工作任务为引领,强调课程内容的易用性和岗位要求的匹配性,课程内容与全国计算机等级考试、"1+X"WPS办公应用职业技能等级证书,技能…',
|
||
// thumbnail: 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPng80fbbc0cab537164b6d85a9a7dcea31848f9becbaceafadb4ea618af4fde9554',
|
||
// status: 'completed',
|
||
// rating: 541,
|
||
// chapters: 9,
|
||
// lessons: 54,
|
||
// duration: '12小时43分钟',
|
||
// watchedTime: '12小时43分钟',
|
||
// progress: 100
|
||
// }
|
||
// ]
|
||
|
||
// 模拟作业数据(基于蓝湖UI设计)
|
||
const mockAssignments: Assignment[] = [
|
||
{
|
||
id: 1,
|
||
teacherName: '张老师',
|
||
teacherAvatar: '/images/traings/traing1.png',
|
||
assignTime: '2024-01-15',
|
||
status: '待提交',
|
||
title: '教育心理学课程设计作业',
|
||
description: '请根据所学的教育心理学理论,设计一个完整的课程教学方案,包括教学目标、教学内容、教学方法、教学评价等方面。要求理论联系实际,体现现代教育理念。',
|
||
attachments: [
|
||
{ icon: '/images/traings/traing1.png', name: '作业要求.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '参考资料.docx' },
|
||
{ icon: '/images/traings/traing1.png', name: '模板文件.pptx' },
|
||
{ icon: '/images/traings/traing1.png', name: '评分标准.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '案例分析.xlsx' }
|
||
],
|
||
mainImage: '/images/traings/traing1.png'
|
||
},
|
||
{
|
||
id: 2,
|
||
teacherName: '李老师',
|
||
teacherAvatar: '/images/traings/traing1.png',
|
||
assignTime: '2024-01-20',
|
||
status: '已完成',
|
||
title: '现代教育技术应用实践报告',
|
||
description: '结合本学期所学的现代教育技术知识,选择一个具体的教学场景,设计并实施一个融合信息技术的教学活动,撰写实践报告。',
|
||
attachments: [
|
||
{ icon: '/images/traings/traing1.png', name: '实践指导.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '报告模板.docx' },
|
||
{ icon: '/images/traings/traing1.png', name: '技术工具清单.xlsx' },
|
||
{ icon: '/images/traings/traing1.png', name: '评价量表.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '优秀案例.pptx' }
|
||
],
|
||
mainImage: '/images/traings/traing1.png'
|
||
},
|
||
{
|
||
id: 3,
|
||
teacherName: '王老师',
|
||
teacherAvatar: '/images/traings/traing1.png',
|
||
assignTime: '2024-01-18',
|
||
status: '未完成',
|
||
title: '数字化教学资源开发',
|
||
description: '开发一套完整的数字化教学资源,包括课件制作、视频录制、在线测试设计等,要求体现现代教育技术的应用特点。',
|
||
attachments: [
|
||
{ icon: '/images/traings/traing1.png', name: '开发指南.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '技术要求.docx' },
|
||
{ icon: '/images/traings/traing1.png', name: '示例资源.zip' }
|
||
],
|
||
mainImage: '/images/traings/traing1.png'
|
||
},
|
||
{
|
||
id: 4,
|
||
teacherName: '刘老师',
|
||
teacherAvatar: '/images/traings/traing1.png',
|
||
assignTime: '2024-01-10',
|
||
status: '已完成',
|
||
title: '在线教育平台使用报告',
|
||
description: '体验并分析主流在线教育平台的功能特点,撰写详细的使用报告和改进建议。',
|
||
attachments: [
|
||
{ icon: '/images/traings/traing1.png', name: '平台列表.pdf' },
|
||
{ icon: '/images/traings/traing1.png', name: '评价标准.docx' }
|
||
],
|
||
mainImage: '/images/traings/traing1.png'
|
||
}
|
||
]
|
||
|
||
// 模拟考试数据
|
||
const mockExams: Exam[] = [
|
||
{
|
||
id: 1,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'upcoming',
|
||
score: null
|
||
},
|
||
{
|
||
id: 2,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'ongoing',
|
||
score: null
|
||
},
|
||
{
|
||
id: 3,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'finished',
|
||
score: 90
|
||
},
|
||
{
|
||
id: 4,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'upcoming',
|
||
score: null
|
||
},
|
||
{
|
||
id: 5,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'ongoing',
|
||
score: null
|
||
},
|
||
{
|
||
id: 6,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'finished',
|
||
score: 90
|
||
},
|
||
{
|
||
id: 7,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'upcoming',
|
||
score: null
|
||
},
|
||
{
|
||
id: 8,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'finished',
|
||
score: 90
|
||
},
|
||
{
|
||
id: 9,
|
||
title: 'C++语言程序设计基础考试',
|
||
examDate: '2025-07-18 10:00',
|
||
duration: 120,
|
||
questionCount: 100,
|
||
description: '考试涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
status: 'ongoing',
|
||
score: null
|
||
}
|
||
]
|
||
|
||
// 模拟考试详情数据
|
||
// const mockExamDetails: { [key: number]: ExamDetail } = {
|
||
// 3: {
|
||
// id: 3,
|
||
// title: 'C++语言程序设计基础考试',
|
||
// examDate: '2025-07-30 12:00',
|
||
// duration: 100,
|
||
// totalQuestions: 120,
|
||
// correctCount: 90,
|
||
// wrongCount: 10,
|
||
// score: 98,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书' },
|
||
// { id: 'B', text: 'B.应急处理措施' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// type: 'multiple',
|
||
// title: '[多选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书', image: '/images/exam/option-a.png' },
|
||
// { id: 'B', text: 'B.应急处理措施', image: '/images/exam/option-b.png' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证', image: '/images/exam/option-d.png' },
|
||
// { id: 'E', text: 'E.产品标签' }
|
||
// ],
|
||
// correctAnswers: ['A', 'B'],
|
||
// userAnswers: ['A', 'B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// },
|
||
// 6: {
|
||
// id: 6,
|
||
// title: 'C++语言程序设计基础考试',
|
||
// examDate: '2025-07-30 12:00',
|
||
// duration: 100,
|
||
// totalQuestions: 120,
|
||
// correctCount: 90,
|
||
// wrongCount: 10,
|
||
// score: 98,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书' },
|
||
// { id: 'B', text: 'B.应急处理措施' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// type: 'multiple',
|
||
// title: '[多选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书', image: '/images/exam/option-a.png' },
|
||
// { id: 'B', text: 'B.应急处理措施', image: '/images/exam/option-b.png' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证', image: '/images/exam/option-d.png' },
|
||
// { id: 'E', text: 'E.产品标签' }
|
||
// ],
|
||
// correctAnswers: ['A', 'B'],
|
||
// userAnswers: ['A', 'B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// },
|
||
// 8: {
|
||
// id: 8,
|
||
// title: 'C++语言程序设计基础考试',
|
||
// examDate: '2025-07-30 12:00',
|
||
// duration: 100,
|
||
// totalQuestions: 120,
|
||
// correctCount: 90,
|
||
// wrongCount: 10,
|
||
// score: 98,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书' },
|
||
// { id: 'B', text: 'B.应急处理措施' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// type: 'multiple',
|
||
// title: '[多选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书', image: '/images/exam/option-a.png' },
|
||
// { id: 'B', text: 'B.应急处理措施', image: '/images/exam/option-b.png' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证', image: '/images/exam/option-d.png' },
|
||
// { id: 'E', text: 'E.产品标签' }
|
||
// ],
|
||
// correctAnswers: ['A', 'B'],
|
||
// userAnswers: ['A', 'B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// },
|
||
// 9: {
|
||
// id: 9,
|
||
// title: 'C++语言程序设计基础考试',
|
||
// examDate: '2025-07-30 12:00',
|
||
// duration: 100,
|
||
// totalQuestions: 120,
|
||
// correctCount: 90,
|
||
// wrongCount: 10,
|
||
// score: 98,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书' },
|
||
// { id: 'B', text: 'B.应急处理措施' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// type: 'multiple',
|
||
// title: '[多选题]',
|
||
// content: '危险化学品生产企业应当提供危险化学品安全技术说明书,并在包装(包括外包装)上标识,或者将技术与包装内危险化学品相符的化学品()和安全技术说明书。',
|
||
// options: [
|
||
// { id: 'A', text: 'A.操作规范说明书', image: '/images/exam/option-a.png' },
|
||
// { id: 'B', text: 'B.应急处理措施', image: '/images/exam/option-b.png' },
|
||
// { id: 'C', text: 'C.安全标签' },
|
||
// { id: 'D', text: 'D.产品合格证', image: '/images/exam/option-d.png' },
|
||
// { id: 'E', text: 'E.产品标签' }
|
||
// ],
|
||
// correctAnswers: ['A', 'B'],
|
||
// userAnswers: ['A', 'B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// }
|
||
// }
|
||
|
||
// 模拟练习数据
|
||
// const mockPractices: Practice[] = [
|
||
// {
|
||
// id: 1,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 120,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'ongoing',
|
||
// score: null,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'finished',
|
||
// score: 90,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// },
|
||
// {
|
||
// id: 3,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'finished',
|
||
// score: 90,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// },
|
||
// {
|
||
// id: 4,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 120,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'ongoing',
|
||
// score: null,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// },
|
||
// {
|
||
// id: 5,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'finished',
|
||
// score: 90,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// },
|
||
// {
|
||
// id: 6,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// questionCount: 100,
|
||
// description: '练习涵盖C++基础语法、面向对象编程、数据结构等核心内容,旨在全面评估学生对C++编程语言的掌握程度和实际应用能力。',
|
||
// status: 'finished',
|
||
// score: 90,
|
||
// correctCount: 18,
|
||
// wrongCount: 15
|
||
// }
|
||
// ]
|
||
|
||
// 模拟活动数据
|
||
// const mockActivities: Activity[] = [
|
||
// {
|
||
// id: 1,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 120,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'ongoing',
|
||
// score: null
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'finished',
|
||
// score: null
|
||
// },
|
||
// {
|
||
// id: 3,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'finished',
|
||
// score: null
|
||
// },
|
||
// {
|
||
// id: 4,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 120,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'ongoing',
|
||
// score: null
|
||
// },
|
||
// {
|
||
// id: 5,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'finished',
|
||
// score: null
|
||
// },
|
||
// {
|
||
// id: 6,
|
||
// title: '2025计算机二级',
|
||
// subtitle: 'C语言讲练综合班',
|
||
// courseTitle: '2025计算机二级C语言讲练综合班',
|
||
// activityDate: '2025-07-18 10:00',
|
||
// duration: 88,
|
||
// activityType: '激励类活动',
|
||
// registeredCount: '100/200',
|
||
// description: 'C++语言程序设计基础练习题,涵盖C++基础语法、面向对象编程、数据结构等核心内容。',
|
||
// status: 'finished',
|
||
// score: null
|
||
// }
|
||
// ]
|
||
|
||
// 模拟关注数据
|
||
const mockFollows = [
|
||
{
|
||
id: 1,
|
||
name: '张教授',
|
||
role: '教育心理学教授',
|
||
description: '专注于教育心理学研究,发表多篇学术论文',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'recent',
|
||
visitCount: 15,
|
||
isFollowing: true
|
||
},
|
||
{
|
||
id: 2,
|
||
name: '李老师',
|
||
role: '数学教师',
|
||
description: '拥有10年教学经验,擅长数学教学方法创新',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'recent',
|
||
visitCount: 8,
|
||
isFollowing: false
|
||
},
|
||
{
|
||
id: 3,
|
||
name: '王同学',
|
||
role: '学习伙伴',
|
||
description: '北京理工大学计算机学院教授计算机计算机计算',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'frequent',
|
||
visitCount: 25,
|
||
isFollowing: true
|
||
},
|
||
{
|
||
id: 4,
|
||
name: '刘同学',
|
||
role: '学习伙伴',
|
||
description: '学习小组组长,组织能力强',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'frequent',
|
||
visitCount: 32,
|
||
isFollowing: false
|
||
},
|
||
{
|
||
id: 5,
|
||
name: '陈博士',
|
||
role: '计算机科学教授',
|
||
description: '人工智能与机器学习专家,发表论文50余篇',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'recent',
|
||
visitCount: 12,
|
||
isFollowing: true
|
||
},
|
||
{
|
||
id: 6,
|
||
name: '赵同学',
|
||
role: '学习伙伴',
|
||
description: '编程爱好者,经常分享学习心得',
|
||
avatar: '/images/profile/avater.png',
|
||
type: 'all',
|
||
category: 'frequent',
|
||
visitCount: 28,
|
||
isFollowing: false
|
||
}
|
||
]
|
||
|
||
// 模拟消息数据 - 已移除,使用API数据
|
||
|
||
// 模拟点赞消息数据 - 已移除,使用API数据
|
||
|
||
// 模拟练习详情数据
|
||
// const mockPracticeDetails: { [key: number]: PracticeDetail } = {
|
||
// 2: {
|
||
// id: 2,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-30 14:00',
|
||
// duration: 88,
|
||
// totalQuestions: 100,
|
||
// correctCount: 18,
|
||
// wrongCount: 15,
|
||
// score: 90,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: 'C++中,下列哪个关键字用于定义类?',
|
||
// options: [
|
||
// { id: 'A', text: 'A.struct' },
|
||
// { id: 'B', text: 'B.class' },
|
||
// { id: 'C', text: 'C.union' },
|
||
// { id: 'D', text: 'D.enum' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// },
|
||
// {
|
||
// id: 2,
|
||
// type: 'multiple',
|
||
// title: '[多选题]',
|
||
// content: 'C++中,下列哪些是面向对象编程的特性?',
|
||
// options: [
|
||
// { id: 'A', text: 'A.封装' },
|
||
// { id: 'B', text: 'B.继承' },
|
||
// { id: 'C', text: 'C.多态' },
|
||
// { id: 'D', text: 'D.递归' },
|
||
// { id: 'E', text: 'E.抽象' }
|
||
// ],
|
||
// correctAnswers: ['A', 'B', 'C', 'E'],
|
||
// userAnswers: ['A', 'B', 'C'],
|
||
// isCorrect: false
|
||
// }
|
||
// ]
|
||
// },
|
||
// 3: {
|
||
// id: 3,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-30 14:00',
|
||
// duration: 88,
|
||
// totalQuestions: 100,
|
||
// correctCount: 18,
|
||
// wrongCount: 15,
|
||
// score: 90,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: 'C++中,下列哪个关键字用于定义类?',
|
||
// options: [
|
||
// { id: 'A', text: 'A.struct' },
|
||
// { id: 'B', text: 'B.class' },
|
||
// { id: 'C', text: 'C.union' },
|
||
// { id: 'D', text: 'D.enum' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// },
|
||
// 5: {
|
||
// id: 5,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-30 14:00',
|
||
// duration: 88,
|
||
// totalQuestions: 100,
|
||
// correctCount: 18,
|
||
// wrongCount: 15,
|
||
// score: 90,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: 'C++中,下列哪个关键字用于定义类?',
|
||
// options: [
|
||
// { id: 'A', text: 'A.struct' },
|
||
// { id: 'B', text: 'B.class' },
|
||
// { id: 'C', text: 'C.union' },
|
||
// { id: 'D', text: 'D.enum' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// },
|
||
// 6: {
|
||
// id: 6,
|
||
// title: 'C++语言程序设计基础练习题',
|
||
// practiceDate: '2025-07-30 14:00',
|
||
// duration: 88,
|
||
// totalQuestions: 100,
|
||
// correctCount: 18,
|
||
// wrongCount: 15,
|
||
// score: 90,
|
||
// questions: [
|
||
// {
|
||
// id: 1,
|
||
// type: 'single',
|
||
// title: '[单选题]',
|
||
// content: 'C++中,下列哪个关键字用于定义类?',
|
||
// options: [
|
||
// { id: 'A', text: 'A.struct' },
|
||
// { id: 'B', text: 'B.class' },
|
||
// { id: 'C', text: 'C.union' },
|
||
// { id: 'D', text: 'D.enum' }
|
||
// ],
|
||
// correctAnswers: ['B'],
|
||
// userAnswers: ['B'],
|
||
// isCorrect: true
|
||
// }
|
||
// ]
|
||
// }
|
||
// }
|
||
|
||
// 获取筛选后的所有课程
|
||
// const allFilteredCourses = computed(() => {
|
||
// if (activeCourseTab.value === 'learning') {
|
||
// return mockCourses.filter(course => course.status === 'learning')
|
||
// } else if (activeCourseTab.value === 'completed') {
|
||
// return mockCourses.filter(course => course.status === 'completed')
|
||
// }
|
||
// return mockCourses
|
||
// })
|
||
|
||
// 计算总页数
|
||
// const totalPages = computed(() => {
|
||
// return Math.ceil(allFilteredCourses.value.length / pageSize.value)
|
||
// })
|
||
|
||
// 当前页显示的课程
|
||
// const filteredCourses = computed(() => {
|
||
// const start = (currentPage.value - 1) * pageSize.value
|
||
// const end = start + pageSize.value
|
||
// return allFilteredCourses.value.slice(start, end)
|
||
// })
|
||
|
||
// 获取筛选后的作业
|
||
const filteredAssignments = computed(() => {
|
||
if (activeHomeworkTab.value === 'pending') {
|
||
return mockAssignments.filter(assignment => assignment.status === '待提交' || assignment.status === '未完成')
|
||
} else if (activeHomeworkTab.value === 'completed') {
|
||
return mockAssignments.filter(assignment => assignment.status === '已完成' || assignment.status === '已完成')
|
||
}
|
||
return mockAssignments
|
||
})
|
||
|
||
// 获取筛选后的考试
|
||
const filteredExams = computed(() => {
|
||
if (activeExamTab.value === 'upcoming') {
|
||
return mockExams.filter(exam => exam.status === 'upcoming')
|
||
} else if (activeExamTab.value === 'ongoing') {
|
||
return mockExams.filter(exam => exam.status === 'ongoing')
|
||
} else if (activeExamTab.value === 'finished') {
|
||
return mockExams.filter(exam => exam.status === 'finished')
|
||
}
|
||
return mockExams
|
||
})
|
||
|
||
// 获取筛选后的练习
|
||
// const filteredPractices = computed(() => {
|
||
// if (activePracticeTab.value === 'ongoing') {
|
||
// return mockPractices.filter(practice => practice.status === 'ongoing')
|
||
// } else if (activePracticeTab.value === 'finished') {
|
||
// return mockPractices.filter(practice => practice.status === 'finished')
|
||
// }
|
||
// return mockPractices
|
||
// })
|
||
|
||
// 获取筛选后的活动
|
||
// const filteredActivities = computed(() => {
|
||
// if (activeActivityTab.value === 'ongoing') {
|
||
// return mockActivities.filter(activity => activity.status === 'ongoing')
|
||
// } else if (activeActivityTab.value === 'finished') {
|
||
// return mockActivities.filter(activity => activity.status === 'finished')
|
||
// }
|
||
// return mockActivities
|
||
// })
|
||
|
||
// 获取筛选后的关注
|
||
const filteredFollows = computed(() => {
|
||
if (activeFollowsTab.value === 'recent') {
|
||
return mockFollows.filter(follow => follow.category === 'recent')
|
||
} else if (activeFollowsTab.value === 'frequent') {
|
||
return mockFollows.filter(follow => follow.category === 'frequent')
|
||
}
|
||
return mockFollows
|
||
})
|
||
|
||
// 计算属性用于模板中的条件判断
|
||
const isCoursesTab = computed(() => activeTab.value === 'courses')
|
||
const isHomeworkTab = computed(() => activeTab.value === 'homework')
|
||
const isExamTab = computed(() => activeTab.value === 'exam')
|
||
const isPracticeTab = computed(() => activeTab.value === 'practice')
|
||
const isActivityTab = computed(() => activeTab.value === 'activity')
|
||
const isFollowsTab = computed(() => activeTab.value === 'follows')
|
||
const isMessageTab = computed(() => activeTab.value === 'message')
|
||
|
||
// 处理菜单选择
|
||
const handleMenuSelect = (key: TabType) => {
|
||
activeTab.value = key
|
||
router.push(`/profile/${key}`)
|
||
// message.info(`切换到${getTabTitle(key)}`)
|
||
}
|
||
|
||
// 获取状态文本
|
||
// const getStatusText = (status: string) => {
|
||
// switch (status) {
|
||
// case 'learning':
|
||
// return '学习中'
|
||
// case 'completed':
|
||
// return '已完结'
|
||
// default:
|
||
// return '未开始'
|
||
// }
|
||
// }
|
||
|
||
// 跳转到课程
|
||
// const goToCourse = (courseId: number) => {
|
||
// message.info(`跳转到课程 ${courseId}`)
|
||
// }
|
||
|
||
// 分页器方法
|
||
// const goToPage = (page: number | string) => {
|
||
// if (typeof page === 'number') {
|
||
// if (page >= 1 && page <= totalPages.value) {
|
||
// currentPage.value = page
|
||
// }
|
||
// } else {
|
||
// switch (page) {
|
||
// case 'first':
|
||
// if (currentPage.value > 1) {
|
||
// currentPage.value = 1
|
||
// }
|
||
// break
|
||
// case 'prev':
|
||
// if (currentPage.value > 1) {
|
||
// currentPage.value--
|
||
// }
|
||
// break
|
||
// case 'next':
|
||
// if (currentPage.value < totalPages.value) {
|
||
// currentPage.value++
|
||
// }
|
||
// break
|
||
// case 'last':
|
||
// if (currentPage.value < totalPages.value) {
|
||
// currentPage.value = totalPages.value
|
||
// }
|
||
// break
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
// 监听筛选变化,重置到第一页
|
||
// const handleCourseTabChange = (tab: string) => {
|
||
// activeCourseTab.value = tab
|
||
// currentPage.value = 1
|
||
// }
|
||
|
||
// 处理作业筛选变化
|
||
const handleHomeworkTabChange = (tab: string) => {
|
||
activeHomeworkTab.value = tab
|
||
}
|
||
|
||
// 处理考试筛选变化
|
||
const handleExamTabChange = (tab: string) => {
|
||
activeExamTab.value = tab
|
||
}
|
||
|
||
// 处理练习筛选变化
|
||
// const handlePracticeTabChange = (tab: string) => {
|
||
// activePracticeTab.value = tab
|
||
// }
|
||
|
||
// 处理活动筛选变化
|
||
// const handleActivityTabChange = (tab: string) => {
|
||
// activeActivityTab.value = tab
|
||
// }
|
||
|
||
// 处理关注筛选变化
|
||
const handleFollowsTabChange = (tab: string) => {
|
||
activeFollowsTab.value = tab
|
||
}
|
||
|
||
// 获取考试状态文本
|
||
const getExamStatusText = (status: string) => {
|
||
switch (status) {
|
||
case 'upcoming':
|
||
return '未开始'
|
||
case 'ongoing':
|
||
return '进行中'
|
||
case 'finished':
|
||
return '已结束'
|
||
default:
|
||
return '未知状态'
|
||
}
|
||
}
|
||
|
||
// 开始考试
|
||
const startExam = (examId: number) => {
|
||
message.info(`开始考试 ${examId}`)
|
||
}
|
||
|
||
// 继续考试
|
||
const continueExam = (examId: number) => {
|
||
// message.info(`继续考试 ${examId}`)
|
||
router.push(`/exam/notice/${examId}`)
|
||
}
|
||
|
||
// 查看考试结果
|
||
const viewExamResult = (examId: number) => {
|
||
router.push(`/exam-detail/${examId}?source=exam`)
|
||
}
|
||
|
||
// 继续练习
|
||
// const continuePractice = (practiceId: number) => {
|
||
// message.info(`继续练习 ${practiceId}`)
|
||
// }
|
||
|
||
// 查看练习详情
|
||
// const viewPracticeDetail = (practiceId: number) => {
|
||
// router.push(`/exam-detail/${practiceId}?source=practice`)
|
||
// }
|
||
|
||
// 继续活动
|
||
// const continueActivity = (id: number) => {
|
||
// console.log('继续活动:', id)
|
||
// message.info(`继续活动 ${id}`)
|
||
// }
|
||
|
||
// 查看活动详情
|
||
// const viewActivityDetail = (id: number) => {
|
||
// router.push(`/activity/${id}`)
|
||
// }
|
||
|
||
// 切换关注状态
|
||
const toggleFollow = (id: number) => {
|
||
const follow = mockFollows.find(f => f.id === id)
|
||
if (follow) {
|
||
follow.isFollowing = !follow.isFollowing
|
||
const action = follow.isFollowing ? '关注' : '取消关注'
|
||
message.info(`已${action}用户 ${follow.name}`)
|
||
}
|
||
}
|
||
|
||
// 加载消息数量统计
|
||
const loadMessageCounts = async () => {
|
||
try {
|
||
messageCountsLoading.value = true
|
||
console.log('🔄 开始加载消息数量统计...')
|
||
console.log('📊 当前消息数量状态:', {
|
||
instantMessageCount: instantMessageCount.value,
|
||
commentMessageCount: commentMessageCount.value,
|
||
likeMessageCount: likeMessageCount.value,
|
||
systemMessageCount: systemMessageCount.value
|
||
})
|
||
|
||
// 并行加载各类消息数量
|
||
const results = await Promise.allSettled([
|
||
loadInstantMessageCount(),
|
||
loadCommentMessageCount(),
|
||
loadLikeMessageCount(),
|
||
loadSystemMessageCount()
|
||
])
|
||
|
||
console.log('📊 消息数量加载结果:', results)
|
||
console.log('📊 加载后的消息数量状态:', {
|
||
instantMessageCount: instantMessageCount.value,
|
||
commentMessageCount: commentMessageCount.value,
|
||
likeMessageCount: likeMessageCount.value,
|
||
systemMessageCount: systemMessageCount.value
|
||
})
|
||
|
||
// 添加调试信息:检查界面显示的数量
|
||
console.log('🔍 界面显示检查:')
|
||
console.log(' - 即时消息显示:', instantMessageCount.value > 0 ? instantMessageCount.value : '不显示')
|
||
console.log(' - 评论和@显示:', commentMessageCount.value > 0 ? commentMessageCount.value : '不显示')
|
||
console.log(' - 点赞显示:', likeMessageCount.value > 0 ? likeMessageCount.value : '不显示')
|
||
console.log(' - 系统消息显示:', systemMessageCount.value > 0 ? systemMessageCount.value : '不显示')
|
||
|
||
} catch (error) {
|
||
console.error('❌ 加载消息数量失败:', error)
|
||
} finally {
|
||
messageCountsLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 加载即时消息数量
|
||
const loadInstantMessageCount = async () => {
|
||
try {
|
||
console.log('🔍 开始加载即时消息数量...')
|
||
// 由于即时消息接口可能不存在,使用备用方案
|
||
instantMessageCount.value = 0
|
||
console.log('✅ 即时消息数量设置为:', instantMessageCount.value)
|
||
} catch (error) {
|
||
console.error('❌ 获取即时消息数量失败:', error)
|
||
instantMessageCount.value = 0
|
||
}
|
||
}
|
||
|
||
// 加载评论和@消息数量
|
||
const loadCommentMessageCount = async () => {
|
||
try {
|
||
console.log('🔍 开始加载评论和@消息数量...')
|
||
const response = await MessageApi.getCommentsAtMessages({ current: 1, size: 100 })
|
||
console.log('🔍 评论和@消息数量API响应:', response)
|
||
|
||
if (response.data && response.data.result && response.data.result.records) {
|
||
// 只统计未读消息数量
|
||
const unreadCount = response.data.result.records.filter((item: any) => item.readFlag === 0).length
|
||
commentMessageCount.value = unreadCount
|
||
console.log('✅ 评论和@消息未读数量:', commentMessageCount.value, '(总数:', response.data.result.total, ')')
|
||
} else {
|
||
commentMessageCount.value = 0
|
||
console.log('⚠️ 评论和@消息数量API返回数据格式不正确,设置为0')
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 获取评论消息数量失败:', error)
|
||
commentMessageCount.value = 0
|
||
}
|
||
}
|
||
|
||
// 加载点赞消息数量
|
||
const loadLikeMessageCount = async () => {
|
||
try {
|
||
console.log('🔍 开始加载点赞消息数量...')
|
||
const response = await MessageApi.getLikesMessages({ current: 1, size: 100 })
|
||
console.log('🔍 点赞消息数量API响应:', response)
|
||
|
||
if (response.data && response.data.result && response.data.result.records) {
|
||
// 只统计未读消息数量
|
||
const unreadCount = response.data.result.records.filter((item: any) => item.readFlag === 0).length
|
||
likeMessageCount.value = unreadCount
|
||
console.log('✅ 点赞消息未读数量:', likeMessageCount.value, '(总数:', response.data.result.total, ')')
|
||
} else {
|
||
likeMessageCount.value = 0
|
||
console.log('⚠️ 点赞消息数量API返回数据格式不正确,设置为0')
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 获取点赞消息数量失败:', error)
|
||
likeMessageCount.value = 0
|
||
}
|
||
}
|
||
|
||
// 加载系统消息数量
|
||
const loadSystemMessageCount = async () => {
|
||
try {
|
||
console.log('🔍 开始加载系统消息数量...')
|
||
const response = await MessageApi.getSystemMessages({ pageNo: 1, pageSize: 100 })
|
||
console.log('🔍 系统消息数量API响应:', response)
|
||
|
||
if (response.data && response.data.records) {
|
||
// 只统计未读消息数量
|
||
const unreadCount = response.data.records.filter((item: any) => item.readFlag === 0).length
|
||
systemMessageCount.value = unreadCount
|
||
console.log('✅ 系统消息未读数量:', systemMessageCount.value, '(总数:', response.data.total, ')')
|
||
} else {
|
||
systemMessageCount.value = 0
|
||
console.log('⚠️ 系统消息数量API返回数据格式不正确,设置为0')
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 获取系统消息数量失败:', error)
|
||
systemMessageCount.value = 0
|
||
}
|
||
}
|
||
|
||
// 消息相关方法
|
||
const handleMessageTabChange = (tab: string) => {
|
||
activeMessageTab.value = tab
|
||
|
||
// 每次切换消息标签时,都加载消息数量统计
|
||
loadMessageCounts()
|
||
|
||
// 当切换到评论和@消息标签时,加载评论和@消息数据
|
||
if (tab === 'comment') {
|
||
loadCommentMessages()
|
||
}
|
||
|
||
// 当切换到点赞消息标签时,加载点赞消息数据
|
||
if (tab === 'like') {
|
||
loadLikeMessages()
|
||
}
|
||
|
||
// 当切换到系统消息标签时,加载系统消息数据
|
||
if (tab === 'system') {
|
||
loadSystemMessages()
|
||
}
|
||
}
|
||
|
||
// 加载评论和@消息数据
|
||
const loadCommentMessages = async () => {
|
||
try {
|
||
commentMessagesLoading.value = true
|
||
console.log('🔍 开始加载评论和@消息,页码:', commentMessagesCurrentPage.value)
|
||
|
||
const response = await MessageApi.getCommentsAtMessages({
|
||
current: commentMessagesCurrentPage.value,
|
||
size: commentMessagesPageSize.value
|
||
})
|
||
|
||
console.log('🔍 评论和@消息API响应:', response)
|
||
|
||
if (response.data) {
|
||
const result = response.data
|
||
console.log('✅ 评论和@消息数据:', result)
|
||
|
||
if (result.success && result.result) {
|
||
commentMessages.value = result.result.records.map(transformCommentMessageData)
|
||
commentMessagesTotal.value = result.result.total || result.result.records.length
|
||
} else {
|
||
console.warn('⚠️ 评论和@消息API返回数据格式不正确:', result)
|
||
commentMessages.value = []
|
||
commentMessagesTotal.value = 0
|
||
}
|
||
console.log('✅ 转换后的评论和@消息:', commentMessages.value)
|
||
} else {
|
||
console.warn('⚠️ 评论和@消息API返回错误:', response)
|
||
commentMessages.value = []
|
||
commentMessagesTotal.value = 0
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 加载评论和@消息失败:', error)
|
||
commentMessages.value = []
|
||
commentMessagesTotal.value = 0
|
||
} finally {
|
||
commentMessagesLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 加载点赞消息数据
|
||
const loadLikeMessages = async () => {
|
||
try {
|
||
likeMessagesLoading.value = true
|
||
console.log('🔍 开始加载点赞消息,页码:', likeMessagesCurrentPage.value)
|
||
|
||
const response = await MessageApi.getLikesMessages({
|
||
current: likeMessagesCurrentPage.value,
|
||
size: likeMessagesPageSize.value
|
||
})
|
||
|
||
console.log('🔍 点赞消息API响应:', response)
|
||
|
||
if (response.data) {
|
||
const result = response.data
|
||
console.log('✅ 点赞消息数据:', result)
|
||
|
||
if (result.success && result.result) {
|
||
likeMessages.value = result.result.records.map(transformLikeMessageData)
|
||
likeMessagesTotal.value = result.result.total || result.result.records.length
|
||
} else {
|
||
console.warn('⚠️ 点赞消息API返回数据格式不正确:', result)
|
||
likeMessages.value = []
|
||
likeMessagesTotal.value = 0
|
||
}
|
||
console.log('✅ 转换后的点赞消息:', likeMessages.value)
|
||
} else {
|
||
console.warn('⚠️ 点赞消息API返回错误:', response)
|
||
likeMessages.value = []
|
||
likeMessagesTotal.value = 0
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 加载点赞消息失败:', error)
|
||
likeMessages.value = []
|
||
likeMessagesTotal.value = 0
|
||
} finally {
|
||
likeMessagesLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 加载系统消息数据
|
||
const loadSystemMessages = async () => {
|
||
try {
|
||
systemMessagesLoading.value = true
|
||
console.log('🔍 开始加载系统消息,页码:', systemMessagesCurrentPage.value)
|
||
|
||
const response = await MessageApi.getSystemMessages({
|
||
pageNo: systemMessagesCurrentPage.value,
|
||
pageSize: systemMessagesPageSize.value
|
||
})
|
||
|
||
console.log('🔍 系统消息API响应:', response)
|
||
|
||
if (response.data) {
|
||
const result = response.data
|
||
console.log('✅ 系统消息数据:', result)
|
||
|
||
// 检查数据结构,可能是直接的records数组或者包含records的对象
|
||
if (Array.isArray(result)) {
|
||
// 如果直接返回数组
|
||
systemMessages.value = result.map(transformSystemMessageData)
|
||
systemMessagesTotal.value = result.length
|
||
} else if (result.records && Array.isArray(result.records)) {
|
||
// 如果返回包含records的对象
|
||
systemMessages.value = result.records.map(transformSystemMessageData)
|
||
systemMessagesTotal.value = result.total || result.records.length
|
||
} else if ((result as any).result && (result as any).result.records && Array.isArray((result as any).result.records)) {
|
||
// 如果返回嵌套的result结构
|
||
systemMessages.value = (result as any).result.records.map(transformSystemMessageData)
|
||
systemMessagesTotal.value = (result as any).result.total || (result as any).result.records.length
|
||
} else {
|
||
// 其他情况,显示空状态
|
||
console.warn('⚠️ 系统消息API返回数据格式不正确:', result)
|
||
systemMessages.value = []
|
||
systemMessagesTotal.value = 0
|
||
}
|
||
|
||
console.log('✅ 转换后的系统消息:', systemMessages.value)
|
||
} else {
|
||
console.warn('⚠️ 系统消息API返回错误:', response)
|
||
// 显示空状态
|
||
systemMessages.value = []
|
||
systemMessagesTotal.value = 0
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ 加载系统消息失败:', error)
|
||
// 显示空状态
|
||
systemMessages.value = []
|
||
systemMessagesTotal.value = 0
|
||
} finally {
|
||
systemMessagesLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 查看系统消息详情
|
||
const goToSystemMessageDetail = async (msg: SystemMessage) => {
|
||
console.log('🔍 查看系统消息详情:', msg)
|
||
|
||
// 如果点击的是当前选中的消息,则关闭详情
|
||
if (selectedMessage.value && selectedMessage.value.id === msg.id) {
|
||
showMessageDetail.value = false
|
||
selectedMessage.value = null
|
||
return
|
||
}
|
||
|
||
selectedMessage.value = msg
|
||
showMessageDetail.value = true
|
||
|
||
// 如果消息未读,自动标记为已读
|
||
if (!msg.isRead) {
|
||
await markMessageAsRead(msg.id)
|
||
}
|
||
}
|
||
|
||
// 标记消息为已读
|
||
const markMessageAsRead = async (messageId: string) => {
|
||
if (markingAsRead.value) return
|
||
|
||
markingAsRead.value = true
|
||
try {
|
||
console.log('📝 标记消息为已读,messageId:', messageId)
|
||
|
||
const response = await MessageApi.markSystemMessageAsRead(messageId)
|
||
console.log('📝 标记已读API响应:', response)
|
||
|
||
// 检查API返回的成功状态
|
||
if (response.data && (response.data.success === true || response.data.code === 0)) {
|
||
// 更新本地状态
|
||
const messageIndex = systemMessages.value.findIndex(msg => msg.id === messageId)
|
||
if (messageIndex !== -1) {
|
||
systemMessages.value[messageIndex].isRead = true
|
||
}
|
||
|
||
if (selectedMessage.value && selectedMessage.value.id === messageId) {
|
||
selectedMessage.value.isRead = true
|
||
}
|
||
|
||
message.success(response.data.message || '已标记为已读')
|
||
console.log('✅ 标记已读成功')
|
||
} else {
|
||
console.log('❌ API返回错误:', response.data)
|
||
message.error(response.data?.message || '标记已读失败')
|
||
}
|
||
} catch (err: any) {
|
||
console.error('❌ 标记已读失败:', err)
|
||
// 检查是否是网络错误或其他具体错误
|
||
if (err.response && err.response.status) {
|
||
message.error(`标记已读失败: ${err.response.status} - ${err.response.statusText}`)
|
||
} else if (err.message) {
|
||
message.error(`标记已读失败: ${err.message}`)
|
||
} else {
|
||
message.error('标记已读失败,请稍后重试')
|
||
}
|
||
} finally {
|
||
markingAsRead.value = false
|
||
}
|
||
}
|
||
|
||
// 关闭消息详情
|
||
const closeMessageDetail = () => {
|
||
showMessageDetail.value = false
|
||
selectedMessage.value = null
|
||
}
|
||
|
||
// 排序后的系统消息
|
||
const sortedSystemMessages = computed(() => {
|
||
if (sortByTime.value === 'none') {
|
||
return systemMessages.value
|
||
}
|
||
|
||
return [...systemMessages.value].sort((a, b) => {
|
||
const dateA = new Date(a.date).getTime()
|
||
const dateB = new Date(b.date).getTime()
|
||
|
||
if (sortByTime.value === 'desc') {
|
||
return dateB - dateA // 最新在前
|
||
} else {
|
||
return dateA - dateB // 最旧在前
|
||
}
|
||
})
|
||
})
|
||
|
||
// 排序后的点赞消息
|
||
const sortedLikeMessages = computed(() => {
|
||
if (sortByTime.value === 'none') {
|
||
return likeMessages.value
|
||
}
|
||
|
||
return [...likeMessages.value].sort((a, b) => {
|
||
const dateA = new Date(a.date).getTime()
|
||
const dateB = new Date(b.date).getTime()
|
||
|
||
if (sortByTime.value === 'desc') {
|
||
return dateB - dateA // 最新在前
|
||
} else {
|
||
return dateA - dateB // 最旧在前
|
||
}
|
||
})
|
||
})
|
||
|
||
// 排序后的评论消息
|
||
const sortedCommentMessages = computed(() => {
|
||
if (sortByTime.value === 'none') {
|
||
return commentMessages.value
|
||
}
|
||
|
||
return [...commentMessages.value].sort((a, b) => {
|
||
const dateA = new Date(a.date).getTime()
|
||
const dateB = new Date(b.date).getTime()
|
||
|
||
if (sortByTime.value === 'desc') {
|
||
return dateB - dateA // 最新在前
|
||
} else {
|
||
return dateA - dateB // 最旧在前
|
||
}
|
||
})
|
||
})
|
||
|
||
// 获取排序状态显示文本
|
||
const getSortText = () => {
|
||
switch (sortByTime.value) {
|
||
case 'desc':
|
||
return '按时间 ↓'
|
||
case 'asc':
|
||
return '按时间 ↑'
|
||
default:
|
||
return '按时间'
|
||
}
|
||
}
|
||
|
||
// 按时间排序
|
||
const toggleSortByTime = () => {
|
||
// 循环切换排序状态: none -> desc -> asc -> none
|
||
if (sortByTime.value === 'none') {
|
||
sortByTime.value = 'desc' // 最新在前
|
||
} else if (sortByTime.value === 'desc') {
|
||
sortByTime.value = 'asc' // 最旧在前
|
||
} else {
|
||
sortByTime.value = 'none' // 不排序
|
||
}
|
||
|
||
console.log('🔄 切换排序状态:', sortByTime.value)
|
||
}
|
||
|
||
// 全部已读
|
||
const markAllAsRead = async () => {
|
||
if (markingAllAsRead.value) return
|
||
|
||
markingAllAsRead.value = true
|
||
try {
|
||
console.log('📝 开始标记全部消息为已读...')
|
||
|
||
// 收集所有未读消息的ID
|
||
const unreadSystemMessages = systemMessages.value.filter((msg: SystemMessage) => !msg.isRead)
|
||
const unreadLikeMessages = likeMessages.value.filter((msg: LikeMessage) => !msg.isRead)
|
||
const unreadCommentMessages = commentMessages.value.filter((msg: Message) => !msg.isRead)
|
||
|
||
console.log('📝 未读消息统计:', {
|
||
system: unreadSystemMessages.length,
|
||
like: unreadLikeMessages.length,
|
||
comment: unreadCommentMessages.length
|
||
})
|
||
|
||
// 批量调用单条标记已读接口
|
||
const promises: Promise<any>[] = []
|
||
|
||
// 标记系统消息为已读
|
||
unreadSystemMessages.forEach((msg: SystemMessage) => {
|
||
promises.push(MessageApi.markSystemMessageAsRead(msg.id))
|
||
})
|
||
|
||
// 标记点赞消息为已读(使用系统消息接口,因为都是同一个后端接口)
|
||
unreadLikeMessages.forEach((msg: LikeMessage) => {
|
||
promises.push(MessageApi.markSystemMessageAsRead(msg.id))
|
||
})
|
||
|
||
// 标记评论消息为已读
|
||
unreadCommentMessages.forEach((msg: Message) => {
|
||
promises.push(MessageApi.markSystemMessageAsRead(msg.id))
|
||
})
|
||
|
||
// 等待所有请求完成
|
||
const results = await Promise.allSettled(promises)
|
||
console.log('📝 批量标记已读结果:', results)
|
||
|
||
// 统计成功和失败的数量
|
||
const successCount = results.filter(result => result.status === 'fulfilled').length
|
||
const failCount = results.filter(result => result.status === 'rejected').length
|
||
|
||
// 如果没有未读消息,直接返回
|
||
if (unreadSystemMessages.length === 0 && unreadLikeMessages.length === 0 && unreadCommentMessages.length === 0) {
|
||
message.info('所有消息都已经是已读状态')
|
||
console.log('✅ 没有未读消息需要标记')
|
||
return
|
||
}
|
||
|
||
if (successCount > 0) {
|
||
// 更新所有消息的已读状态
|
||
systemMessages.value.forEach((msg: SystemMessage) => {
|
||
msg.isRead = true
|
||
})
|
||
likeMessages.value.forEach((msg: LikeMessage) => {
|
||
msg.isRead = true
|
||
})
|
||
commentMessages.value.forEach((msg: Message) => {
|
||
msg.isRead = true
|
||
})
|
||
|
||
// 更新消息数量统计
|
||
instantMessageCount.value = 0
|
||
commentMessageCount.value = 0
|
||
likeMessageCount.value = 0
|
||
systemMessageCount.value = 0
|
||
|
||
if (failCount > 0) {
|
||
message.warning(`已标记 ${successCount} 条消息为已读,${failCount} 条失败`)
|
||
} else {
|
||
message.success(`成功标记 ${successCount} 条消息为已读`)
|
||
}
|
||
console.log('✅ 全部已读完成,成功:', successCount, '失败:', failCount)
|
||
} else {
|
||
message.error('标记全部已读失败,请稍后重试')
|
||
}
|
||
} catch (err: any) {
|
||
console.error('❌ 标记全部已读失败:', err)
|
||
if (err.response && err.response.status) {
|
||
message.error(`标记全部已读失败: ${err.response.status} - ${err.response.statusText}`)
|
||
} else if (err.message) {
|
||
message.error(`标记全部已读失败: ${err.message}`)
|
||
} else {
|
||
message.error('标记全部已读失败,请稍后重试')
|
||
}
|
||
} finally {
|
||
markingAllAsRead.value = false
|
||
}
|
||
}
|
||
|
||
// 获取操作文本
|
||
const getActionText = (type: string) => {
|
||
switch (type) {
|
||
case 'comment':
|
||
return '评论了我'
|
||
case 'mention':
|
||
return '@了我'
|
||
case 'reply':
|
||
return '回复了我'
|
||
default:
|
||
return '评论了我'
|
||
}
|
||
}
|
||
|
||
// 获取点赞操作文本
|
||
const getLikeActionText = (type: string) => {
|
||
switch (type) {
|
||
case 'comment':
|
||
return '点赞了我的评论'
|
||
case 'course':
|
||
return '点赞了我'
|
||
default:
|
||
return '点赞了我'
|
||
}
|
||
}
|
||
|
||
// 下载相关方法
|
||
const handleDownloadTabChange = (tab: string) => {
|
||
activeDownloadTab.value = tab
|
||
}
|
||
|
||
// 筛选后的下载文件
|
||
const filteredDownloadFiles = computed(() => {
|
||
// 如果在子目录中,返回空数组显示空页面
|
||
if (isInSubDirectory.value) {
|
||
return []
|
||
}
|
||
|
||
let files = downloadFiles.filter(file => file.category === activeDownloadTab.value)
|
||
|
||
if (downloadFilter.type !== 'all') {
|
||
files = files.filter(file => file.type === downloadFilter.type)
|
||
}
|
||
|
||
if (downloadFilter.keyword) {
|
||
files = files.filter(file =>
|
||
file.name.toLowerCase().includes(downloadFilter.keyword.toLowerCase())
|
||
)
|
||
}
|
||
|
||
return files
|
||
})
|
||
|
||
// 文件菜单操作
|
||
const toggleFileMenu = (fileId: number) => {
|
||
activeFileMenu.value = activeFileMenu.value === fileId ? null : fileId
|
||
}
|
||
|
||
const handleFileClick = (file: any) => {
|
||
// 单击文件时的处理逻辑(如选中文件等)
|
||
console.log('单击文件:', file.name)
|
||
}
|
||
|
||
const handleFolderDoubleClick = (file: any) => {
|
||
if (file.type === 'folder') {
|
||
// 双击文件夹,进入子目录(显示空页面)
|
||
isInSubDirectory.value = true
|
||
currentPath.value = ['课件', file.name]
|
||
console.log('进入文件夹:', file.name)
|
||
}
|
||
}
|
||
|
||
const goBack = () => {
|
||
// 返回上级目录
|
||
isInSubDirectory.value = false
|
||
currentPath.value = []
|
||
}
|
||
|
||
const getFileIcon = (fileId?: number) => {
|
||
if (activeDownloadTab.value === 'certificate') {
|
||
// 证书标签页使用证书图标
|
||
return '/images/profile/certificate.jpg'
|
||
} else if (activeDownloadTab.value === 'homework') {
|
||
// 作业标签页使用不同的作业相关图标
|
||
const homeworkImages = [
|
||
'/images/profile/word.png',
|
||
'/images/profile/pdf.png',
|
||
'/images/profile/ppt.png',
|
||
'/images/profile/xls.png',
|
||
'/images/profile/zip.png',
|
||
'/images/profile/word.png'
|
||
]
|
||
const index = (fileId || 0) % homeworkImages.length
|
||
return homeworkImages[index]
|
||
} else if (isInSubDirectory.value) {
|
||
// 子目录使用子目录图标
|
||
return 'https://lanhu-oss-2537-2.lanhuapp.com/SketchPngf45333052202c303acc2c06223c26b820d330459ce2d452a21a3132fbbeab442'
|
||
} else {
|
||
// 默认文件夹图标
|
||
return '/images/profile/folder.png'
|
||
}
|
||
}
|
||
|
||
const createNewFolder = () => {
|
||
message.info('新建文件夹功能开发中...')
|
||
}
|
||
|
||
const renameFile = (fileId: number) => {
|
||
message.info(`重命名文件 ${fileId}`)
|
||
activeFileMenu.value = null
|
||
}
|
||
|
||
const deleteFile = (fileId: number) => {
|
||
message.info(`删除文件 ${fileId}`)
|
||
activeFileMenu.value = null
|
||
}
|
||
|
||
// 开始回复消息
|
||
const startReply = (messageId: string) => {
|
||
replyingMessageId.value = messageId
|
||
replyContent.value = ''
|
||
}
|
||
|
||
// 取消回复
|
||
const cancelReply = () => {
|
||
replyingMessageId.value = null
|
||
replyContent.value = ''
|
||
}
|
||
|
||
// 发送回复
|
||
const sendReply = (messageId: string) => {
|
||
if (!replyContent.value.trim()) {
|
||
message.error('请输入回复内容')
|
||
return
|
||
}
|
||
|
||
// 这里可以添加实际的发送逻辑
|
||
message.success('回复发送成功')
|
||
|
||
// 更新消息数据中的回复内容
|
||
const messageIndex = commentMessages.value.findIndex(msg => msg.id === messageId)
|
||
if (messageIndex !== -1) {
|
||
commentMessages.value[messageIndex].replyContent = replyContent.value
|
||
commentMessages.value[messageIndex].hasReply = true
|
||
}
|
||
|
||
cancelReply()
|
||
}
|
||
|
||
// 获取筛选后的消息
|
||
const filteredMessages = computed(() => {
|
||
if (activeMessageTab.value === 'comment') {
|
||
return sortedCommentMessages.value
|
||
}
|
||
return []
|
||
})
|
||
|
||
// 数据转换函数 - 将后端数据转换为前端格式
|
||
const transformCommentMessageData = (backendItem: BackendMessageItem): Message => {
|
||
let senderName = '未知用户'
|
||
let senderAvatar = '/images/profile/default-avatar.png'
|
||
let content = ''
|
||
let courseName = ''
|
||
let type: 'comment' | 'mention' | 'reply' = 'comment'
|
||
|
||
try {
|
||
if (backendItem.msgContent) {
|
||
const parsedContent = JSON.parse(backendItem.msgContent)
|
||
console.log('🔍 解析评论消息内容:', parsedContent)
|
||
|
||
if (parsedContent.sender) {
|
||
senderName = parsedContent.sender.username || '未知用户'
|
||
senderAvatar = parsedContent.sender.avatar || '/images/profile/default-avatar.png'
|
||
}
|
||
|
||
if (parsedContent.entity) {
|
||
courseName = parsedContent.entity.title || ''
|
||
content = parsedContent.entity.content || ''
|
||
|
||
// 根据消息类型确定type
|
||
if (parsedContent.entity.type === 'comment') {
|
||
type = 'comment'
|
||
} else if (parsedContent.entity.type === 'mention') {
|
||
type = 'mention'
|
||
} else if (parsedContent.entity.type === 'reply') {
|
||
type = 'reply'
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('⚠️ 解析评论消息内容失败:', error)
|
||
content = backendItem.msgContent || ''
|
||
}
|
||
|
||
return {
|
||
id: String(backendItem.id),
|
||
senderName,
|
||
senderAvatar,
|
||
content,
|
||
courseName,
|
||
date: backendItem.sendTime || new Date().toLocaleString('zh-CN'),
|
||
isRead: backendItem.readFlag === 1,
|
||
hasReply: false,
|
||
replyContent: '',
|
||
type
|
||
}
|
||
}
|
||
|
||
const transformLikeMessageData = (backendItem: BackendMessageItem): LikeMessage => {
|
||
let userName = '未知用户'
|
||
let userAvatar = '/images/profile/default-avatar.png'
|
||
let type: 'comment' | 'course' = 'course'
|
||
let courseName = ''
|
||
let content = ''
|
||
|
||
try {
|
||
if (backendItem.msgContent) {
|
||
const parsedContent = JSON.parse(backendItem.msgContent)
|
||
console.log('🔍 解析点赞消息内容:', parsedContent)
|
||
|
||
if (parsedContent.sender) {
|
||
userName = parsedContent.sender.username || '未知用户'
|
||
userAvatar = parsedContent.sender.avatar || '/images/profile/default-avatar.png'
|
||
}
|
||
|
||
if (parsedContent.entity) {
|
||
courseName = parsedContent.entity.title || ''
|
||
if (parsedContent.entity.type === 'comment') {
|
||
type = 'comment'
|
||
content = parsedContent.entity.content || ''
|
||
} else {
|
||
type = 'course'
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('⚠️ 解析点赞消息内容失败:', error)
|
||
}
|
||
|
||
return {
|
||
id: String(backendItem.id),
|
||
userName,
|
||
userAvatar,
|
||
type,
|
||
courseName,
|
||
content,
|
||
date: backendItem.sendTime || new Date().toLocaleString('zh-CN'),
|
||
isRead: backendItem.readFlag === 1
|
||
}
|
||
}
|
||
|
||
const transformSystemMessageData = (backendItem: BackendMessageItem): SystemMessage => {
|
||
let title = backendItem.titile || '系统消息'
|
||
let subtitle = '暂无内容'
|
||
|
||
// 解析 msgContent 中的JSON数据
|
||
try {
|
||
if (backendItem.msgContent) {
|
||
const parsedContent = JSON.parse(backendItem.msgContent)
|
||
console.log('🔍 解析系统消息内容:', parsedContent)
|
||
|
||
// 根据消息类型生成标题和内容
|
||
if (parsedContent.sender && parsedContent.comment) {
|
||
// 评论消息
|
||
title = `${parsedContent.sender.username} 评论了你的课程`
|
||
subtitle = parsedContent.comment.content || '暂无评论内容'
|
||
|
||
// 处理 @ 提及
|
||
subtitle = processAtMentions(subtitle)
|
||
} else if (parsedContent.sender && parsedContent.entity) {
|
||
// 其他类型的消息
|
||
title = `${parsedContent.sender.username} 的${parsedContent.entity.type}消息`
|
||
subtitle = parsedContent.entity.title || '暂无内容'
|
||
} else {
|
||
// 直接使用原始内容
|
||
subtitle = backendItem.msgContent
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('⚠️ 解析系统消息内容失败:', error)
|
||
// 如果解析失败,直接使用原始内容
|
||
subtitle = backendItem.msgContent || '暂无内容'
|
||
}
|
||
|
||
return {
|
||
id: String(backendItem.id),
|
||
title,
|
||
subtitle,
|
||
date: backendItem.sendTime || new Date().toLocaleString('zh-CN'),
|
||
isRead: backendItem.readFlag === 1
|
||
}
|
||
}
|
||
|
||
// 处理 @ 提及的函数
|
||
const processAtMentions = (content: string): string => {
|
||
if (!content) return content
|
||
|
||
// 将 [user:id:username] 格式转换为 @username
|
||
return content.replace(/\[user:(\d+):([^\]]+)\]/g, '@$2')
|
||
}
|
||
|
||
// 获取筛选后的系统消息
|
||
const filteredSystemMessages = computed(() => {
|
||
if (activeMessageTab.value === 'system') {
|
||
return sortedSystemMessages.value
|
||
}
|
||
return []
|
||
})
|
||
|
||
// 获取筛选后的点赞消息
|
||
const filteredLikeMessages = computed(() => {
|
||
if (activeMessageTab.value === 'like') {
|
||
return sortedLikeMessages.value
|
||
}
|
||
return []
|
||
})
|
||
|
||
// 获取标签标题
|
||
const getTabTitle = (tab: TabType) => {
|
||
const titles: Record<TabType, string> = {
|
||
courses: '我的课程',
|
||
homework: '我的作业',
|
||
exam: '我的考试',
|
||
practice: '我的练习',
|
||
activity: '我的活动',
|
||
follows: '我的关注',
|
||
message: '我的消息',
|
||
materials: '我的资料',
|
||
download: '我的下载'
|
||
}
|
||
return titles[tab] || '未知页面'
|
||
}
|
||
|
||
// 上传作业弹窗状态
|
||
const showModal = ref(false)
|
||
const currentAssignment = ref<Assignment | null>(null)
|
||
const uploadForm = reactive({
|
||
title: '',
|
||
content: '',
|
||
files: [] as File[]
|
||
})
|
||
|
||
|
||
|
||
// 作业详情视图状态
|
||
const showDetailView = ref(false)
|
||
const detailAssignment = ref<Assignment | null>(null)
|
||
|
||
// 草稿箱视图状态
|
||
const showDraftBoxView = ref(false)
|
||
const draftAssignment = ref<Assignment | null>(null)
|
||
|
||
// 考试详情视图状态
|
||
|
||
|
||
// // 获取答题卡项目的样式类
|
||
// const getAnswerItemClass = (index: number) => {
|
||
// // 模拟答题状态:前10题答对,第11-15题答错,其余未答
|
||
// if (index <= 10) {
|
||
// return 'correct'
|
||
// } else if (index <= 15) {
|
||
// return 'wrong'
|
||
// } else {
|
||
// return 'unanswered'
|
||
// }
|
||
// }
|
||
|
||
// 查看作业详情
|
||
const viewAssignmentDetail = (assignment: Assignment) => {
|
||
detailAssignment.value = assignment
|
||
showDetailView.value = true
|
||
showDraftBoxView.value = false
|
||
}
|
||
|
||
// 返回作业列表
|
||
// const backToAssignmentList = () => {
|
||
// showDetailView.value = false
|
||
// detailAssignment.value = null
|
||
// }
|
||
|
||
// 从详情页面跳转到上传作业
|
||
const showUploadFromDetail = () => {
|
||
showUploadModal(detailAssignment.value!)
|
||
}
|
||
|
||
// 显示草稿箱
|
||
const showDraftBox = () => {
|
||
// 模拟草稿箱数据,实际应该从后端获取
|
||
draftAssignment.value = {
|
||
id: 1,
|
||
title: '教育心理学课程设计作业',
|
||
description: '请根据所学的教育心理学理论,设计一个完整的课程教学方案,包括教学目标、教学内容、教学方法、教学评价等方面。要求理论联系实际,体现现代教育理念。',
|
||
teacherName: '张老师',
|
||
teacherAvatar: '/images/traings/traing1.png',
|
||
assignTime: '2024-01-15',
|
||
status: '草稿',
|
||
attachments: [
|
||
{ icon: '/images/auth/file.png', name: 'file1.pdf' },
|
||
{ icon: '/images/auth/file.png', name: 'file2.pdf' }
|
||
],
|
||
mainImage: '/images/traings/traing1.png'
|
||
}
|
||
showDraftBoxView.value = true
|
||
showDetailView.value = false
|
||
}
|
||
|
||
// 返回作业列表(从草稿箱)
|
||
const backFromDraftBox = () => {
|
||
showDraftBoxView.value = false
|
||
draftAssignment.value = null
|
||
}
|
||
|
||
// 重新编辑草稿
|
||
const reEditDraft = () => {
|
||
showUploadModal(draftAssignment.value!)
|
||
}
|
||
|
||
// 显示上传作业弹窗
|
||
const showUploadModal = (assignment: Assignment) => {
|
||
currentAssignment.value = assignment
|
||
uploadForm.title = ''
|
||
uploadForm.content = ''
|
||
uploadForm.files = []
|
||
showModal.value = true
|
||
}
|
||
|
||
// 关闭上传作业弹窗
|
||
const closeUploadModal = () => {
|
||
showModal.value = false
|
||
currentAssignment.value = null
|
||
}
|
||
|
||
// 提交作业
|
||
const submitAssignment = () => {
|
||
if (!uploadForm.title.trim()) {
|
||
message.error('请输入标题')
|
||
return
|
||
}
|
||
|
||
if (!uploadForm.content.trim()) {
|
||
message.error('请输入内容')
|
||
return
|
||
}
|
||
|
||
if (uploadForm.files.length === 0) {
|
||
message.error('请上传至少一个文件')
|
||
return
|
||
}
|
||
|
||
// 这里可以添加实际的提交逻辑
|
||
message.success('作业提交成功')
|
||
closeUploadModal()
|
||
}
|
||
|
||
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')
|
||
if (shouldRefresh === 'true') {
|
||
isRefreshing.value = true
|
||
sessionStorage.removeItem('refreshProfile')
|
||
|
||
// 延迟刷新,给用户一个视觉反馈
|
||
setTimeout(() => {
|
||
window.location.reload()
|
||
}, 100)
|
||
}
|
||
|
||
// 获取菜单
|
||
await getMenu()
|
||
|
||
const tabKey = <TabType>route.params.tabKey || 'courses'
|
||
handleMenuSelect(tabKey)
|
||
|
||
// 如果默认进入消息标签页,自动加载消息数量统计
|
||
if (tabKey === 'message') {
|
||
loadMessageCounts()
|
||
}
|
||
})
|
||
|
||
onActivated(() => {
|
||
// 检查是否需要刷新
|
||
const shouldRefresh = sessionStorage.getItem('refreshProfile')
|
||
if (shouldRefresh === 'true') {
|
||
isRefreshing.value = true
|
||
sessionStorage.removeItem('refreshProfile')
|
||
|
||
// 延迟刷新,给用户一个视觉反馈
|
||
setTimeout(() => {
|
||
window.location.reload()
|
||
}, 100)
|
||
}
|
||
|
||
// 如果当前在消息标签页,自动加载消息数量统计
|
||
if (activeTab.value === 'message') {
|
||
loadMessageCounts()
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 刷新遮罩样式 */
|
||
.refresh-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(255, 255, 255, 0.9);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 9999;
|
||
backdrop-filter: blur(4px);
|
||
}
|
||
|
||
.refresh-content {
|
||
text-align: center;
|
||
color: #333;
|
||
}
|
||
|
||
.refresh-spinner {
|
||
width: 40px;
|
||
height: 40px;
|
||
border: 4px solid #f3f3f3;
|
||
border-top: 4px solid #3498db;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
margin: 0 auto 16px;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
/* 基础布局类 */
|
||
.flex-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.flex-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
}
|
||
|
||
.justify-between {
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* 主页面容器 */
|
||
.profile-page {
|
||
width: 100vw;
|
||
min-height: calc(100vh - 6.4vh);
|
||
/* 减去顶部导航栏高度 */
|
||
background: #f6f6f6;
|
||
padding: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 主要内容区域 */
|
||
.profile-content {
|
||
/* width: 80vw; */
|
||
/* 调整为80vw */
|
||
min-height: 1415px;
|
||
margin: 3vh auto 0 auto;
|
||
/* 距离顶部40px转换为vh */
|
||
position: relative;
|
||
background: #f6f6f6;
|
||
}
|
||
|
||
/* 左侧侧边栏 */
|
||
.block_14 {
|
||
position: relative;
|
||
width: 13.4vw;
|
||
height: auto;
|
||
background: #ffffff;
|
||
/* 改为白色背景 */
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-bottom: 30px;
|
||
/* 内容居中 */
|
||
}
|
||
|
||
/* 用户头像和姓名 */
|
||
.image_7 {
|
||
width: 5vw !important;
|
||
/* 调整头像大小,覆盖SafeAvatar的内联样式 */
|
||
height: 5vw !important;
|
||
border-radius: 50%;
|
||
margin: 2.6vh auto 0 auto;
|
||
/* 居中显示 */
|
||
}
|
||
|
||
.image_7 img {
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
|
||
.text_72 {
|
||
width: 100%;
|
||
height: auto;
|
||
font-size: 1.1vw;
|
||
/* 调整字体大小 */
|
||
color: rgba(0, 0, 0, 1);
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: center;
|
||
line-height: 1.6vh;
|
||
margin: 0.9vh 0 0 0;
|
||
/* 居中显示 */
|
||
}
|
||
|
||
/* 菜单背景 */
|
||
.box_22 {
|
||
width: 12vw;
|
||
/* 调整菜单背景宽度,适应缩小的导航栏 */
|
||
height: auto;
|
||
/* 自适应高度 */
|
||
background: transparent;
|
||
/* 去掉背景色 */
|
||
border-radius: 0.6vw;
|
||
/* 12px转换为vw */
|
||
margin: 2.55vh 0;
|
||
/* 去掉左右边距,因为父容器已经居中 */
|
||
padding: 1.04vh 0;
|
||
/* 20px 0转换 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
/* 菜单项居中 */
|
||
}
|
||
|
||
/* 分割线 */
|
||
.menu-divider {
|
||
width: 11vw;
|
||
/* 与菜单项宽度一致 */
|
||
height: 0.05vh;
|
||
/* 1px转换为vh */
|
||
background: #E6E6E6;
|
||
margin: 0;
|
||
/* 上下间距 */
|
||
}
|
||
|
||
/* 菜单项 */
|
||
.image-text_19,
|
||
.image-text_20,
|
||
.image-text_21,
|
||
.image-text_22,
|
||
.image-text_23,
|
||
.image-text_24,
|
||
.image-text_25,
|
||
.image-text_26,
|
||
.image-text_27 {
|
||
width: 11vw;
|
||
/* 进一步缩小菜单项宽度,适应新的导航栏宽度 */
|
||
height: auto;
|
||
/* 自适应高度 */
|
||
min-height: 3vh;
|
||
/* 设置最小高度,让盒子更大 */
|
||
margin: .5vh;
|
||
/* 减小间距:从2.34vh减少到1.5vh */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: left;
|
||
/* 菜单项内容居中 */
|
||
cursor: pointer;
|
||
padding: 1.5vh 0 1.5vh 1.8vw;
|
||
/* 增加上下内边距,让盒子更高 */
|
||
border-radius: 0.31vw;
|
||
/* 6px转换为vw */
|
||
transition: all 0.3s ease;
|
||
background: transparent;
|
||
/* 默认透明背景 */
|
||
}
|
||
|
||
.image-text_19:hover,
|
||
.image-text_20:hover,
|
||
.image-text_21:hover,
|
||
.image-text_22:hover,
|
||
.image-text_23:hover,
|
||
.image-text_24:hover,
|
||
.image-text_25:hover,
|
||
.image-text_26:hover,
|
||
.image-text_27:hover {
|
||
background: #eff7fc;
|
||
/* 悬停时背景色 */
|
||
}
|
||
|
||
/* 激活状态的菜单项 */
|
||
.image-text_19.active,
|
||
.image-text_20.active,
|
||
.image-text_21.active,
|
||
.image-text_22.active,
|
||
.image-text_23.active,
|
||
.image-text_24.active,
|
||
.image-text_25.active,
|
||
.image-text_26.active,
|
||
.image-text_27.active {
|
||
background: #eff7fc;
|
||
/* 激活时背景色 */
|
||
}
|
||
|
||
/* 菜单图标 */
|
||
.image_8,
|
||
.label_4,
|
||
.label_5,
|
||
.label_6,
|
||
.thumbnail_40,
|
||
.label_7,
|
||
.image_9,
|
||
.thumbnail_41,
|
||
.thumbnail_42 {
|
||
width: 1.04vw;
|
||
/* 20px转换为vw */
|
||
height: 1.04vw;
|
||
margin-right: 0.78vw;
|
||
/* 15px转换为vw */
|
||
}
|
||
|
||
/* 菜单文字 */
|
||
.text-group_19,
|
||
.text-group_20,
|
||
.text-group_21,
|
||
.text-group_22,
|
||
.text-group_23,
|
||
.text-group_24,
|
||
.text-group_25,
|
||
.text-group_26,
|
||
.text-group_27 {
|
||
font-size: 16px;
|
||
/* 20px转换为vw */
|
||
color: rgba(102, 102, 102, 1);
|
||
/* 默认灰色 */
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
line-height: 1.46vh;
|
||
/* 28px转换为vh */
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
/* 激活状态的菜单文字颜色 */
|
||
.image-text_19.active .text-group_19,
|
||
.image-text_20.active .text-group_20,
|
||
.image-text_21.active .text-group_21,
|
||
.image-text_22.active .text-group_22,
|
||
.image-text_23.active .text-group_23,
|
||
.image-text_24.active .text-group_24,
|
||
.image-text_25.active .text-group_25,
|
||
.image-text_27.active .text-group_27,
|
||
.image-text_26.active .text-group_26 {
|
||
color: rgba(2, 134, 206, 1);
|
||
/* 激活时蓝色 */
|
||
}
|
||
|
||
/* 悬停状态的菜单文字颜色 */
|
||
.image-text_19:hover .text-group_19,
|
||
.image-text_20:hover .text-group_20,
|
||
.image-text_21:hover .text-group_21,
|
||
.image-text_22:hover .text-group_22,
|
||
.image-text_23:hover .text-group_23,
|
||
.image-text_24:hover .text-group_24,
|
||
.image-text_25:hover .text-group_25,
|
||
.image-text_27:hover .text-group_27,
|
||
.image-text_26:hover .text-group_26 {
|
||
color: rgba(2, 134, 206, 1);
|
||
/* 悬停时蓝色 */
|
||
}
|
||
|
||
/* 菜单项图标悬停效果 */
|
||
.image-text_19 .hover-icon,
|
||
.image-text_20 .hover-icon,
|
||
.image-text_21 .hover-icon,
|
||
.image-text_22 .hover-icon,
|
||
.image-text_23 .hover-icon,
|
||
.image-text_24 .hover-icon,
|
||
.image-text_25 .hover-icon,
|
||
.image-text_26 .hover-icon,
|
||
.image-text_27 .hover-icon {
|
||
display: none;
|
||
}
|
||
|
||
.image-text_19:hover .default-icon,
|
||
.image-text_20:hover .default-icon,
|
||
.image-text_21:hover .default-icon,
|
||
.image-text_22:hover .default-icon,
|
||
.image-text_23:hover .default-icon,
|
||
.image-text_24:hover .default-icon,
|
||
.image-text_25:hover .default-icon,
|
||
.image-text_26:hover .default-icon,
|
||
.image-text_27:hover .default-icon {
|
||
display: none;
|
||
}
|
||
|
||
.image-text_19:hover .hover-icon,
|
||
.image-text_20:hover .hover-icon,
|
||
.image-text_21:hover .hover-icon,
|
||
.image-text_22:hover .hover-icon,
|
||
.image-text_23:hover .hover-icon,
|
||
.image-text_24:hover .hover-icon,
|
||
.image-text_25:hover .hover-icon,
|
||
.image-text_26:hover .hover-icon,
|
||
.image-text_27:hover .hover-icon {
|
||
display: block;
|
||
}
|
||
|
||
/* 激活状态的图标显示 */
|
||
.image-text_19.active .default-icon,
|
||
.image-text_20.active .default-icon,
|
||
.image-text_21.active .default-icon,
|
||
.image-text_22.active .default-icon,
|
||
.image-text_23.active .default-icon,
|
||
.image-text_24.active .default-icon,
|
||
.image-text_25.active .default-icon,
|
||
.image-text_26.active .default-icon,
|
||
.image-text_27.active .default-icon {
|
||
display: none;
|
||
}
|
||
|
||
.image-text_19.active .hover-icon,
|
||
.image-text_20.active .hover-icon,
|
||
.image-text_21.active .hover-icon,
|
||
.image-text_22.active .hover-icon,
|
||
.image-text_23.active .hover-icon,
|
||
.image-text_24.active .hover-icon,
|
||
.image-text_25.active .hover-icon,
|
||
.image-text_26.active .hover-icon,
|
||
.image-text_27.active .hover-icon {
|
||
display: block;
|
||
}
|
||
|
||
/* 右侧课程列表区域 */
|
||
.group_5 {
|
||
width: 65vw;
|
||
/* 保持60vw宽度 */
|
||
min-height: calc(100vh - 6.4vh);
|
||
padding: 2.08vh 1.9vw;
|
||
/* 40px转换为vh和vw */
|
||
background: rgba(255, 255, 255, 1);
|
||
overflow-y: auto;
|
||
margin-left: 1.56vw;
|
||
margin-bottom: 30px;
|
||
}
|
||
|
||
/* 课程筛选标签 */
|
||
.text-wrapper_1 {
|
||
width: 100%;
|
||
height: 2.08vh;
|
||
/* 40px转换为vh */
|
||
align-items: center;
|
||
margin: 20px 0 20px 0;
|
||
/* 32px转换为vh */
|
||
gap: 2.81vw;
|
||
/* 54px转换为vw:54/1920*100 = 2.81vw */
|
||
}
|
||
|
||
.text_12,
|
||
.text_13,
|
||
.text_14,
|
||
.text_15 {
|
||
font-size: 0.94vw;
|
||
/* 18px转换为vw */
|
||
color: #000;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
cursor: pointer;
|
||
padding: 0.42vh 0;
|
||
/* 去掉左右内边距,只保留上下 */
|
||
transition: color 0.3s ease;
|
||
/* 只保留颜色过渡 */
|
||
background: transparent;
|
||
/* 确保背景透明 */
|
||
}
|
||
|
||
.text_12.active,
|
||
.text_13.active,
|
||
.text_14.active,
|
||
.text_15.active {
|
||
color: rgba(2, 134, 206, 1);
|
||
/* 只改变字体颜色,去掉背景色 */
|
||
}
|
||
|
||
.text_12:hover,
|
||
.text_13:hover,
|
||
.text_14:hover,
|
||
.text_15:hover {
|
||
color: rgba(2, 134, 206, 1);
|
||
}
|
||
|
||
/* 课程区域分割线 */
|
||
.course-divider {
|
||
width: 100%;
|
||
/* 与课程卡片宽度一致 */
|
||
height: 1.5px;
|
||
/* 1px转换为vh */
|
||
background: #E6E6E6;
|
||
margin-bottom: 1.67vh;
|
||
/* 与课程列表的间距 */
|
||
}
|
||
|
||
/* 课程列表 */
|
||
.course-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.25vh;
|
||
/* 24px转换为vh */
|
||
}
|
||
|
||
/* 课程卡片 */
|
||
.box_2 {
|
||
width: 100%;
|
||
min-height: 10.42vh;
|
||
/* 200px转换为vh */
|
||
background: rgba(255, 255, 255, 1);
|
||
border: none;
|
||
/* 去掉边框 */
|
||
border-radius: 0.6vw;
|
||
/* 12px转换为vw */
|
||
padding: 1.04vh 1.04vw;
|
||
/* 20px转换 */
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.box_2:hover {
|
||
box-shadow: 0 0.21vh 1.04vh rgba(0, 0, 0, 0.1);
|
||
/* 0 4px 20px转换 */
|
||
transform: translateY(-0.1vh);
|
||
/* -2px转换为vh */
|
||
}
|
||
|
||
/* 课程缩略图区域 */
|
||
.block_4 {
|
||
margin-right: 1.04vw;
|
||
}
|
||
|
||
.box_3 {
|
||
width: 202px;
|
||
/* 200px转换为vw */
|
||
height: 156px;
|
||
/* 大幅增加高度到300px转换为vh,让图片展示到外部盒子高度 */
|
||
position: relative;
|
||
border-radius: 5px;
|
||
/* 8px转换为vw */
|
||
overflow: hidden;
|
||
}
|
||
|
||
.thumbnail_4 {
|
||
width: 100%;
|
||
height: 156px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
/* 状态标签 */
|
||
.status-image-container {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 10;
|
||
}
|
||
|
||
.status-image {
|
||
width: 66px;
|
||
height: 22px;
|
||
}
|
||
|
||
.status-text {
|
||
position: absolute;
|
||
top: 26vh;
|
||
/* 12px转换为vh */
|
||
right: 0.63vw;
|
||
/* 调整到右侧 */
|
||
padding: 0.21vh 0.63vw;
|
||
/* 4px 12px转换 */
|
||
border-radius: 0.21vw;
|
||
/* 4px转换为vw */
|
||
font-size: 0.63vw;
|
||
/* 12px转换为vw */
|
||
color: rgba(255, 255, 255, 1);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.status-text.learning {
|
||
background: rgba(82, 196, 26, 1);
|
||
}
|
||
|
||
.status-text.completed {
|
||
background: rgba(24, 144, 255, 1);
|
||
}
|
||
|
||
/* 课程信息区域 */
|
||
.block_5 {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 课程标题和评分 */
|
||
.group_6 {
|
||
align-items: center;
|
||
margin-bottom: 0.42vh;
|
||
/* 8px转换为vh */
|
||
gap: 0.63vw;
|
||
/* 12px转换为vw */
|
||
}
|
||
|
||
.text_16 {
|
||
font-size: 18px;
|
||
/* 18px转换为vw */
|
||
color: #000000;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: 600;
|
||
flex: 1;
|
||
}
|
||
|
||
.thumbnail_5 {
|
||
width: 0.83vw;
|
||
/* 16px转换为vw */
|
||
height: 0.83vw;
|
||
}
|
||
|
||
.text_17 {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #999999;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
}
|
||
|
||
/* 讲师信息 */
|
||
.text_18 {
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
color: #999;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
margin-bottom: 0.42vh;
|
||
/* 8px转换为vh */
|
||
}
|
||
|
||
/* 课程描述 */
|
||
.text_19 {
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
color: #999;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
line-height: 1.5;
|
||
margin-top: 5px;
|
||
margin-bottom: 22px;
|
||
/* 16px转换为vh */
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 课程统计信息 */
|
||
.group_7 {
|
||
align-items: center;
|
||
gap: 5px;
|
||
/* 20px转换为vw */
|
||
}
|
||
|
||
.thumbnail_6,
|
||
.thumbnail_7 {
|
||
width: 14px;
|
||
height: 14px;
|
||
}
|
||
|
||
.thumbnail_8 {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.text_20,
|
||
.text_21,
|
||
.text_22 {
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
color: #999;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
/* 操作按钮 */
|
||
.text-wrapper_2 {
|
||
background: #0288D1;
|
||
border-radius: 5px;
|
||
/* 6px转换为vw */
|
||
padding: 6px 22px;
|
||
/* 8px 16px转换 */
|
||
cursor: pointer;
|
||
transition: background-color 0.3s ease;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.text-wrapper_2:hover {
|
||
background: rgba(2, 134, 206, 0.8);
|
||
}
|
||
|
||
.text_23 {
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
color: white;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 分页器样式 */
|
||
.pagination-wrapper {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-top: 4.17vh;
|
||
/* 80px转换为vh,增加上方间距 */
|
||
padding: 1.04vh 0;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.pagination {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.52vw;
|
||
/* 10px转换为vw */
|
||
}
|
||
|
||
.pagination-item {
|
||
min-width: 38px;
|
||
height: 38px;
|
||
background: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #666666;
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
cursor: pointer;
|
||
border-radius: 0.21vw;
|
||
/* 4px转换为vw */
|
||
transition: all 0.3s ease;
|
||
padding: 0.52vh 0.83vw;
|
||
/* 10px 16px转换 */
|
||
border: 0.05vw solid rgba(232, 232, 232, 1);
|
||
}
|
||
|
||
.pagination-item:hover {
|
||
color: rgba(2, 134, 206, 1);
|
||
border-color: rgba(2, 134, 206, 1);
|
||
}
|
||
|
||
.pagination-item.active {
|
||
background: #0088D1;
|
||
color: rgba(255, 255, 255, 1);
|
||
border-color: #0088D1;
|
||
}
|
||
|
||
.pagination-item.disabled {
|
||
color: rgba(204, 204, 204, 1);
|
||
cursor: not-allowed;
|
||
border-color: rgba(232, 232, 232, 1);
|
||
}
|
||
|
||
.pagination-item.disabled:hover {
|
||
color: rgba(204, 204, 204, 1);
|
||
border-color: rgba(232, 232, 232, 1);
|
||
background: rgba(248, 248, 248, 1);
|
||
}
|
||
|
||
.nav-button {
|
||
min-width: 3.65vw;
|
||
border: none;
|
||
}
|
||
|
||
.page-number {
|
||
min-width: 2.08vw;
|
||
/* 40px转换为vw,页码按钮保持原宽度 */
|
||
}
|
||
|
||
/* 作业部分样式 - 严格按照蓝湖UI */
|
||
.homework-content {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 作业卡片主容器 */
|
||
.group_11 {
|
||
padding-top: 15px;
|
||
position: relative;
|
||
width: 100%;
|
||
/* 1033px转换为vw */
|
||
min-height: 25vh;
|
||
/* 设置最小高度 */
|
||
height: auto;
|
||
/* 改为自适应高度 */
|
||
/* background: url('https://lanhu-oss-2537-2.lanhuapp.com/SketchPng75139e59843c2accc2ef713eac90adeeea2be065395a76d5e5e3d7365677e090') -0.05vw -0.05vh no-repeat; */
|
||
background-size: 100% auto;
|
||
/* 背景图宽度100%,高度自适应 */
|
||
background-color: #fff;
|
||
/* 添加背景色,避免内容超出背景图范围时显示问题 */
|
||
margin: 0.2vh 0 3vh 0;
|
||
/* 减少底部间距,避免卡片挤在一起 */
|
||
/* padding-top: 3vh;
|
||
padding-bottom: 3vh; */
|
||
/* 增加内边距确保内容不会溢出 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
border: 2px solid #ECECEC;
|
||
|
||
}
|
||
|
||
/* 头部信息容器 */
|
||
.box_5 {
|
||
/* width: 51.46vw; */
|
||
/* 988px转换为vw */
|
||
height: 2.81vh;
|
||
/* 54px转换为vh */
|
||
margin: 1.15vh 0 0 1.2vw;
|
||
/* 22px 0 0 23px转换 */
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 教师信息 */
|
||
.image-text_2 {
|
||
width: 8.07vw;
|
||
/* 155px转换为vw */
|
||
height: 2.81vh;
|
||
/* 54px转换为vh */
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 3.3vh;
|
||
/* 25px转换为vh (25/1920*100) */
|
||
position: relative;
|
||
gap: 8px;
|
||
}
|
||
|
||
.avatar-line {
|
||
position: absolute;
|
||
left: -4px;
|
||
top: 53%;
|
||
transform: translateY(-50%);
|
||
width: 57px;
|
||
height: 56px;
|
||
border-radius: 50%;
|
||
border: 2px solid #0288D1;
|
||
}
|
||
|
||
/* 教师头像 */
|
||
.image_22 {
|
||
width: 2.71vw;
|
||
/* 52px转换为vw */
|
||
height: 2.71vw;
|
||
/* 改为vw单位,保持正圆形 */
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
margin-top: 2vh;
|
||
/* 头像向下移动 */
|
||
}
|
||
|
||
.image-avatar {
|
||
width: 2.71vw;
|
||
/* 52px转换为vw */
|
||
height: 2.71vw;
|
||
border: 2px solid #000;
|
||
background-color: pink;
|
||
}
|
||
|
||
/* 教师详细信息容器 */
|
||
.text-group_3 {
|
||
width: 4.43vw;
|
||
/* 85px转换为vw */
|
||
height: auto;
|
||
/* 改为自适应高度 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
/* 增加垂直间距 */
|
||
margin-left: 0.52vw;
|
||
/* 10px转换为vw,头像和姓名之间的间距 */
|
||
margin-top: -2vh;
|
||
/* 25px转换为vh (25/1920*100) */
|
||
}
|
||
|
||
/* 教师姓名 */
|
||
.text_30 {
|
||
width: 2.81vw;
|
||
/* 54px转换为vw */
|
||
height: 1.3vh;
|
||
/* 25px转换为vh */
|
||
overflow-wrap: break-word;
|
||
color: rgba(51, 51, 51, 1);
|
||
font-size: 0.94vw;
|
||
/* 18px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.3vh;
|
||
/* 恢复原来的行高 */
|
||
margin-top: 0.5vh;
|
||
/* 调整姓名位置 */
|
||
}
|
||
|
||
/* 作业时间 */
|
||
.text_31 {
|
||
width: 4.43vw;
|
||
/* 85px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
overflow-wrap: break-word;
|
||
color: #999999;
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
margin-top: 1.2vh;
|
||
margin-top: 15px;
|
||
/* 调整时间与姓名的间距 */
|
||
}
|
||
|
||
/* 作业状态 */
|
||
.text_32 {
|
||
width: auto;
|
||
/* 42px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
overflow-wrap: break-word;
|
||
color: rgba(153, 153, 153, 1);
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
margin-top: 0.47vh;
|
||
margin-right: 25px;
|
||
/* 9px转换为vh */
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.text_32 img {
|
||
margin-right: 7px;
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
/* 作业内容区域 */
|
||
.text-group_4 {
|
||
/* width: 48.02vw; */
|
||
/* 922px转换为vw */
|
||
height: auto;
|
||
/* 改为自适应高度 */
|
||
margin: 4vh 1vw 0 5vw;
|
||
/* 减少顶部margin,让内容更紧凑 */
|
||
flex-grow: 1;
|
||
/* 允许内容区域伸展 */
|
||
}
|
||
|
||
/* 作业标题 */
|
||
.text_33 {
|
||
width: 16.67vw;
|
||
/* 320px转换为vw */
|
||
min-height: 1.46vh;
|
||
/* 最小高度,允许内容增长 */
|
||
height: auto;
|
||
/* 自适应高度 */
|
||
overflow-wrap: break-word;
|
||
color: rgba(0, 0, 0, 1);
|
||
font-size: 1.04vw;
|
||
/* 20px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: normal;
|
||
/* 允许文本换行 */
|
||
line-height: 1.8vh;
|
||
/* 增加行高,提高可读性 */
|
||
padding-top: 10px;
|
||
padding-bottom: 5px;
|
||
margin-bottom: 1vh;
|
||
/* 添加底部间距 */
|
||
display: block;
|
||
/* 确保是块级元素 */
|
||
}
|
||
|
||
/* 作业描述容器 */
|
||
.description-container {
|
||
/* width: 48.02vw; */
|
||
/* 922px转换为vw */
|
||
position: relative;
|
||
}
|
||
|
||
/* 作业描述 */
|
||
.text_34 {
|
||
width: 100%;
|
||
min-height: 1.15vh;
|
||
/* 最小高度 */
|
||
height: auto;
|
||
/* 自适应高度 */
|
||
overflow-wrap: break-word;
|
||
color: rgba(102, 102, 102, 1);
|
||
font-size: 0.83vw;
|
||
/* 16px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: normal;
|
||
/* 允许文本换行 */
|
||
line-height: 1.8vh;
|
||
/* 增加行高,提高可读性 */
|
||
display: block;
|
||
/* 确保是块级元素 */
|
||
margin-top: 0;
|
||
/* 移除顶部间距,因为已经在标题添加了底部间距 */
|
||
transition: all 0.3s ease;
|
||
/* 添加过渡动画 */
|
||
}
|
||
|
||
/* 文本截断样式 */
|
||
.text_34.text-truncated {
|
||
/* display: -webkit-box; */
|
||
-webkit-line-clamp: 1;
|
||
line-height: 1.4;
|
||
/* 限制显示1行 */
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* 展开/收起按钮 */
|
||
.expand-toggle {
|
||
color: #1890ff;
|
||
cursor: pointer;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
margin-left: 0.5vw;
|
||
user-select: none;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.expand-toggle:hover {
|
||
color: #40a9ff;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
/* 作业详情弹窗样式 */
|
||
.assignment-detail {
|
||
padding: 20px 0;
|
||
}
|
||
|
||
.detail-header {
|
||
/* padding-bottom: 20px; */
|
||
}
|
||
|
||
.detail-header h2 {
|
||
margin: 0 0 15px 0;
|
||
color: #333;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.assignment-meta {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.teacher-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.teacher-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.teacher-name {
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.assignment-time {
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.assignment-status {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.assignment-status.未完成,
|
||
.assignment-status.待提交 {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.assignment-status.已完成,
|
||
.assignment-status.已完成 {
|
||
color: #52c41a;
|
||
}
|
||
|
||
.detail-content h3 {
|
||
margin: 20px 0 10px 0;
|
||
color: #333;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.description-full {
|
||
background: #f8f9fa;
|
||
padding: 15px;
|
||
border-radius: 6px;
|
||
line-height: 1.6;
|
||
color: #333;
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.attachments-section {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.attachment-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.attachment-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 10px;
|
||
background: #f8f9fa;
|
||
border-radius: 6px;
|
||
border: 1px solid #e9ecef;
|
||
}
|
||
|
||
.attachment-icon {
|
||
width: 24px;
|
||
height: 24px;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.attachment-name {
|
||
color: #333;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 附件区域 */
|
||
.box_6 {
|
||
/* width: 48.65vw; */
|
||
/* 934px转换为vw */
|
||
height: auto;
|
||
/* 改为自适应高度 */
|
||
margin: 0.94vh 0 0 5vw;
|
||
/* 18px 0 0 67px转换 */
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* 附件小图标 */
|
||
.thumbnail_6 {
|
||
width: 0.83vw;
|
||
/* 16px转换为vw */
|
||
height: 0.83vw;
|
||
/* 保持宽高比一致 */
|
||
}
|
||
|
||
/* 附件大图标 */
|
||
.image_23 {
|
||
width: 0.83vw;
|
||
/* 16px转换为vw */
|
||
height: 2.03vh;
|
||
/* 39px转换为vh */
|
||
margin: 6.51vh 0 0 0.94vw;
|
||
/* 125px 0 0 18px转换 */
|
||
}
|
||
|
||
/* 附件数量文本 */
|
||
.text_35 {
|
||
width: 4.27vw;
|
||
/* 82px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
overflow-wrap: break-word;
|
||
color: rgba(153, 153, 153, 1);
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
margin: 7.76vh 0 0 0.31vw;
|
||
/* 149px 0 0 6px转换 */
|
||
position: absolute;
|
||
}
|
||
|
||
/* 附件头部区域 */
|
||
.attachment-header {
|
||
position: relative;
|
||
height: 3vh;
|
||
margin-bottom: 1vh;
|
||
}
|
||
|
||
/* 附件图片容器 */
|
||
.attachment-images {
|
||
display: flex;
|
||
gap: 0.7vw;
|
||
align-items: center;
|
||
margin-top: 1vh;
|
||
/* margin-left: 2.5vh; */
|
||
}
|
||
|
||
.attachment-number-container {
|
||
justify-content: left;
|
||
gap: 0;
|
||
align-items: center;
|
||
}
|
||
|
||
.attachment-number-icon {
|
||
width: 14px;
|
||
height: 12px;
|
||
}
|
||
|
||
.attachment-number-text {
|
||
margin-left: 5px;
|
||
font-size: 14px;
|
||
color: #999;
|
||
}
|
||
|
||
/* 附件图片样式 - 使用flex布局避免重叠 */
|
||
.image_24,
|
||
.image_25,
|
||
.image_26,
|
||
.image_27,
|
||
.image_28 {
|
||
width: 6.5vw;
|
||
/* 缩小图片尺寸 */
|
||
height: 6.5vw;
|
||
/* 保持正方形 */
|
||
object-fit: cover;
|
||
border: 0.05vw solid #e9ecef;
|
||
}
|
||
|
||
/* 作业按钮区域 */
|
||
.assignment-buttons {
|
||
display: flex;
|
||
gap: 1vw;
|
||
margin: 2vh 0 2vh 4.95vw;
|
||
}
|
||
|
||
/* 提交按钮容器 */
|
||
.text-wrapper_8 {
|
||
height: 1.72vh;
|
||
/* 33px转换为vh */
|
||
width: 5.31vw;
|
||
/* 102px转换为vw */
|
||
position: relative;
|
||
/* 改为相对定位 */
|
||
cursor: pointer;
|
||
align-self: flex-start;
|
||
/* 按钮靠左对齐 */
|
||
border-radius: 0.2vw;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: #0288D1;
|
||
color: #fff;
|
||
}
|
||
|
||
/* 上传作业按钮 - 未完成状态 */
|
||
.submit-button {
|
||
width: 102px;
|
||
height: 33px;
|
||
border: 1px solid #0288D1;
|
||
}
|
||
|
||
.anew-button {
|
||
width: 102px;
|
||
height: 33px;
|
||
background-color: #fff;
|
||
color: #0288D1 !important;
|
||
border: 1px solid #0288D1;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 查看情况按钮 - 未完成状态 */
|
||
.view-button {
|
||
width: 102px;
|
||
height: 33px;
|
||
background-color: white;
|
||
border: 1px solid #0288D1;
|
||
color: #0288D1;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 查看详情按钮 - 已完成状态 */
|
||
.details-button {
|
||
width: 102px;
|
||
height: 33px;
|
||
background-color: #0288D1;
|
||
color: white !important;
|
||
}
|
||
|
||
/* 提交按钮文字 */
|
||
.text_36 {
|
||
width: auto;
|
||
/* 自适应宽度 */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
overflow-wrap: break-word;
|
||
color: #fff;
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
line-height: 1.04vh;
|
||
margin: 0;
|
||
}
|
||
|
||
.text-view {
|
||
color: #0288D1;
|
||
}
|
||
|
||
/* 主图样式 */
|
||
.image_29 {
|
||
position: absolute;
|
||
left: 4.95vw;
|
||
/* 95px转换为vw */
|
||
top: 12vh;
|
||
/* 调整位置,避免与附件重叠 */
|
||
width: 6.98vw;
|
||
/* 134px转换为vw */
|
||
height: 6.98vh;
|
||
/* 134px转换为vh */
|
||
object-fit: cover;
|
||
border-radius: 0.3vw;
|
||
border: 0.05vw solid #e9ecef;
|
||
}
|
||
|
||
/* 蓝湖UI作业样式完成 */
|
||
|
||
/* 考试页面样式 - 网格布局 */
|
||
.exam-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.exam-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.exam-card {
|
||
background: #ffffff;
|
||
border: 1.5px solid #D8D8D8;
|
||
padding: 20px;
|
||
position: relative;
|
||
min-height: 280px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.exam-card:hover {
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.exam-title {
|
||
font-size: 16px;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
line-height: 1.4;
|
||
border-bottom: 1.5px solid #E6E6E6;
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
.exam-score-badge {
|
||
position: absolute;
|
||
top: 11px;
|
||
right: 18px;
|
||
background: white;
|
||
border: 1px solid #FF6F0F;
|
||
border-radius: 4px;
|
||
padding: 0 11px;
|
||
}
|
||
|
||
.score-text {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
color: #FF6F0F;
|
||
}
|
||
|
||
.score-text span {
|
||
margin-left: 2px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.exam-details {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.exam-meta-item {
|
||
display: flex;
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.meta-label {
|
||
color: #999;
|
||
min-width: 70px;
|
||
}
|
||
|
||
.meta-value {
|
||
color: #999;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.exam-description {
|
||
padding: 8px 10px;
|
||
font-size: 12px;
|
||
color: #497087;
|
||
margin-bottom: auto;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
-webkit-line-clamp: 3;
|
||
-webkit-box-orient: vertical;
|
||
background-color: #F5F8FB;
|
||
}
|
||
|
||
.exam-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: auto;
|
||
padding-top: 16px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.exam-status-left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.exam-status-text {
|
||
font-size: 12px;
|
||
color: #999;
|
||
}
|
||
|
||
.exam-action-right {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 6px 16px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.3s ease;
|
||
min-width: 80px;
|
||
}
|
||
|
||
.upcoming-btn {
|
||
background: #F5F8FB;
|
||
color: #999999;
|
||
border: none;
|
||
}
|
||
|
||
.upcoming-btn:hover {
|
||
background: #e8e8e8;
|
||
}
|
||
|
||
.ongoing-btn {
|
||
background: #0288D1;
|
||
color: white;
|
||
}
|
||
|
||
.ongoing-btn:hover {
|
||
background: #40a9ff;
|
||
}
|
||
|
||
.finished-btn {
|
||
background: #0288D1;
|
||
color: white;
|
||
}
|
||
|
||
.finished-btn:hover {
|
||
background: #01579B;
|
||
}
|
||
|
||
.files-container {
|
||
margin: 15px 20px 0 83px;
|
||
/* width: 100%; */
|
||
background-color: #F5F9FC;
|
||
height: 48px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.file-items {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 10px;
|
||
cursor: pointer;
|
||
gap: 4px;
|
||
}
|
||
|
||
.file-items span {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.files-icon {
|
||
width: 15px;
|
||
height: 15px;
|
||
}
|
||
|
||
.course-name {
|
||
margin-left: 0px;
|
||
color: #497087;
|
||
}
|
||
|
||
.course-name span {
|
||
color: #6AA5CC;
|
||
}
|
||
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.exam-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.exam-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 16px;
|
||
}
|
||
|
||
.exam-card {
|
||
padding: 16px;
|
||
min-height: 240px;
|
||
}
|
||
|
||
/* 考试标题在小屏幕上给分数留出空间并允许换行 */
|
||
.exam-title {
|
||
padding-right: 80px;
|
||
/* 给分数徽章留出空间 */
|
||
word-wrap: break-word;
|
||
word-break: break-word;
|
||
white-space: normal;
|
||
}
|
||
|
||
/* 分数徽章保持在右上角不换行 */
|
||
.exam-score-badge {
|
||
position: absolute;
|
||
top: 16px;
|
||
right: 16px;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
|
||
/* 更小屏幕的适配 */
|
||
@media (max-width: 480px) {
|
||
.exam-card {
|
||
padding: 12px;
|
||
min-height: 220px;
|
||
}
|
||
|
||
.exam-title {
|
||
padding-right: 70px;
|
||
/* 给分数徽章留出更多空间 */
|
||
font-size: 14px;
|
||
}
|
||
|
||
.exam-score-badge {
|
||
top: 12px;
|
||
right: 12px;
|
||
}
|
||
|
||
.score-text {
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
/* 简化的作业卡片样式 */
|
||
.assignment-card-simple {
|
||
width: 100%;
|
||
margin-bottom: 2vh;
|
||
}
|
||
|
||
/* 其他内容样式 */
|
||
.other-content {
|
||
width: 100%;
|
||
padding: 2.08vh 2.08vw;
|
||
/* 40px转换 */
|
||
text-align: center;
|
||
}
|
||
|
||
.other-content h2 {
|
||
font-size: 1.25vw;
|
||
/* 24px转换为vw */
|
||
color: rgba(51, 51, 51, 1);
|
||
margin-bottom: 1.04vh;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.other-content p {
|
||
font-size: 0.83vw;
|
||
/* 16px转换为vw */
|
||
color: rgba(153, 153, 153, 1);
|
||
}
|
||
|
||
/* 作业分隔线 */
|
||
.assignment-divider {
|
||
width: 100%;
|
||
height: 1px;
|
||
background-color: #E5E5E5;
|
||
margin: 0.89vh 0;
|
||
/* 17px转换为vh */
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1440px) {
|
||
.profile-page {
|
||
max-width: 100vw;
|
||
}
|
||
|
||
.profile-content {
|
||
max-width: 100vw;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 1024px) {
|
||
.profile-content {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.block_14 {
|
||
width: 100%;
|
||
min-height: auto;
|
||
order: 2;
|
||
border-right: none;
|
||
border-top: 0.05vw solid rgba(232, 232, 232, 1);
|
||
}
|
||
|
||
.group_5 {
|
||
width: 100%;
|
||
order: 1;
|
||
min-height: auto;
|
||
margin-left: 0;
|
||
/* 移动端取消左边距 */
|
||
}
|
||
|
||
.box_2 {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.block_4 {
|
||
width: 100%;
|
||
margin-right: 0;
|
||
margin-bottom: 0.83vh;
|
||
/* 16px转换为vh */
|
||
}
|
||
|
||
.box_3 {
|
||
width: 100%;
|
||
height: 18vh;
|
||
/* 平板端大幅增加高度,让图片展示到外部盒子高度 */
|
||
}
|
||
|
||
/* 调整用户信息区域为横向布局 */
|
||
.image_7 {
|
||
margin: 1.04vh 0 0 1.04vw;
|
||
/* 20px转换 */
|
||
width: 4.17vw !important;
|
||
/* 80px转换为vw,覆盖SafeAvatar样式 */
|
||
height: 4.17vw !important;
|
||
}
|
||
|
||
.text_72 {
|
||
margin: 1.04vh 0 0 1.04vw;
|
||
/* 20px转换 */
|
||
width: auto;
|
||
text-align: left;
|
||
}
|
||
|
||
.box_22 {
|
||
margin: 1.04vh 0;
|
||
/* 移动端保持居中 */
|
||
width: 90%;
|
||
/* 移动端调整宽度 */
|
||
height: auto;
|
||
padding: 1.04vh 0;
|
||
/* 移动端调整内边距 */
|
||
}
|
||
|
||
.image-text_19,
|
||
.image-text_20,
|
||
.image-text_21,
|
||
.image-text_22,
|
||
.image-text_23,
|
||
.image-text_24,
|
||
.image-text_25,
|
||
.image-text_26 {
|
||
width: 80%;
|
||
/* 移动端菜单项宽度 */
|
||
margin: 1.5vh 0;
|
||
/* 保持与桌面端一致的间距 */
|
||
padding: 1.2vh 2vw;
|
||
/* 保持与桌面端一致的内边距 */
|
||
min-height: 3vh;
|
||
/* 保持最小高度 */
|
||
}
|
||
|
||
.menu-divider {
|
||
width: 80%;
|
||
/* 移动端分割线宽度 */
|
||
margin: 1.5vh 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.group_5 {
|
||
padding: 1.04vh 1.04vw;
|
||
/* 20px转换 */
|
||
}
|
||
|
||
.text-wrapper_1 {
|
||
justify-content: flex-start;
|
||
/* 改为左对齐 */
|
||
gap: 4vw;
|
||
/* 手机端调整间距 */
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.text_12,
|
||
.text_13,
|
||
.text_14 {
|
||
font-size: 2.16px;
|
||
/* 手机端调整字体大小 */
|
||
padding: 10px 0;
|
||
/* 保持无左右内边距 */
|
||
}
|
||
|
||
.course-divider {
|
||
width: 100%;
|
||
/* 手机端也保持与课程卡片宽度一致 */
|
||
}
|
||
|
||
.pagination-wrapper {
|
||
margin-top: 6vh;
|
||
/* 手机端增加更多上方间距 */
|
||
}
|
||
|
||
.pagination {
|
||
gap: 2vw;
|
||
/* 手机端增加间距 */
|
||
}
|
||
|
||
.pagination-item {
|
||
min-width: 8vw;
|
||
/* 手机端增加按钮宽度 */
|
||
height: 4vh;
|
||
/* 手机端增加按钮高度 */
|
||
font-size: 2.5vw;
|
||
/* 手机端调整字体大小 */
|
||
padding: 1vh 2vw;
|
||
}
|
||
|
||
.nav-button {
|
||
min-width: 12vw;
|
||
/* 手机端导航按钮更宽 */
|
||
}
|
||
|
||
.page-number {
|
||
min-width: 8vw;
|
||
/* 手机端页码按钮宽度 */
|
||
}
|
||
|
||
/* 作业部分响应式 */
|
||
.assignment-card {
|
||
width: 90vw;
|
||
height: auto;
|
||
min-height: 30vh;
|
||
margin: 2vh 5vw;
|
||
background-size: 100% 100%;
|
||
}
|
||
|
||
.assignment-header {
|
||
width: 85vw;
|
||
height: auto;
|
||
margin: 2vh 2.5vw;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 1vh;
|
||
}
|
||
|
||
.teacher-info {
|
||
width: auto;
|
||
height: auto;
|
||
gap: 2vw;
|
||
}
|
||
|
||
.teacher-avatar {
|
||
width: 8vw;
|
||
height: 8vw;
|
||
}
|
||
|
||
.teacher-details {
|
||
width: auto;
|
||
height: auto;
|
||
}
|
||
|
||
.teacher-name {
|
||
font-size: 3vw;
|
||
width: auto;
|
||
height: auto;
|
||
}
|
||
|
||
.assignment-time {
|
||
font-size: 2.5vw;
|
||
width: auto;
|
||
height: auto;
|
||
margin-top: 0.5vh;
|
||
}
|
||
|
||
.assignment-status {
|
||
font-size: 2.5vw;
|
||
width: auto;
|
||
height: auto;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.assignment-content {
|
||
width: 85vw;
|
||
height: auto;
|
||
margin: 2vh 2.5vw;
|
||
}
|
||
|
||
.assignment-title {
|
||
font-size: 3.5vw;
|
||
width: auto;
|
||
height: auto;
|
||
white-space: normal;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.assignment-description {
|
||
font-size: 2.8vw;
|
||
width: auto;
|
||
height: auto;
|
||
white-space: normal;
|
||
line-height: 1.4;
|
||
margin-top: 1vh;
|
||
}
|
||
|
||
.assignment-attachments {
|
||
width: 85vw;
|
||
height: auto;
|
||
margin: 2vh 2.5vw;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 2vh;
|
||
}
|
||
|
||
.attachment-list {
|
||
flex-wrap: wrap;
|
||
gap: 2vw;
|
||
}
|
||
|
||
.attachment-item {
|
||
width: 15vw;
|
||
height: 15vw;
|
||
}
|
||
|
||
.attachment-count {
|
||
font-size: 2.5vw;
|
||
width: auto;
|
||
height: auto;
|
||
margin-left: 0;
|
||
}
|
||
|
||
.attachment-actions {
|
||
width: auto;
|
||
height: auto;
|
||
gap: 2vw;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.action-btn {
|
||
width: 20vw;
|
||
height: 6vh;
|
||
border-radius: 1vw;
|
||
}
|
||
|
||
.download-btn span,
|
||
.submit-btn span {
|
||
font-size: 2.5vw;
|
||
width: auto;
|
||
height: auto;
|
||
margin: 0;
|
||
}
|
||
|
||
.assignment-main-image {
|
||
position: relative;
|
||
left: 2.5vw;
|
||
top: 0;
|
||
width: 20vw;
|
||
height: 20vw;
|
||
margin-top: 2vh;
|
||
}
|
||
|
||
.other-content {
|
||
padding: 4vh 4vw;
|
||
}
|
||
|
||
.other-content h2 {
|
||
font-size: 4vw;
|
||
margin-bottom: 2vh;
|
||
}
|
||
|
||
.other-content p {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.group_7 {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 0.42vh;
|
||
/* 8px转换为vh */
|
||
}
|
||
|
||
.box_2 {
|
||
padding: 0.83vh 0.83vw;
|
||
/* 16px转换 */
|
||
}
|
||
|
||
.block_4 {
|
||
margin-bottom: 0.63vh;
|
||
/* 12px转换为vh */
|
||
}
|
||
|
||
.box_3 {
|
||
height: 20vh;
|
||
/* 手机端大幅增加高度,让图片展示到外部盒子高度 */
|
||
}
|
||
}
|
||
|
||
@media (max-width: 576px) {
|
||
.profile-page {
|
||
padding: 0;
|
||
}
|
||
|
||
.group_5 {
|
||
padding: 0.83vh 0.83vw;
|
||
/* 16px转换 */
|
||
}
|
||
|
||
.text-wrapper_1 {
|
||
gap: 0.83vw;
|
||
/* 16px转换为vw */
|
||
}
|
||
|
||
.text_12,
|
||
.text_13,
|
||
.text_14 {
|
||
font-size: 0.83vw;
|
||
/* 16px转换为vw */
|
||
padding: 0.31vh 0.63vw;
|
||
/* 6px 12px转换 */
|
||
}
|
||
|
||
/* 平板端面包屑样式 */
|
||
.breadcrumb-nav {
|
||
font-size: 1vw;
|
||
/* 平板端调整字体大小 */
|
||
}
|
||
|
||
.breadcrumb-item {
|
||
width: 5vw;
|
||
/* 平板端调整宽度 */
|
||
font-size: 1vw;
|
||
/* 平板端调整字体大小 */
|
||
line-height: 1.3vh;
|
||
/* 平板端调整行高 */
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
width: 4.5vw;
|
||
/* 平板端调整宽度 */
|
||
font-size: 1vw;
|
||
/* 平板端调整字体大小 */
|
||
line-height: 1.3vh;
|
||
/* 平板端调整行高 */
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
margin: 0 0.8vw;
|
||
/* 平板端调整间距 */
|
||
}
|
||
|
||
.box_2 {
|
||
padding: 0.63vh 0.63vw;
|
||
/* 12px转换 */
|
||
}
|
||
|
||
.text_16 {
|
||
font-size: 0.83vw;
|
||
|
||
}
|
||
|
||
.text_19 {
|
||
font-size: 0.68vw;
|
||
/* 13px转换为vw */
|
||
}
|
||
|
||
.group_7 {
|
||
gap: 0.31vh;
|
||
/* 6px转换为vh */
|
||
}
|
||
|
||
.text_20,
|
||
.text_21,
|
||
.text_22 {
|
||
font-size: 0.63vw;
|
||
/* 12px转换为vw */
|
||
}
|
||
|
||
/* 手机端面包屑样式 */
|
||
.breadcrumb-nav {
|
||
font-size: 3.5vw;
|
||
/* 手机端调整字体大小 */
|
||
margin-bottom: 2vh;
|
||
/* 手机端增加底部间距 */
|
||
}
|
||
|
||
.breadcrumb-item {
|
||
width: 15vw;
|
||
/* 手机端调整宽度 */
|
||
font-size: 3.5vw;
|
||
/* 手机端调整字体大小 */
|
||
line-height: 2vh;
|
||
/* 手机端调整行高 */
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
width: 13vw;
|
||
/* 手机端调整宽度 */
|
||
font-size: 3.5vw;
|
||
/* 手机端调整字体大小 */
|
||
line-height: 2vh;
|
||
/* 手机端调整行高 */
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
margin: 0 2vw;
|
||
/* 手机端调整间距 */
|
||
}
|
||
}
|
||
|
||
/* 上传作业弹窗样式 */
|
||
.assignment-info {
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
background-color: #f9f9f9;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.assignment-info h3 {
|
||
margin-top: 0;
|
||
margin-bottom: 10px;
|
||
font-size: 18px;
|
||
color: #333;
|
||
}
|
||
|
||
.assignment-info p {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.file-list {
|
||
margin-top: 10px;
|
||
max-height: 200px;
|
||
overflow-y: auto;
|
||
border: 1px solid #eee;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.file-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.file-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.modal-footer {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
margin-top: -30px;
|
||
}
|
||
|
||
.modal-footer button {
|
||
width: 100px;
|
||
height: 42px;
|
||
background: #0088D1;
|
||
border: none;
|
||
color: white;
|
||
border-radius: 5px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.cancel {
|
||
background: #E2F5FF !important;
|
||
color: #0088D1 !important;
|
||
border: 1px solid #0088D1 !important;
|
||
}
|
||
|
||
/* 作业详情视图样式 */
|
||
.detail-header {
|
||
display: flex;
|
||
align-items: center;
|
||
/* margin-bottom: 15px; */
|
||
}
|
||
|
||
/* 面包屑导航样式 */
|
||
.breadcrumb-nav {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #666;
|
||
margin-bottom: 1.04vh;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.breadcrumb-item {
|
||
width: 3.39vw;
|
||
/* 65px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #333333;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.breadcrumb-item:hover {
|
||
color: #0056b3;
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
margin: 0 0.52vw;
|
||
/* 10px转换为vw */
|
||
color: #999;
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
width: 2.97vw;
|
||
/* 57px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #999999;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
.description-full-view {
|
||
white-space: pre-wrap;
|
||
line-height: 1.6;
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 考试详情页面样式 */
|
||
.exam-detail-overlay {
|
||
position: fixed;
|
||
top: 60px;
|
||
/* 留出导航栏的空间 */
|
||
left: 0;
|
||
width: 100%;
|
||
height: calc(100% - 60px);
|
||
/* 减去导航栏的高度 */
|
||
background: #f5f5f5;
|
||
z-index: 999;
|
||
/* 降低z-index,确保导航栏可见 */
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.exam-detail-container {
|
||
margin: 0 auto;
|
||
background: #f5f5f5;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.exam-detail-header {
|
||
margin: auto;
|
||
width: 1420px;
|
||
padding: 24px 0;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.breadcrumb {
|
||
font-size: 14px;
|
||
color: #666;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.breadcrumb-link {
|
||
height: 20px;
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-size: 14px;
|
||
color: #333333;
|
||
line-height: 20px;
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.breadcrumb-link:hover {
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.breadcrumb-separator {
|
||
margin: 0 8px;
|
||
color: #999999;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
height: 20px;
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-size: 14px;
|
||
color: #999999;
|
||
line-height: 20px;
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.exam-detail-content {
|
||
margin: auto;
|
||
max-width: 1420px;
|
||
display: flex;
|
||
gap: 24px;
|
||
padding: 0;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.exam-questions-section {
|
||
flex: 1;
|
||
background: white;
|
||
padding: 24px;
|
||
}
|
||
|
||
.exam-title-section {
|
||
margin-bottom: 24px;
|
||
padding-bottom: 16px;
|
||
border-bottom: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.exam-main-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0;
|
||
}
|
||
|
||
.questions-container {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.question-item {
|
||
background: white;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.question-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.question-number {
|
||
color: #0088D1;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.question-type {
|
||
color: #1890ff;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.question-score {
|
||
width: 36px;
|
||
height: 20px;
|
||
background: #EEF9FF;
|
||
color: #1890ff;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
margin-left: auto;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 25%;
|
||
}
|
||
|
||
.question-content {
|
||
font-size: 16px;
|
||
color: #333;
|
||
line-height: 1.6;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.question-options {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.option-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 1053px;
|
||
height: 50px;
|
||
background: #F5F8FB;
|
||
padding: 0 16px;
|
||
margin-bottom: 8px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.option-item.option-selected {
|
||
background: #F5F8FB !important;
|
||
}
|
||
|
||
.option-item.option-correct {
|
||
background: #f6ffed;
|
||
}
|
||
|
||
.option-item.option-wrong {
|
||
background: #fff2f0;
|
||
}
|
||
|
||
.option-checkbox {
|
||
margin-right: 12px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.option-checkbox input[type="checkbox"] {
|
||
width: 14px;
|
||
height: 14px;
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
-moz-appearance: none;
|
||
background: white;
|
||
border: 1px solid #d9d9d9;
|
||
cursor: pointer;
|
||
position: relative;
|
||
}
|
||
|
||
.option-checkbox input[type="checkbox"]:checked {
|
||
background: #1890ff;
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
.option-checkbox input[type="checkbox"]:checked::after {
|
||
content: '✓';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
color: white;
|
||
font-size: 10px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.option-content {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.option-text {
|
||
font-size: 14px;
|
||
color: #333;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.option-image {
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.option-image img {
|
||
max-width: 200px;
|
||
height: auto;
|
||
border: 1px solid #e8e8e8;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.question-footer {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.answer-status-box {
|
||
width: 100px;
|
||
height: 33px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-size: 14px;
|
||
color: #FFFFFF;
|
||
line-height: 20px;
|
||
text-align: center;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
.answer-status-box.status-correct {
|
||
background: #0288D1;
|
||
}
|
||
|
||
.answer-status-box.status-wrong {
|
||
background: #ff4d4f;
|
||
}
|
||
|
||
.question-stats {
|
||
display: flex;
|
||
gap: 16px;
|
||
flex: 1;
|
||
}
|
||
|
||
.correct-answer,
|
||
.user-answer {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.question-result {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.result-correct {
|
||
color: #52c41a;
|
||
}
|
||
|
||
.result-wrong {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.question-analysis {
|
||
margin-top: 16px;
|
||
padding: 16px;
|
||
background: #fafafa;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.analysis-title {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.analysis-content {
|
||
font-size: 14px;
|
||
color: #497087;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.exam-submit-section {
|
||
margin-top: 24px;
|
||
text-align: left;
|
||
margin-left: 16px;
|
||
}
|
||
|
||
.submit-btn {
|
||
background: #1890ff;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 6px;
|
||
padding: 12px 24px;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
display: inline-block;
|
||
transition: background-color 0.3s ease;
|
||
}
|
||
|
||
.submit-btn:hover {
|
||
background: #40a9ff;
|
||
}
|
||
|
||
.submit-text {
|
||
font-weight: 500;
|
||
}
|
||
|
||
.submit-stats {
|
||
font-size: 12px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.submit-score {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.exam-info-section {
|
||
width: 300px;
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.score-circle-container {
|
||
background: white;
|
||
padding: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.score-circle {
|
||
width: 120px;
|
||
height: 120px;
|
||
border-radius: 50%;
|
||
background: conic-gradient(#1890ff 0deg 352deg, #e8e8e8 352deg 360deg);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin: 0 auto 12px;
|
||
position: relative;
|
||
}
|
||
|
||
.score-inner {
|
||
width: 90px;
|
||
height: 90px;
|
||
border-radius: 50%;
|
||
background: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.score-number {
|
||
font-size: 32px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.score-label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.exam-stats {
|
||
background: white;
|
||
padding: 24px;
|
||
}
|
||
|
||
.stat-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.stat-item:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 10px;
|
||
color: #497087;
|
||
}
|
||
|
||
.stat-value {
|
||
margin-left: 20px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.stat-value span {
|
||
margin-left: 2px;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.stat-value.correct {
|
||
color: #3F76ED;
|
||
}
|
||
|
||
.stat-value.wrong {
|
||
color: #FE2E2F;
|
||
}
|
||
|
||
.answer-stats {
|
||
background: white;
|
||
padding: 24px;
|
||
}
|
||
|
||
.stats-row {
|
||
display: flex;
|
||
gap: 12px;
|
||
}
|
||
|
||
.stat-box {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 16px 8px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.stat-box.correct {
|
||
background: #f6ffed;
|
||
border: 1px solid #b7eb8f;
|
||
}
|
||
|
||
.stat-box.wrong {
|
||
background: #fff2f0;
|
||
border: 1px solid #ffb3b3;
|
||
}
|
||
|
||
.stat-box.total {
|
||
background: #e6f7ff;
|
||
border: 1px solid #91d5ff;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.stat-box.correct .stat-number {
|
||
color: #52c41a;
|
||
}
|
||
|
||
.stat-box.wrong .stat-number {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.stat-box.total .stat-number {
|
||
color: #1890ff;
|
||
}
|
||
|
||
.stat-text {
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
.answer-card {
|
||
background: white;
|
||
padding: 24px;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.card-sections {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.card-section {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.card-section:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.answer-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(5, 1fr);
|
||
gap: 8px;
|
||
}
|
||
|
||
.answer-item {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 4px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.answer-item.correct {
|
||
background: #1890ff;
|
||
color: white;
|
||
}
|
||
|
||
.answer-item.wrong {
|
||
background: #ff4d4f;
|
||
color: white;
|
||
}
|
||
|
||
.answer-item.unanswered {
|
||
background: #f5f5f5;
|
||
color: #999;
|
||
border: 1px solid #e8e8e8;
|
||
}
|
||
|
||
.answer-item:hover {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.card-legend {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
padding-top: 16px;
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.legend-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.legend-color {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.legend-color.correct {
|
||
background: #1890ff;
|
||
}
|
||
|
||
.legend-color.wrong {
|
||
background: #ff4d4f;
|
||
}
|
||
|
||
.legend-text {
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
.legend-checkbox {
|
||
margin-left: auto;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.legend-checkbox input[type="checkbox"] {
|
||
width: 14px;
|
||
height: 14px;
|
||
}
|
||
|
||
.legend-checkbox label {
|
||
font-size: 12px;
|
||
color: #666;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1024px) {
|
||
.exam-detail-content {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.exam-info-section {
|
||
width: 100%;
|
||
}
|
||
|
||
.stats-row {
|
||
justify-content: center;
|
||
}
|
||
|
||
.stat-box {
|
||
max-width: 120px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.exam-detail-content {
|
||
padding: 16px;
|
||
}
|
||
|
||
.question-item {
|
||
padding: 16px;
|
||
}
|
||
|
||
.answer-grid {
|
||
grid-template-columns: repeat(4, 1fr);
|
||
}
|
||
|
||
.score-circle {
|
||
width: 100px;
|
||
height: 100px;
|
||
}
|
||
|
||
.score-inner {
|
||
width: 75px;
|
||
height: 75px;
|
||
}
|
||
|
||
.score-number {
|
||
font-size: 24px;
|
||
}
|
||
}
|
||
|
||
/* 练习页面样式 - 网格布局 */
|
||
.practice-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.exam-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20px;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.practice-card {
|
||
background: #ffffff;
|
||
border: 1px solid #e8e8e8;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
position: relative;
|
||
min-height: 280px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.practice-card:hover {
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.practice-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 16px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.practice-score-badge {
|
||
position: absolute;
|
||
top: 11px;
|
||
right: 18px;
|
||
background: white;
|
||
border: 1px solid #FF6F0F;
|
||
border-radius: 4px;
|
||
padding: 0 11px;
|
||
}
|
||
|
||
.practice-details {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.practice-meta-item {
|
||
display: flex;
|
||
margin-bottom: 8px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.practice-description {
|
||
font-size: 13px;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
margin-bottom: 16px;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 3;
|
||
-webkit-box-orient: vertical;
|
||
}
|
||
|
||
.practice-stats {
|
||
display: flex;
|
||
gap: 16px;
|
||
height: 54px;
|
||
background: #F5F8FB;
|
||
align-items: center;
|
||
justify-content: space-evenly;
|
||
}
|
||
|
||
.divider {
|
||
width: 1px;
|
||
height: 20px;
|
||
background: #EBEBEB;
|
||
}
|
||
|
||
|
||
.stats-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
flex: 1;
|
||
}
|
||
|
||
.stats-item.correct .stats-number {
|
||
color: #1890ff;
|
||
}
|
||
|
||
.stats-item.wrong .stats-number {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.stats-label {
|
||
font-size: 12px;
|
||
color: #666;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.stats-number {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.practice-intro {
|
||
padding: 12px;
|
||
background: #f8f9fa;
|
||
border-radius: 6px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.intro-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.intro-content {
|
||
padding-bottom: 10px;
|
||
font-size: 14px;
|
||
color: #666;
|
||
line-height: 1.5;
|
||
border-bottom: 1.5px solid #E6E6E6;
|
||
}
|
||
|
||
.practice-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: auto;
|
||
padding-top: 16px;
|
||
border-top: 1px solid #f0f0f0;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.practice-status-left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.practice-status-text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.practice-action-right {
|
||
display: flex;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.practice-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.practice-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 16px;
|
||
}
|
||
|
||
.practice-card {
|
||
padding: 16px;
|
||
min-height: 240px;
|
||
}
|
||
}
|
||
|
||
/* 活动页面样式 - 网格布局 */
|
||
.activity-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.activity-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 1.04vw;
|
||
/* 20px转换为vw */
|
||
margin-top: 1.04vh;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.activity-card {
|
||
background: #ffffff;
|
||
border: 1px solid #e8e8e8;
|
||
/* 8px转换为vw */
|
||
padding: 0;
|
||
/* 移除内边距,让图片可以占满顶部 */
|
||
position: relative;
|
||
min-height: 14.58vh;
|
||
/* 280px转换为vh */
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: all 0.3s ease;
|
||
overflow: hidden;
|
||
/* 确保图片不会溢出圆角 */
|
||
}
|
||
|
||
.activity-card:hover {
|
||
box-shadow: 0 0.21vw 0.63vw rgba(0, 0, 0, 0.1);
|
||
/* 0 4px 12px转换 */
|
||
transform: translateY(-0.1vh);
|
||
/* -2px转换为vh */
|
||
}
|
||
|
||
/* 活动卡片顶部图片容器 */
|
||
.activity-card-image {
|
||
width: 100%;
|
||
height: 179px;
|
||
/* 179px转换为vh (179/1080*100) */
|
||
overflow: hidden;
|
||
/* 只有顶部圆角 */
|
||
}
|
||
|
||
/* 活动卡片图片 */
|
||
.activity-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
|
||
.activity-score-badge {
|
||
position: absolute;
|
||
top: 0.83vw;
|
||
/* 16px转换为vw */
|
||
right: 0.83vw;
|
||
/* 16px转换为vw */
|
||
background: #FF6B35;
|
||
color: white;
|
||
padding: 0.21vw 0.42vw;
|
||
/* 4px 8px转换为vw */
|
||
border-radius: 0.21vw;
|
||
/* 4px转换为vw */
|
||
font-size: 0.63vw;
|
||
/* 12px转换为vw */
|
||
font-weight: 500;
|
||
z-index: 1;
|
||
}
|
||
|
||
.activity-title {
|
||
font-size: 16px;
|
||
/* 16px转换为vw */
|
||
/* font-weight: 600; */
|
||
color: #333;
|
||
margin: 15px 0 5px 0;
|
||
/* 0 0 16px 0转换 */
|
||
line-height: 1.4;
|
||
padding: 0 1.04vw;
|
||
/* 添加左右内边距 */
|
||
font-weight: 600;
|
||
}
|
||
|
||
.activity-details {
|
||
/* 20px转换为vh */
|
||
padding: 0 1.04vw;
|
||
/* 添加左右内边距 */
|
||
}
|
||
|
||
.activity-meta-item {
|
||
margin-bottom: 10px;
|
||
/* 8px转换为vh */
|
||
font-size: 14px;
|
||
/* 13px转换为vw */
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.activity-intro {
|
||
flex: 1;
|
||
margin-bottom: 1.04vh;
|
||
/* 20px转换为vh */
|
||
padding: 0 1.04vw;
|
||
/* 添加左右内边距 */
|
||
}
|
||
|
||
.intro-title {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 0.42vh;
|
||
/* 8px转换为vh */
|
||
}
|
||
|
||
.intro-content {
|
||
font-size: 14px;
|
||
/* 13px转换为vw */
|
||
color: #666;
|
||
line-height: 1.5;
|
||
margin-bottom: 10px;
|
||
/* 16px转换为vh */
|
||
/* display: -webkit-box; */
|
||
-webkit-line-clamp: 3;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.activity-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: auto;
|
||
padding: 5px 15px 15px 15px;
|
||
/* 添加内边距 */
|
||
}
|
||
|
||
.activity-status-left {
|
||
/* flex: 1; */
|
||
}
|
||
|
||
.activity-status-text {
|
||
font-size: 12px;
|
||
/* 13px转换为vw */
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 活动状态颜色 - 与练习中保持一致 */
|
||
.activity-status-text.ongoing {
|
||
color: #FF520F;
|
||
/* 进行中 - 橙色 */
|
||
}
|
||
|
||
.activity-status-text.finished {
|
||
color: #999999;
|
||
/* 已结束 - 灰色 */
|
||
}
|
||
|
||
.activity-action-right {
|
||
display: flex;
|
||
}
|
||
|
||
/* 活动已结束按钮样式 - 灰色 */
|
||
.activity-finished-btn {
|
||
background-color: #999999 !important;
|
||
border-color: #999999 !important;
|
||
color: #ffffff !important;
|
||
}
|
||
|
||
.activity-finished-btn:hover {
|
||
background-color: #808080 !important;
|
||
border-color: #808080 !important;
|
||
}
|
||
|
||
/* 活动响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.activity-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.activity-score-badge {
|
||
font-size: 1vw;
|
||
padding: 0.3vw 0.6vw;
|
||
}
|
||
|
||
.activity-title {
|
||
font-size: 1.2vw;
|
||
}
|
||
|
||
.activity-meta-item {
|
||
font-size: 1vw;
|
||
}
|
||
|
||
.intro-title {
|
||
font-size: 1.1vw;
|
||
}
|
||
|
||
.intro-content {
|
||
font-size: 1vw;
|
||
}
|
||
|
||
.activity-status-text {
|
||
font-size: 1vw;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.activity-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 2vw;
|
||
}
|
||
|
||
.activity-card {
|
||
padding: 0;
|
||
/* 保持无内边距,让图片占满顶部 */
|
||
min-height: 30vh;
|
||
}
|
||
|
||
/* 手机端活动卡片图片 */
|
||
.activity-card-image {
|
||
height: 12vh;
|
||
/* 手机端增加图片高度 */
|
||
}
|
||
|
||
/* 手机端活动内容区域添加内边距 */
|
||
.activity-title,
|
||
.activity-details,
|
||
.activity-intro {
|
||
padding-left: 3vw;
|
||
padding-right: 3vw;
|
||
}
|
||
|
||
.activity-footer {
|
||
padding: 0 3vw 3vw;
|
||
}
|
||
|
||
.activity-score-badge {
|
||
font-size: 2.5vw;
|
||
padding: 1vw 2vw;
|
||
top: 2vw;
|
||
right: 2vw;
|
||
}
|
||
|
||
.activity-title {
|
||
font-size: 3.5vw;
|
||
margin-bottom: 2vh;
|
||
}
|
||
|
||
.activity-meta-item {
|
||
font-size: 2.8vw;
|
||
margin-bottom: 1vh;
|
||
}
|
||
|
||
.intro-title {
|
||
font-size: 3vw;
|
||
margin-bottom: 1vh;
|
||
}
|
||
|
||
.intro-content {
|
||
font-size: 2.8vw;
|
||
margin-bottom: 2vh;
|
||
}
|
||
|
||
.activity-status-text {
|
||
font-size: 2.8vw;
|
||
}
|
||
}
|
||
|
||
/* 消息页面样式 */
|
||
.message-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.message-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
/* 20px转换为vh */
|
||
padding: 10px 0;
|
||
border-bottom: 1.5px solid #e6e6e6;
|
||
}
|
||
|
||
.message-tabs {
|
||
display: flex;
|
||
gap: 2.08vw;
|
||
/* 40px转换为vw */
|
||
}
|
||
|
||
.message-tab-item {
|
||
font-size: 0.94vw;
|
||
/* 18px转换为vw */
|
||
color: #666;
|
||
cursor: pointer;
|
||
padding: 0.52vh 0;
|
||
/* 10px转换为vh */
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.52vw;
|
||
/* 10px转换为vw */
|
||
}
|
||
|
||
.message-tab-item.active {
|
||
color: #1890ff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 移除蓝色下划线
|
||
.message-tab-item.active::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 0.1vh;
|
||
background-color: #1890ff;
|
||
}
|
||
*/
|
||
|
||
.message-count {
|
||
position: absolute;
|
||
top: 0;
|
||
right: -30%;
|
||
background: #ff4d4f;
|
||
color: white;
|
||
font-size: 0.63vw;
|
||
/* 12px转换为vw */
|
||
width: 14px;
|
||
height: 14px;
|
||
/* 2px 6px转换 */
|
||
border-radius: 50%;
|
||
/* 10px转换为vw */
|
||
/* 20px转换为vw */
|
||
text-align: center;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.message-actions {
|
||
display: flex;
|
||
gap: 1.04vw;
|
||
align-items: center;
|
||
/* 20px转换为vw */
|
||
}
|
||
|
||
.action-link {
|
||
/* width: 2.92vw; */
|
||
/* 56px转换为vw */
|
||
/* height: 1.04vh; */
|
||
/* 20px转换为vh */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #000000;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
/* 使用flexbox确保垂直居中 */
|
||
}
|
||
|
||
.action-link:hover {
|
||
color: #000000;
|
||
/* 悬停时保持黑色 */
|
||
text-decoration: none;
|
||
/* 移除下划线 */
|
||
}
|
||
|
||
.action-link.disabled {
|
||
opacity: 0.6;
|
||
cursor: not-allowed;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.action-link.active {
|
||
color: #1890ff;
|
||
font-weight: 500;
|
||
}
|
||
/* 操作图标样式 */
|
||
.action-icon {
|
||
width: 0.94vw;
|
||
/* 18px转换为vw */
|
||
height: 0.94vw;
|
||
/* 18px转换为vw */
|
||
margin-right: 0.26vw;
|
||
/* 5px转换为vw */
|
||
vertical-align: middle;
|
||
display: inline-block;
|
||
position: relative;
|
||
top: -0.05vw;
|
||
/* 微调垂直位置 */
|
||
}
|
||
|
||
.message-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.04vh;
|
||
/* 20px转换为vh,消息项之间的间距 */
|
||
}
|
||
|
||
.message-list-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1vh;
|
||
}
|
||
.message-item {
|
||
position: relative;
|
||
background: white;
|
||
border: 1px solid #D8D8D8;
|
||
/* 8px转换为vw */
|
||
transition: border-color 0.3s ease;
|
||
}
|
||
|
||
.message-item:hover {
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
/* 右上角未读标识 */
|
||
.unread-indicator-top-right {
|
||
position: absolute;
|
||
top: 0.52vh;
|
||
/* 10px转换为vh */
|
||
right: 0.52vw;
|
||
/* 10px转换为vw */
|
||
width: 0.42vw;
|
||
/* 8px转换为vw */
|
||
height: 0.42vw;
|
||
/* 8px转换为vw */
|
||
background: #ff4d4f;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.message-main {
|
||
padding: 1.04vh 1.04vw;
|
||
/* 20px转换 */
|
||
/* margin-left: 1.04vw; */
|
||
/* 为未读标识留出空间 */
|
||
}
|
||
|
||
.message-user {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.73vw;
|
||
/* 14px转换为vw */
|
||
margin-bottom: 0.73vh;
|
||
/* 14px转换为vh */
|
||
width: 100%;
|
||
/* 确保占满宽度 */
|
||
position: relative;
|
||
}
|
||
|
||
/* 消息头像样式 */
|
||
.image_22 {
|
||
width: 49px;
|
||
/* 42px转换为vw */
|
||
height: 49px;
|
||
/* 42px转换为vw */
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
flex-shrink: 0;
|
||
margin-top: 0.1vh;
|
||
/* 2px转换为vh,微调位置 */
|
||
}
|
||
|
||
.user-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
/* 确保内容不会溢出 */
|
||
}
|
||
|
||
.user-content {
|
||
margin-bottom: 0.31vh;
|
||
/* 6px转换为vh */
|
||
overflow: hidden;
|
||
/* 隐藏溢出内容 */
|
||
}
|
||
|
||
/* 新的消息样式 */
|
||
.user-name {
|
||
font-family: PingFangSC, PingFang SC, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #0388D1;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.action-type {
|
||
font-family: PingFangSC, PingFang SC, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #0388D1;
|
||
line-height: 20px;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
.message-content {
|
||
font-family: PingFangSC, PingFang SC, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #000000;
|
||
line-height: 20px;
|
||
}
|
||
|
||
|
||
|
||
.message-text {
|
||
width: auto;
|
||
/* 自适应宽度 */
|
||
height: auto;
|
||
/* 自适应高度 */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #0388D1;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
display: inline;
|
||
/* 改为inline,让文字在一行显示 */
|
||
white-space: nowrap;
|
||
/* 不换行 */
|
||
overflow: hidden;
|
||
/* 隐藏溢出 */
|
||
text-overflow: ellipsis;
|
||
/* 超出显示省略号 */
|
||
max-width: 100%;
|
||
/* 最大宽度为容器宽度 */
|
||
}
|
||
|
||
/* 课程信息容器 */
|
||
.course-info-container {
|
||
width: 100%;
|
||
/* 942px转换为vw */
|
||
/* height: 5.21vh; */
|
||
padding: 0.52vh 0.57vw;
|
||
/* 100px转换为vh,进一步增加高度 */
|
||
background: #F5F8FB;
|
||
background-size: 100% 100%;
|
||
margin-top: 0.26vh;
|
||
/* 5px转换为vh */
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
/* 垂直居中 */
|
||
justify-content: flex-start;
|
||
/* 水平左对齐 */
|
||
padding: 1.04vh 0.57vw;
|
||
/* 20px 11px转换为vh/vw,增加上下内边距 */
|
||
}
|
||
|
||
.course-label {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: #999999;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.course-name {
|
||
font-family: PingFangSC, PingFang SC, -apple-system, BlinkMacSystemFont, sans-serif;
|
||
font-weight: 400;
|
||
font-size: 14px;
|
||
color: #608297;
|
||
line-height: 20px;
|
||
}
|
||
|
||
.message-time {
|
||
position: absolute;
|
||
right: 20px;
|
||
top: 0.57vw;
|
||
/* 90px转换为vw */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
font-size: 0.63vw;
|
||
/* 12px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: rgba(153, 153, 153, 1);
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
margin-left: auto;
|
||
flex-shrink: 0;
|
||
align-self: flex-start;
|
||
margin-top: 0.05vh;
|
||
/* 1px转换为vh,微调位置 */
|
||
/* 30px转换为vh,让时间下移 */
|
||
}
|
||
|
||
.message-actions-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
margin-top: 1.56vh;
|
||
/* 30px转换为vh,增加距离上方的距离 */
|
||
margin-bottom: 1.09vh;
|
||
/* 21px转换为vh */
|
||
margin-left: 0.36vw;
|
||
/* 7px转换为vw */
|
||
position: relative;
|
||
width: 100%;
|
||
}
|
||
|
||
.message-action-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* 确保内容水平居中 */
|
||
gap: 0;
|
||
/* 移除图标和文字间距,让它们紧贴 */
|
||
padding: 0;
|
||
border: none;
|
||
background: none;
|
||
width: auto;
|
||
/* 自适应宽度 */
|
||
height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
color: #999999;
|
||
line-height: 1.04vh;
|
||
/* 20px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
white-space: nowrap;
|
||
/* 防止文字换行 */
|
||
}
|
||
|
||
/* 回复按钮位置 */
|
||
.reply-btn {
|
||
margin-left: 2.92vw;
|
||
/* 56px转换为vw */
|
||
}
|
||
|
||
/* 删除按钮位置 */
|
||
.delete-btn {
|
||
margin-left: 0.78vw;
|
||
/* 15px转换为vw,减小与回复按钮的间距 */
|
||
}
|
||
|
||
/* 举报按钮位置 - 在最右边 */
|
||
.report-btn {
|
||
position: absolute;
|
||
right: 7px;
|
||
}
|
||
|
||
/* 消息操作按钮中的图标样式 */
|
||
.message-action-btn .action-icon {
|
||
width: 0.73vw;
|
||
/* 14px转换为vw */
|
||
height: 0.73vw;
|
||
/* 14px转换为vw */
|
||
margin-right: 0.26vw;
|
||
/* 5px转换为vw */
|
||
vertical-align: middle;
|
||
display: inline-block;
|
||
position: relative;
|
||
top: -0.03vw;
|
||
/* 微调垂直位置 */
|
||
}
|
||
|
||
/* 点赞消息样式 */
|
||
.like-message-item {
|
||
position: relative;
|
||
background: white;
|
||
border: 1px solid #D8D8D8;
|
||
transition: border-color 0.3s ease;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.like-message-item:hover {
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
.like-message-main {
|
||
padding: 1.04vh 1.04vw;
|
||
}
|
||
|
||
.like-message-user {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.73vw;
|
||
margin-bottom: 0.73vh;
|
||
}
|
||
|
||
.like-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.like-content {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.26vw;
|
||
margin-bottom: 0.52vh;
|
||
}
|
||
|
||
.like-content-preview {
|
||
margin-top: 0.52vh;
|
||
padding: 0.52vh 0.73vw;
|
||
background-color: #f5f5f5;
|
||
border-radius: 4px;
|
||
border-left: 3px solid #1890ff;
|
||
}
|
||
|
||
.content-preview {
|
||
font-size: 0.73vw;
|
||
color: #666;
|
||
font-style: italic;
|
||
}
|
||
|
||
/* 加载状态样式 */
|
||
.loading-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 40px 20px;
|
||
background: white;
|
||
border: 1.5px solid #D8D8D8;
|
||
border-radius: 0;
|
||
margin-bottom: 1.04vh;
|
||
}
|
||
|
||
.loading-text {
|
||
color: #666;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 空状态样式 */
|
||
.empty-state {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
padding: 40px 20px;
|
||
background: white;
|
||
border: 1.5px solid #D8D8D8;
|
||
border-radius: 0;
|
||
margin-bottom: 1.04vh;
|
||
}
|
||
|
||
.empty-text {
|
||
color: #999;
|
||
font-size: 14px;
|
||
}
|
||
|
||
/* 消息详情容器样式 */
|
||
.message-detail-container {
|
||
background: white;
|
||
border: 1.5px solid #D8D8D8;
|
||
border-radius: 0;
|
||
margin-bottom: 1.04vh;
|
||
min-height: 200px;
|
||
}
|
||
|
||
.message-detail-header {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 16px 20px;
|
||
border-bottom: 1px solid #e6e6e6;
|
||
background: #f8f9fa;
|
||
gap: 12px;
|
||
}
|
||
|
||
.back-btn {
|
||
background: none;
|
||
border: none;
|
||
color: #1890ff;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.back-btn:hover {
|
||
background: #e6f7ff;
|
||
}
|
||
|
||
.detail-title {
|
||
margin: 0;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.message-detail-content {
|
||
padding: 20px;
|
||
}
|
||
|
||
.message-detail-info {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 16px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.message-detail-icon {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.message-detail-text {
|
||
flex: 1;
|
||
}
|
||
|
||
.message-detail-title {
|
||
margin: 0 0 8px 0;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.message-detail-time {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.message-detail-body {
|
||
padding: 16px;
|
||
background: #f8f9fa;
|
||
border-radius: 2px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.message-detail-subtitle {
|
||
font-size: 14px;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.message-detail-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
}
|
||
/* 系统消息样式 */
|
||
.system-message-item {
|
||
position: relative;
|
||
background: white;
|
||
border: 1.5px solid #D8D8D8;
|
||
border-radius: 0;
|
||
transition: border-color 0.3s ease;
|
||
height: auto;
|
||
min-height: 90px;
|
||
/* 132px转换为vh */
|
||
margin-bottom: 1.04vh;
|
||
display: flex;
|
||
align-items: center;
|
||
/* 20px转换为vh */
|
||
}
|
||
|
||
.system-message-item:hover {
|
||
border-color: #1890ff;
|
||
}
|
||
|
||
.system-message-main {
|
||
padding: 10px 0;
|
||
/* 24px 20px转换 */
|
||
margin-left: 15px;
|
||
/* 30px转换为vw */
|
||
width: 100%;
|
||
}
|
||
|
||
.system-message-user {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
gap: 0.73vw;
|
||
/* 14px转换为vw */
|
||
margin-bottom: 0.73vh;
|
||
/* 14px转换为vh */
|
||
width: 100%;
|
||
position: relative;
|
||
/* 为绝对定位的时间提供参考 */
|
||
}
|
||
|
||
.system-icon {
|
||
width: 45px;
|
||
/* 42px转换为vw */
|
||
height: 45px;
|
||
/* 42px转换为vw */
|
||
background: rgba(3, 136, 209, 1);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
margin-top: 0.1vh;
|
||
background-image: url('/images/profile/root.png');
|
||
background-size: 100% 100%;
|
||
}
|
||
|
||
.system-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.system-title {
|
||
font-size: 16px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: #333;
|
||
line-height: 1.5;
|
||
/* 使用相对行高,确保文字不错位 */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
margin-bottom: 0.52vh;
|
||
/* 10px转换为vh */
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.system-subtitle-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
}
|
||
|
||
.system-subtitle {
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: #999;
|
||
line-height: 1.5;
|
||
/* 使用相对行高,确保文字不错位 */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
/* flex: 1; */
|
||
/* 20px转换为vw,与查看详情保持间距 */
|
||
}
|
||
|
||
.system-detail-link {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: rgba(3, 136, 209, 1);
|
||
line-height: 1.5;
|
||
/* 使用相对行高,确保文字不错位 */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
cursor: pointer;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.system-detail-link:hover {
|
||
text-decoration: underline;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.system-time {
|
||
padding-right: 20px;
|
||
/* 90px转换为vw */
|
||
font-size: 12px;
|
||
/* 12px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: rgba(153, 153, 153, 1);
|
||
text-align: left;
|
||
white-space: nowrap;
|
||
line-height: 1.5;
|
||
/* 使用相对行高,确保文字不错位 */
|
||
margin-left: auto;
|
||
/* 推到右边 */
|
||
flex-shrink: 0;
|
||
align-self: flex-start;
|
||
}
|
||
|
||
.message-action-btn:hover {
|
||
/* 移除背景色,只保持透明 */
|
||
background: none;
|
||
color: #999999;
|
||
/* 保持原色不变 */
|
||
}
|
||
|
||
.message-action-btn.reply-btn:hover {
|
||
background: none;
|
||
color: #999999;
|
||
/* 保持原色不变 */
|
||
}
|
||
|
||
.message-action-btn.delete-btn:hover {
|
||
background: none;
|
||
color: #999999;
|
||
/* 保持原色不变 */
|
||
}
|
||
|
||
.message-action-btn.report-btn:hover {
|
||
background: none;
|
||
color: #999999;
|
||
/* 保持原色不变 */
|
||
}
|
||
|
||
.reply-section {
|
||
margin-top: 0.73vh;
|
||
}
|
||
|
||
.reply-input-container {
|
||
padding: 0 0 0 3vw;
|
||
}
|
||
|
||
.reply-textarea {
|
||
width: 100%;
|
||
min-height: 3.91vh;
|
||
/* 75px转换为vh */
|
||
border: 1.5px solid #D8D8D8;
|
||
/* 6px转换为vw */
|
||
padding: 0.52vh 0.52vw;
|
||
/* 10px转换 */
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
line-height: 1.5;
|
||
resize: vertical;
|
||
font-family: inherit;
|
||
|
||
}
|
||
|
||
.reply-textarea:focus {
|
||
outline: none;
|
||
border-color: #1890ff;
|
||
box-shadow: 0 0 0 0.1vw rgba(24, 144, 255, 0.2);
|
||
}
|
||
|
||
.reply-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 0.52vw;
|
||
/* 10px转换为vw */
|
||
margin-top: 0.52vh;
|
||
/* 10px转换为vh */
|
||
}
|
||
|
||
.cancel-btn,
|
||
.send-btn {
|
||
padding: 0.31vh 0.83vw;
|
||
/* 6px 16px转换 */
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 0.31vw;
|
||
/* 6px转换为vw */
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.cancel-btn {
|
||
background: white;
|
||
color: #666;
|
||
}
|
||
|
||
.cancel-btn:hover {
|
||
border-color: #40a9ff;
|
||
color: #40a9ff;
|
||
}
|
||
|
||
.send-btn {
|
||
width: 80px;
|
||
height: 28px;
|
||
background: #0288D1;
|
||
color: white;
|
||
border-color: #1890ff;
|
||
border-radius: 0;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.send-btn:hover {
|
||
background: #40a9ff;
|
||
border-color: #40a9ff;
|
||
}
|
||
|
||
.draftbox {
|
||
margin-left: auto;
|
||
cursor: pointer;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.draftbox img {
|
||
width: 16px;
|
||
height: 16px;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.draftbox span {
|
||
font-size: 16px;
|
||
color: #000;
|
||
}
|
||
|
||
.draftbox:hover {
|
||
color: #40a9ff;
|
||
}
|
||
|
||
.breadcrumb-wrapper {
|
||
padding: 5px 0;
|
||
}
|
||
|
||
.breadcrumb-wrapper .text_15 {
|
||
font-size: 13px;
|
||
}
|
||
|
||
.homework {
|
||
color: #A2A2A2;
|
||
}
|
||
|
||
/* 消息页面响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.message-header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 1vh;
|
||
}
|
||
|
||
.message-tabs {
|
||
gap: 3vw;
|
||
}
|
||
|
||
.message-tab-item {
|
||
font-size: 1.2vw;
|
||
}
|
||
}
|
||
|
||
/* 消息页面响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.message-header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 1vh;
|
||
}
|
||
|
||
.message-tabs {
|
||
gap: 3vw;
|
||
}
|
||
|
||
.message-tab-item {
|
||
font-size: 1.2vw;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 3vw;
|
||
height: 3vw;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 1.1vw;
|
||
}
|
||
|
||
.message-text {
|
||
font-size: 1.1vw;
|
||
width: auto;
|
||
/* 响应式下自适应宽度 */
|
||
height: auto;
|
||
/* 响应式下自适应高度 */
|
||
line-height: 1.5;
|
||
/* 响应式下调整行高 */
|
||
white-space: nowrap;
|
||
/* 保持不换行 */
|
||
overflow: hidden;
|
||
/* 隐藏溢出 */
|
||
text-overflow: ellipsis;
|
||
/* 超出显示省略号 */
|
||
}
|
||
|
||
.course-label,
|
||
.course-name,
|
||
.message-time {
|
||
font-size: 1vw;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.message-header {
|
||
padding: 0 3vw;
|
||
}
|
||
|
||
.message-tabs {
|
||
gap: 5vw;
|
||
}
|
||
|
||
.message-tab-item {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.message-count {
|
||
font-size: 2.5vw;
|
||
padding: 0.5vh 1.5vw;
|
||
}
|
||
|
||
.action-link {
|
||
font-size: 2.8vw;
|
||
}
|
||
|
||
.message-main {
|
||
padding: 3vh 3vw;
|
||
margin-left: 2vw;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 8vw;
|
||
height: 8vw;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 3.2vw;
|
||
}
|
||
|
||
.message-text {
|
||
font-size: 3.2vw;
|
||
width: auto;
|
||
/* 手机端自适应宽度 */
|
||
height: auto;
|
||
/* 手机端自适应高度 */
|
||
line-height: 1.5;
|
||
/* 手机端调整行高 */
|
||
white-space: nowrap;
|
||
/* 保持不换行 */
|
||
overflow: hidden;
|
||
/* 隐藏溢出 */
|
||
text-overflow: ellipsis;
|
||
/* 超出显示省略号 */
|
||
}
|
||
|
||
.course-label,
|
||
.course-name,
|
||
.message-time {
|
||
font-size: 2.8vw;
|
||
}
|
||
|
||
/* 手机端课程信息容器调整 */
|
||
.course-info-container {
|
||
width: 90vw;
|
||
height: auto;
|
||
padding: 1vh 3vw;
|
||
}
|
||
|
||
/* 手机端系统消息调整 */
|
||
.system-message-item {
|
||
min-height: 15vh;
|
||
}
|
||
|
||
.system-message-main {
|
||
padding: 3vh 3vw;
|
||
margin-left: 2vw;
|
||
}
|
||
|
||
.system-icon {
|
||
width: 8vw;
|
||
height: 8vw;
|
||
}
|
||
|
||
.system-title,
|
||
.system-subtitle,
|
||
.system-detail-link,
|
||
.system-time {
|
||
font-size: 2.8vw;
|
||
}
|
||
|
||
.action-btn {
|
||
font-size: 2.8vw;
|
||
padding: 1vh 2vw;
|
||
}
|
||
|
||
.reply-textarea {
|
||
font-size: 3vw;
|
||
padding: 2vh 2vw;
|
||
}
|
||
|
||
.cancel-btn,
|
||
.send-btn {
|
||
font-size: 2.8vw;
|
||
padding: 1.5vh 3vw;
|
||
}
|
||
}
|
||
|
||
/* 我的下载页面样式 */
|
||
.download-content {
|
||
background: white;
|
||
border-radius: 0.42vw;
|
||
/* 8px转换为vw */
|
||
padding: 0 0 1.04vh 0;
|
||
/* 底部添加20px内边距,确保内容不被截断 */
|
||
margin: 1.04vh 0;
|
||
/* 20px转换为vh */
|
||
overflow: visible;
|
||
/* 确保内容完全可见 */
|
||
}
|
||
|
||
/* 面包屑控制区域样式 */
|
||
.breadcrumb-controls {
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
padding-top: 1.56vh;
|
||
/* 30px 40px转换 */
|
||
}
|
||
|
||
/* 面包屑导航样式 */
|
||
.breadcrumb-nav {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.breadcrumb-text {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #666;
|
||
cursor: pointer;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
.breadcrumb-text:hover {
|
||
color: #1890ff;
|
||
}
|
||
|
||
.breadcrumb-current {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 子目录中的文件项样式调整 */
|
||
.download-content.in-subdirectory .file-item .file-icon {
|
||
margin-left: 0 !important;
|
||
/* 子目录中移除左边距 */
|
||
}
|
||
|
||
.download-content.in-subdirectory .file-item .file-name {
|
||
margin-top: 1.56vh !important;
|
||
/* 子目录中文件名下移30px */
|
||
}
|
||
|
||
/* 子目录特有样式 */
|
||
.subdirectory-item .file-icon {
|
||
margin-left: 0 !important;
|
||
/* 移除左边距 */
|
||
}
|
||
|
||
.subdirectory-item .file-name {
|
||
margin-top: 2.04vh !important;
|
||
/* 20px转换为vh,下移文件名 */
|
||
}
|
||
|
||
/* 证书网格特有样式 - 一行显示3个 */
|
||
.certificate-grid {
|
||
grid-template-columns: repeat(3, 1fr) !important;
|
||
/* 固定3列 */
|
||
gap: 1.5vw !important;
|
||
/* 减少间距,给证书更多空间 */
|
||
justify-content: center;
|
||
width: 100% !important;
|
||
/* 确保占满容器宽度 */
|
||
}
|
||
|
||
.certificate-grid .file-item {
|
||
width: 100% !important;
|
||
/* 占满网格单元格宽度 */
|
||
height: auto !important;
|
||
/* 高度自适应内容 */
|
||
min-height: 15vh !important;
|
||
/* 增加最小高度给证书更多空间 */
|
||
background: white !important;
|
||
/* 证书背景色改为白色 */
|
||
padding: 2.6vh 2.6vw !important;
|
||
/* 50px转换为vw/vh,上下左右50px间距 */
|
||
display: flex !important;
|
||
/* 使用flex布局 */
|
||
flex-direction: column !important;
|
||
/* 垂直排列 */
|
||
align-items: center !important;
|
||
/* 水平居中 */
|
||
justify-content: center !important;
|
||
/* 垂直居中 */
|
||
}
|
||
|
||
.certificate-grid .file-item .file-icon {
|
||
width: 100% !important;
|
||
/* 占满容器宽度 */
|
||
height: auto !important;
|
||
/* 高度自适应 */
|
||
max-width: 20vw !important;
|
||
/* 增大最大宽度限制 */
|
||
margin: 0 auto 2.6vh auto !important;
|
||
/* 居中显示,底部留50px间距(2.6vh) */
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
}
|
||
|
||
.certificate-grid .file-item .folder-icon {
|
||
width: 100% !important;
|
||
/* 图片占满图标容器 */
|
||
height: auto !important;
|
||
/* 高度自适应保持比例 */
|
||
max-width: 100% !important;
|
||
/* 最大宽度不超过容器 */
|
||
min-height: 8vh !important;
|
||
/* 设置最小高度确保图片足够大 */
|
||
object-fit: contain !important;
|
||
/* 保持图片比例,完整显示 */
|
||
}
|
||
|
||
.certificate-grid .file-item .file-name {
|
||
margin-top: 0.5vh !important;
|
||
/* 证书名字与图片间距约25px */
|
||
text-align: center !important;
|
||
/* 文字居中 */
|
||
padding: 0 1.3vw !important;
|
||
/* 左右内边距约25px */
|
||
}
|
||
|
||
/* 作业网格特有样式 - 一行显示6个,参考图片布局 */
|
||
.homework-grid {
|
||
grid-template-columns: repeat(6, 1fr) !important;
|
||
/* 固定6列 */
|
||
gap: 1vw !important;
|
||
/* 减少间距 */
|
||
justify-content: center;
|
||
width: 100% !important;
|
||
/* 确保占满容器宽度 */
|
||
}
|
||
|
||
.homework-grid .file-item {
|
||
width: 100% !important;
|
||
/* 占满网格单元格宽度 */
|
||
height: auto !important;
|
||
/* 高度自适应内容 */
|
||
min-height: 201px !important;
|
||
/* 设置最小高度 */
|
||
background: white !important;
|
||
/* 白色背景 */
|
||
padding: 1.5vh 1vw !important;
|
||
/* 适当的内边距 */
|
||
display: flex !important;
|
||
/* 使用flex布局 */
|
||
flex-direction: column !important;
|
||
/* 垂直排列 */
|
||
align-items: center !important;
|
||
/* 水平居中 */
|
||
justify-content: center !important;
|
||
/* 垂直居中 */
|
||
border: 1.5px solid #D8D8D8 !important;
|
||
/* 添加边框 */
|
||
}
|
||
|
||
.homework-grid .file-item .file-icon {
|
||
/* 高度自适应 */
|
||
width: 64px;
|
||
height: 64px;
|
||
/* 限制最大宽度 */
|
||
margin: 0 auto 1vh auto !important;
|
||
/* 居中显示,底部留间距 */
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center !important;
|
||
}
|
||
|
||
.homework-grid .file-item .folder-icon {
|
||
width: 100% !important;
|
||
/* 图片占满图标容器 */
|
||
height: auto !important;
|
||
/* 高度自适应保持比例 */
|
||
max-width: 100% !important;
|
||
/* 最大宽度不超过容器 */
|
||
min-height: 4vh !important;
|
||
/* 设置最小高度 */
|
||
object-fit: contain !important;
|
||
/* 保持图片比例,完整显示 */
|
||
}
|
||
|
||
.homework-grid .file-item .file-name {
|
||
margin-top: 20px !important;
|
||
/* 文件名与图片间距 */
|
||
text-align: center !important;
|
||
/* 文字居中 */
|
||
padding: 0 0.5vw !important;
|
||
/* 左右内边距 */
|
||
font-size: 14px !important;
|
||
/* 较小的字体 */
|
||
color: #333 !important;
|
||
/* 文字颜色 */
|
||
}
|
||
|
||
.download-header {
|
||
padding: 0 0 1vh 0;
|
||
/* 30px 40px转换 */
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.download-tabs {
|
||
display: flex;
|
||
gap: 2.08vw;
|
||
/* 40px转换为vw */
|
||
}
|
||
|
||
.download-tab-item {
|
||
font-size: 0.83vw;
|
||
/* 16px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
font-weight: normal;
|
||
color: #666;
|
||
cursor: pointer;
|
||
padding: 0.52vh 0;
|
||
/* 10px转换为vh */
|
||
border-bottom: 2px solid transparent;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.download-tab-item.active {
|
||
color: #1890ff;
|
||
font-weight: 500;
|
||
/* 移除蓝色下划线 */
|
||
}
|
||
|
||
.download-tab-item:hover {
|
||
color: #1890ff;
|
||
}
|
||
|
||
/* 筛选和操作区域 */
|
||
.download-controls {
|
||
height: 32px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 30px;
|
||
margin-bottom: 10px;
|
||
/* padding: 1.56vh 2.08vw; */
|
||
/* 30px 40px转换 */
|
||
/* 移除下方边框线条 */
|
||
}
|
||
|
||
.download-filters {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 2.08vw;
|
||
/* 40px转换为vw */
|
||
}
|
||
|
||
.filter-group,
|
||
.search-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.52vw;
|
||
/* 10px转换为vw */
|
||
}
|
||
|
||
.filter-label,
|
||
.search-label {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #333;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.filter-select {
|
||
width: 9.21vw;
|
||
/* 100px转换为vw */
|
||
height: 32px;
|
||
/* 80px转换为vh,增加一倍高度 */
|
||
padding: 0.52vh 0.52vw;
|
||
/* 10px转换,增加内边距 */
|
||
border: 1px solid #d9d9d9;
|
||
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #333;
|
||
background: white;
|
||
}
|
||
|
||
.search-input-container {
|
||
display: flex;
|
||
align-items: center;
|
||
position: relative;
|
||
}
|
||
|
||
.search-input {
|
||
width: 10.42vw;
|
||
/* 200px转换为vw */
|
||
height: 32px;
|
||
/* 80px转换为vh,增加一倍高度 */
|
||
padding: 0.26vh 2.08vw 0.26vh 0.52vw;
|
||
/* 5px 40px 5px 10px转换,右侧留空给按钮 */
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 0;
|
||
/* 移除圆角,变成直角 */
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #333;
|
||
background: white;
|
||
}
|
||
|
||
.search-btn {
|
||
position: absolute;
|
||
right: 20px;
|
||
/* 5px转换为vw */
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 16px;
|
||
/* 30px转换为vw */
|
||
height: 16px;
|
||
/* 30px转换为vh */
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.search-icon {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.download-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1.04vw;
|
||
/* 20px转换为vw */
|
||
}
|
||
|
||
.file-count {
|
||
/* width: 5.83vw; */
|
||
/* 112px转换为vw */
|
||
/* height: 0.73vh; */
|
||
/* 14px转换为vh */
|
||
font-family: AppleSystemUIFont, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
font-size: 10px;
|
||
/* 10px转换为vw */
|
||
color: #999999;
|
||
line-height: 0.73vh;
|
||
/* 14px转换为vh */
|
||
text-align: left;
|
||
font-style: normal;
|
||
text-transform: none;
|
||
}
|
||
|
||
.new-folder-btn {
|
||
width: 109px;
|
||
height: 31px;
|
||
background: #0288D1;
|
||
/* 10px 20px转换 */
|
||
color: white;
|
||
border: none;
|
||
/* 4px转换为vw */
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.new-folder-btn:hover {
|
||
background: #40a9ff;
|
||
}
|
||
|
||
/* 文件网格样式 */
|
||
.files-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, 9.17vw);
|
||
/* 自适应列数,每列157px */
|
||
gap: 20px;
|
||
/* 30px转换为vw,增加间距 */
|
||
/* padding: 2.08vh 2.08vw 3.13vh 2.08vw; 上40px 左右40px 下60px,确保底部边框可见 */
|
||
padding: 20px 0;
|
||
justify-content: start;
|
||
overflow: visible;
|
||
/* 确保内容不被截断 */
|
||
}
|
||
|
||
.file-item {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
width: 157px;
|
||
height: 201px;
|
||
/* 157px转换为vw */
|
||
min-height: 10.47vh;
|
||
/* 最小高度201px,允许自适应增长 */
|
||
padding: 1.04vh 0.52vw;
|
||
/* 上下20px 左右10px */
|
||
border: 1px solid #D8D8D8 !important;
|
||
/* 强制显示边框 */
|
||
border-radius: 0;
|
||
/* 移除圆角,变成直角 */
|
||
background: white;
|
||
transition: all 0.3s ease;
|
||
cursor: pointer;
|
||
box-sizing: border-box;
|
||
margin-bottom: 0.26vh;
|
||
/* 2px转换为vh,确保底部边框可见 */
|
||
}
|
||
|
||
.file-item:hover {
|
||
background: #f5f5f5;
|
||
border-color: #bfbfbf;
|
||
}
|
||
|
||
.file-menu {
|
||
position: absolute;
|
||
top: 0.52vh;
|
||
/* 10px转换为vh */
|
||
right: 0.52vw;
|
||
/* 10px转换为vw */
|
||
z-index: 10;
|
||
}
|
||
|
||
.file-menu-btn {
|
||
margin-top: 10px;
|
||
width: 13px;
|
||
height: 13px;
|
||
/* 24px转换为vh */
|
||
border: none;
|
||
background: none;
|
||
/* 移除背景 */
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 0.83vw;
|
||
/* 16px转换为vw */
|
||
color: #666;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.file-menu-btn:hover {
|
||
background: none;
|
||
/* 移除悬停背景 */
|
||
}
|
||
|
||
.more-icon {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
}
|
||
|
||
.file-menu-dropdown {
|
||
position: absolute;
|
||
top: 100%;
|
||
right: 0;
|
||
background: white;
|
||
border: 1px solid #d9d9d9;
|
||
border-radius: 0.21vw;
|
||
/* 4px转换为vw */
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
z-index: 20;
|
||
min-width: 4.17vw;
|
||
/* 80px转换为vw */
|
||
}
|
||
|
||
.menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.21vw;
|
||
/* 4px转换为vw,减小图标和文字间距 */
|
||
padding: 0.52vh 0.73vw;
|
||
/* 10px 14px转换 */
|
||
font-size: 14px;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #000;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
white-space: nowrap;
|
||
/* 确保文字水平展示,不换行 */
|
||
}
|
||
|
||
.menu-icon {
|
||
width: 18px;
|
||
/* 84px转换为vw,增加一倍 */
|
||
height: 18px;
|
||
/* 24px转换为vh,增加一倍 */
|
||
object-fit: contain;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.menu-item:hover {
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.menu-item:first-child {
|
||
border-radius: 0.21vw 0.21vw 0 0;
|
||
/* 4px转换为vw */
|
||
}
|
||
|
||
.menu-item:last-child {
|
||
border-radius: 0 0 0.21vw 0.21vw;
|
||
/* 4px转换为vw */
|
||
}
|
||
|
||
.file-icon {
|
||
width: 131px;
|
||
/* 100px转换为vw */
|
||
height: 131px;
|
||
/* 100px转换为vw */
|
||
margin-left: 0.5vw;
|
||
margin-top: 1.5vh;
|
||
/* 30px转换为vh,增加顶部间距,图片下移 */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.folder-icon {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: contain;
|
||
max-width: 100%;
|
||
max-height: 100%;
|
||
}
|
||
|
||
.folder-icon-css {
|
||
font-size: 2.5vw;
|
||
/* 48px转换为vw */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 0.73vw;
|
||
/* 14px转换为vw */
|
||
font-family: Helvetica, 'Microsoft YaHei', Arial, sans-serif;
|
||
color: #333;
|
||
text-align: center;
|
||
word-break: break-all;
|
||
line-height: 1.2;
|
||
margin-top: -0.26vh;
|
||
/* 5px转换为vh,减小与图标的间距,文件名上移 */
|
||
margin-bottom: 0.52vh;
|
||
/* 10px转换为vh,底部间距,确保不贴边框 */
|
||
padding: 0 0.26vw;
|
||
/* 左右5px内边距 */
|
||
width: 100%;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.download-tabs {
|
||
gap: 3vw;
|
||
}
|
||
|
||
.download-tab-item {
|
||
font-size: 1vw;
|
||
}
|
||
|
||
.download-controls {
|
||
flex-direction: column;
|
||
gap: 2vh;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.download-filters {
|
||
gap: 3vw;
|
||
}
|
||
|
||
.filter-select {
|
||
width: 8vw;
|
||
font-size: 1vw;
|
||
}
|
||
|
||
.search-input {
|
||
width: 15vw;
|
||
font-size: 1vw;
|
||
}
|
||
|
||
.files-grid {
|
||
grid-template-columns: repeat(auto-fit, 12vw);
|
||
/* 平板端调整文件项宽度 */
|
||
gap: 2vw;
|
||
}
|
||
|
||
|
||
|
||
.file-item {
|
||
width: 12vw;
|
||
height: 18vh;
|
||
/* 增加平板端高度 */
|
||
}
|
||
|
||
.file-icon {
|
||
width: 8vw;
|
||
height: 8vw;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 1vw;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
}
|
||
|
||
@media (max-width: 576px) {
|
||
|
||
.download-content {
|
||
margin: 2vh 1vw;
|
||
border-radius: 1vw;
|
||
}
|
||
|
||
.download-header {
|
||
padding: 3vh 4vw;
|
||
}
|
||
|
||
.download-tabs {
|
||
gap: 6vw;
|
||
}
|
||
|
||
.download-tab-item {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.download-controls {
|
||
padding: 3vh 4vw;
|
||
flex-direction: column;
|
||
gap: 3vh;
|
||
}
|
||
|
||
.download-filters {
|
||
flex-direction: column;
|
||
gap: 2vh;
|
||
width: 100%;
|
||
}
|
||
|
||
.filter-group,
|
||
.search-group {
|
||
width: 100%;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.filter-select {
|
||
width: 20vw;
|
||
font-size: 3.5vw;
|
||
height: 6vh;
|
||
}
|
||
|
||
.search-input {
|
||
width: 50vw;
|
||
font-size: 3.5vw;
|
||
height: 6vh;
|
||
padding: 2vh 8vw 2vh 3vw;
|
||
}
|
||
|
||
.search-btn {
|
||
width: 6vw;
|
||
height: 6vh;
|
||
}
|
||
|
||
.download-actions {
|
||
width: 100%;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.file-count {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.new-folder-btn {
|
||
font-size: 3vw;
|
||
padding: 2vh 4vw;
|
||
}
|
||
|
||
.files-grid {
|
||
grid-template-columns: repeat(auto-fit, 40vw);
|
||
/* 手机端文件项宽度 */
|
||
gap: 4vw;
|
||
padding: 4vh 4vw;
|
||
justify-content: center;
|
||
}
|
||
|
||
|
||
|
||
.file-item {
|
||
width: 40vw;
|
||
height: 30vh;
|
||
/* 增加手机端高度 */
|
||
}
|
||
|
||
.file-icon {
|
||
width: 20vw;
|
||
height: 20vw;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.file-menu-btn {
|
||
width: 6vw;
|
||
height: 6vh;
|
||
font-size: 4vw;
|
||
}
|
||
|
||
.menu-item {
|
||
font-size: 3.5vw;
|
||
padding: 2vh 3vw;
|
||
}
|
||
}
|
||
|
||
/* 包含@的消息高亮样式 */
|
||
.mention-highlight {
|
||
color: #E02424 !important;
|
||
}
|
||
|
||
/* 关注页面样式 */
|
||
.follows-content {
|
||
width: 100%;
|
||
}
|
||
|
||
.follows-list {
|
||
margin-top: 20px;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 1.56vh 1.04vw;
|
||
}
|
||
|
||
.follow-item {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
padding: 2.08vh 0;
|
||
background: white;
|
||
transition: all 0.3s ease;
|
||
text-align: left;
|
||
}
|
||
|
||
.follow-avatar {
|
||
margin-right: 1.04vw;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.avatar-image {
|
||
width: 75px;
|
||
height: 75px;
|
||
border-radius: 50%;
|
||
object-fit: cover;
|
||
border: 2px solid #f0f0f0;
|
||
}
|
||
|
||
.follow-right-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.78vh;
|
||
}
|
||
|
||
.follow-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.26vh;
|
||
}
|
||
|
||
.follow-name {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: #333;
|
||
margin-bottom: 0.26vh;
|
||
}
|
||
|
||
.follow-role {
|
||
font-size: 12px;
|
||
color: #707070;
|
||
margin-bottom: 0.26vh;
|
||
}
|
||
|
||
.follow-description {
|
||
font-size: 0.73vw;
|
||
color: #999;
|
||
line-height: 1.4;
|
||
margin-bottom: 0.26vh;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.follow-visits {
|
||
font-size: 0.68vw;
|
||
color: #1890ff;
|
||
margin-bottom: 0.52vh;
|
||
}
|
||
|
||
.follow-actions {
|
||
display: flex;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.follow-btn {
|
||
width: 80px;
|
||
height: 23px;
|
||
border: none;
|
||
font-size: 10px;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
white-space: nowrap;
|
||
border-radius: 0;
|
||
}
|
||
|
||
/* 取消关注状态 */
|
||
.follow-btn.not-following {
|
||
background: #0288D1;
|
||
color: white;
|
||
}
|
||
|
||
.follow-btn.not-following:hover {
|
||
background: #0277BD;
|
||
}
|
||
|
||
/* 已关注状态 */
|
||
.follow-btn.following {
|
||
background: #F5F8FB;
|
||
color: #999999;
|
||
}
|
||
|
||
.follow-btn.following:hover {
|
||
background: #E8F4FD;
|
||
color: #666666;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.follows-list {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
/* 作业网格响应式 */
|
||
.homework-grid {
|
||
grid-template-columns: repeat(4, 1fr) !important;
|
||
gap: 1.5vw !important;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.follows-list {
|
||
grid-template-columns: 1fr;
|
||
padding: 0 3vw;
|
||
gap: 3vh 0;
|
||
}
|
||
|
||
.follow-item {
|
||
padding: 4vh 3vw;
|
||
border-radius: 1vh;
|
||
}
|
||
|
||
.avatar-image {
|
||
width: 15vw;
|
||
height: 15vw;
|
||
}
|
||
|
||
.follow-name {
|
||
font-size: 4vw;
|
||
}
|
||
|
||
.follow-role {
|
||
font-size: 3.5vw;
|
||
}
|
||
|
||
.follow-description {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.follow-visits {
|
||
font-size: 3vw;
|
||
}
|
||
|
||
.follow-btn {
|
||
padding: 2vh 4vw;
|
||
font-size: 3.5vw;
|
||
border-radius: 1vh;
|
||
}
|
||
|
||
/* 作业网格移动端响应式 */
|
||
.homework-grid {
|
||
grid-template-columns: repeat(3, 1fr) !important;
|
||
gap: 2vw !important;
|
||
}
|
||
|
||
.homework-grid .file-item {
|
||
min-height: 15vh !important;
|
||
padding: 2vh 1.5vw !important;
|
||
}
|
||
|
||
.homework-grid .file-item .file-icon {
|
||
max-width: 20vw !important;
|
||
}
|
||
|
||
.homework-grid .file-item .file-name {
|
||
font-size: 3vw !important;
|
||
padding: 0 1vw !important;
|
||
}
|
||
}
|
||
|
||
/* 文件列表样式 */
|
||
.file-list {
|
||
margin-top: 12px;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12px;
|
||
}
|
||
|
||
.file-list-section .file-item {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #f8f9fa;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 6px;
|
||
padding: 8px 12px;
|
||
min-width: 200px;
|
||
position: relative;
|
||
}
|
||
|
||
.file-list-section .file-icon {
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.file-list-section .file-icon img {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
.file-list-section .file-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.file-list-section .file-name {
|
||
font-size: 12px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
margin-bottom: 2px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.file-list-section .file-size {
|
||
font-size: 11px;
|
||
color: #666;
|
||
}
|
||
|
||
.file-list-section .file-delete {
|
||
background: none;
|
||
border: none;
|
||
cursor: pointer;
|
||
padding: 2px;
|
||
font-size: 14px;
|
||
color: #999;
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.file-delete:hover {
|
||
color: #d03050;
|
||
}
|
||
|
||
/* 自定义弹窗样式 */
|
||
.custom-modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.custom-modal {
|
||
background: #F7F7F7;
|
||
width: 799px;
|
||
max-width: 90vw;
|
||
max-height: 758px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-content {
|
||
padding: 22px;
|
||
width: 100%;
|
||
background: #F7F7F7;
|
||
}
|
||
|
||
/* 弹窗表单标签样式 */
|
||
.n-form-item-label {
|
||
font-size: 18px !important;
|
||
color: #333 !important;
|
||
font-weight: 500;
|
||
}
|
||
|
||
/* 弹窗表单项目间距 */
|
||
.n-form-item {
|
||
margin-bottom: 24px !important;
|
||
}
|
||
|
||
/* 弹窗表单项目内部间距 */
|
||
.n-form-item-blank {
|
||
margin-top: 8px !important;
|
||
}
|
||
|
||
/* 弹窗底部按钮区域 */
|
||
.modal-footer {
|
||
display: flex;
|
||
gap: 12px;
|
||
}
|
||
|
||
/* 自定义表单样式 */
|
||
.form-item {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.form-label {
|
||
display: block;
|
||
font-size: 14px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.required {
|
||
color: #d03050;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
min-height: 50px;
|
||
padding: 12px 16px;
|
||
border: 1px solid #e0e0e0;
|
||
font-size: 14px;
|
||
color: #333;
|
||
background: white;
|
||
transition: border-color 0.2s;
|
||
}
|
||
|
||
.form-input:focus {
|
||
outline: none;
|
||
border-color: #18a058;
|
||
}
|
||
|
||
.form-input::placeholder {
|
||
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> |