浏览代码

Merge branch 'master' of https://git.cocorobo.cn/jack/PPT

SanHQin 18 小时之前
父节点
当前提交
7255291b55
共有 1 个文件被更改,包括 191 次插入36 次删除
  1. 191 36
      src/views/Student/index.vue

+ 191 - 36
src/views/Student/index.vue

@@ -100,6 +100,16 @@
           <span class="btn-text">{{ isSubmitting ? '提交中...' : '作业提交' }}</span>
         </div>
 
+        <!-- 刷新iframe按钮 -->
+        <div class="refresh-page-btn" 
+          v-if="currentSlideHasIframe"
+          :style="{ right: getRefreshButtonRight() + 'px' }" 
+          @click="handleRefreshPage"
+          v-tooltip="'刷新iframe内容'">
+          <Refresh class="tool-btn" />
+          <span class="btn-text">刷新</span>
+        </div>
+
         <!-- 功能组件 -->
         <SlideThumbnails v-if="slideThumbnailModelVisible" :turnSlideToIndex="goToSlide"
           @close="slideThumbnailModelVisible = false" />
@@ -239,6 +249,7 @@ import DialoguePanel from './components/DialoguePanel.vue'
 import ChoiceStatistics from './components/ChoiceStatistics.vue'
 import * as Y from 'yjs'
 import { WebsocketProvider } from 'y-websocket'
+import { Refresh } from '@icon-park/vue-next'
 
 
 // 导入图片资源
@@ -325,9 +336,7 @@ const slidePanelCollapsed = ref(false)
 // 右侧面板当前显示的内容:'homework' | 'dialogue' | 'choice'
 const rightPanelMode = ref<'homework' | 'dialogue' | 'choice'>('homework')
 
-// 定时器相关
-const workTimer = ref<number | null>(null)
-const workUpdateInterval = 5000 // 5秒更新一次
+// 移除定时器相关代码,改用socket监听
 
 const courseDetail = ref<any>({})
 const studentArray = ref<any>([])
@@ -397,26 +406,7 @@ const autoSwitchToAvailablePanel = () => {
   }
 }
 
