diff --git a/public/images/teacher/分组76.png b/public/images/teacher/分组76.png new file mode 100644 index 0000000..458f7a2 Binary files /dev/null and b/public/images/teacher/分组76.png differ diff --git a/public/images/teacher/切片_58.png b/public/images/teacher/切片_58.png new file mode 100644 index 0000000..9d4f924 Binary files /dev/null and b/public/images/teacher/切片_58.png differ diff --git a/public/images/teacher/加号(2).png b/public/images/teacher/加号(2).png new file mode 100644 index 0000000..159d332 Binary files /dev/null and b/public/images/teacher/加号(2).png differ diff --git a/public/images/teacher/加号(3).png b/public/images/teacher/加号(3).png new file mode 100644 index 0000000..997793d Binary files /dev/null and b/public/images/teacher/加号(3).png differ diff --git a/public/images/teacher/加号_4.png b/public/images/teacher/加号_4.png new file mode 100644 index 0000000..02df121 Binary files /dev/null and b/public/images/teacher/加号_4.png differ diff --git a/public/images/teacher/路径18.png b/public/images/teacher/路径18.png new file mode 100644 index 0000000..994dac2 Binary files /dev/null and b/public/images/teacher/路径18.png differ diff --git a/public/images/teacher/路径4.png b/public/images/teacher/路径4.png new file mode 100644 index 0000000..5cb70ed Binary files /dev/null and b/public/images/teacher/路径4.png differ diff --git a/public/images/teacher/路径5.png b/public/images/teacher/路径5.png new file mode 100644 index 0000000..8c4375f Binary files /dev/null and b/public/images/teacher/路径5.png differ diff --git a/public/images/teacher/路径_2.png b/public/images/teacher/路径_2.png new file mode 100644 index 0000000..c5fbdf3 Binary files /dev/null and b/public/images/teacher/路径_2.png differ diff --git a/src/components/admin/CourseComponents/CourseCategory.vue b/src/components/admin/CourseComponents/CourseCategory.vue index bd3e562..ff9f7c4 100644 --- a/src/components/admin/CourseComponents/CourseCategory.vue +++ b/src/components/admin/CourseComponents/CourseCategory.vue @@ -114,14 +114,15 @@ const navigateToCreateCourse = () => { max-width: 100%; height: auto; min-height: 1181px; - margin-right: 28px; + margin: 0; /* 移除所有边距 */ box-sizing: border-box; - padding: 10px; /* 添加内边距以便更好地观察布局 */ + padding: 5px; /* 减少内边距 */ position: relative; /* 添加相对定位,使分页按钮的绝对定位基于此容器 */ + overflow-x: hidden; /* 防止水平滚动 */ } .top { white-space: nowrap; /* 防止链接换行 */ - padding: 0 20px; + padding: 0 8px; /* 进一步减少左右padding */ height: 60px; display: flex; align-items: center; @@ -219,9 +220,13 @@ const navigateToCreateCourse = () => { .course-grid { display: grid; - grid-template-columns: repeat(6, 1fr); - gap: 20px; + grid-template-columns: repeat(4, 1fr); /* 默认4列,确保100%缩放下不被截断 */ + gap: 12px; /* 进一步减少间距 */ margin-bottom: 20px; + width: 100%; + max-width: 100%; + box-sizing: border-box; + padding: 0 3px; /* 减少内边距 */ } .course-card { @@ -374,9 +379,11 @@ const navigateToCreateCourse = () => { aspect-ratio: 150 / 105; /* 居中 */ display: block; - margin: 5px auto 10px; + margin: 5px auto 20px; /* 增加图片下方间距从10px到20px */ position: relative; top: -10px; + object-fit: cover; + object-position: center; } .course-name{ width: 80%; @@ -391,21 +398,24 @@ const navigateToCreateCourse = () => { white-space: nowrap; /* 强制文本在一行显示 */ overflow: hidden; /* 隐藏超出容器的文本 */ text-overflow: ellipsis; /* 溢出部分用省略号表示 */ - margin-top: -5px; + margin-top: 0; /* 移除负边距,让文字与图片保持正常距离 */ + margin-bottom: 15px; /* 添加底部边距,让文字不挨着底部 */ } /* 分页样式 */ .pagination { display: flex; justify-content: center; - position: absolute; - bottom: 61px; + position: relative; + margin-top: 40px; + margin-bottom: 40px; left: 0; right: 0; } .pagination-content { - width: 703px; + width: 100%; + max-width: 703px; height: 38px; display: flex; justify-content: center; @@ -413,6 +423,7 @@ const navigateToCreateCourse = () => { margin: 0 auto; border-radius: 4px; padding: 0 10px; + box-sizing: border-box; } .page-numbers { @@ -472,4 +483,304 @@ const navigateToCreateCourse = () => { border-color: #1890ff; } +/* 响应式设计 - 让卡片图片和文字响应式放大 */ + +/* 超大屏幕 (≥1920px) - 图片和文字放大 */ +@media (min-width: 1920px) { + .course-category { + max-width: 1800px; + margin: 0 auto; + padding: 20px; + background: #f5f5f5; + border-radius: 8px; + } + + .course-grid { + grid-template-columns: repeat(6, 1fr); + gap: 30px; + } + + .course-card { + aspect-ratio: 200 / 220; + } + + .course-info img { + width: 85%; + margin: 8px auto 25px; + } + + .course-name { + font-size: 16px; + height: 24px; + line-height: 24px; + width: 85%; + margin-bottom: 18px; + } + + .section-title { + width: 60px; + height: 24px; + font-size: 14px; + } + + .more-icon { + font-size: 20px; + } +} + +/* 超大屏幕 (1600px+) */ +@media (min-width: 1600px) { + .course-category { + max-width: 1500px; + margin: 0 auto; + padding: 15px; + } + + .course-grid { + grid-template-columns: repeat(6, 1fr); + gap: 20px; + } + + .course-info img { + width: 82%; + margin: 6px auto 22px; + } + + .course-name { + font-size: 15px; + height: 22px; + line-height: 22px; + width: 82%; + margin-bottom: 16px; + } + + .section-title { + width: 55px; + height: 22px; + font-size: 13px; + } +} + +/* 大屏幕 (1400px-1599px) */ +@media (max-width: 1599px) and (min-width: 1400px) { + .course-grid { + grid-template-columns: repeat(5, 1fr); + gap: 15px; + } +} + +/* 标准屏幕 (1300px-1399px) */ +@media (max-width: 1399px) and (min-width: 1300px) { + .course-grid { + grid-template-columns: repeat(4, 1fr); + gap: 15px; + } +} + +/* 中等屏幕 (1200px-1299px) */ +@media (max-width: 1299px) and (min-width: 1200px) { + .course-grid { + grid-template-columns: repeat(4, 1fr); + gap: 15px; + } + + .course-card { + aspect-ratio: 190 / 210; + } + + .course-info img { + width: 80%; + } + + .course-name { + font-size: 14px; + width: 80%; + margin-bottom: 15px; + } +} + +/* 小屏幕 (900px-1199px) */ +@media (max-width: 1199px) and (min-width: 900px) { + .course-grid { + grid-template-columns: repeat(4, 1fr); + gap: 18px; + } + + .course-card { + aspect-ratio: 180 / 200; + } + + .course-info img { + width: 78%; + margin: 5px auto 18px; + } + + .course-name { + font-size: 13px; + height: 18px; + line-height: 18px; + width: 78%; + margin-bottom: 14px; + } + + .section-title { + width: 48px; + height: 18px; + font-size: 11px; + } +} + +/* 平板 (600px-899px) */ +@media (max-width: 899px) and (min-width: 600px) { + .course-category { + padding: 10px; + } + + .course-grid { + grid-template-columns: repeat(3, 1fr); + gap: 15px; + } + + .course-card { + aspect-ratio: 170 / 190; + } + + .course-info img { + width: 75%; + margin: 4px auto 15px; + } + + .course-name { + font-size: 12px; + height: 16px; + line-height: 16px; + width: 75%; + margin-bottom: 12px; + } + + .section-title { + width: 45px; + height: 16px; + font-size: 10px; + } + + .more-icon { + font-size: 16px; + } + + /* 调整顶部操作区域 */ + .top { + flex-direction: column; + gap: 15px; + } + + .actions { + flex-direction: column; + gap: 10px; + } + + .search-container { + width: 100%; + } + + .search-container input { + width: 70%; + } +} + +/* 移动端 (≤599px) */ +@media (max-width: 599px) { + .course-category { + padding: 8px; + } + + .course-grid { + grid-template-columns: repeat(2, 1fr); + gap: 12px; + } + + .course-card { + aspect-ratio: 160 / 180; + } + + .course-info img { + width: 70%; + margin: 3px auto 12px; + } + + .course-name { + font-size: 11px; + height: 14px; + line-height: 14px; + width: 70%; + margin-bottom: 10px; + } + + .section-title { + width: 40px; + height: 14px; + font-size: 9px; + } + + .more-icon { + font-size: 14px; + } + + /* 顶部区域移动端优化 */ + .top { + flex-direction: column; + gap: 10px; + padding: 10px 0; + } + + .nav-links { + justify-content: center; + } + + .nav-links a { + padding: 8px 12px; + font-size: 14px; + } + + .actions { + flex-direction: column; + gap: 8px; + width: 100%; + } + + .create-btn { + width: 100%; + padding: 10px; + } + + .search-container { + width: 100%; + } + + .search-container input { + width: 70%; + padding: 8px; + } + + .search-btn { + padding: 8px 12px; + } + + /* 分页区域移动端优化 */ + .pagination-content { + width: 100%; + padding: 0 5px; + } + + .page-numbers { + flex-wrap: wrap; + gap: 5px; + } + + .page-number { + padding: 5px 8px; + font-size: 12px; + } +} + diff --git a/src/components/admin/CourseComponents/CourseCreate.vue b/src/components/admin/CourseComponents/CourseCreate.vue index fc5109a..dc7cac0 100644 --- a/src/components/admin/CourseComponents/CourseCreate.vue +++ b/src/components/admin/CourseComponents/CourseCreate.vue @@ -49,23 +49,21 @@ :render-tag="renderInstructorTag" /> -
+
* 排序:
+
+ +
- - -
- -
@@ -170,23 +168,24 @@
- -
-
- * - 课程简介: + +
+
+
+ * + 课程简介: +
-
- - -
- + +
+ +
diff --git a/src/components/admin/CourseComponents/css/CourseCreate.css b/src/components/admin/CourseComponents/css/CourseCreate.css index 1efcfc0..8730059 100644 --- a/src/components/admin/CourseComponents/css/CourseCreate.css +++ b/src/components/admin/CourseComponents/css/CourseCreate.css @@ -71,15 +71,17 @@ .course-create-page { background-color: rgba(255, 255, 255, 1); position: relative; - height: 1712px; - overflow: hidden; + min-height: 1712px; + height: auto; + overflow: visible; } .course-form-container { - height: 1211px; + min-height: 1211px; + height: auto; background-size: 100% 100%; /* width: 1565px; */ - position: absolute; + position: relative; } /* 第一行:课程名称和分类 */ @@ -233,7 +235,10 @@ .course-sort-section { height: 42px; margin-left: 159px; - width: 530px; + width: 630px; + display: flex; + align-items: center; + gap: 10px; } .course-sort-label { @@ -246,14 +251,14 @@ text-align: right; white-space: nowrap; line-height: 18px; - margin-top: 9px; + flex-shrink: 0; } /* 排序输入框 */ .course-sort-input-wrapper { - position: absolute; - left: 974px; - top: 102px; + position: relative; + left: 0; + top: 0; width: 560px; height: 42px; background-size: 562px 44px; @@ -262,6 +267,7 @@ padding: 0 12px; display: flex; align-items: center; + flex-shrink: 0; } .sort-input { @@ -521,12 +527,18 @@ line-height: 18px; } + /* 课程简介整体区域 */ + .course-description-section { + width: 1452px; + margin: 42px 0 0 41px; + } + /* 课程简介标题 */ .course-description-header { position: relative; - width: 1452px; + width: 100%; height: 20px; - margin: 42px 0 0 41px; + margin-bottom: -30px; } .course-description-label { @@ -563,9 +575,10 @@ height: 336px; background-size: 100% 100%; width: 1340px; - position: absolute; - left: 170px; - top: 453px; + position: relative; + left: 0; + top: 0; + margin-left: 129px; border-radius: 8px; padding: 13px 19px; background: white; @@ -617,13 +630,14 @@ /* 设置选项区域 */ .course-settings-section { - margin-top: 20px; + margin: 30px 0 0 41px; + width: 1400px; } .stop-on-leave-setting { width: 350px; height: 24px; - margin: 334px 0 0 31px; + margin: 20px 0 0 31px; display: flex; align-items: center; justify-content: space-between; @@ -655,7 +669,7 @@ .video-speed-setting { width: 350px; height: 24px; - margin: 29px 0 0 63px; + margin: 20px 0 0 63px; display: flex; align-items: center; justify-content: space-between; @@ -664,7 +678,7 @@ .video-text-setting { width: 350px; height: 24px; - margin: 31px 0 0 63px; + margin: 20px 0 0 63px; display: flex; align-items: center; justify-content: space-between; @@ -674,7 +688,7 @@ .points-setting-row { width: 800px; height: 40px; - margin: 21px 0 140px 95px; + margin: 21px 0 40px 95px; display: flex; align-items: center; gap: 10px; @@ -792,10 +806,10 @@ /* 底部按钮区域 */ .form-action-buttons { - position: absolute; - left: -325px; - top: 1149px; - width: 1917px; + position: relative; + left: 0; + top: 0; + width: 100%; height: 91px; background-size: 1920px 139px; display: flex; @@ -803,6 +817,7 @@ justify-content: flex-end; padding-right: 100px; gap: 15px; + margin-top: 60px; } .button-spacer { @@ -861,17 +876,120 @@ font-size: 14px; } - /* 响应式设计 */ - @media (max-width: 1920px) { + /* 响应式设计 - 保持原有布局不变,只在特定屏幕尺寸下优化 */ + + /* 大屏幕优化 (≥1920px) - 让表单居中显示 */ + @media (min-width: 1920px) { .course-create-page { - width: 100%; - min-width: 1200px; + display: flex; + justify-content: center; + align-items: flex-start; + background-color: #f5f5f5; + } + + .course-form-container { + background: white; + border-radius: 8px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); + padding: 40px; + margin: 0 auto; } } - @media (max-width: 1400px) { - .course-basic-info-row, .instructor-sort-row, .course-time-row { - width: 90%; - margin-left: 5%; + /* 中等屏幕 (1400px-1919px) - 保持原有布局 */ + @media (max-width: 1919px) and (min-width: 1400px) { + .course-create-page { + width: 100%; + min-width: 1400px; + } + } + + /* 小屏幕适配 (1200px-1399px) */ + @media (max-width: 1399px) and (min-width: 1200px) { + .course-create-page { + width: 100%; + overflow-x: auto; + } + + .course-form-container { + min-width: 1200px; + } + + /* 稍微缩小一些元素的宽度 */ + .course-basic-info-row { + width: 1100px; + margin-left: 50px; + } + + .instructor-sort-row { + width: 1150px; + margin-left: 50px; + } + + .course-time-row { + width: 1250px; + margin-left: 50px; + } + + .course-description-section { + width: 1250px; + margin-left: 50px; + } + + .description-editor-container { + width: 1150px; + margin-left: 80px; + } + } + + /* 平板适配 (768px-1199px) */ + @media (max-width: 1199px) and (min-width: 768px) { + .course-create-page { + width: 100%; + overflow-x: auto; + padding: 20px; + } + + .course-form-container { + min-width: 800px; + position: relative; + transform: scale(0.8); + transform-origin: top left; + } + } + + /* 移动端适配 (≤767px) */ + @media (max-width: 767px) { + .course-create-page { + width: 100%; + overflow-x: auto; + padding: 10px; + } + + .course-form-container { + min-width: 600px; + position: relative; + transform: scale(0.6); + transform-origin: top left; + } + + /* 调整一些关键元素以适应移动端 */ + .form-action-buttons { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background: white; + border-top: 1px solid #e0e0e0; + z-index: 1000; + transform: none; + width: 100%; + justify-content: center; + padding: 15px; + } + + .cancel-button, + .submit-button { + transform: scale(1.2); } } \ No newline at end of file diff --git a/src/components/admin/CourseManagement.vue b/src/components/admin/CourseManagement.vue index 7e357f2..aae3741 100644 --- a/src/components/admin/CourseManagement.vue +++ b/src/components/admin/CourseManagement.vue @@ -204,8 +204,10 @@ import CourseCategory from './CourseComponents/CourseCategory.vue' .content-container { flex: 1; - padding: 20px 20px 20px 5px; + padding: 8px 8px 8px 5px; /* 进一步减少padding */ min-height: 100vh; box-sizing: border-box; + max-width: calc(100vw - 274px - 21px); /* 更精确的宽度计算 */ + overflow-x: hidden; /* 防止水平滚动 */ } diff --git a/src/components/common/DeleteFolderConfirmModal.vue b/src/components/common/DeleteFolderConfirmModal.vue new file mode 100644 index 0000000..11a51cc --- /dev/null +++ b/src/components/common/DeleteFolderConfirmModal.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/src/router/index.ts b/src/router/index.ts index 8d99c0b..b4db1d0 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -59,6 +59,8 @@ import ExamLibrary from '@/views/teacher/course/ExamPages/ExamLibrary.vue' import MarkingCenter from '@/views/teacher/course/ExamPages/MarkingCenter.vue' import AddExam from '@/views/teacher/course/ExamPages/AddExam.vue' +import ChapterEditor from '@/views/teacher/course/ChapterEditor.vue' + // ========== 路由配置 ========== const routes: RouteRecordRaw[] = [ // 管理后台路由 @@ -101,7 +103,8 @@ const routes: RouteRecordRaw[] = [ name: 'CourseAnalysis', component: CourseAnalysis, meta: { title: '课程分析' } - } + }, + ] }, { @@ -129,6 +132,7 @@ const routes: RouteRecordRaw[] = [ component: ChapterManagement, meta: { title: '章节管理' } }, + { path: 'homework', name: 'HomeworkManagement', @@ -231,10 +235,17 @@ const routes: RouteRecordRaw[] = [ name: 'StudentManagement', component: StudentManagement, meta: { title: '学员管理' } + }, + { + path: 'chapter-editor-teacher/:courseId', + name: 'ChapterEditor', + component: ChapterEditor, + meta: { title: '章节编辑' } } ] }, + // 帮助中心 { path: '/help-center', diff --git a/src/views/teacher/course/ChapterEditor.vue b/src/views/teacher/course/ChapterEditor.vue index 1e1c6a7..5ac6fd4 100644 --- a/src/views/teacher/course/ChapterEditor.vue +++ b/src/views/teacher/course/ChapterEditor.vue @@ -1,12 +1,26 @@ @@ -71,12 +83,11 @@ import { ref, computed, h, onMounted, onUnmounted } from 'vue' import { NButton, NDropdown, NTag, useMessage, NDataTable, NConfigProvider, zhCN, dateZhCN } from 'naive-ui' import type { DataTableColumns, DropdownOption } from 'naive-ui' import AddCoursewareModal from './AddCoursewareModal.vue' +import UploadFileModal from './UploadFileModal.vue' +import DeleteFolderConfirmModal from '@/components/common/DeleteFolderConfirmModal.vue' const message = useMessage() -// 控制模态框显示 -const showAddCoursewareModal = ref(false) - // 文件类型定义 interface FileItem { id: number @@ -96,6 +107,17 @@ const searchKeyword = ref('') // 选中的文件行 const selectedFiles = ref([]) +// 控制模态框显示 +const showAddCoursewareModal = ref(false) +const showUploadFileModal = ref(false) +const showDeleteConfirmModal = ref(false) + +// 存储待删除的项目信息 +const itemsToDelete = ref<{ type: 'single' | 'multiple', data: any }>({ type: 'single', data: null }) + +// 存储当前要上传文件的目标文件夹 +const currentUploadTarget = ref(null) + // 文件列表数据 const fileList = ref([ { @@ -565,6 +587,11 @@ const addCourseware = () => { showAddCoursewareModal.value = true } +// 关闭添加课件模态框 +const closeAddCoursewareModal = () => { + showAddCoursewareModal.value = false +} + const createFolder = () => { message.info('新建文件夹功能') } @@ -576,16 +603,12 @@ const moveFiles = () => { const deleteSelected = () => { if (selectedFiles.value.length === 0) return - if (confirm(`确定要删除选中的 ${selectedFiles.value.length} 个文件吗?`)) { - selectedFiles.value.forEach((id: number) => { - const index = fileList.value.findIndex((f: FileItem) => f.id === id) - if (index > -1) { - fileList.value.splice(index, 1) - } - }) - selectedFiles.value = [] - message.success('删除成功') + // 存储要删除的文件信息 + itemsToDelete.value = { + type: 'multiple', + data: selectedFiles.value } + showDeleteConfirmModal.value = true } const searchFiles = () => { @@ -593,7 +616,14 @@ const searchFiles = () => { } const uploadFile = (file: FileItem) => { - message.info('上传文件: ' + file.name) + currentUploadTarget.value = file + showUploadFileModal.value = true +} + +// 关闭上传文件模态框 +const closeUploadFileModal = () => { + showUploadFileModal.value = false + currentUploadTarget.value = null } const viewFile = (file: FileItem) => { @@ -601,13 +631,44 @@ const viewFile = (file: FileItem) => { } const deleteFile = (file: FileItem) => { - if (confirm('确定要删除这个文件吗?')) { + // 存储要删除的文件信息 + itemsToDelete.value = { + type: 'single', + data: file + } + showDeleteConfirmModal.value = true +} + +// 确认删除 +const confirmDelete = () => { + if (itemsToDelete.value.type === 'multiple') { + // 批量删除 + const idsToDelete = itemsToDelete.value.data as number[] + idsToDelete.forEach((id: number) => { + const index = fileList.value.findIndex((f: FileItem) => f.id === id) + if (index > -1) { + fileList.value.splice(index, 1) + } + }) + selectedFiles.value = [] + message.success(`成功删除 ${idsToDelete.length} 个文件`) + } else { + // 单个删除 + const file = itemsToDelete.value.data as FileItem const index = fileList.value.findIndex((f: FileItem) => f.id === file.id) if (index > -1) { fileList.value.splice(index, 1) message.success('删除成功') } } + showDeleteConfirmModal.value = false + itemsToDelete.value = { type: 'single', data: null } +} + +// 取消删除 +const cancelDelete = () => { + showDeleteConfirmModal.value = false + itemsToDelete.value = { type: 'single', data: null } } const renameFile = (file: FileItem) => { @@ -689,11 +750,6 @@ const toggleFolder = (folder: FileItem) => { folder.expanded = !folder.expanded } } - -// 关闭模态框 -const closeModal = () => { - showAddCoursewareModal.value = false -}