feat: 完善课程详情页面;修复课程详情页面打包问题

This commit is contained in:
QDKF 2025-09-07 03:59:41 +08:00
parent e39010c484
commit 21b76b9683
5 changed files with 1335 additions and 2 deletions

View File

@ -1,3 +1,593 @@
<template>
<div>教师课程详情</div>
<div class="teacher-course-detail">
<!-- 顶部图片 -->
<div class="top-image-container" v-if="showTopImage">
<img src="/images/teacher/顶部.png" alt="顶部图片" class="top-image">
<button class="close-button" @click="handleClose">关闭</button>
</div>
<!-- 顶部导航 -->
<div class="top-navigation">
<n-button text @click="goBack" class="back-button">
返回
</n-button>
</div>
<!-- 主要内容区域 -->
<div class="main-content">
<!-- 左侧课程图片 -->
<div class="course-image-section">
<img src="/images/teacher/fj.png" alt="课程封面" class="course-image" />
</div>
<!-- 右侧课程信息 -->
<div class="course-info-section">
<h1 class="course-title">{{ courseInfo.title }}</h1>
<p class="course-description">{{ courseInfo.description }}</p>
<!-- 课程关键信息 -->
<div class="course-metrics">
<div class="metric-item">
<span class="metric-label">课程时间:</span>
<span class="metric-value">{{ courseInfo.courseTime }}</span>
</div>
<div class="metric-item">
<span class="metric-label">课程分类:</span>
<span class="metric-value">{{ courseInfo.category }}</span>
</div>
<div class="metric-item">
<span class="metric-label">课时:</span>
<span class="metric-value">{{ courseInfo.duration }}</span>
</div>
<div class="metric-item">
<span class="metric-label">课程讲师:</span>
<span class="metric-value">{{ courseInfo.instructor }}</span>
</div>
<div class="metric-item">
<span class="metric-label">教师团队:</span>
<span class="metric-value">{{ courseInfo.teacherCount }}</span>
</div>
<div class="metric-item">
<span class="metric-label">课程积分:</span>
<span class="metric-value">{{ courseInfo.credits }}</span>
</div>
</div>
<!-- 开课学期选择 -->
<div class="semester-section">
<span class="semester-label">开课1学期</span>
<n-select v-model:value="selectedSemester" :options="semesterOptions" class="semester-select" size="small" />
</div>
</div>
</div>
<!-- 底部统计数据 -->
<div class="bottom-stats-section">
<div class="stats-container">
<div class="stat-item">
<div class="stat-label">累计课程浏览量</div>
<div class="stat-value">{{ courseStats.views }}</div>
</div>
<div class="stat-item">
<div class="stat-label">累计报名人数</div>
<div class="stat-value">{{ courseStats.enrollments }}</div>
</div>
<div class="stat-item">
<div class="stat-label">累计章节学习人数</div>
<div class="stat-value">{{ courseStats.learners }}</div>
</div>
<div class="stat-item">
<div class="stat-label">累计互动评论人数</div>
<div class="stat-value">{{ courseStats.comments }}</div>
</div>
</div>
<!-- 分割线 -->
<div class="divider"></div>
<!-- 进入课程按钮 -->
<div class="action-section">
<n-button type="primary" size="large" class="enter-course-btn">
进入课程
</n-button>
</div>
</div>
<!-- 课程标签页 -->
<div class="course-tabs">
<div class="tab-nav">
<button class="tab-btn" :class="{ active: activeTab === 'intro' }" @click="activeTab = 'intro'">课程介绍</button>
<button class="tab-btn" :class="{ active: activeTab === 'team' }" @click="activeTab = 'team'">教学团队</button>
<button class="tab-btn" :class="{ active: activeTab === 'chapters' }"
@click="activeTab = 'chapters'">章节目录</button>
<button class="tab-btn" :class="{ active: activeTab === 'comments' }"
@click="activeTab = 'comments'">评论</button>
</div>
<!-- 标签页内容区域 -->
<div class="tab-content">
<transition name="tab-fade" mode="out-in">
<!-- 课程介绍内容 -->
<div v-if="activeTab === 'intro'" key="intro" class="tab-pane">
<CourseIntro />
</div>
<!-- 教学团队内容 -->
<div v-else-if="activeTab === 'team'" key="team" class="tab-pane">
<TeachingTeam />
</div>
<!-- 章节目录内容 -->
<div v-else-if="activeTab === 'chapters'" key="chapters" class="tab-pane">
<ChapterList />
</div>
<!-- 评论内容 -->
<div v-else-if="activeTab === 'comments'" key="comments" class="tab-pane">
<CourseComments />
</div>
</transition>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { NButton, NSelect } from 'naive-ui'
import CourseIntro from './tabs/CourseIntro.vue'
import TeachingTeam from './tabs/TeachingTeam.vue'
import ChapterList from './tabs/ChapterList.vue'
import CourseComments from './tabs/CourseComments.vue'
const router = useRouter()
//
const showTopImage = ref(true) // /
//
const courseInfo = ref({
title: '课程名称课程名称课',
description: '本课程旨在带领学生系统地学习【课程核心领域】的知识。我们将从【最基础的概念】讲起,逐步深入到【高级主题或应用】。通过理论与实践相结合的方式,学生不仅能够掌握【具体的理论知识】,还能获得【具体的实践技能,如解决XX问题、开发XX应用等】。',
courseTime: '2025-08-25-2026.08-25',
category: '分类名称',
duration: '4小时28分钟',
instructor: '王建国',
teacherCount: 1,
credits: 60
})
//
const courseStats = ref({
views: 0,
enrollments: 0,
learners: 0,
comments: 0
})
//
const selectedSemester = ref('2025-2026-1')
const semesterOptions = [
{ label: '2025-2026第一学期', value: '2025-2026-1' },
{ label: '2025-2026第二学期', value: '2025-2026-2' }
]
//
const activeTab = ref('intro')
//
const goBack = () => {
if (window.history.length > 1) {
router.go(-1)
} else {
router.push('/teacher/course-management')
}
}
const handleClose = () => {
showTopImage.value = false //
}
</script>
<style scoped>
.teacher-course-detail {
background: #fff;
min-height: 100vh;
}
/* 顶部图片容器 */
.top-image-container {
position: relative;
width: 100%;
height: 130px;
overflow: hidden;
}
.top-image {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
object-fit: cover;
}
/* 关闭按钮样式 */
.close-button {
position: absolute;
top: 0;
right: 15px;
width: 30px;
height: 20px;
background-color: #7192DC;
color: white;
border: none;
font-size: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
transition: background-color 0.3s ease;
}
.close-button:hover {
background-color: #999999;
}
/* 顶部导航 */
.top-navigation {
display: flex;
align-items: center;
padding: 25px 30px;
background: #fff;
border-bottom: 1.5px solid #e6e6e6;
position: sticky;
top: 0;
z-index: 100;
}
.back-button {
margin-right: 16px;
color: #333;
background: #F7F8FA;
border-radius: 4px;
padding: 8px 16px;
font-size: 14px;
min-width: 74px;
height: 34px;
display: flex;
align-items: center;
justify-content: center;
}
.back-button:hover {
color: #0288D1;
background: #e3f2fd;
}
.page-title {
font-size: 18px;
font-weight: 600;
color: #333;
}
/* 主要内容区域 */
.main-content {
display: flex;
gap: 40px;
max-width: 1420px;
margin: 25px auto;
}
/* 左侧课程图片 */
.course-image-section {
flex: 0 0 305px;
}
.course-image {
width: 100%;
height: 215px;
object-fit: cover;
}
/* 右侧课程信息 */
.course-info-section {
flex: 1;
display: flex;
flex-direction: column;
gap: 15px;
}
.course-title {
font-size: 22px;
font-weight: 500;
color: #333;
margin: 0;
line-height: 1.2;
}
.course-description {
font-size: 14px;
color: #666;
line-height: 1.6;
margin-bottom: 10px;
}
/* 课程关键信息 */
.course-metrics {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.metric-item {
display: flex;
align-items: center;
gap: 12px;
}
.metric-label {
font-size: 14px;
color: #666;
min-width: 80px;
}
.metric-value {
font-size: 14px;
color: #666666;
font-weight: 500;
}
/* 开课学期选择 */
.semester-section {
display: flex;
align-items: center;
gap: 20px;
margin-top: 8px;
}
.semester-label {
font-size: 18px;
color: #333;
}
.semester-select {
width: 181px;
}
/* 学期选择器样式 */
.semester-select :deep(.n-base-selection-label) {
background-color: #0C99DA !important;
padding: 4px 4px;
border: none !important;
color: white !important;
font-size: 14px !important;
width: 181px !important;
height: 37px !important;
}
.semester-select :deep(.n-base-selection-input__content) {
color: white !important;
font-size: 14px !important;
}
.semester-select :deep(.n-base-suffix__arrow) {
color: white !important;
}
.semester-select :deep(.n-base-suffix__arrow svg) {
fill: white !important;
}
/* 底部统计数据 */
.bottom-stats-section {
background: #F1F3F4;
width: 1420px;
margin: 35px auto;
padding: 15px 55px;
display: flex;
justify-content: space-between;
align-items: center;
}
.stats-container {
display: flex;
gap: 200px;
}
/* 分割线 */
.divider {
width: 1px;
height: 40px;
background-color: #E0E0E0;
margin: 0 20px;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.stat-label {
font-size: 12px;
color: #999;
text-align: left;
}
.stat-value {
font-size: 16px;
font-weight: 500;
color: #333;
}
/* 操作区域 */
.action-section {
flex-shrink: 0;
}
.enter-course-btn {
width: 136px !important;
height: 37px !important;
font-size: 14px !important;
font-weight: 600 !important;
border-radius: 2px !important;
background: #0C99DA !important;
border: none !important;
color: #fff !important;
transition: all 0.3s ease;
}
.enter-course-btn:hover {
background: #0A8BC7 !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(12, 153, 218, 0.3);
}
/* 课程标签页 */
.course-tabs {
background: #fff;
margin-top: 40px;
max-width: 1420px;
margin-left: auto;
margin-right: auto;
}
.tab-nav {
display: flex;
justify-content: center;
border-bottom: 1px solid #E6E6E6;
margin-bottom: 20px;
}
.tab-btn {
background: none;
border: none;
padding: 12px 0;
margin-right: 54px;
font-size: 16px;
color: #333;
cursor: pointer;
position: relative;
transition: color 0.3s;
}
.tab-btn.active {
color: #0C99DA;
font-weight: 500;
}
.tab-btn.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 3px;
background: #0C99DA;
}
.tab-btn:hover {
color: #0C99DA;
}
.tab-content {
min-height: 300px;
padding: 0 0 24px 0;
}
/* Tab切换过渡动画 */
.tab-fade-enter-active,
.tab-fade-leave-active {
transition: all 0.3s ease;
}
.tab-fade-enter-from {
opacity: 0;
transform: translateX(20px);
}
.tab-fade-leave-to {
opacity: 0;
transform: translateX(-20px);
}
.tab-pane {
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式设计 */
@media (max-width: 768px) {
.top-image-container {
height: 100px;
}
}
@media (max-width: 480px) {
.top-image-container {
height: 80px;
}
}
@media (max-width: 1024px) {
.main-content {
flex-direction: column;
padding: 20px;
}
.course-image-section {
flex: none;
}
.course-image {
height: 250px;
}
.bottom-stats-section {
flex-direction: column;
gap: 24px;
padding: 24px 20px;
}
.stats-container {
gap: 32px;
}
}
@media (max-width: 768px) {
.stats-container {
flex-wrap: wrap;
gap: 24px;
}
.stat-item {
flex: 1;
min-width: 120px;
}
.course-title {
font-size: 24px;
}
.course-description {
font-size: 14px;
}
}
</style>

View File

@ -0,0 +1,298 @@
<template>
<div class="chapters-content">
<h4>章节目录</h4>
<div class="chapter-list">
<div class="chapter-section">
<div class="chapter-header" @click="toggleChapter(0)">
<div class="chapter-info">
<span class="chapter-number">第一章</span>
<span class="chapter-title">课前准备</span>
</div>
<span class="chapter-toggle" :class="{ 'expanded': chapters[0].expanded }">
<svg width="12" height="12" viewBox="0 0 12 12">
<path d="M4 3l4 3-4 3" stroke="currentColor" stroke-width="1.5" fill="none" />
</svg>
</span>
</div>
<div v-if="chapters[0].expanded" class="chapter-lessons">
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">开课彩蛋:新开始新征程</span>
</div>
<div class="lesson-duration">
<span class="duration-text">01:03:56</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">课程定位与目标</span>
</div>
<div class="lesson-duration">
<span class="duration-text">00:44:05</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">教学安排及学习建议</span>
</div>
<div class="lesson-duration">
<span class="duration-text">00:52:22</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge resource">资料</div>
<div class="lesson-info">
<span class="lesson-title">课前准备PPT</span>
</div>
<div class="lesson-duration">
<img src="/images/courses/download.png" alt="下载" class="duration-download-icon">
</div>
</div>
</div>
</div>
</div>
<div class="chapter-section">
<div class="chapter-header" @click="toggleChapter(1)">
<div class="chapter-info">
<span class="chapter-number">第一章</span>
<span class="chapter-title">课前准备</span>
</div>
<span class="chapter-toggle" :class="{ 'expanded': chapters[1].expanded }">
<svg width="12" height="12" viewBox="0 0 12 12">
<path d="M4 3l4 3-4 3" stroke="currentColor" stroke-width="1.5" fill="none" />
</svg>
</span>
</div>
<div v-if="chapters[1].expanded" class="chapter-lessons">
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">开课彩蛋:新开始新征程</span>
</div>
<div class="lesson-duration">
<span class="duration-text">01:03:56</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">课程定位与目标</span>
</div>
<div class="lesson-duration">
<span class="duration-text">00:44:05</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge video">视频</div>
<div class="lesson-info">
<span class="lesson-title">教学安排及学习建议</span>
</div>
<div class="lesson-duration">
<span class="duration-text">00:52:22</span>
<img src="/images/courses/video.png" alt="视频" class="duration-play-icon">
</div>
</div>
</div>
<div class="lesson-item">
<div class="lesson-content">
<div class="lesson-type-badge resource">资料</div>
<div class="lesson-info">
<span class="lesson-title">课前准备PPT</span>
</div>
<div class="lesson-duration">
<img src="/images/courses/download.png" alt="下载" class="duration-download-icon">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
//
const chapters = ref([
{
id: 1,
title: '课前准备',
expanded: true
},
{
id: 2,
title: '课前准备',
expanded: true
}
])
// /
const toggleChapter = (index: number) => {
chapters.value[index].expanded = !chapters.value[index].expanded
}
</script>
<style scoped>
.chapters-content h4 {
font-size: 16px;
font-weight: 500;
color: #333;
margin: 0 0 12px 0;
}
.chapter-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.chapter-section {
}
.chapter-section:last-child {
border-bottom: none;
}
.chapter-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
background: #F5F8FB;
cursor: pointer;
transition: background-color 0.2s;
margin-top: 8px;
margin-bottom: 8px;
border-radius: 5px;
}
.chapter-header:hover {
background: #fafafa;
}
.chapter-info {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.chapter-number {
font-size: 14px;
color: #333;
min-width: 20px;
}
.chapter-title {
font-size: 14px;
font-weight: 500;
color: #333;
}
.chapter-toggle {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
transition: transform 0.2s;
}
.chapter-toggle {
transform: rotate(90deg);
}
.chapter-toggle.expanded {
transform: rotate(270deg);
}
.chapter-lessons {
padding: 0 16px 16px 16px;
}
.lesson-item {
margin-bottom: 8px;
}
.lesson-content {
display: flex;
align-items: center;
padding: 8px 0;
cursor: pointer;
}
.lesson-type-badge {
display: inline-block;
padding: 2px 0px;
border-radius: 3px;
font-size: 12px;
font-weight: 500;
margin-right: 12px;
min-width: 35px;
text-align: center;
background: transparent;
border: 1px solid #E1E1E1;
color: #C0C0C0;
}
.lesson-info {
flex: 1;
}
.lesson-title {
font-size: 14px;
color: #333;
line-height: 1.4;
}
.lesson-duration {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #666;
}
.duration-text {
font-size: 12px;
color: #E1E1E1;
font-weight: 500;
}
.duration-play-icon {
width: 14px;
height: 14px;
object-fit: contain;
}
.duration-download-icon {
width: 14px;
height: 14px;
object-fit: contain;
}
</style>

View File

@ -0,0 +1,348 @@
<template>
<div class="comments-content">
<h4>评论</h4>
<div class="comment-list">
<div class="comment-item" v-for="comment in displayComments" :key="comment.id">
<div class="comment-avatar">
<img :src="comment.avatar" :alt="comment.username" />
</div>
<div class="comment-content">
<div class="comment-header">
<span class="comment-username">{{ comment.username }}</span>
<span v-if="comment.type === 'instructor'" class="instructor-badge">讲师</span>
</div>
<div class="comment-text">{{ comment.content }}</div>
<div class="comment-actions">
<button v-if="comment.isPinned" class="action-btn">
<span class="top">置顶评论</span>
</button>
<button class="action-btn">
<span>{{ comment.time }}</span>
</button>
<button class="action-btn" @click="startReply(comment.id, comment.username)">回复</button>
</div>
<!-- 回复区域 -->
<div class="comment-replies" v-if="comment.replies && comment.replies.length > 0">
<div class="reply-item instructor-reply" v-for="reply in comment.replies" :key="reply.id">
<div class="reply-avatar">
<img :src="reply.avatar" :alt="reply.username" />
</div>
<div class="reply-content">
<div class="reply-main">
<div class="reply-header">
<span class="reply-username">{{ reply.username }}</span>
<span class="reply-badge instructor">{{ reply.badge }}</span>
</div>
<div class="reply-text">{{ reply.content }}</div>
</div>
<div class="reply-footer">
<span class="reply-time">{{ reply.time }}</span>
<div class="reply-actions">
<button class="reply-action-btn">回复</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
//
const displayComments = ref([
{
id: 1,
username: '春暖花开°C',
avatar: '/images/activity/1.png',
time: '2025.07.23 16:28',
content: '为了让科学教育有效,它必须广泛包容,而且应该认识到科学教师、科学家、家庭和社区如何合作实现学习和教学的目标。',
isPinned: true,
type: 'pinned',
replies: [
{
id: 'r1',
username: '汪波',
avatar: '/images/activity/3.png',
time: '2025.07.23 16:28',
content: '欢迎大家👋又不懂的地方可以私信老师',
type: 'instructor',
badge: '讲师'
}
]
},
{
id: 2,
username: '春暖花开°C',
avatar: '/images/activity/2.png',
time: '2025.07.23 16:28',
content: '来了来了!老师讲的好好啊~',
isPinned: false,
type: 'comment',
replies: []
},
{
id: 3,
username: '春暖花开°C',
avatar: '/images/activity/4.png',
time: '2025.07.23 16:28',
content: '为了让科学教育有效,它必须广泛包容,而且应该认识到科学教师、科学家、家庭和社区如何合作实现学习和教学的目标。',
isPinned: true,
type: 'pinned',
replies: [
{
id: 'r2',
username: '汪波',
avatar: '/images/activity/6.png',
time: '2025.07.23 16:28',
content: '欢迎大家👋又不懂的地方可以私信老师',
type: 'instructor',
badge: '讲师'
}
]
},
{
id: 4,
username: '春暖花开°C',
avatar: '/images/activity/5.png',
time: '2025.07.23 16:28',
content: '来了来了!老师讲的好好啊~',
isPinned: false,
type: 'comment',
replies: []
},
{
id: 5,
username: '春暖花开°C',
avatar: '/images/activity/7.png',
time: '2025.07.23 16:28',
content: '为了让科学教育有效,它必须广泛包容,而且应该认识到科学教师、科学家、家庭和社区如何合作实现学习和教学的目标。',
isPinned: true,
type: 'pinned',
replies: []
}
])
//
const replyingTo = ref<number | null>(null)
const replyToUsername = ref('')
//
const startReply = (commentId: number, username: string) => {
replyingTo.value = commentId
replyToUsername.value = username
}
//
// const cancelReply = () => {
// replyingTo.value = null
// replyToUsername.value = ''
// }
</script>
<style scoped>
.comments-content h4 {
font-size: 18px;
font-weight: 500;
color: #333;
margin: 0 0 12px 0;
}
.comment-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.comment-item {
display: flex;
gap: 12px;
}
.comment-avatar img {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
}
.comment-content {
flex: 1;
}
.comment-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.comment-username {
font-size: 14px;
font-weight: 600;
color: #333;
}
.instructor-badge {
display: inline-block;
padding: 2px 6px;
background: #EEF9FF;
color: #008BD7;
font-size: 10px;
border-radius: 2px;
margin-left: 8px;
font-weight: 500;
}
.comment-text {
font-size: 14px;
line-height: 1.6;
color: #333;
margin-bottom: 12px;
}
.comment-actions {
display: flex;
align-items: center;
gap: 16px;
}
.action-btn {
background: none;
border: none;
font-size: 12px;
color: #999;
cursor: pointer;
display: flex;
align-items: center;
gap: 14px;
transition: color 0.3s;
}
.action-btn:hover {
color: #1890ff;
}
.action-btn .top {
background: #FFF4F4;
color: #FF304B;
padding: 4px 6px;
border-radius: 20px;
font-size: 10px;
font-weight: 500;
}
/* 回复和二级评论样式 */
.comment-replies {
margin-top: 12px;
}
.reply-item {
display: flex;
gap: 12px;
margin-bottom: 16px;
position: relative;
}
.reply-item:last-child {
margin-bottom: 0;
}
.reply-avatar {
flex-shrink: 0;
}
.reply-avatar img {
width: 24px;
height: 24px;
border-radius: 50%;
object-fit: cover;
}
.reply-content {
flex: 1;
}
.reply-main {
display: flex;
align-items: flex-start;
gap: 12px;
margin-bottom: 8px;
}
.reply-header {
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.reply-username {
font-size: 14px;
color: #666;
}
.reply-badge {
width: 32px;
height: 20px;
text-align: center;
line-height: 20px;
font-size: 10px;
font-weight: 500;
}
.reply-badge.instructor {
background: #EEF9FF;
color: #008BD7;
}
.reply-badge.user {
background: #f6ffed;
color: #52c41a;
}
.reply-time {
font-size: 12px;
color: #999;
}
.reply-text {
font-size: 14px;
line-height: 1.5;
color: #333;
flex: 1;
}
.reply-footer {
display: flex;
justify-content: left;
align-items: center;
margin-top: 8px;
gap: 15px;
}
.reply-actions {
display: flex;
align-items: center;
gap: 12px;
}
.reply-action-btn {
background: none;
border: none;
font-size: 12px;
color: #999;
cursor: pointer;
transition: color 0.3s;
}
.reply-action-btn:hover {
color: #1890ff;
}
</style>

View File

@ -0,0 +1,26 @@
<template>
<div class="intro-content">
<h4>课程介绍</h4>
<img src="/images/courses/课程介绍区.png" alt="课程介绍图片" class="course-intro-image">
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.intro-content h4 {
font-size: 18px;
font-weight: 500;
color: #333;
margin: 0 0 12px 0;
}
.course-intro-image {
width: 100%;
max-width: 100%;
height: auto;
}
</style>

View File

@ -0,0 +1,71 @@
<template>
<div class="team-content">
<h4>教学团队</h4>
<div class="speaker-container">
<div class="speaker">
<img src="/images/special/avatar1.png" alt="讲师1">
<div>
<div class="speaker-name">汪波</div>
<div class="speaker-title">教授</div>
</div>
</div>
<div class="speaker">
<img src="/images/special/avatar1.png" alt="讲师2">
<div>
<div class="speaker-name">汪波</div>
<div class="speaker-title">教授</div>
</div>
</div>
<div class="speaker">
<img src="/images/special/avatar1.png" alt="讲师3">
<div>
<div class="speaker-name">汪波</div>
<div class="speaker-title">教授</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
//
</script>
<style scoped>
.team-content h4 {
font-size: 16px;
font-weight: 500;
color: #333;
margin: 0 0 12px 0;
}
.speaker-container {
display: flex;
align-items: center;
border-radius: 5px;
gap: 10px;
}
.speaker {
display: flex;
align-items: center;
margin-right: 10px;
}
.speaker img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 10px;
}
.speaker-name {
font-size: 16px;
font-weight: bold;
}
.speaker-title {
font-size: 12px;
color: #999999;
}
</style>