|
@@ -8,6 +8,14 @@
|
|
|
v-contextmenu="contextmenus"
|
|
|
v-click-outside="removeEditorAreaFocus"
|
|
|
>
|
|
|
+ <!-- 全屏Loading状态 -->
|
|
|
+ <div v-if="isCourseLoading" class="fullscreen-loading-overlay">
|
|
|
+ <div class="loading-content">
|
|
|
+ <div class="loading-spinner"></div>
|
|
|
+ <div class="loading-text">正在加载课程内容...</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
<ElementCreateSelection
|
|
|
v-if="creatingElement"
|
|
|
@created="data => insertElementFromCreateSelection(data)"
|
|
@@ -153,6 +161,7 @@ import WebpageLinkEditDialog from './WebpageLinkEditDialog.vue'
|
|
|
import Modal from '@/components/Modal.vue'
|
|
|
import api from '@/services/course'
|
|
|
import useImport from '@/hooks/useImport'
|
|
|
+import message from '@/utils/message'
|
|
|
|
|
|
|
|
|
// 定义组件props
|
|
@@ -196,6 +205,9 @@ const openWebpageLinkEditDialog = (elementId: string, currentUrl: string) => {
|
|
|
webpageLinkEditDialogVisible.value = true
|
|
|
}
|
|
|
|
|
|
+// 课程加载loading状态
|
|
|
+const isCourseLoading = ref(false)
|
|
|
+
|
|
|
watch(handleElementId, () => {
|
|
|
mainStore.setActiveGroupElementId('')
|
|
|
})
|
|
@@ -226,7 +238,7 @@ const { pasteElement } = useCopyAndPasteElement()
|
|
|
const { enterScreeningFromStart } = useScreening()
|
|
|
const { updateSlideIndex } = useSlideHandler()
|
|
|
const { createTextElement, createShapeElement } = useCreateElement()
|
|
|
-const { readJSON } = useImport()
|
|
|
+const { readJSON, getFile } = useImport()
|
|
|
|
|
|
// 组件渲染时,如果存在元素焦点,需要清除
|
|
|
// 这种情况存在于:有焦点元素的情况下进入了放映模式,再退出时,需要清除原先的焦点(因为可能已经切换了页面)
|
|
@@ -240,11 +252,44 @@ onMounted(() => {
|
|
|
})
|
|
|
|
|
|
const getCourseDetail = async () => {
|
|
|
- const res = await api.getCourseDetail(props.courseid as string)
|
|
|
- console.log(res)
|
|
|
- const courseDetail = res[0][0]
|
|
|
- const pptdata = JSON.parse(courseDetail.chapters).pptData ? JSON.parse(courseDetail.chapters).pptData : []
|
|
|
- readJSON(pptdata, true)
|
|
|
+ // 显示全屏loading
|
|
|
+ isCourseLoading.value = true
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await api.getCourseDetail(props.courseid as string)
|
|
|
+ console.log(res)
|
|
|
+ const courseDetail = res[0][0]
|
|
|
+ const pptJSONUrl = JSON.parse(courseDetail.chapters).pptData ? JSON.parse(courseDetail.chapters).pptData : ''
|
|
|
+ console.log(pptJSONUrl)
|
|
|
+
|
|
|
+ if (pptJSONUrl) {
|
|
|
+ const pptdata = await getFile(pptJSONUrl)
|
|
|
+ // pptdata.data 是 ArrayBuffer,需要先转成字符串再解析为 JSON
|
|
|
+ let jsonStr = ''
|
|
|
+ if (pptdata && pptdata.data) {
|
|
|
+ // 先将 ArrayBuffer 转为字符串
|
|
|
+ const uint8Array = new Uint8Array(pptdata.data)
|
|
|
+ jsonStr = new TextDecoder('utf-8').decode(uint8Array)
|
|
|
+ try {
|
|
|
+ const jsonObj = JSON.parse(jsonStr)
|
|
|
+ readJSON(jsonObj, true)
|
|
|
+ }
|
|
|
+ catch (e) {
|
|
|
+ console.error('解析pptdata.data失败:', e)
|
|
|
+ message.error('解析PPT数据失败')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (error) {
|
|
|
+ console.error('获取课程详情失败:', error)
|
|
|
+ message.error('获取课程详情失败')
|
|
|
+ isCourseLoading.value = false
|
|
|
+ }
|
|
|
+ finally {
|
|
|
+ // 隐藏loading
|
|
|
+ isCourseLoading.value = false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
@@ -401,6 +446,47 @@ provide(injectKeySlideScale, canvasScale)
|
|
|
background-color: $lightGray;
|
|
|
position: relative;
|
|
|
}
|
|
|
+
|
|
|
+/* 全屏Loading样式 */
|
|
|
+.fullscreen-loading-overlay {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background: rgba(255, 255, 255, 0.95);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 9999;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-content {
|
|
|
+ text-align: center;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-spinner {
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ border: 5px solid #f3f3f3;
|
|
|
+ border-top: 5px solid #1890ff;
|
|
|
+ border-radius: 50%;
|
|
|
+ animation: spin 1s linear infinite;
|
|
|
+ margin: 0 auto 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.loading-text {
|
|
|
+ font-size: 16px;
|
|
|
+ color: #666;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes spin {
|
|
|
+ 0% { transform: rotate(0deg); }
|
|
|
+ 100% { transform: rotate(360deg); }
|
|
|
+}
|
|
|
+
|
|
|
.drag-mask {
|
|
|
cursor: grab;
|
|
|
@include absolute-0();
|