feat:作业编辑接口替换;章节编辑新增字段替换,回显功能完善
This commit is contained in:
parent
b2ec1e2015
commit
f80fcb7025
@ -505,6 +505,63 @@ export class TeachCourseApi {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询视频章节
|
||||
*/
|
||||
static async getSectionVideo(courseId:string,sectionId: string): Promise<ApiResponseWithResult<any>> {
|
||||
try {
|
||||
const response = await ApiRequest.get<{ result: any }>(`/aiol/aiolCourse/${courseId}/section_video/${sectionId}`)
|
||||
console.log('📑 查询小节绑定的视频响应:', response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('❌ 查询小节绑定的视频失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询文档章节
|
||||
*/
|
||||
static async getSectionDocument(courseId:string,sectionId: string): Promise<ApiResponseWithResult<any>> {
|
||||
try {
|
||||
const response = await ApiRequest.get<{ result: any }>(`/aiol/aiolCourse/${courseId}/section_document/${sectionId}`)
|
||||
console.log('📑 查询小节绑定的文档响应:', response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('❌ 查询小节绑定的文档失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询考试章节
|
||||
*/
|
||||
static async getSectionExam(courseId:string,sectionId: string): Promise<ApiResponseWithResult<any>> {
|
||||
try {
|
||||
const response = await ApiRequest.get<{ result: any }>(`/aiol/aiolCourse/${courseId}/section_exam/${sectionId}`)
|
||||
console.log('📑 查询小节绑定的考试响应:', response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('❌ 查询小节绑定的考试失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询作业章节
|
||||
*/
|
||||
static async getSectionHomeWork(courseId:string,sectionId: string): Promise<ApiResponseWithResult<any>> {
|
||||
try {
|
||||
const response = await ApiRequest.get<{ result: any }>(`/aiol/aiolCourse/${courseId}/section_homework/${sectionId}`)
|
||||
console.log('📑 查询小节绑定的作业响应:', response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('❌ 查询小节绑定的作业失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 作业相关类型定义
|
||||
@ -603,9 +660,9 @@ export class HomeworkApi {
|
||||
*/
|
||||
static async editHomework(data: EditHomeworkRequest): Promise<ApiResponse<any>> {
|
||||
try {
|
||||
console.log('🚀 发送编辑作业请求:', { url: '/aiol/aiolHomework/edit', data })
|
||||
console.log('🚀 发送编辑作业请求:', { url: '/aiol/aiolHomework/teacher_edit', data })
|
||||
|
||||
const response = await ApiRequest.put<any>('/aiol/aiolHomework/edit', data)
|
||||
const response = await ApiRequest.post<any>('/aiol/aiolHomework/teacher_edit', data)
|
||||
|
||||
console.log('✏️ 编辑作业响应:', response)
|
||||
return response
|
||||
@ -1079,4 +1136,21 @@ class DiscussionApi {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论取消置顶
|
||||
*/
|
||||
static async untopComment(commentId: string): Promise<ApiResponse> {
|
||||
try {
|
||||
console.log('🚀 发送评论取消置顶请求:', { url: `/aiol/aiolComment/untop/${commentId}`, commentId })
|
||||
|
||||
const response = await ApiRequest.get<ApiResponse>(`/aiol/aiolComment/untop/${commentId}`)
|
||||
|
||||
console.log('👍 评论取消置顶响应:', response)
|
||||
return response
|
||||
} catch (error) {
|
||||
console.error('❌ 评论取消置顶失败:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
<n-select v-model:value="selectedType" :options="typeOptions" placeholder="全部" class="type-select" />
|
||||
</div> -->
|
||||
<div class="search-item">
|
||||
<n-input v-model:value="searchKeyword" placeholder="搜索试卷" />
|
||||
<n-input v-model:value="searchKeyword" type="text" placeholder="搜索试卷" />
|
||||
</div>
|
||||
<div class="info-text">
|
||||
已全部加载,共{{ totalCount }}份考试/练习
|
||||
@ -70,14 +70,14 @@
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-section">
|
||||
<!-- <div class="pagination-section">
|
||||
<CustomPagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:total="totalCount"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
/>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
@ -94,7 +94,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { NModal, NButton, NTag } from 'naive-ui'
|
||||
import CustomPagination from './CustomPagination.vue'
|
||||
// import CustomPagination from './CustomPagination.vue'
|
||||
import { TeachCourseApi } from '@/api/modules/teachCourse'
|
||||
|
||||
interface ExamPaper {
|
||||
@ -123,7 +123,7 @@ const props = defineProps<Props>()
|
||||
const selectedType = ref('全部')
|
||||
const searchKeyword = ref('')
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
// const pageSize = ref(10)
|
||||
const selectedExamId = ref<number | null>(null)
|
||||
|
||||
// 类型选项
|
||||
|
@ -77,7 +77,7 @@ defineExpose({
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from {
|
||||
|
@ -78,11 +78,11 @@
|
||||
<span>班级管理</span>
|
||||
</router-link>
|
||||
</div>
|
||||
<router-link to="/teacher/my-resources" class="nav-item" :class="{ active: activeNavItem === 2 }"
|
||||
<!-- <router-link to="/teacher/my-resources" class="nav-item" :class="{ active: activeNavItem === 2 }"
|
||||
@click="setActiveNavItem(2)">
|
||||
<img :src="activeNavItem === 2 ? '/images/teacher/我的资源(选中).png' : '/images/teacher/我的资源.png'" alt="">
|
||||
<span>我的资源</span>
|
||||
</router-link>
|
||||
</router-link> -->
|
||||
<router-link to="/teacher/message-center" class="nav-item" :class="{ active: activeNavItem === 5 }"
|
||||
@click="setActiveNavItem(5)">
|
||||
<img :src="activeNavItem === 5 ? '/images/profile/message-active.png' : '/images/profile/message.png'"
|
||||
@ -150,8 +150,19 @@
|
||||
<span class="breadcrumb-side"></span>
|
||||
<div class="custom-breadcrumb">
|
||||
<!-- 左侧课程管理 -->
|
||||
<span class="breadcrumb-item clickable first-item"
|
||||
@click="handleBreadcrumbClick('/teacher/course-management')">课程管理</span>
|
||||
<div class="breadcrumb-item clickable first-item" v-if="isCourseEditor">
|
||||
<n-button text @click="handleBreadcrumbClick('/teacher/course-management')">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<ChevronBackSharp />
|
||||
</n-icon>
|
||||
</template>
|
||||
课程管理
|
||||
</n-button>
|
||||
</div>
|
||||
<!-- <span class="breadcrumb-item clickable first-item"
|
||||
@click="handleBreadcrumbClick('/teacher/course-management')" v-else>课程管理</span> -->
|
||||
|
||||
<!-- 右侧路径 -->
|
||||
<div class="breadcrumb-path">
|
||||
<span v-for="(item, index) in breadcrumbPathItems" :key="index" class="breadcrumb-item" :class="{
|
||||
@ -177,6 +188,7 @@ import { ref, onMounted, computed, watch, nextTick } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ChevronDownOutline } from '@vicons/ionicons5'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { ChevronBackSharp } from '@vicons/ionicons5'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
@ -214,6 +226,8 @@ const breadcrumbDisplay = computed(() => {
|
||||
return true;
|
||||
});
|
||||
|
||||
const isCourseEditor = computed(() => route.path.includes('course-editor') || route.path.includes('chapter-editor-teacher'));
|
||||
|
||||
const setActiveNavItem = (index: number) => {
|
||||
activeNavItem.value = index;
|
||||
// 如果不是考试管理,关闭考试管理子菜单
|
||||
@ -615,18 +629,13 @@ const breadcrumbPathItems = computed(() => {
|
||||
);
|
||||
}
|
||||
|
||||
console.log('课程编辑器页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
// 如果在章节编辑页面,显示课程管理>课程管理>课程名称>章节>章节名称 格式
|
||||
// 如果在章节编辑页面,显示课程管理>课程名称>新建/编辑章节
|
||||
if (currentPath.includes('chapter-editor-teacher')) {
|
||||
const courseId = route.params.courseId;
|
||||
let breadcrumbs = [
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
},
|
||||
{
|
||||
title: '课程管理',
|
||||
path: '/teacher/course-management'
|
||||
@ -636,22 +645,16 @@ const breadcrumbPathItems = computed(() => {
|
||||
path: `/teacher/course-editor/${courseId}`
|
||||
},
|
||||
{
|
||||
title: '章节',
|
||||
title: route.query.mode === 'add' ? '新建章节' : '编辑章节',
|
||||
path: `/teacher/course-editor/${courseId}/chapters`
|
||||
},
|
||||
{
|
||||
title: '章节名称',
|
||||
path: currentPath
|
||||
}
|
||||
];
|
||||
|
||||
console.log('章节编辑页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
// 学员管理模块的面包屑逻辑
|
||||
if (currentPath.includes('student-management')) {
|
||||
console.log('学员管理页面路径:', currentPath);
|
||||
let breadcrumbs: Array<{ title: string, path: string }> = [];
|
||||
|
||||
if (currentPath.includes('student-library')) {
|
||||
@ -667,7 +670,6 @@ const breadcrumbPathItems = computed(() => {
|
||||
}
|
||||
];
|
||||
} else if (currentPath.includes('class-management')) {
|
||||
console.log('匹配到班级管理页面');
|
||||
breadcrumbs = [
|
||||
{
|
||||
title: '学员中心',
|
||||
@ -679,7 +681,6 @@ const breadcrumbPathItems = computed(() => {
|
||||
}
|
||||
];
|
||||
} else if (currentPath.endsWith('/student-management')) {
|
||||
console.log('匹配到学员管理主页面');
|
||||
breadcrumbs = [
|
||||
{
|
||||
title: '学员中心',
|
||||
@ -688,7 +689,6 @@ const breadcrumbPathItems = computed(() => {
|
||||
];
|
||||
}
|
||||
|
||||
console.log('学员管理页面面包屑:', breadcrumbs);
|
||||
return breadcrumbs;
|
||||
}
|
||||
|
||||
@ -1030,10 +1030,10 @@ const updateActiveNavItem = () => {
|
||||
/* Firefox */
|
||||
-ms-overflow-style: none;
|
||||
/* IE and Edge */
|
||||
}
|
||||
}
|
||||
|
||||
/* 隐藏Webkit浏览器的滚动条 */
|
||||
.sidebar-container::-webkit-scrollbar {
|
||||
/* 隐藏Webkit浏览器的滚动条 */
|
||||
.sidebar-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -1135,6 +1135,7 @@ const updateActiveNavItem = () => {
|
||||
.orchestration-nav {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.nav-container .nav-item {
|
||||
margin-left: 15px;
|
||||
width: 210px;
|
||||
@ -1244,6 +1245,7 @@ const updateActiveNavItem = () => {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.router-view-container {
|
||||
flex: 1;
|
||||
padding: 10px 25px;
|
||||
@ -1316,6 +1318,7 @@ const updateActiveNavItem = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
@ -1355,5 +1358,3 @@ const updateActiveNavItem = () => {
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
@ -655,7 +655,7 @@ onMounted(() => {
|
||||
/* 搜索过渡效果 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from {
|
||||
|
@ -651,7 +651,7 @@ const handleIssuanceConfirm = (selectedExams: any[]) => {
|
||||
/* 表格过渡动画 */
|
||||
.table-fade-enter-active,
|
||||
.table-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.table-fade-enter-from {
|
||||
@ -665,7 +665,7 @@ const handleIssuanceConfirm = (selectedExams: any[]) => {
|
||||
}
|
||||
|
||||
.table-fade-move {
|
||||
transition: transform 0.3s ease;
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
/* ========== 空状态样式 ========== */
|
||||
|
@ -843,7 +843,7 @@ document.addEventListener('click', closeFileMenu)
|
||||
|
||||
/* 过渡动画 */
|
||||
.certificate-fade-enter-active {
|
||||
transition: all 0.5s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.certificate-fade-leave-active {
|
||||
@ -861,7 +861,7 @@ document.addEventListener('click', closeFileMenu)
|
||||
}
|
||||
|
||||
.certificate-fade-move {
|
||||
transition: transform 0.5s ease;
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
|
||||
/* 确保动画可见 */
|
||||
|
@ -125,8 +125,7 @@
|
||||
<div class="lesson-section flex-row justify-end">
|
||||
<span class="lesson-label-text required">小节名称:</span>
|
||||
<div class="lesson-input-container">
|
||||
<n-input v-model:value="section.lessonName" placeholder="请输入小节名称"
|
||||
@blur="() => handleLessonBlur(section)" @focus="handleLessonFocus" />
|
||||
<n-input v-model:value="section.lessonName" placeholder="请输入小节名称" @focus="handleLessonFocus" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -493,7 +492,7 @@
|
||||
|
||||
<!-- 删除小节确认对话框 -->
|
||||
<n-modal v-model:show="showDeleteSectionModal" :mask-closable="false" preset="dialog" title="确认删除"
|
||||
:positive-text="'确定删除'" :negative-text="'取消'" @positive-click="confirmDeleteSection"
|
||||
:positive-text="'确定删除'" :negative-text="'取消'" :loading="deleting" @positive-click="confirmDeleteSection"
|
||||
@negative-click="cancelDeleteSection">
|
||||
<template #header>
|
||||
<span>确认删除小节</span>
|
||||
@ -611,8 +610,7 @@ const chapter = ref<Chapter>({
|
||||
id: 1,
|
||||
lessonName: '开课彩蛋新开始',
|
||||
sectionType: 'video', // 小节类型字段,默认为视频
|
||||
targetType: null, // 目标类型:0=视频,1=图片,2=资料,3=练习题,4=作业,5=考试
|
||||
targetId: null, // 目标ID:对应类型下选中的资源/内容ID
|
||||
targetId: null, // 目标ID:对应type类型下选中的资源/内容ID
|
||||
// 视频相关字段
|
||||
videoUploadOption: '',
|
||||
videoFiles: [],
|
||||
@ -844,72 +842,72 @@ const saveSection = async (section: any, sortOrder: number = 1) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确定targetType和targetId
|
||||
const getTargetTypeAndId = (section: any) => {
|
||||
console.log('🔍 确定小节的targetType和targetId', section);
|
||||
// 确定type和targetId
|
||||
const getTypeAndTargetId = (section: any) => {
|
||||
console.log('🔍 确定小节的type和targetId', section);
|
||||
|
||||
// 根据小节类型和选中资源确定targetType和targetId
|
||||
let targetType = null;
|
||||
// 根据小节类型和选中资源确定type和targetId
|
||||
let type = null;
|
||||
let targetId = null;
|
||||
|
||||
switch (section.sectionType) {
|
||||
case 'video':
|
||||
if (section.selectedVideoResource && section.selectedVideoResource.id) {
|
||||
targetType = 'resource'; // 视频类型
|
||||
type = 0; // 视频对应type=0
|
||||
targetId = String(section.selectedVideoResource.id);
|
||||
} else if (section.targetType === 'resource' && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 0; // 视频对应type=0
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
case 'material':
|
||||
if (section.selectedMaterialResource && section.selectedMaterialResource.id) {
|
||||
targetType = 2; // 资料类型
|
||||
type = 1; // 资料对应type=1
|
||||
targetId = String(section.selectedMaterialResource.id);
|
||||
} else if (section.targetType === 2 && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 1; // 资料对应type=1
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
case 'exercise':
|
||||
if (section.selectedExercise && section.selectedExercise.id) {
|
||||
targetType = 3; // 练习题类型
|
||||
type = 4; // 练习对应type=4
|
||||
targetId = String(section.selectedExercise.id);
|
||||
} else if (section.targetType === 3 && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 4; // 练习对应type=4
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
case 'homework':
|
||||
if (section.selectedHomework && section.selectedHomework.id) {
|
||||
targetType = 'homework'; // 作业类型
|
||||
type = 3; // 作业对应type=3
|
||||
targetId = String(section.selectedHomework.id);
|
||||
} else if (section.targetType === 'homework' && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 3; // 作业对应type=3
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
case 'exam':
|
||||
if (section.selectedExam && section.selectedExam.id) {
|
||||
targetType = 'exam'; // 考试类型
|
||||
type = 2; // 考试对应type=2
|
||||
targetId = String(section.selectedExam.id);
|
||||
} else if (section.targetType === 'exam' && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 2; // 考试对应type=2
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
case 'discussion':
|
||||
if (section.selectedDiscussion && section.selectedDiscussion.id) {
|
||||
targetType = 6; // 讨论类型
|
||||
type = 5; // 讨论对应type=5
|
||||
targetId = String(section.selectedDiscussion.id);
|
||||
} else if (section.targetType === 6 && section.targetId) {
|
||||
// 保持现有的targetType和targetId(用于编辑模式)
|
||||
targetType = section.targetType;
|
||||
} else if (section.targetId) {
|
||||
// 保持现有的targetId(用于编辑模式)
|
||||
type = 5; // 讨论对应type=5
|
||||
targetId = String(section.targetId);
|
||||
}
|
||||
break;
|
||||
@ -917,19 +915,18 @@ const saveSection = async (section: any, sortOrder: number = 1) => {
|
||||
break;
|
||||
}
|
||||
|
||||
return { targetType, targetId };
|
||||
return { type, targetId };
|
||||
};
|
||||
|
||||
const { targetType, targetId } = getTargetTypeAndId(section);
|
||||
const { type, targetId } = getTypeAndTargetId(section);
|
||||
|
||||
const sectionData = {
|
||||
courseId: courseId,
|
||||
name: section.lessonName.trim(),
|
||||
type: 0, // 基础类型,暂不传递具体的小节类型
|
||||
type: type, // 根据小节类型确定的type值(0-5)
|
||||
sortOrder: sortOrder, // 使用传入的排序号
|
||||
parentId: String(currentChapter.value.id), // 确保父章节ID是字符串
|
||||
level: 2, // 2=节
|
||||
targetType: targetType, // 目标类型
|
||||
targetId: targetId // 目标ID
|
||||
};
|
||||
|
||||
@ -1055,6 +1052,13 @@ const expandSection = (sectionId: number) => {
|
||||
console.log('展开小节:', sectionId);
|
||||
};
|
||||
|
||||
// 获取小节资源信息
|
||||
// const loadSelectedResources = async (sectionId: number | string) => {
|
||||
// console.log('🔍 加载小节资源信息,sectionId:', sectionId);
|
||||
// // 这里可以根据sectionId调用API获取资源信息
|
||||
// return
|
||||
// };
|
||||
|
||||
// 加载章节列表
|
||||
const loadChapters = async () => {
|
||||
try {
|
||||
@ -1125,30 +1129,32 @@ const loadChapters = async () => {
|
||||
// 转换小节数据
|
||||
if (editChapterData.sections && Array.isArray(editChapterData.sections)) {
|
||||
console.log('🔍 原始小节数据:', editChapterData.sections);
|
||||
editChapterData.sections.forEach((sectionData: any) => {
|
||||
const sectionId = sectionData.id; // 保持原始ID类型
|
||||
console.log('🔍 处理小节:', { originalId: sectionData.id, name: sectionData.name, targetType: sectionData.targetType, targetId: sectionData.targetId });
|
||||
|
||||
// 根据targetType确定小节类型
|
||||
// 使用 for...of 处理异步操作
|
||||
for (const sectionData of editChapterData.sections) {
|
||||
const sectionId = sectionData.id; // 保持原始ID类型
|
||||
console.log('🔍 处理小节:', { originalId: sectionData.id, name: sectionData.name, type:sectionData.type, targetId: sectionData.targetId });
|
||||
|
||||
// 根据type确定小节类型
|
||||
let sectionType = 'video'; // 默认为视频类型
|
||||
if (sectionData.targetType !== null && sectionData.targetType !== undefined) {
|
||||
switch (sectionData.targetType) {
|
||||
if (sectionData.type !== null && sectionData.type !== undefined) {
|
||||
switch (sectionData.type) {
|
||||
case 0:
|
||||
sectionType = 'video';
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
sectionType = 'material';
|
||||
break;
|
||||
case 3:
|
||||
sectionType = 'exercise';
|
||||
break;
|
||||
case 4:
|
||||
sectionType = 'homework';
|
||||
break;
|
||||
case 5:
|
||||
case 2:
|
||||
sectionType = 'exam';
|
||||
break;
|
||||
case 6:
|
||||
case 3:
|
||||
sectionType = 'homework';
|
||||
break;
|
||||
case 4:
|
||||
sectionType = 'exercise';
|
||||
break;
|
||||
case 5:
|
||||
sectionType = 'discussion';
|
||||
break;
|
||||
default:
|
||||
@ -1161,7 +1167,6 @@ const loadChapters = async () => {
|
||||
id: sectionId, // 直接使用原始ID,不进行类型转换
|
||||
lessonName: sectionData.name || '未命名小节',
|
||||
sectionType: sectionType,
|
||||
targetType: sectionData.targetType || null, // 保存原始的targetType
|
||||
targetId: sectionData.targetId || null, // 保存原始的targetId
|
||||
// 视频相关字段
|
||||
videoUploadOption: '',
|
||||
@ -1179,69 +1184,70 @@ const loadChapters = async () => {
|
||||
// contentDescription: sectionData.description || ''
|
||||
};
|
||||
|
||||
// 如果有targetType和targetId,根据类型设置选中的资源信息
|
||||
if (sectionData.targetType !== null && sectionData.targetId) {
|
||||
if (sectionData.targetType === 0) {
|
||||
// 进行小节资源回显查询 - 等待异步完成
|
||||
const dataRes = await getSelectedResources(sectionData);
|
||||
|
||||
// 如果查询到了资源数据,根据type类型设置选中的资源信息
|
||||
if (dataRes) {
|
||||
if (sectionData.type === 0) {
|
||||
// 视频类型
|
||||
newSection.videoUploadOption = '从课件库选择';
|
||||
// 创建一个简单的资源对象用于显示
|
||||
newSection.selectedVideoResource = {
|
||||
id: sectionData.targetId,
|
||||
name: `视频资源 (ID: ${sectionData.targetId})`,
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
name: dataRes.name || dataRes.fileName || `视频资源 (ID: ${sectionData.targetId})`,
|
||||
type: 0,
|
||||
fileSize: 0,
|
||||
createTime: '',
|
||||
fileUrl: ''
|
||||
fileSize: dataRes.fileSize || 0,
|
||||
createTime: dataRes.createTime || '',
|
||||
fileUrl: dataRes.fileUrl || dataRes.url || ''
|
||||
};
|
||||
} else if (sectionData.targetType === 2) {
|
||||
} else if (sectionData.type === 1) {
|
||||
// 资料类型
|
||||
newSection.materialUploadOption = '从资源库选择';
|
||||
// 创建一个简单的资源对象用于显示
|
||||
newSection.selectedMaterialResource = {
|
||||
id: sectionData.targetId,
|
||||
name: `资料文档 (ID: ${sectionData.targetId})`,
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
name: dataRes.name || dataRes.fileName || `资料文档 (ID: ${sectionData.targetId})`,
|
||||
type: 2,
|
||||
fileSize: 0,
|
||||
createTime: '',
|
||||
fileUrl: ''
|
||||
fileSize: dataRes.fileSize || 0,
|
||||
createTime: dataRes.createTime || '',
|
||||
fileUrl: dataRes.fileUrl || dataRes.url || ''
|
||||
};
|
||||
} else if (sectionData.targetType === 3) {
|
||||
// 练习类型
|
||||
newSection.selectedExercise = {
|
||||
id: sectionData.targetId,
|
||||
title: `练习 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 4) {
|
||||
// 作业类型
|
||||
newSection.selectedHomework = {
|
||||
id: sectionData.targetId,
|
||||
title: `作业 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 5) {
|
||||
} else if (sectionData.type === 2) {
|
||||
// 考试类型
|
||||
newSection.selectedExam = {
|
||||
id: sectionData.targetId,
|
||||
title: `考试 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
title: dataRes.title || dataRes.name || `考试 (ID: ${sectionData.targetId})`,
|
||||
createTime: dataRes.createTime || '',
|
||||
updateTime: dataRes.updateTime || ''
|
||||
};
|
||||
} else if (sectionData.targetType === 6) {
|
||||
} else if (sectionData.type === 3) {
|
||||
// 作业类型
|
||||
newSection.selectedHomework = {
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
title: dataRes.title || dataRes.name || `作业 (ID: ${sectionData.targetId})`,
|
||||
createTime: dataRes.createTime || '',
|
||||
updateTime: dataRes.updateTime || ''
|
||||
};
|
||||
} else if (sectionData.type === 4) {
|
||||
// 练习类型
|
||||
newSection.selectedExercise = {
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
title: dataRes.title || dataRes.name || `练习 (ID: ${sectionData.targetId})`,
|
||||
createTime: dataRes.createTime || '',
|
||||
updateTime: dataRes.updateTime || ''
|
||||
};
|
||||
} else if (sectionData.type === 5) {
|
||||
// 讨论类型
|
||||
newSection.selectedDiscussion = {
|
||||
id: sectionData.targetId,
|
||||
title: `讨论 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
id: dataRes.id || sectionData.targetId,
|
||||
title: dataRes.title || dataRes.name || `讨论 (ID: ${sectionData.targetId})`,
|
||||
createTime: dataRes.createTime || '',
|
||||
updateTime: dataRes.updateTime || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
newChapter.sections.push(newSection);
|
||||
});
|
||||
}
|
||||
console.log('🔍 转换后的小节数据:', newChapter.sections);
|
||||
}
|
||||
|
||||
@ -1273,214 +1279,7 @@ const loadChapters = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑模式:加载现有章节数据(兼容旧版本URL参数方式)
|
||||
const editChapterId = route.query.chapterId as string;
|
||||
if (editChapterId) {
|
||||
console.log('✏️ 编辑特定章节模式,章节ID:', editChapterId);
|
||||
} else {
|
||||
console.log('✏️ 编辑模式:加载第一个章节数据');
|
||||
}
|
||||
|
||||
// 使用新的章节接口
|
||||
const response = await TeachCourseApi.getCourseSections(courseId);
|
||||
|
||||
console.log('🔍 完整API响应:', response);
|
||||
console.log('🔍 响应数据:', response.data);
|
||||
|
||||
// 处理API响应结构
|
||||
let chapterData = null;
|
||||
if (response.data && response.data.result) {
|
||||
chapterData = response.data.result;
|
||||
console.log('✅ 从服务器加载的章节数据 (result):', chapterData);
|
||||
} else if (Array.isArray(response.data)) {
|
||||
chapterData = response.data;
|
||||
console.log('✅ 从服务器加载的章节数据 (array):', chapterData);
|
||||
}
|
||||
|
||||
if (chapterData && Array.isArray(chapterData)) {
|
||||
console.log('✅ 章节数据数量:', chapterData.length);
|
||||
|
||||
// 按level分组:章(level=1)和节(level=2)
|
||||
const chaptersData = chapterData.filter((item: any) => item.level === 1);
|
||||
const sectionsData = chapterData.filter((item: any) => item.level === 2);
|
||||
|
||||
console.log('📚 章数据:', chaptersData);
|
||||
console.log('📖 节数据:', sectionsData);
|
||||
|
||||
// 构建章节结构 - 根据是否指定章节ID来处理
|
||||
if (chaptersData.length > 0) {
|
||||
let targetChapterData = null;
|
||||
|
||||
if (editChapterId) {
|
||||
// 查找指定ID的章节
|
||||
targetChapterData = chaptersData.find((ch: any) => ch.id === editChapterId);
|
||||
if (!targetChapterData) {
|
||||
console.error('❌ 未找到指定ID的章节:', editChapterId);
|
||||
message.error('未找到指定的章节');
|
||||
return;
|
||||
}
|
||||
console.log('🎯 找到目标章节:', targetChapterData);
|
||||
} else {
|
||||
// 默认加载第一个章节
|
||||
targetChapterData = chaptersData[0];
|
||||
console.log('📚 加载第一个章节:', targetChapterData);
|
||||
}
|
||||
|
||||
const newChapter: Chapter = {
|
||||
id: parseInt(targetChapterData.id || '0'),
|
||||
name: targetChapterData.name || '未命名章节',
|
||||
sections: []
|
||||
};
|
||||
|
||||
// 找到属于这个章的节
|
||||
const chapterSections = sectionsData.filter((section: any) => section.parent_id === targetChapterData.id);
|
||||
chapterSections.forEach((sectionData: any) => {
|
||||
// 根据targetType确定小节类型
|
||||
let sectionType = 'video'; // 默认为视频类型
|
||||
if (sectionData.targetType !== null && sectionData.targetType !== undefined) {
|
||||
switch (sectionData.targetType) {
|
||||
case 0:
|
||||
sectionType = 'video';
|
||||
break;
|
||||
case 2:
|
||||
sectionType = 'material';
|
||||
break;
|
||||
case 3:
|
||||
sectionType = 'exercise';
|
||||
break;
|
||||
case 4:
|
||||
sectionType = 'homework';
|
||||
break;
|
||||
case 5:
|
||||
sectionType = 'exam';
|
||||
break;
|
||||
case 6:
|
||||
sectionType = 'discussion';
|
||||
break;
|
||||
default:
|
||||
sectionType = 'video';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const newSection: any = {
|
||||
id: parseInt(sectionData.id || '0'),
|
||||
lessonName: sectionData.name || '未命名小节',
|
||||
sectionType: sectionType,
|
||||
targetType: sectionData.targetType || null, // 保存原始的targetType
|
||||
targetId: sectionData.targetId || null, // 保存原始的targetId
|
||||
// 视频相关字段
|
||||
videoUploadOption: '',
|
||||
videoFiles: [],
|
||||
selectedVideoResource: null,
|
||||
// 资料相关字段
|
||||
materialUploadOption: '',
|
||||
materialFiles: [],
|
||||
selectedMaterialResource: null,
|
||||
// 原有字段(保持兼容性)
|
||||
coursewareName: '课件准备PPT',
|
||||
coursewareUploadOption: '',
|
||||
coursewareFiles: [],
|
||||
contentTitle: sectionData.name || '未命名小节',
|
||||
// contentDescription: '节描述'
|
||||
};
|
||||
|
||||
// 如果有targetType和targetId,根据类型设置选中的资源信息
|
||||
if (sectionData.targetType !== null && sectionData.targetId) {
|
||||
if (sectionData.targetType === 0) {
|
||||
// 视频类型
|
||||
newSection.videoUploadOption = '从课件库选择';
|
||||
// 创建一个简单的资源对象用于显示
|
||||
newSection.selectedVideoResource = {
|
||||
id: sectionData.targetId,
|
||||
name: `视频资源 (ID: ${sectionData.targetId})`,
|
||||
type: 0,
|
||||
fileSize: 0,
|
||||
createTime: '',
|
||||
fileUrl: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 2) {
|
||||
// 资料类型
|
||||
newSection.materialUploadOption = '从资源库选择';
|
||||
// 创建一个简单的资源对象用于显示
|
||||
newSection.selectedMaterialResource = {
|
||||
id: sectionData.targetId,
|
||||
name: `资料文档 (ID: ${sectionData.targetId})`,
|
||||
type: 2,
|
||||
fileSize: 0,
|
||||
createTime: '',
|
||||
fileUrl: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 3) {
|
||||
// 练习类型
|
||||
newSection.selectedExercise = {
|
||||
id: sectionData.targetId,
|
||||
title: `练习 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 4) {
|
||||
// 作业类型
|
||||
newSection.selectedHomework = {
|
||||
id: sectionData.targetId,
|
||||
title: `作业 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 5) {
|
||||
// 考试类型
|
||||
newSection.selectedExam = {
|
||||
id: sectionData.targetId,
|
||||
title: `考试 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
} else if (sectionData.targetType === 6) {
|
||||
// 讨论类型
|
||||
newSection.selectedDiscussion = {
|
||||
id: sectionData.targetId,
|
||||
title: `讨论 (ID: ${sectionData.targetId})`,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
newChapter.sections.push(newSection);
|
||||
});
|
||||
|
||||
// 更新单个章节
|
||||
chapter.value = newChapter;
|
||||
|
||||
// 默认展开第一个小节
|
||||
autoExpandFirstSection();
|
||||
|
||||
message.success(`成功加载章节:${chapter.value.name}`);
|
||||
} else {
|
||||
// 如果没有找到章节数据,可能是新课程,创建默认空章节
|
||||
console.log('📝 没有找到章节数据,创建默认章节');
|
||||
const defaultChapter: Chapter = {
|
||||
id: 0,
|
||||
name: '',
|
||||
sections: []
|
||||
};
|
||||
chapter.value = defaultChapter;
|
||||
message.info('当前课程还没有章节,请添加第一个章节');
|
||||
}
|
||||
} else {
|
||||
console.warn('⚠️ 没有获取到章节数据');
|
||||
console.warn('⚠️ 响应结构:', response);
|
||||
console.warn('⚠️ 响应数据:', response.data);
|
||||
|
||||
// 创建默认空章节
|
||||
const defaultChapter: Chapter = {
|
||||
id: 0,
|
||||
name: '',
|
||||
sections: []
|
||||
};
|
||||
chapter.value = defaultChapter;
|
||||
message.info('当前课程还没有章节,请添加第一个章节');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 加载章节失败:', error);
|
||||
console.error('❌ 错误详情:', error);
|
||||
@ -1598,27 +1397,27 @@ const openDiscussionCreator = (section: any) => {
|
||||
// };
|
||||
|
||||
// 课节相关方法
|
||||
const handleLessonBlur = async (section: any) => {
|
||||
console.log('课节名称已更新:', section.lessonName);
|
||||
if (section.lessonName && section.lessonName.trim()) {
|
||||
// 同步更新 contentTitle,使侧边栏显示的名称与编辑的名称一致
|
||||
section.contentTitle = section.lessonName;
|
||||
// const handleLessonBlur = async (section: any) => {
|
||||
// console.log('课节名称已更新:', section.lessonName);
|
||||
// if (section.lessonName && section.lessonName.trim()) {
|
||||
// // 同步更新 contentTitle,使侧边栏显示的名称与编辑的名称一致
|
||||
// section.contentTitle = section.lessonName;
|
||||
|
||||
// 如果章节已经保存(有有效ID),则自动保存小节
|
||||
if (currentChapter.value.id && currentChapter.value.id !== 0) {
|
||||
console.log('📝 章节已存在,自动保存小节');
|
||||
// 找到当前小节在数组中的索引,用于确定排序号
|
||||
const sectionIndex = currentChapter.value.sections.findIndex((s: any) => s.id === section.id);
|
||||
const sortOrder = sectionIndex >= 0 ? sectionIndex + 1 : 1;
|
||||
const saved = await saveSection(section, sortOrder);
|
||||
if (saved) {
|
||||
message.success('小节保存成功');
|
||||
}
|
||||
} else {
|
||||
console.log('📝 章节尚未保存,小节将在章节保存时一并保存');
|
||||
}
|
||||
}
|
||||
};
|
||||
// // 如果章节已经保存(有有效ID),则自动保存小节
|
||||
// if (currentChapter.value.id && currentChapter.value.id !== 0) {
|
||||
// console.log('📝 章节已存在,自动保存小节');
|
||||
// // 找到当前小节在数组中的索引,用于确定排序号
|
||||
// const sectionIndex = currentChapter.value.sections.findIndex((s: any) => s.id === section.id);
|
||||
// const sortOrder = sectionIndex >= 0 ? sectionIndex + 1 : 1;
|
||||
// const saved = await saveSection(section, sortOrder);
|
||||
// if (saved) {
|
||||
// message.success('小节保存成功');
|
||||
// }
|
||||
// } else {
|
||||
// console.log('📝 章节尚未保存,小节将在章节保存时一并保存');
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleLessonFocus = () => {
|
||||
console.log('开始编辑课节名称');
|
||||
@ -1679,13 +1478,11 @@ const handleExamLibraryConfirm = (selectedExam: any) => {
|
||||
if (examLibraryType.value === '0') {
|
||||
// 练习
|
||||
currentEditingSection.value.selectedExercise = selectedExam;
|
||||
currentEditingSection.value.targetType = 3; // 练习类型
|
||||
currentEditingSection.value.targetId = selectedExam.id;
|
||||
message.success(`已选择练习:${selectedExam.title}`);
|
||||
} else if (examLibraryType.value === '1') {
|
||||
// 考试
|
||||
currentEditingSection.value.selectedExam = selectedExam;
|
||||
currentEditingSection.value.targetType = 5; // 考试类型
|
||||
currentEditingSection.value.targetId = selectedExam.id;
|
||||
message.success(`已选择考试:${selectedExam.title}`);
|
||||
}
|
||||
@ -1701,7 +1498,6 @@ const handleHomeworkLibraryConfirm = (selectedHomework: any) => {
|
||||
if (currentEditingSection.value && selectedHomework) {
|
||||
// 更新当前编辑小节的作业信息
|
||||
currentEditingSection.value.selectedHomework = selectedHomework;
|
||||
currentEditingSection.value.targetType = 4; // 作业类型
|
||||
currentEditingSection.value.targetId = selectedHomework.id;
|
||||
|
||||
console.log('已设置作业到小节:', currentEditingSection.value);
|
||||
@ -1719,7 +1515,6 @@ const handleDiscussionLibraryConfirm = (selectedDiscussion: any) => {
|
||||
if (currentEditingSection.value && selectedDiscussion) {
|
||||
// 更新当前编辑小节的讨论信息
|
||||
currentEditingSection.value.selectedDiscussion = selectedDiscussion;
|
||||
currentEditingSection.value.targetType = 6; // 讨论类型
|
||||
currentEditingSection.value.targetId = selectedDiscussion.id;
|
||||
|
||||
console.log('已设置讨论到小节:', currentEditingSection.value);
|
||||
@ -1733,7 +1528,6 @@ const handleDiscussionLibraryConfirm = (selectedDiscussion: any) => {
|
||||
// 清除选择的讨论
|
||||
const clearSelectedDiscussion = (section: any) => {
|
||||
section.selectedDiscussion = null;
|
||||
section.targetType = null;
|
||||
section.targetId = null;
|
||||
message.success('已移除选择的讨论');
|
||||
};
|
||||
@ -1741,7 +1535,6 @@ const clearSelectedDiscussion = (section: any) => {
|
||||
// 清除选择的作业
|
||||
const clearSelectedHomework = (section: any) => {
|
||||
section.selectedHomework = null;
|
||||
section.targetType = null;
|
||||
section.targetId = null;
|
||||
message.success('已移除选择的作业');
|
||||
};
|
||||
@ -1749,14 +1542,12 @@ const clearSelectedHomework = (section: any) => {
|
||||
// 清除练习
|
||||
const clearSelectedExercise = (section: any) => {
|
||||
section.selectedExercise = null;
|
||||
section.targetType = null;
|
||||
section.targetId = null;
|
||||
message.success('已移除选择的练习');
|
||||
};
|
||||
// 清除考试
|
||||
const clearSelectedExam = (section: any) => {
|
||||
section.selectedExam = null;
|
||||
section.targetType = null;
|
||||
section.targetId = null;
|
||||
message.success('已移除选择的考试');
|
||||
};
|
||||
@ -1783,26 +1574,60 @@ const removeLessonSection = (sectionId: number) => {
|
||||
};
|
||||
|
||||
// 确认删除小节
|
||||
const confirmDeleteSection = () => {
|
||||
const confirmDeleteSection = async () => {
|
||||
if (!sectionToDelete.value) {
|
||||
message.error('删除信息丢失');
|
||||
return;
|
||||
}
|
||||
|
||||
const index = currentChapter.value.sections.findIndex((section: any) => section.id === sectionToDelete.value!.sectionId);
|
||||
const sectionId = sectionToDelete.value.sectionId;
|
||||
const section = currentChapter.value.sections.find((s: any) => s.id === sectionId);
|
||||
|
||||
if (!section) {
|
||||
message.error('未找到要删除的小节');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
deleting.value = true;
|
||||
|
||||
console.log(section,sectionId);
|
||||
|
||||
|
||||
// 判断是否为已保存的小节(有真实ID)还是本地新增的小节
|
||||
if (section.id && !section.id.includes('temp')) {
|
||||
// 已保存的小节,需要调用删除接口
|
||||
console.log('🗑️ 删除已保存的小节,ID:', section.id);
|
||||
await TeachCourseApi.deleteCourseSection(section.id.toString());
|
||||
console.log('✅ 小节删除接口调用成功');
|
||||
message.success('小节删除成功');
|
||||
} else {
|
||||
// 本地新增的小节,只需要从数组中移除
|
||||
console.log('🗑️ 删除本地新增的小节,临时ID:', section.id);
|
||||
message.success('小节删除成功');
|
||||
}
|
||||
|
||||
// 从页面数组中移除小节
|
||||
const index = currentChapter.value.sections.findIndex((s: any) => s.id === sectionId);
|
||||
if (index > -1) {
|
||||
currentChapter.value.sections.splice(index, 1);
|
||||
message.success('小节删除成功');
|
||||
console.log('📝 已从页面数组中移除小节');
|
||||
}
|
||||
|
||||
// 如果删除的是当前展开的小节,自动展开第一个小节
|
||||
if (activeCollapsePanels.value.includes(sectionToDelete.value.sectionId.toString())) {
|
||||
if (activeCollapsePanels.value.includes(sectionId.toString())) {
|
||||
autoExpandFirstSection();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ 删除小节失败:', error);
|
||||
message.error('删除小节失败,请重试');
|
||||
} finally {
|
||||
deleting.value = false;
|
||||
// 清理状态
|
||||
showDeleteSectionModal.value = false;
|
||||
sectionToDelete.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 取消删除小节
|
||||
@ -1825,8 +1650,7 @@ const clearSelectedResource = (section: any, resourceType: number) => {
|
||||
section.materialFiles = [];
|
||||
}
|
||||
|
||||
// 清除目标类型和ID
|
||||
section.targetType = null;
|
||||
// 清除目标ID
|
||||
section.targetId = null;
|
||||
|
||||
message.success(`已清除${resourceType === 0 ? '视频' : '资料'}选择`);
|
||||
@ -1891,13 +1715,11 @@ const handleResourceSelect = (selectedResources: any[]) => {
|
||||
// 视频资源
|
||||
currentEditingSection.value.videoUploadOption = '从课件库选择';
|
||||
currentEditingSection.value.selectedVideoResource = resource;
|
||||
currentEditingSection.value.targetType = 0; // 视频类型
|
||||
currentEditingSection.value.targetId = resource.id;
|
||||
} else if (currentResourceType.value === 2) {
|
||||
// 资料资源
|
||||
currentEditingSection.value.materialUploadOption = '从资源库选择';
|
||||
currentEditingSection.value.selectedMaterialResource = resource;
|
||||
currentEditingSection.value.targetType = 2; // 资料类型
|
||||
currentEditingSection.value.targetId = resource.id;
|
||||
}
|
||||
|
||||
@ -1913,13 +1735,11 @@ const handleResourceUpload = (resource: any) => {
|
||||
// 视频资源
|
||||
currentEditingSection.value.videoUploadOption = '本地上传';
|
||||
currentEditingSection.value.selectedVideoResource = resource;
|
||||
currentEditingSection.value.targetType = 0; // 视频类型
|
||||
currentEditingSection.value.targetId = resource.id;
|
||||
} else if (currentResourceType.value === 2) {
|
||||
// 资料资源
|
||||
currentEditingSection.value.materialUploadOption = '本地上传';
|
||||
currentEditingSection.value.selectedMaterialResource = resource;
|
||||
currentEditingSection.value.targetType = 2; // 资料类型
|
||||
currentEditingSection.value.targetId = resource.id;
|
||||
}
|
||||
|
||||
@ -1961,11 +1781,37 @@ const updateSectionSort = async () => {
|
||||
|
||||
console.log(`📝 更新小节 "${section.lessonName}" 排序为: ${index + 1}`);
|
||||
|
||||
// 根据sectionType确定type值
|
||||
let type = 0; // 默认为视频
|
||||
switch (section.sectionType) {
|
||||
case 'video':
|
||||
type = 0;
|
||||
break;
|
||||
case 'material':
|
||||
type = 1;
|
||||
break;
|
||||
case 'exam':
|
||||
type = 2;
|
||||
break;
|
||||
case 'homework':
|
||||
type = 3;
|
||||
break;
|
||||
case 'exercise':
|
||||
type = 4;
|
||||
break;
|
||||
case 'discussion':
|
||||
type = 5;
|
||||
break;
|
||||
default:
|
||||
type = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
const sectionData = {
|
||||
id: String(section.id),
|
||||
courseId: courseId,
|
||||
name: section.lessonName.trim(),
|
||||
type: 0,
|
||||
type: type, // 根据小节类型确定的type值
|
||||
sortOrder: index + 1, // 从1开始的排序号
|
||||
parentId: String(currentChapter.value.id),
|
||||
level: 2
|
||||
@ -2045,6 +1891,119 @@ const getSectionTypeStyle = (value: string) => {
|
||||
return typeStyles[value] || 'default';
|
||||
};
|
||||
|
||||
// 查询小节资源回显数据
|
||||
const getSelectedResources = async (sectionData: any) => {
|
||||
if (!sectionData?.id || !courseId.value) {
|
||||
console.warn('⚠️ sectionData.id 或 courseId 为空,无法查询资源');
|
||||
return;
|
||||
}
|
||||
|
||||
const { id: sectionId, type } = sectionData;
|
||||
|
||||
let data:any
|
||||
|
||||
try {
|
||||
console.log('🔍 开始查询小节资源回显数据,sectionId:', sectionId, 'type:', type, 'courseId:', courseId.value);
|
||||
|
||||
// 根据type调用对应的接口
|
||||
switch (type) {
|
||||
case 0: {
|
||||
// 视频类型
|
||||
console.log('📹 查询视频资源...');
|
||||
const videoResult = await TeachCourseApi.getSectionVideo(courseId.value, sectionId);
|
||||
console.log(videoResult);
|
||||
|
||||
if (videoResult.data?.result) {
|
||||
console.log('📹 视频资源查询成功:', videoResult.data.result);
|
||||
// TODO: 更新对应小节的视频资源显示
|
||||
data = videoResult.data.result;
|
||||
} else {
|
||||
console.log('📹 视频资源查询无数据');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
// 资料类型
|
||||
console.log('📄 查询文档资源...');
|
||||
const documentResult = await TeachCourseApi.getSectionDocument(courseId.value, sectionId);
|
||||
if (documentResult.data?.result) {
|
||||
console.log('📄 文档资源查询成功:', documentResult.data.result);
|
||||
// TODO: 更新对应小节的文档资源显示
|
||||
data = documentResult.data.result;
|
||||
|
||||
} else {
|
||||
console.log('📄 文档资源查询无数据');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
// 考试类型
|
||||
console.log('📝 查询考试资源...');
|
||||
const examResult = await TeachCourseApi.getSectionExam(courseId.value, sectionId);
|
||||
if (examResult.data?.result) {
|
||||
console.log('📝 考试资源查询成功:', examResult.data.result);
|
||||
// TODO: 更新对应小节的考试资源显示
|
||||
|
||||
data = examResult.data.result;
|
||||
} else {
|
||||
console.log('📝 考试资源查询无数据');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
// 作业类型
|
||||
console.log('📋 查询作业资源...');
|
||||
const homeworkResult = await TeachCourseApi.getSectionHomeWork(courseId.value, sectionId);
|
||||
if (homeworkResult.data?.result) {
|
||||
console.log('📋 作业资源查询成功:', homeworkResult.data.result);
|
||||
// TODO: 更新对应小节的作业资源显示
|
||||
data = homeworkResult.data.result
|
||||
} else {
|
||||
console.log('📋 作业资源查询无数据');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
// 练习类型
|
||||
console.log('🏃 练习资源接口暂未实现');
|
||||
// TODO: 预留练习资源接口
|
||||
// const exerciseResult = await TeachCourseApi.getSectionExercise(courseId.value, sectionId);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: {
|
||||
// 讨论类型
|
||||
console.log('💬 讨论资源接口暂未实现');
|
||||
// TODO: 预留讨论资源接口
|
||||
// const discussionResult = await TeachCourseApi.getSectionDiscussion(courseId.value, sectionId);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
console.warn('⚠️ 未知的小节类型:', type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果返回的是数组格式,默认取第一项
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
data = data[0];
|
||||
console.log('📦 检测到数组格式数据,已取第一项:', data);
|
||||
}
|
||||
|
||||
console.log('✅ 小节资源回显查询完成');
|
||||
return data
|
||||
|
||||
} catch (error:any) {
|
||||
message.error(`❌ 查询小节资源回显失败:${error.message}`)
|
||||
console.error('❌ 查询小节资源回显失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
router.back();
|
||||
}
|
||||
|
@ -605,10 +605,11 @@ const columns: DataTableColumns<Chapter> = [
|
||||
const getTypeText = (type: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
'0': '视频',
|
||||
'1': '文档',
|
||||
'2': '音频',
|
||||
'3': '测试',
|
||||
'4': '作业'
|
||||
'1': '资料',
|
||||
'2': '考试',
|
||||
'3': '作业',
|
||||
'4': '练习',
|
||||
'5': '讨论',
|
||||
}
|
||||
return typeMap[type] || '-'
|
||||
}
|
||||
|
@ -779,7 +779,7 @@ onMounted(async () => {
|
||||
/* Tab切换过渡动画 */
|
||||
.tab-fade-enter-active,
|
||||
.tab-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.tab-fade-enter-from {
|
||||
@ -793,7 +793,7 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.tab-pane {
|
||||
animation: fadeIn 0.3s ease;
|
||||
animation: fadeIn 0.1s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
|
@ -319,7 +319,7 @@ const hideSidebar = computed(() => {
|
||||
/* 内容区域过渡动画 */
|
||||
.content-transition-enter-active,
|
||||
.content-transition-leave-active {
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.content-transition-enter-from {
|
||||
|
@ -85,7 +85,7 @@
|
||||
</template>
|
||||
点赞 ({{ reply.likes }})
|
||||
</n-button>
|
||||
<n-button quaternary @click="topReply(reply)" v-if="reply.isTop">
|
||||
<n-button quaternary @click="unTopReply(reply)" v-if="reply.isTop">
|
||||
<template #icon>
|
||||
<n-icon size="20">
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
@ -450,11 +450,26 @@ const topReply = (item: any) => {
|
||||
DiscussionApi.topComment(item.id).then(() => {
|
||||
item.isPinned = true
|
||||
message.success('已置顶')
|
||||
loadDiscussionInfo()
|
||||
loadRepliesList()
|
||||
}).catch(() => {
|
||||
message.error('置顶失败,请重试')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const unTopReply = (item: any) => {
|
||||
DiscussionApi.untopComment(item.id).then(() => {
|
||||
item.isPinned = false
|
||||
message.success('已取消置顶')
|
||||
loadDiscussionInfo()
|
||||
loadRepliesList()
|
||||
}).catch(() => {
|
||||
message.error('取消置顶失败,请重试')
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const replyToReply = (reply: any) => {
|
||||
replyTarget.value = reply
|
||||
showReplyToReplyModal.value = true
|
||||
|
@ -390,7 +390,7 @@ console.log('CourseStatistics component loaded with ECharts and Tab functionalit
|
||||
/* Tab切换过渡动画 */
|
||||
.tab-fade-enter-active,
|
||||
.tab-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.1s ease;
|
||||
}
|
||||
|
||||
.tab-fade-enter-from {
|
||||
|
Loading…
x
Reference in New Issue
Block a user