完成资源案例
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
<div class="courses-grid">
|
||||
<div
|
||||
class="course-card"
|
||||
v-for="course in initCourses"
|
||||
v-for="(course, index) in initCourses"
|
||||
:key="course.id"
|
||||
@click="selectCourse(course)"
|
||||
style="cursor: pointer"
|
||||
@@ -69,7 +69,7 @@
|
||||
<div class="courses-grid">
|
||||
<div
|
||||
class="course-card"
|
||||
v-for="course in onlineCourses"
|
||||
v-for="(course, index) in onlineCourses"
|
||||
:key="course.id"
|
||||
@click="selectCourse(course)"
|
||||
style="cursor: pointer"
|
||||
@@ -142,10 +142,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="chapters[chapter.id]?.expanded && chapter.children?.length" class="sub-chapters-container">
|
||||
<div v-for="sub in chapter.children.sort((a,b)=>a.sort-b.sort)" :key="sub.id" class="sub-chapter-item">
|
||||
<div v-for="sub in chapter.children.sort((a: Chapter, b: Chapter) => a.sort - b.sort)" :key="sub.id" class="sub-chapter-item">
|
||||
<div class="sub-chapter-title">{{ sub.title }}</div>
|
||||
<div v-if="sub.children?.length" class="grand-children-container">
|
||||
<div v-for="grand in sub.children.sort((a,b)=>a.sort-b.sort)" :key="grand.id" class="grand-child-title">
|
||||
<div v-for="grand in sub.children.sort((a: Chapter, b: Chapter) => a.sort - b.sort)" :key="grand.id" class="grand-child-title">
|
||||
{{ grand.title }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -417,21 +417,105 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
// ==================== 核心类型定义 ====================
|
||||
/** 线上课程类型 */
|
||||
interface Course {
|
||||
id: number;
|
||||
cover_url: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
intro: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 教学案例类型 */
|
||||
interface TeachingCase {
|
||||
id: number;
|
||||
title: string;
|
||||
tutor_name: string;
|
||||
tutor_title: string;
|
||||
student_names?: string;
|
||||
content: string;
|
||||
cover_url: string;
|
||||
create_time: string;
|
||||
update_time: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 视频案例类型 */
|
||||
interface VideoCase {
|
||||
id: number;
|
||||
video_url: string;
|
||||
title: string;
|
||||
intro: string;
|
||||
designer_names: string;
|
||||
tutor_names: string;
|
||||
create_time: string;
|
||||
update_time: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 课程章节类型 */
|
||||
interface Chapter {
|
||||
id: number;
|
||||
title: string;
|
||||
children?: Chapter[];
|
||||
sort: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 拓展资源类型 */
|
||||
interface Resource {
|
||||
id: number;
|
||||
title: string;
|
||||
resource_url: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 学生活动类型 */
|
||||
interface Activity {
|
||||
id: number;
|
||||
title: string;
|
||||
content: string;
|
||||
start_time: string;
|
||||
end_time: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 教师类型 */
|
||||
interface Teacher {
|
||||
id: number;
|
||||
avatar: string;
|
||||
name: string;
|
||||
title: string;
|
||||
intro: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** 接口响应基础类型 */
|
||||
interface ApiResponse<T = any> {
|
||||
code?: number;
|
||||
message?: string;
|
||||
data?: T;
|
||||
list?: T[];
|
||||
total?: number;
|
||||
}
|
||||
|
||||
// ==================== 全局状态 ====================
|
||||
const activeTab = ref('online');
|
||||
const selectedCourse = ref(null);
|
||||
const selectedCase = ref(null);
|
||||
const playingVideo = ref(null);
|
||||
const activeDetailTab = ref('content');
|
||||
const chapters = ref({});
|
||||
const activeTab = ref<'online' | 'teaching' | 'video'>('online');
|
||||
const selectedCourse = ref<Course | null>(null);
|
||||
const selectedCase = ref<TeachingCase | null>(null);
|
||||
const playingVideo = ref<VideoCase | null>(null);
|
||||
const activeDetailTab = ref<'content' | 'resource' | 'activity' | 'team'>('content');
|
||||
const chapters = ref<Record<number, { expanded: boolean }>>({});
|
||||
|
||||
// 线上课程
|
||||
const onlineCourses = ref([]);
|
||||
const initCourses = ref([]);
|
||||
const onlineCourses = ref<Course[]>([]);
|
||||
const initCourses = ref<Course[]>([]);
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const totalCount = ref(0);
|
||||
@@ -443,7 +527,7 @@ const showFullCourseList = ref(false);
|
||||
const searchKeyword = ref('');
|
||||
|
||||
// 教学案例
|
||||
const caseList = ref([]);
|
||||
const caseList = ref<TeachingCase[]>([]);
|
||||
const casePage = ref(1);
|
||||
const caseSize = 20;
|
||||
const caseTotal = ref(0);
|
||||
@@ -454,7 +538,7 @@ const caseError = ref('');
|
||||
const caseKeyword = ref('');
|
||||
|
||||
// 视频案例
|
||||
const videoList = ref([]);
|
||||
const videoList = ref<VideoCase[]>([]);
|
||||
const videoPage = ref(1);
|
||||
const videoSize = 10;
|
||||
const videoTotal = ref(0);
|
||||
@@ -465,53 +549,53 @@ const videoError = ref('');
|
||||
const videoKeyword = ref('');
|
||||
|
||||
// 课程详情
|
||||
const courseChapters = ref([]);
|
||||
const courseChapters = ref<Chapter[]>([]);
|
||||
const loadingChapters = ref(false);
|
||||
const chapterError = ref('');
|
||||
const resourceList = ref([]);
|
||||
const resourceList = ref<Resource[]>([]);
|
||||
const resourcePage = ref(1);
|
||||
const resourcePageSize = 20;
|
||||
const hasMoreResources = ref(true);
|
||||
const loadingResources = ref(false);
|
||||
const loadingMoreResources = ref(false);
|
||||
const resourceError = ref('');
|
||||
const activityList = ref([]);
|
||||
const activityList = ref<Activity[]>([]);
|
||||
const activityPage = ref(1);
|
||||
const activityPageSize = 10;
|
||||
const hasMoreActivities = ref(true);
|
||||
const loadingActivities = ref(false);
|
||||
const loadingMoreActivities = ref(false);
|
||||
const activityError = ref('');
|
||||
const teacherList = ref([]);
|
||||
const teacherList = ref<Teacher[]>([]);
|
||||
const teacherPage = ref(1);
|
||||
const teacherPageSize = 10;
|
||||
const hasMoreTeachers = ref(true);
|
||||
const loadingTeachers = ref(false);
|
||||
const loadingMoreTeachers = ref(false);
|
||||
const teacherError = ref('');
|
||||
const currentCourseId = ref(null);
|
||||
const currentCourseId = ref<number | null>(null);
|
||||
|
||||
// ==================== 工具函数 ====================
|
||||
const formatDate = (time) => (time ? time.split(' ')[0] : '');
|
||||
const formatTime = (timeStr) => (timeStr ? timeStr.split('.')[0].replace(' ', ' ') : '');
|
||||
const onAvatarError = (e) => { e.target.src = 'https://via.placeholder.com/80?text=头像'; };
|
||||
const onVideoError = (e) => { console.error('视频加载失败:', e); alert('视频加载失败'); };
|
||||
const onVideoLoaded = (e) => { e.target.currentTime = 0.1; };
|
||||
const formatDate = (time: string | undefined) => (time ? time.split(' ')[0] : '');
|
||||
const formatTime = (timeStr: string | undefined) => (timeStr ? timeStr.split('.')[0]?.replace(' ', ' ') : '');
|
||||
const onAvatarError = (e: Event) => { (e.target as HTMLImageElement).src = 'https://via.placeholder.com/80?text=头像'; };
|
||||
const onVideoError = (e: Event) => { console.error('视频加载失败:', e); alert('视频加载失败'); };
|
||||
const onVideoLoaded = (e: Event) => { (e.target as HTMLVideoElement).currentTime = 0.1; };
|
||||
|
||||
const getFileExtension = (url) => {
|
||||
const getFileExtension = (url: string | undefined) => {
|
||||
if (!url) return '';
|
||||
const fileName = url.split('/').pop().split('?')[0];
|
||||
const fileName = url.split('/').pop()?.split('?')[0] || '';
|
||||
const parts = fileName.split('.');
|
||||
return parts.length > 1 ? parts.pop().toLowerCase() : '';
|
||||
return parts.length > 1 ? parts.pop()?.toLowerCase() || '' : '';
|
||||
};
|
||||
const getDisplayTitle = (item) => {
|
||||
const getDisplayTitle = (item: Resource) => {
|
||||
const ext = getFileExtension(item.resource_url);
|
||||
return ext ? `${item.title}.${ext}` : item.title;
|
||||
};
|
||||
const openResource = (url) => { if (url) window.open(url, '_blank'); };
|
||||
const openResource = (url: string | undefined) => { if (url) window.open(url, '_blank'); };
|
||||
|
||||
// ==================== 统一 tab 切换 ====================
|
||||
const setActiveTab = (tab) => {
|
||||
const setActiveTab = (tab: 'content' | 'resource' | 'activity' | 'team') => {
|
||||
if (activeDetailTab.value === tab) return;
|
||||
activeDetailTab.value = tab;
|
||||
if (!selectedCourse.value) return;
|
||||
@@ -522,7 +606,7 @@ const setActiveTab = (tab) => {
|
||||
};
|
||||
|
||||
// ==================== 导航切换 ====================
|
||||
const handleTabChange = (tab) => {
|
||||
const handleTabChange = (tab: 'online' | 'teaching' | 'video') => {
|
||||
activeTab.value = tab;
|
||||
selectedCourse.value = null;
|
||||
selectedCase.value = null;
|
||||
@@ -538,16 +622,16 @@ const initOnlineCourses = async () => {
|
||||
loadingInit.value = true;
|
||||
try {
|
||||
const res = await fetchCoursePage(1, '');
|
||||
onlineCourses.value = res.list;
|
||||
totalCount.value = res.total;
|
||||
onlineCourses.value = res.list as Course[];
|
||||
totalCount.value = res.total || 0;
|
||||
currentPage.value = 1;
|
||||
hasMore.value = currentPage.value * pageSize.value < totalCount.value;
|
||||
initCourses.value = onlineCourses.value.slice(0, 3);
|
||||
} catch { errorMsg.value = '加载失败'; } finally { loadingInit.value = false; }
|
||||
};
|
||||
|
||||
const fetchCoursePage = async (page, keyword) => {
|
||||
const { data } = await axios.post('http://localhost:8080/api/courses/list', {
|
||||
const fetchCoursePage = async (page: number, keyword: string): Promise<ApiResponse<Course>> => {
|
||||
const { data } = await axios.post<ApiResponse<Course>>('http://localhost:8080/api/courses/list', {
|
||||
page, size: pageSize.value, status: 1, keyword: keyword || ''
|
||||
});
|
||||
if (!data?.list) throw new Error();
|
||||
@@ -558,8 +642,8 @@ const handleCourseSearch = async () => {
|
||||
loadingInit.value = true;
|
||||
try {
|
||||
const res = await fetchCoursePage(1, searchKeyword.value);
|
||||
onlineCourses.value = res.list;
|
||||
totalCount.value = res.total;
|
||||
onlineCourses.value = res.list as Course[];
|
||||
totalCount.value = res.total || 0;
|
||||
currentPage.value = 1;
|
||||
hasMore.value = currentPage.value * pageSize.value < totalCount.value;
|
||||
} catch { errorMsg.value = '搜索失败'; } finally { loadingInit.value = false; }
|
||||
@@ -570,9 +654,10 @@ const loadNextPage = async () => {
|
||||
loadingMore.value = true;
|
||||
try {
|
||||
const res = await fetchCoursePage(currentPage.value + 1, searchKeyword.value);
|
||||
onlineCourses.value.push(...res.list);
|
||||
const newCourses = res.list as Course[];
|
||||
onlineCourses.value.push(...newCourses);
|
||||
currentPage.value++;
|
||||
hasMore.value = currentPage.value * pageSize.value < totalCount.value;
|
||||
hasMore.value = currentPage.value * pageSize.value < (res.total || 0);
|
||||
} catch { errorMsg.value = '加载失败'; } finally { loadingMore.value = false; }
|
||||
};
|
||||
|
||||
@@ -587,15 +672,15 @@ const initCases = async () => {
|
||||
caseError.value = '';
|
||||
try {
|
||||
const res = await fetchCasePage(1, caseKeyword.value);
|
||||
caseList.value = res.list;
|
||||
caseTotal.value = res.total;
|
||||
caseList.value = res.list as TeachingCase[];
|
||||
caseTotal.value = res.total || 0;
|
||||
casePage.value = 1;
|
||||
caseHasMore.value = casePage.value * caseSize < caseTotal.value;
|
||||
} catch { caseError.value = '加载失败'; } finally { caseLoading.value = false; }
|
||||
};
|
||||
|
||||
const fetchCasePage = async (page, keyword) => {
|
||||
const { data } = await axios.post('http://localhost:8080/api/teaching-cases/list', {
|
||||
const fetchCasePage = async (page: number, keyword: string): Promise<ApiResponse<TeachingCase>> => {
|
||||
const { data } = await axios.post<ApiResponse<TeachingCase>>('http://localhost:8080/api/teaching-cases/list', {
|
||||
page, size: caseSize, keyword: keyword || '', sort: 0
|
||||
});
|
||||
if (!data?.list || typeof data.total !== 'number') throw new Error();
|
||||
@@ -606,8 +691,8 @@ const searchCases = async () => {
|
||||
caseLoading.value = true;
|
||||
try {
|
||||
const res = await fetchCasePage(1, caseKeyword.value);
|
||||
caseList.value = res.list;
|
||||
caseTotal.value = res.total;
|
||||
caseList.value = res.list as TeachingCase[];
|
||||
caseTotal.value = res.total || 0;
|
||||
casePage.value = 1;
|
||||
caseHasMore.value = casePage.value * caseSize < caseTotal.value;
|
||||
} catch { caseError.value = '搜索失败'; } finally { caseLoading.value = false; }
|
||||
@@ -618,13 +703,14 @@ const loadMoreCases = async () => {
|
||||
caseLoadingMore.value = true;
|
||||
try {
|
||||
const res = await fetchCasePage(casePage.value + 1, caseKeyword.value);
|
||||
caseList.value.push(...res.list);
|
||||
const newCases = res.list as TeachingCase[];
|
||||
caseList.value.push(...newCases);
|
||||
casePage.value++;
|
||||
caseHasMore.value = casePage.value * caseSize < caseTotal.value;
|
||||
caseHasMore.value = casePage.value * caseSize < (res.total || 0);
|
||||
} catch { caseError.value = '加载更多失败'; } finally { caseLoadingMore.value = false; }
|
||||
};
|
||||
|
||||
const selectCase = (item) => { selectedCase.value = item; };
|
||||
const selectCase = (item: TeachingCase) => { selectedCase.value = item; };
|
||||
const backToCaseList = () => { selectedCase.value = null; };
|
||||
|
||||
// ==================== 视频案例 ====================
|
||||
@@ -633,15 +719,15 @@ const initVideos = async () => {
|
||||
videoError.value = '';
|
||||
try {
|
||||
const res = await fetchVideoPage(1, videoKeyword.value);
|
||||
videoList.value = res.list;
|
||||
videoTotal.value = res.total;
|
||||
videoList.value = res.list as VideoCase[];
|
||||
videoTotal.value = res.total || 0;
|
||||
videoPage.value = 1;
|
||||
videoHasMore.value = videoPage.value * videoSize < videoTotal.value;
|
||||
} catch { videoError.value = '加载失败'; } finally { videoLoading.value = false; }
|
||||
};
|
||||
|
||||
const fetchVideoPage = async (page, keyword) => {
|
||||
const { data } = await axios.post('http://localhost:8080/api/video-cases/list', {
|
||||
const fetchVideoPage = async (page: number, keyword: string): Promise<ApiResponse<VideoCase>> => {
|
||||
const { data } = await axios.post<ApiResponse<VideoCase>>('http://localhost:8080/api/video-cases/list', {
|
||||
page, size: videoSize, keyword: keyword || '', sort: 0
|
||||
});
|
||||
if (!data?.list || typeof data.total !== 'number') throw new Error();
|
||||
@@ -652,8 +738,8 @@ const searchVideos = async () => {
|
||||
videoLoading.value = true;
|
||||
try {
|
||||
const res = await fetchVideoPage(1, videoKeyword.value);
|
||||
videoList.value = res.list;
|
||||
videoTotal.value = res.total;
|
||||
videoList.value = res.list as VideoCase[];
|
||||
videoTotal.value = res.total || 0;
|
||||
videoPage.value = 1;
|
||||
videoHasMore.value = videoPage.value * videoSize < videoTotal.value;
|
||||
} catch { videoError.value = '搜索失败'; } finally { videoLoading.value = false; }
|
||||
@@ -664,95 +750,160 @@ const loadMoreVideos = async () => {
|
||||
videoLoadingMore.value = true;
|
||||
try {
|
||||
const res = await fetchVideoPage(videoPage.value + 1, videoKeyword.value);
|
||||
videoList.value.push(...res.list);
|
||||
const newVideos = res.list as VideoCase[];
|
||||
videoList.value.push(...newVideos);
|
||||
videoPage.value++;
|
||||
videoHasMore.value = videoPage.value * videoSize < videoTotal.value;
|
||||
videoHasMore.value = videoPage.value * videoSize < (res.total || 0);
|
||||
} catch { videoError.value = '加载更多失败'; } finally { videoLoadingMore.value = false; }
|
||||
};
|
||||
|
||||
const playVideo = (item) => { playingVideo.value = item; };
|
||||
const playVideo = (item: VideoCase) => { playingVideo.value = item; };
|
||||
const backToVideoList = () => { playingVideo.value = null; };
|
||||
|
||||
// ==================== 课程详情 ====================
|
||||
const fetchCourseContent = async (id) => {
|
||||
const fetchCourseContent = async (id: number) => {
|
||||
loadingChapters.value = true;
|
||||
try {
|
||||
const { data } = await axios.post('http://localhost:8080/api/course-content/list', { course_id: id, parent_id: 0 });
|
||||
const { data } = await axios.post<ApiResponse<Chapter>>('http://localhost:8080/api/course-content/list', { course_id: id, parent_id: 0 });
|
||||
if (data.code === 0 && Array.isArray(data.data)) {
|
||||
courseChapters.value = data.data.sort((a,b)=>a.sort-b.sort);
|
||||
courseChapters.value = data.data.sort((a: Chapter, b: Chapter) => a.sort - b.sort);
|
||||
courseChapters.value.forEach(c => chapters.value[c.id] = { expanded: false });
|
||||
}
|
||||
} catch { chapterError.value = '加载失败'; } finally { loadingChapters.value = false; }
|
||||
};
|
||||
|
||||
const toggleChapter = (id) => {
|
||||
const toggleChapter = (id: number) => {
|
||||
if (!chapters.value[id]) chapters.value[id] = { expanded: false };
|
||||
chapters.value[id].expanded = !chapters.value[id].expanded;
|
||||
};
|
||||
|
||||
const fetchResources = async (page = 1, reset = false) => {
|
||||
if (reset) { resourceList.value = []; resourcePage.value = 1; hasMoreResources.value = true; resourceError.value = ''; loadingResources.value = true; }
|
||||
else loadingMoreResources.value = true;
|
||||
if (!selectedCourse.value) return;
|
||||
if (reset) {
|
||||
resourceList.value = [];
|
||||
resourcePage.value = 1;
|
||||
hasMoreResources.value = true;
|
||||
resourceError.value = '';
|
||||
loadingResources.value = true;
|
||||
} else {
|
||||
loadingMoreResources.value = true;
|
||||
}
|
||||
try {
|
||||
const { data } = await axios.post('http://localhost:8080/api/course-resource/list', {
|
||||
course_id: selectedCourse.value.id, page, page_size: resourcePageSize
|
||||
const { data } = await axios.post<ApiResponse<Resource>>('http://localhost:8080/api/course-resource/list', {
|
||||
course_id: selectedCourse.value.id,
|
||||
page,
|
||||
page_size: resourcePageSize
|
||||
});
|
||||
if (!data?.list || typeof data.total !== 'number') throw new Error();
|
||||
if (reset) resourceList.value = data.list; else resourceList.value.push(...data.list);
|
||||
const newResources = data.list as Resource[];
|
||||
if (reset) resourceList.value = newResources;
|
||||
else resourceList.value.push(...newResources);
|
||||
resourcePage.value = page;
|
||||
hasMoreResources.value = page * resourcePageSize < data.total;
|
||||
currentCourseId.value = selectedCourse.value.id;
|
||||
} catch { resourceError.value = reset ? '加载失败' : '加载更多失败'; }
|
||||
finally { loadingResources.value = false; loadingMoreResources.value = false; }
|
||||
} catch {
|
||||
resourceError.value = reset ? '加载失败' : '加载更多失败';
|
||||
} finally {
|
||||
loadingResources.value = false;
|
||||
loadingMoreResources.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreResources = () => { if (loadingMoreResources.value || !hasMoreResources.value) return; fetchResources(resourcePage.value + 1); };
|
||||
const loadMoreResources = () => {
|
||||
if (loadingMoreResources.value || !hasMoreResources.value) return;
|
||||
fetchResources(resourcePage.value + 1);
|
||||
};
|
||||
|
||||
const fetchActivities = async (page = 1, reset = false) => {
|
||||
if (reset) { activityList.value = []; activityPage.value = 1; hasMoreActivities.value = true; activityError.value = ''; loadingActivities.value = true; }
|
||||
else loadingMoreActivities.value = true;
|
||||
if (!selectedCourse.value) return;
|
||||
if (reset) {
|
||||
activityList.value = [];
|
||||
activityPage.value = 1;
|
||||
hasMoreActivities.value = true;
|
||||
activityError.value = '';
|
||||
loadingActivities.value = true;
|
||||
} else {
|
||||
loadingMoreActivities.value = true;
|
||||
}
|
||||
try {
|
||||
const { data } = await axios.post('http://localhost:8080/api/course-activity/list', {
|
||||
course_id: selectedCourse.value.id, page, page_size: activityPageSize
|
||||
const { data } = await axios.post<ApiResponse<Activity>>('http://localhost:8080/api/course-activity/list', {
|
||||
course_id: selectedCourse.value.id,
|
||||
page,
|
||||
page_size: activityPageSize
|
||||
});
|
||||
if (!data || typeof data.total !== 'number' || !Array.isArray(data.list)) throw new Error();
|
||||
if (reset) activityList.value = data.list; else activityList.value.push(...data.list);
|
||||
const newActivities = data.list as Activity[];
|
||||
if (reset) activityList.value = newActivities;
|
||||
else activityList.value.push(...newActivities);
|
||||
activityPage.value = page;
|
||||
hasMoreActivities.value = page * activityPageSize < data.total;
|
||||
currentCourseId.value = selectedCourse.value.id;
|
||||
} catch { activityError.value = reset ? '加载失败' : '加载更多失败'; }
|
||||
finally { loadingActivities.value = false; loadingMoreActivities.value = false; }
|
||||
} catch {
|
||||
activityError.value = reset ? '加载失败' : '加载更多失败';
|
||||
} finally {
|
||||
loadingActivities.value = false;
|
||||
loadingMoreActivities.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreActivities = () => { if (loadingMoreActivities.value || !hasMoreActivities.value) return; fetchActivities(activityPage.value + 1); };
|
||||
const loadMoreActivities = () => {
|
||||
if (loadingMoreActivities.value || !hasMoreActivities.value) return;
|
||||
fetchActivities(activityPage.value + 1);
|
||||
};
|
||||
|
||||
const fetchTeachers = async (page = 1, reset = false) => {
|
||||
if (reset) { teacherList.value = []; teacherPage.value = 1; hasMoreTeachers.value = true; teacherError.value = ''; loadingTeachers.value = true; }
|
||||
else loadingMoreTeachers.value = true;
|
||||
if (!selectedCourse.value) return;
|
||||
if (reset) {
|
||||
teacherList.value = [];
|
||||
teacherPage.value = 1;
|
||||
hasMoreTeachers.value = true;
|
||||
teacherError.value = '';
|
||||
loadingTeachers.value = true;
|
||||
} else {
|
||||
loadingMoreTeachers.value = true;
|
||||
}
|
||||
try {
|
||||
const { data } = await axios.post('http://localhost:8080/api/course-teacher/list', {
|
||||
course_id: selectedCourse.value.id, page, page_size: teacherPageSize
|
||||
const { data } = await axios.post<ApiResponse<Teacher>>('http://localhost:8080/api/course-teacher/list', {
|
||||
course_id: selectedCourse.value.id,
|
||||
page,
|
||||
page_size: teacherPageSize
|
||||
});
|
||||
if (!data || typeof data.total !== 'number' || !Array.isArray(data.list)) throw new Error();
|
||||
if (reset) teacherList.value = data.list; else teacherList.value.push(...data.list);
|
||||
const newTeachers = data.list as Teacher[];
|
||||
if (reset) teacherList.value = newTeachers;
|
||||
else teacherList.value.push(...newTeachers);
|
||||
teacherPage.value = page;
|
||||
hasMoreTeachers.value = page * teacherPageSize < data.total;
|
||||
currentCourseId.value = selectedCourse.value.id;
|
||||
} catch { teacherError.value = reset ? '加载失败' : '加载更多失败'; }
|
||||
finally { loadingTeachers.value = false; loadingMoreTeachers.value = false; }
|
||||
} catch {
|
||||
teacherError.value = reset ? '加载失败' : '加载更多失败';
|
||||
} finally {
|
||||
loadingTeachers.value = false;
|
||||
loadingMoreTeachers.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreTeachers = () => { if (loadingMoreTeachers.value || !hasMoreTeachers.value) return; fetchTeachers(teacherPage.value + 1); };
|
||||
const loadMoreTeachers = () => {
|
||||
if (loadingMoreTeachers.value || !hasMoreTeachers.value) return;
|
||||
fetchTeachers(teacherPage.value + 1);
|
||||
};
|
||||
|
||||
const selectCourse = (course) => {
|
||||
const selectCourse = (course: Course) => {
|
||||
selectedCourse.value = course;
|
||||
currentCourseId.value = course.id;
|
||||
courseChapters.value = []; resourceList.value = []; activityList.value = []; teacherList.value = []; chapters.value = {};
|
||||
courseChapters.value = [];
|
||||
resourceList.value = [];
|
||||
activityList.value = [];
|
||||
teacherList.value = [];
|
||||
chapters.value = {};
|
||||
fetchCourseContent(course.id);
|
||||
activeDetailTab.value = 'content';
|
||||
};
|
||||
|
||||
const handleBackToList = () => { selectedCourse.value = null; currentCourseId.value = null; };
|
||||
const handleBackToList = () => {
|
||||
selectedCourse.value = null;
|
||||
currentCourseId.value = null;
|
||||
};
|
||||
|
||||
// ==================== 初始化 ====================
|
||||
onMounted(() => {
|
||||
|
||||
Reference in New Issue
Block a user