-// 启动作业更新定时器
-const startWorkTimer = () => {
-  if (workTimer.value) {
-    clearInterval(workTimer.value)
-  }
-  workTimer.value = setInterval(() => {
-    console.log('定时器触发,检查作业更新')
-    getWork(true) // 传入 true 表示是更新模式
-  }, workUpdateInterval)
-  console.log('作业更新定时器已启动,间隔:', workUpdateInterval, 'ms')
-}
-
-// 停止作业更新定时器
-const stopWorkTimer = () => {
-  if (workTimer.value) {
-    clearInterval(workTimer.value)
-    workTimer.value = null
-    console.log('作业更新定时器已停止')
-  }
-}
+// 移除定时器相关函数,改用socket监听
 
 // 收缩/展开后重新计算中间画布尺寸(在 DOM 更新并完成过渡后)
 watch([() => workPanelCollapsed.value, () => slidePanelCollapsed.value], async () => {
@@ -586,7 +576,9 @@ const nextSlide = () => {
   }
 }
 
-// 监听slideIndex变化,调用getWork并管理定时器
+
+
+// 监听slideIndex变化,调用getWork
 watch(() => slideIndex.value, (newIndex, oldIndex) => {
   console.log('slideIndex变化,调用getWork', { newIndex, oldIndex })
   if (newIndex !== oldIndex && typeof newIndex === 'number') {
@@ -594,15 +586,11 @@ watch(() => slideIndex.value, (newIndex, oldIndex) => {
     const hasIframe = currentSlideHasIframe.value
     
     if (hasIframe) {
-      console.log('当前页面有iframe,启动作业更新定时器')
-      startWorkTimer()
+      console.log('当前页面有iframe,获取作业数据')
       console.log('触发getWork,当前幻灯片索引:', newIndex)
       getWork()
     }
-    else {
-      console.log('当前页面无iframe,停止作业更新定时器')
-      stopWorkTimer()
-    }
+    
     if (props.type == '1' && isFollowModeActive.value && isCreator.value) {
       api.updateCourseFollowC(newIndex, props.courseid as string)
       sendMessage({slideIndex: newIndex, courseid: props.courseid, type: 'slideIndex'})
@@ -766,7 +754,7 @@ const processIframeLinks = async () => {
                     return element
                   }
                 } 
-                else if (toolType == 45) {
+                else if (toolType == 73) {
                   hasIframe = true
                   
                   // 先尝试获取iframe的contentWindow,如果获取不到再使用HTML方式
@@ -873,10 +861,9 @@ const importJSON = (jsonData: any) => {
         // 延迟500ms后重新显示组件,确保重新渲染完成
         setTimeout(() => {
           showSlideList.value = true
-          // 只有当当前页面存在iframe时才启动作业更新定时器
+          // 只有当当前页面存在iframe时才获取作业数据
           if (currentSlideHasIframe.value && props.type == '1') {
             getWork()
-            startWorkTimer()
           }
           selectCourseSLook()
           console.log('组件重新渲染完成')
@@ -1058,6 +1045,14 @@ const handleHomeworkSubmit = async () => {
               console.log('submitWork同步执行完成')
               message.success('作业提交成功')
               hasSubmitWork = true
+            
+              // 发送作业提交成功的socket消息
+              sendMessage({
+                type: 'homework_submitted',
+                courseid: props.courseid,
+                slideIndex: slideIndex.value,
+                userid: props.userid
+              })
             }
 
             break
@@ -1082,6 +1077,14 @@ const handleHomeworkSubmit = async () => {
           await submitWork(iframeSlideIndex, '72', Cow, '20')
           message.success('作业提交成功')
           hasSubmitWork = true
+          
+          // 发送作业提交成功的socket消息
+          sendMessage({
+            type: 'homework_submitted',
+            courseid: props.courseid,
+            slideIndex: slideIndex.value,
+            userid: props.userid
+          })
         }
       }
       else {
@@ -1153,6 +1156,14 @@ const handleHomeworkSubmit = async () => {
           await submitWork(slideIndex.value, '73', imageUrl, '1') // 73表示截图工具,21表示图片类型
           message.success('页面截图提交成功')
           hasSubmitWork = true
+          
+          // 发送作业提交成功的socket消息
+          sendMessage({
+            type: 'homework_submitted',
+            courseid: props.courseid,
+            slideIndex: slideIndex.value,
+            userid: props.userid
+          })
         }
         catch (error) {
           console.error('截图提交失败:', error)
@@ -1176,6 +1187,66 @@ const handleHomeworkSubmit = async () => {
   }
 }
 
+// 刷新iframe功能
+const handleRefreshPage = () => {
+  console.log('刷新iframe按钮被点击')
+  
+  try {
+    // 获取当前幻灯片中的所有iframe元素
+    const iframes = document.querySelectorAll('.viewer-canvas .screen-slide')[slideIndex.value].querySelectorAll('iframe')
+    console.log('找到iframe元素数量:', iframes.length)
+
+    if (iframes.length === 0) {
+      message.warning('当前页面没有找到iframe元素')
+      return
+    }
+
+    let refreshedCount = 0
+
+    // 遍历所有iframe并刷新
+    for (let i = 0; i < iframes.length; i++) {
+      const iframe = iframes[i] as HTMLIFrameElement
+      const currentSrc = iframe.src
+      
+      if (currentSrc) {
+        console.log(`刷新iframe ${i + 1}:`, currentSrc)
+        
+        // 保存当前src
+        const originalSrc = currentSrc
+        
+        // 清空src触发刷新
+        iframe.src = ''
+        
+        // 短暂延迟后恢复src,确保刷新生效
+        setTimeout(() => {
+          iframe.src = originalSrc
+          console.log(`iframe ${i + 1} 刷新完成`)
+        }, 100)
+        
+        refreshedCount++
+      }
+    }
+
+    if (refreshedCount > 0) {
+      message.success(`刷新完成`)
+      
+      // 如果当前页面有iframe,重新获取作业数据
+      if (currentSlideHasIframe.value && props.type == '1') {
+        setTimeout(() => {
+          getWork()
+        }, 500) // 延迟500ms等待iframe加载完成
+      }
+    }
+    else {
+      message.info('没有找到可刷新的iframe')
+    }
+  }
+  catch (error) {
+    console.error('刷新iframe时出错:', error)
+    message.error('刷新iframe失败')
+  }
+}
+
 // 获取作业提交按钮的右侧位置
 const getHomeworkButtonRight = () => {
   if (isFullscreen.value) {
@@ -1188,6 +1259,18 @@ const getHomeworkButtonRight = () => {
   return 30 // type=2时按钮在右侧30px
 }
 
+// 获取刷新按钮的右侧位置
+const getRefreshButtonRight = () => {
+  if (isFullscreen.value) {
+    return 160 // 全屏时按钮在右侧150px
+  }
+  if (props.type === '1') {
+    // 展开作业区:按钮更靠左;收起时:按钮更靠右侧
+    return workPanelCollapsed.value ? 190 : 560
+  }
+  return 160 // type=2时按钮在右侧150px
+}
+
 
 // 键盘快捷键
 const handleKeydown = (e: KeyboardEvent) => {
@@ -1290,11 +1373,18 @@ const getCourseDetail = async () => {
   }
 }
 
+const getWorkLoading = ref<any>(false)
+
+
 const getWork = async (isUpdate = false) => {
   try {
+    if (getWorkLoading.value) {
+      return
+    }
     if (!isUpdate) {
       workLoading.value = true
     }
+    getWorkLoading.value = true
     console.log('getWork 开始执行,参数:', {
       courseid: props.courseid,
       slideIndex: slideIndex.value,
@@ -1335,17 +1425,20 @@ const getWork = async (isUpdate = false) => {
     }
     
     console.log('getWork 执行成功,结果:', workArray.value)
+    getWorkLoading.value = false
   }
   catch (error) {
     console.error('getWork 执行失败:', error)
     if (!isUpdate) {
       message.error('获取作业信息失败')
     }
+    getWorkLoading.value = false
   }
   finally {
     if (!isUpdate) {
       workLoading.value = false
     }
+    getWorkLoading.value = false
   }
 }
 
@@ -1489,12 +1582,28 @@ const sendMessage = (obj: any) => {
  */
 const getMessages = (msgObj: any) => {
   console.log('message', msgObj)
+  
+  // 处理幻灯片切换消息
   if (props.type == '2' && msgObj.slideIndex && msgObj.type === 'slideIndex') {
     goToSlide(msgObj.slideIndex)
   }
+  
+  // 处理跟随模式状态变化
   if (props.type == '2' && msgObj.type === 'sopen') {
     selectCourseSLook()
   }
+  
+  // 处理作业提交消息 - 当有人提交作业时,重新获取作业数据
+  if (props.type == '1' && msgObj.type === 'homework_submitted' && msgObj.courseid === props.courseid) {
+    console.log('收到作业提交消息,重新获取作业数据')
+    // 延迟一点时间,确保后端数据已更新
+    setTimeout(() => {
+      if (currentSlideHasIframe.value) {
+        getWork(true) // 传入true表示是更新模式
+      }
+    }, 1000)
+  }
+
 }
 
 
@@ -1594,8 +1703,7 @@ onUnmounted(() => {
   // 移除视口尺寸更新事件监听器
   window.removeEventListener('viewportSizeUpdated', handleViewportSizeUpdated)
 
-  // 停止作业更新定时器
-  stopWorkTimer()
+  // 移除定时器清理代码,已改用socket监听
 
   // 清理window上的引用
   if ((window as any).PPTistStudent) {
@@ -1671,7 +1779,7 @@ onUnmounted(() => {
   overflow: auto;
 }
 .layout-content-right.collapsed {
-  width: 48px;
+  width: 52px;
 }
 .right-panel-header {
   display: flex;
@@ -2279,6 +2387,53 @@ onUnmounted(() => {
   }
 }
 
+/* 刷新网页按钮样式 */
+.refresh-page-btn {
+  position: fixed;
+  bottom: 30px;
+  z-index: 100;
+  background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
+  color: white;
+  padding: 12px 20px;
+  border-radius: 25px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
+  transition: all 0.3s ease;
+  font-size: 14px;
+  font-weight: 500;
+
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
+  }
+
+  &:active {
+    transform: translateY(0);
+  }
+
+  .btn-text {
+    white-space: nowrap;
+  }
+
+  .tool-btn {
+    background: transparent;
+    color: white;
+    width: 20px;
+    height: 20px;
+    font-size: 16px;
+    display: flex;
+    align-items: center;
+
+    &:hover {
+      background: transparent;
+      transform: none;
+    }
+  }
+}
+
 /* Loading状态样式 */
 .loading-overlay {
     position: absolute;