<template>
  <div class="pptist-student-viewer" :class="{ 'fullscreen': isFullscreen, 'laser-pen': laserPen }">
    <!-- Loading状态显示 -->
    <div v-if="isLoading" class="loading-overlay">
      <div class="loading-content">
        <div class="loading-spinner"></div>
        <div class="loading-text">正在加载课程内容...</div>
      </div>
    </div>
    <!-- 左侧导航栏 -->
    <div class="layout-content-left" v-show="type == '1'" :class="{ collapsed: slidePanelCollapsed }">
      <div class="thumbnails">
        <div class="viewer-header slide-header">
          <h3 v-show="!slidePanelCollapsed">幻灯片导航</h3>
          <button class="collapse-btn" @click="slidePanelCollapsed = !slidePanelCollapsed" :title="slidePanelCollapsed ? '展开' : '收起'">
            <span v-if="slidePanelCollapsed">›</span>
            <span v-else>‹</span>
          </button>
        </div>
        <div v-show="!slidePanelCollapsed">
          <div class="thumbnail-list">
            <div v-for="(slide, index) in slides" :key="slide.id" class="thumbnail-item"
              :class="{ 'active': slideIndex === index }" @click="goToSlide(index)">
              <div class="label">{{ fillDigit(index + 1, 2) }}</div>
              <ThumbnailSlide class="thumbnail" :slide="slide" :size="168" :visible="true" @click="goToSlide(index)" />
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 中间放映区域 -->
    <div class="layout-content-center">
      <div class="viewer-header" :class="{ 'hidden': isFullscreen }">
        <div class="slide-title">幻灯片 {{ slideIndex + 1 }}</div>
        <div class="viewer-controls">
          <button @click="previousSlide" :disabled="slideIndex === 0" title="上一页" v-if="!isFollowModeActive || props.type == '1'">
            <IconLeftTwo class="control-icon" />
          </button>
          <button @click="nextSlide" :disabled="slideIndex === slides.length - 1" title="下一页" v-if="!isFollowModeActive || props.type == '1'">
            <IconRightTwo class="control-icon" />
          </button>
          <!-- <button @click="resetZoom" title="重置缩放">
                        <IconUndo class="control-icon" />
                    </button> -->
          <button @click="enterFullscreen" title="全屏">
            <IconFullScreenOne class="control-icon" />
          </button>
          <!-- 只有创建人才显示跟随模式按钮 -->
          <button 
            v-if="isCreator" 
            @click="toggleFollowMode" 
            :class="{ 'follow-active': isFollowModeActive }"
          >
            {{ isFollowModeActive ? '关闭跟随模式' : '开启跟随模式' }}
          </button>
          <!-- <button @click="backToEditor" class="back-btn" title="返回编辑">
                        <IconEdit class="control-icon" />
                    </button> -->
        </div>
      </div>

      <div class="viewer-canvas" ref="viewerCanvasRef">

        <!-- 全屏时：使用放映功能 -->
        <!-- <ScreenSlideList :slideWidth="slideWidth"
                    :slideHeight="slideHeight" :animationIndex="0" :turnSlideToId="() => { }"
                    :manualExitFullscreen="() => { }" /> -->

        <!-- 不全屏时：使用编辑模式的显示比例和居中逻辑 -->
        <div class="slide-list-wrap" :style="{
          width: isFullscreen ? '100%' : (slideWidth * canvasScale) + 'px',
          height: isFullscreen ? '100%' : (slideHeight * canvasScale) + 'px',
          left: isFullscreen ? '0' : `${(containerWidth - slideWidth * canvasScale) / 2}px`,
          top: isFullscreen ? '0' : `${(containerHeight - slideHeight * canvasScale) / 2}px`
        }">
          <div class="viewport" v-if="false">
            <div class="background" :style="backgroundStyle"></div>

            <ScreenElement v-for="(element, index) in elementList" :key="element.id" :elementInfo="element"
              :elementIndex="index + 1" :animationIndex="0" :turnSlideToId="() => { }"
              :manualExitFullscreen="() => { }" />
          </div>

          <ScreenSlideList :slideWidth="slideWidth * canvasScale" :slideHeight="slideHeight * canvasScale"
            :animationIndex="0" :turnSlideToId="() => { }" :manualExitFullscreen="() => { }" />
        </div>
        <!-- 全屏时的左右下角工具按钮 -->
        <div v-if="isFullscreen && (!isFollowModeActive || props.type == '1')" class="tools-left">
          <IconLeftTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="previousSlide" />
          <IconRightTwo class="tool-btn" theme="two-tone" :fill="['#111', '#fff']" @click="nextSlide" />
        </div>

        <!-- 作业提交按钮 - 当当前幻灯片包含iframe时显示 -->
        <div v-if="currentSlideHasIframe" class="homework-submit-btn" :class="{ 'submitting': isSubmitting }"
          :style="{ right: getHomeworkButtonRight() + 'px' }" @click="handleHomeworkSubmit"
          v-tooltip="isSubmitting ? '作业提交中...' : '作业提交'">
          <IconEdit v-if="!isSubmitting" class="tool-btn" />
          <div v-else class="loading-spinner"></div>
          <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" />

        <WritingBoardTool :slideWidth="slideWidth" :slideHeight="slideHeight" v-if="writingBoardToolVisible"
          @close="writingBoardToolVisible = false" />

        <CountdownTimer v-if="timerlVisible" @close="timerlVisible = false" />

        <div v-if="isFullscreen && (!isFollowModeActive || props.type == '1')" class="tools-right" :class="{ 'visible': rightToolsVisible }"
          @mouseleave="rightToolsVisible = false" @mouseenter="rightToolsVisible = true">
          <div class="content">
            <div class="tool-btn page-number" @click="slideThumbnailModelVisible = true">幻灯片 {{ slideIndex +
              1 }} / {{ slides.length }}</div>
            <IconWrite class="tool-btn" v-tooltip="'画笔工具'" @click="writingBoardToolVisible = true" />
            <IconMagic class="tool-btn" v-tooltip="'激光笔'" :class="{ 'active': laserPen }" @click="toggleLaserPen" />
            <IconStopwatchStart class="tool-btn" v-tooltip="'计时器'" @click="timerlVisible = !timerlVisible" />
            <IconOffScreenOne class="tool-btn" v-tooltip="'退出全屏'" @click="enterFullscreen" />
          </div>
        </div>
      </div>
    </div>
    <div class="layout-content-right" v-show="type == '1'" :class="{ collapsed: workPanelCollapsed }">
      <div class="thumbnails">
        <div class="viewer-header right-panel-header">
          <h3 v-show="!workPanelCollapsed">{{ 
            rightPanelMode === 'homework' ? '作业区' : 
            rightPanelMode === 'dialogue' ? '对话区' : '统计' 
          }}</h3>
          <button class="collapse-btn" @click="workPanelCollapsed = !workPanelCollapsed" :title="workPanelCollapsed ? '展开' : '收起'">
            <span v-if="workPanelCollapsed">›</span>
            <span v-else>‹</span>
          </button>
        </div>
        
        <!-- 侧边导航标签 - 无论展开还是收缩都显示在左侧 -->
        <div class="side-nav-tabs">
          <button 
            v-if="currentSlideHasIframe"
            class="side-nav-btn" 
            :class="{ active: rightPanelMode === 'homework' }"
            @click="switchToHomework"
            title="作业"
          >
            <img :src="rightPanelMode === 'homework' ? homeworkActiveIcon : homeworkIcon" alt="作业">
          </button>
          <button 
            v-if="isChoiceQuestion"
            class="side-nav-btn" 
            :class="{ active: rightPanelMode === 'choice' }"
            @click="switchToChoice"
            title="统计"
          >
            <img :src="rightPanelMode === 'choice' ? choiceActiveIcon : choiceIcon" alt="统计">
          </button>
          <button 
            class="side-nav-btn" 
            :class="{ active: rightPanelMode === 'dialogue' }"
            @click="switchToDialogue"
            title="对话"
          >
            <img :src="rightPanelMode === 'dialogue' ? dialogueActiveIcon : dialogueIcon" alt="对话">
          </button>
        </div>
        

        
        <!-- 作业区内容 -->
        <div v-show="!workPanelCollapsed && rightPanelMode === 'homework'" class="panel-content">
          <div class="homework-title">已提交</div>
          <div v-if="workLoading" class="homework-loading">正在加载作业...</div>
          <div v-else>
            <div v-if="workArray && workArray.length" class="homework-grid">
              <button class="homework-btn" v-for="(work, idx) in workArray" :key="work.id ?? idx" :title="work.name" @click="openWorkModal(work)">
                <span class="homework-btn__text">{{ work.name }}</span>
              </button>
            </div>
            <div class="homework-empty" v-else>
              暂无作业提交
            </div>
          </div>
          
          <!-- 未提交作业的学生列表 -->
          <div v-if="unsubmittedStudents && unsubmittedStudents.length > 0" class="homework-title" style="margin-top: 20px;">未提交</div>
          <div v-if="unsubmittedStudents && unsubmittedStudents.length > 0">
            <div v-if="studentLoading" class="homework-loading">正在加载学生信息...</div>
            <div v-else>
              <div class="homework-grid">
                <button class="homework-btn unsubmitted" v-for="(student, idx) in unsubmittedStudents" :key="student.id ?? idx" :title="student.name" disabled>
                  <span class="homework-btn__text">{{ student.name }}</span>
                </button>
              </div>
            </div>
          </div>
        </div>
        
        <!-- 对话区内容 -->
        <div v-show="!workPanelCollapsed && rightPanelMode === 'dialogue'" class="panel-content">
          <DialoguePanel :userid="props.userid" :courseid="props.courseid"/>
        </div>
        
        <!-- 选择题统计内容 -->
        <div v-show="!workPanelCollapsed && rightPanelMode === 'choice'" class="panel-content">
          <ChoiceStatistics :workArray="workArray" :elementList="elementList" />
        </div>
      </div>
    </div>
  </div>

  <ShotWorkModal v-model:visible="visibleShot" :work="selectedWork" />
  <QAWorkModal v-model:visible="visibleQA" :work="selectedWork" />
  <ChoiceWorkModal v-model:visible="visibleChoice" :work="selectedWork" />
  <AIWorkModal v-model:visible="visibleAI" :work="selectedWork" />
</template>

<script lang="ts" setup>
import { computed, ref, onMounted, onUnmounted, nextTick, inject, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useSlidesStore } from '@/store'
import { ElementTypes } from '@/types/slides'
import { fillDigit } from '@/utils/common'
import ThumbnailSlide from '@/views/components/ThumbnailSlide/index.vue'
import ScreenSlideList from '@/views/Screen/ScreenSlideList.vue'
import ScreenElement from '@/views/Screen/ScreenElement.vue'
import SlideThumbnails from '@/views/Screen/SlideThumbnails.vue'
import WritingBoardTool from '@/views/Screen/WritingBoardTool.vue'
import CountdownTimer from '@/views/Screen/CountdownTimer.vue'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
import useImport from '@/hooks/useImport'
import message from '@/utils/message'
import api from '@/services/course'
import ShotWorkModal from './components/ShotWorkModal.vue'
import QAWorkModal from './components/QAWorkModal.vue'
import ChoiceWorkModal from './components/ChoiceWorkModal.vue'
import AIWorkModal from './components/AIWorkModal.vue'
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'


// 导入图片资源
import homeworkIcon from '@/assets/img/homework.png'
import homeworkActiveIcon from '@/assets/img/homework-active.png'
import dialogueIcon from '@/assets/img/dialogue.png'
import dialogueActiveIcon from '@/assets/img/dialogue-active.png'
import choiceIcon from '@/assets/img/choice.png'
import choiceActiveIcon from '@/assets/img/choice-active.png'

// 定义组件props
interface Props {
  courseid?: string | null
  userid?: string | null
  oid?: string | null
  org?: string | null
  cid?: string | null
  type?: string | null
}

const props = withDefaults(defineProps<Props>(), {
  courseid: null,
  userid: null,
  oid: null,
  org: null,
  cid: null,
  type: null,
})

// 图标组件通过全局注册，无需导入

const slidesStore = useSlidesStore()
const { slides, slideIndex, currentSlide, viewportSize, viewportRatio } = storeToRefs(slidesStore)

// 添加容器引用，用于计算幻灯片尺寸
const viewerCanvasRef = ref<HTMLElement>()

// 放映相关的状态
const canvasScale = ref(1) // 画布缩放比例
const isFullscreen = ref(false) // 是否全屏
const containerWidth = ref(0) // 容器宽度
const containerHeight = ref(0) // 容器高度

// 全屏工具相关状态
const rightToolsVisible = ref(false)
const writingBoardToolVisible = ref(false)
const timerlVisible = ref(false)
const slideThumbnailModelVisible = ref(false)
const laserPen = ref(false)

// 作业提交状态
const isSubmitting = ref(false)

// 控制组件显示的开关
const showSlideList = ref(true)
const slideWidth = ref(0)
const slideHeight = ref(0)

// 添加loading状态
const isLoading = ref(false)
const workLoading = ref(false)
const studentLoading = ref(false)

// 作业数组
type WorkItem = {
  id?: string | number
  name: string
  type: number | string
  [key: string]: any
}
const workArray = ref<WorkItem[]>([])

// 作业弹窗相关
const selectedWork = ref<any>(null)
const visibleShot = ref(false)
const visibleQA = ref(false)
const visibleChoice = ref(false)
const visibleAI = ref(false)

// 作业区收缩状态
const workPanelCollapsed = ref(false)
// 幻灯片导航收缩状态
const slidePanelCollapsed = ref(false)
// 右侧面板当前显示的内容：'homework' | 'dialogue' | 'choice'
const rightPanelMode = ref<'homework' | 'dialogue' | 'choice'>('homework')

// 移除定时器相关代码，改用socket监听

const courseDetail = ref<any>({})
const studentArray = ref<any>([])

// 跟随模式相关状态
const isCreator = ref(false) // 是否为创建人
const isFollowModeActive = ref(false) // 跟随模式是否开启

// 计算未提交作业的学生
const unsubmittedStudents = computed(() => {
  if (!studentArray.value || !workArray.value) return []
  
  // 获取已提交作业的学生姓名
  const submittedNames = workArray.value.map(work => work.name)
  
  // 过滤出未提交作业的学生
  return studentArray.value.filter((student: any) => !submittedNames.includes(student.name))
})

const docSocket = ref<Y.Doc | null>(null)
const yMessage = ref<any | null>(null)
const providerSocket = ref<WebsocketProvider | null>(null)
const mId = ref<string | null>(null)


// 切换到作业区
const switchToHomework = () => {
  rightPanelMode.value = 'homework'
  if (workPanelCollapsed.value) {
    workPanelCollapsed.value = false
  }
}

// 切换到对话区
const switchToDialogue = () => {
  rightPanelMode.value = 'dialogue'
  if (workPanelCollapsed.value) {
    workPanelCollapsed.value = false
  }
}

// 切换到选择题统计
const switchToChoice = () => {
  rightPanelMode.value = 'choice'
  if (workPanelCollapsed.value) {
    workPanelCollapsed.value = false
  }
}

// 自动切换到可用的面板
const autoSwitchToAvailablePanel = () => {
  // 如果当前在作业区但没有iframe，自动切换到其他可用面板
  if (rightPanelMode.value === 'homework' && !currentSlideHasIframe.value) {
    if (isChoiceQuestion.value) {
      rightPanelMode.value = 'choice'
      console.log('自动切换到统计面板')
    }
    else {
      rightPanelMode.value = 'dialogue'
      console.log('自动切换到对话面板')
    }
  }
  // 如果当前在统计面板但不是选择题，自动切换到对话面板
  else if (rightPanelMode.value === 'choice' && !isChoiceQuestion.value) {
    rightPanelMode.value = 'dialogue'
    console.log('自动切换到对话面板')
  }
}

// 移除定时器相关函数，改用socket监听

// 收缩/展开后重新计算中间画布尺寸（在 DOM 更新并完成过渡后）
watch([() => workPanelCollapsed.value, () => slidePanelCollapsed.value], async () => {
  // 等待本次 DOM 更新
  await nextTick()
  // 先在下一帧计算一次，确保初步布局就绪
  requestAnimationFrame(() => {
    calculateScale()
  })
  // 再在过渡结束后（与左右栏 width .2s 过渡一致）复算一次，确保最终尺寸
  setTimeout(() => {
    calculateScale()
  }, 220)
}, { flush: 'post' })

const openWorkModal = (work: WorkItem) => {
  selectedWork.value = work
  const t = Number(work?.type)
  // if (t !== 1) {
  //   message.warning('暂未开发完成')
  //   return
  // }
  visibleShot.value = false
  visibleQA.value = false
  visibleChoice.value = false
  visibleAI.value = false
  if (t === 1) {
    visibleShot.value = true
  }
  else if (t === 3) {
    visibleQA.value = true
  }
  else if (t === 8) {
    visibleChoice.value = true
  }
  else if (t === 20) {
    visibleAI.value = true
  }
  else {
    message.info('暂不支持的作业类型')
  }
}

// 计算幻灯片尺寸的函数
const calculateSlideSize = () => {
  const slideWrapRef = isFullscreen.value ? document.body : viewerCanvasRef.value
  const winWidth = slideWrapRef?.clientWidth || 0
  const winHeight = slideWrapRef?.clientHeight || 0

  // 根据视口比例计算最佳尺寸
  if (winHeight / winWidth === viewportRatio.value) {
    slideWidth.value = winWidth
    slideHeight.value = winHeight
  }
  else if (winHeight / winWidth > viewportRatio.value) {
    slideWidth.value = winWidth
    slideHeight.value = winWidth * viewportRatio.value
  }
  else {
    slideWidth.value = winHeight / viewportRatio.value
    slideHeight.value = winHeight
  }

  console.log('calculateSlideSize', slideWidth.value, slideHeight.value, viewportRatio.value, canvasScale.value)
}

// 使用编辑模式的缩放逻辑
const calculateScale = () => {
  console.log('calculateScale 开始执行')


  // 获取容器尺寸
  const container = viewerCanvasRef.value || document.querySelector('.viewer-canvas')
  if (container) {
    containerWidth.value = container.clientWidth
    containerHeight.value = container.clientHeight

    console.log('容器尺寸:', {
      width: containerWidth.value,
      height: containerHeight.value
    })

    // 计算基础尺寸
    const baseWidth = viewportSize.value
    const baseHeight = viewportSize.value * viewportRatio.value

    console.log('基础尺寸:', {
      baseWidth,
      baseHeight,
      viewportSize: viewportSize.value,
      viewportRatio: viewportRatio.value
    })

    // 计算缩放比例，让幻灯片能够合理利用空间
    const scaleX = containerWidth.value / baseWidth
    const scaleY = containerHeight.value / baseHeight

    console.log('原始缩放比例:', { scaleX, scaleY })

    // 选择较小的缩放比例，确保幻灯片完全显示且居中，留10%边距
    const scale = Math.min(scaleX, scaleY) * 0.9

    console.log('最终缩放比例:', scale)
    canvasScale.value = isFullscreen.value ? 1 : props.type == '1' ? 1 : 1
    // canvasScale.value = 1
  }
  else {
    console.error('找不到容器元素')
  }
  // 计算幻灯片尺寸
  nextTick(() => {
    setTimeout(() => {
      calculateSlideSize()  
    }, 500)
  })
}

// 简化：直接使用放映功能的缩放逻辑
const resetZoom = () => {
  calculateScale()
}

// 背景样式
const background = computed(() => currentSlide.value?.background)
const { backgroundStyle } = useSlideBackgroundStyle(background)

// 计算当前幻灯片的元素列表
const elementList = computed(() => {
  return currentSlide.value?.elements || []
})

// 检查当前是否为选择题（toolType为45）
const isChoiceQuestion = computed(() => {
  const frame = elementList.value.find(element => element.type === ElementTypes.FRAME)
  return frame?.toolType === 45
})

// 检测当前幻灯片是否包含iframe元素
const currentSlideHasIframe = computed(() => {
  console.log('elementList.value', elementList.value)
  return elementList.value.some(element => element.type === ElementTypes.FRAME)
})

// 跳转到指定幻灯片
const goToSlide = (index: number) => {
  console.log('goToSlide 被调用，目标索引:', index)
  console.log('当前索引:', slideIndex.value)
  
  if (index >= 0 && index < slides.value.length) {
    slidesStore.updateSlideIndex(index)
    console.log('更新后的索引:', slideIndex.value)
  }
  else {
    console.warn('goToSlide: 无效的索引:', index)
  }
}

// 上一页
const previousSlide = () => {
  if (slideIndex.value > 0) {
    const newIndex = slideIndex.value - 1
    console.log('上一页，从', slideIndex.value, '到', newIndex)
    slidesStore.updateSlideIndex(newIndex)
  }
}

// 下一页
const nextSlide = () => {
  if (slideIndex.value < slides.value.length - 1) {
    const newIndex = slideIndex.value + 1
    console.log('下一页，从', slideIndex.value, '到', newIndex)
    slidesStore.updateSlideIndex(newIndex)
  }
}



// 监听slideIndex变化，调用getWork
watch(() => slideIndex.value, (newIndex, oldIndex) => {
  console.log('slideIndex变化，调用getWork', { newIndex, oldIndex })
  if (newIndex !== oldIndex && typeof newIndex === 'number') {
    // 检查新页面是否有iframe
    const hasIframe = currentSlideHasIframe.value
    
    if (hasIframe) {
      console.log('当前页面有iframe，获取作业数据')
      console.log('触发getWork，当前幻灯片索引:', newIndex)
      getWork()
    }
    
    if (props.type == '1' && isFollowModeActive.value && isCreator.value) {
      api.updateCourseFollowC(newIndex, props.courseid as string)
      sendMessage({slideIndex: newIndex, courseid: props.courseid, type: 'slideIndex'})
    }
    // 自动切换到可用的面板
    autoSwitchToAvailablePanel()

  }
}, { immediate: false, deep: false })

// 监听iframe状态变化，自动切换面板
watch(() => currentSlideHasIframe.value, (hasIframe) => {
  if (!hasIframe) {
    autoSwitchToAvailablePanel()
  }
}, { immediate: false })

// 全屏
const enterFullscreen = () => {
  if (document.fullscreenElement) {
    document.exitFullscreen()
  }
  else {
    document.documentElement.requestFullscreen()
  }
}

// 监听全屏状态变化
const handleFullscreenChange = () => {
  isFullscreen.value = !!document.fullscreenElement

  if (isFullscreen.value) {
    // 全屏时不需要计算缩放，直接使用放映功能
    console.log('进入全屏模式')
  }
  else {
    // 退出全屏时重置所有工具状态并重新计算缩放比例
    console.log('退出全屏模式，重置工具状态')

    // 重置所有工具状态
    rightToolsVisible.value = false
    writingBoardToolVisible.value = false
    timerlVisible.value = false
    slideThumbnailModelVisible.value = false
    laserPen.value = false

    // 重新计算缩放比例
    nextTick(() => {
      setTimeout(() => {
        calculateScale()
      }, 1000)
    })
  }
}

// 切换激光笔模式
const toggleLaserPen = () => {
  laserPen.value = !laserPen.value
  console.log('激光笔状态:', laserPen.value ? '开启' : '关闭')
}

// 获取导入导出功能
const { readJSON, exportJSON2, getFile } = useImport()

// 根据iframe的URL查找对应的幻灯片索引
const findSlideIndexByIframeUrl = (iframeUrl: string): number => {
  try {
    console.log('查找iframe对应的幻灯片索引，iframe URL:', iframeUrl)

    // 遍历所有幻灯片，查找包含该iframe URL的幻灯片
    for (let i = 0; i < slides.value.length; i++) {
      const slide = slides.value[i]

      // 检查幻灯片的元素中是否有iframe
      if (slide.elements && slide.elements.length > 0) {
        for (const element of slide.elements) {
          // 检查是否是iframe元素
          if (element.type === ElementTypes.FRAME) {
            // 检查iframe的src是否匹配
            if (element.url === iframeUrl) {
              console.log(`找到匹配的幻灯片，索引: ${i}, 幻灯片ID: ${slide.id}`)
              return i
            }
          }
        }
      }
    }

    // 如果没有找到匹配的幻灯片，返回当前幻灯片索引
    console.log('未找到匹配的幻灯片，使用当前幻灯片索引:', slideIndex.value)
    return slideIndex.value
  }
  catch (error) {
    console.error('查找幻灯片索引时出错:', error)
    return slideIndex.value
  }
}

// 处理iframe链接，为包含workPage的iframe添加必要参数
// 处理iframe链接，为包含workPage的iframe添加必要参数
const processIframeLinks = async () => {
  try {
    console.log('开始处理iframe链接')
    console.log('当前props:', { courseid: props.courseid, userid: props.userid })

    // 从slides数据中查找包含iframe的元素
    let hasIframe = false
    // 由于有异步操作，需整体用Promise.all处理
    const updatedSlides = await Promise.all(
      slides.value.map(async (slide, slideIndex) => {
        if (slide.elements && slide.elements.length > 0) {
          // 这里不能直接用async map，否则会导致类型不对
          const updatedElements = await Promise.all(
            slide.elements.map(async (element) => {
              // 检查是否是iframe元素
              if (element.type === ElementTypes.FRAME && element.url) {
                const iframeSrc = element.url
                const toolType = element.toolType

                if (iframeSrc.includes('workPage')) {
                  hasIframe = true
                  console.log(`处理幻灯片 ${slideIndex + 1} 中的iframe链接:`, iframeSrc)

                  try {
                    // 解析URL，处理hash部分
                    let baseUrl = iframeSrc
                    let hashPart = ''

                    // 分离base URL和hash部分
                    if (iframeSrc.includes('#')) {
                      const parts = iframeSrc.split('#')
                      baseUrl = parts[0]
                      hashPart = parts[1]
                    }

                    // 构建新的hash部分，添加参数
                    // 使用当前幻灯片索引作为task参数
                    let newHash = hashPart
                    if (newHash.includes('?')) {
                      // 如果hash中已经有查询参数，添加&
                      newHash += `&courseid=${props.courseid || ''}&userid=${props.userid || ''}&stage=0&task=${slideIndex}&tool=0`
                    } 
                    else {
                      // 如果hash中没有查询参数，添加?
                      newHash += `?courseid=${props.courseid || ''}&userid=${props.userid || ''}&stage=0&task=${slideIndex}&tool=0`
                    }

                    // 构建新的URL
                    const newUrl = `${baseUrl}#${newHash}`

                    console.log(`幻灯片 ${slideIndex + 1} 的iframe链接已更新:`, newUrl)

                    // 返回更新后的元素
                    return {
                      ...element,
                      url: newUrl
                    }
                  } 
                  catch (error) {
                    console.error(`处理幻灯片 ${slideIndex + 1} 的iframe链接时出错:`, error)
                    return element
                  }
                } 
                else if (toolType == 73) {
                  hasIframe = true
                  
                  // 先尝试获取iframe的contentWindow，如果获取不到再使用HTML方式
                  try {
                    // 创建一个临时的iframe来测试是否能获取contentWindow
                    const tempIframe = document.createElement('iframe')
                    tempIframe.style.display = 'none'
                    tempIframe.src = iframeSrc
                    
                    // 先将临时iframe添加到body，否则onload事件不会触发
                    document.body.appendChild(tempIframe)
                    // 等待iframe加载完成
                    await new Promise((resolve, reject) => {
                      tempIframe.onload = resolve
                      tempIframe.onerror = reject
                      // 可选：设置超时时间，避免长时间无响应
                      setTimeout(() => reject(new Error('Timeout')), 5000)
                    })
                    
                    // 尝试获取contentWindow
                    if (tempIframe.contentWindow && tempIframe.contentWindow.document) {
                      console.log(`iframe ${iframeSrc} 可以获取contentWindow，使用直接加载方式`)
                      // 移除临时iframe
                      document.body.removeChild(tempIframe)
                      
                      return {
                        ...element,
                        isHTML: false,
                        url: iframeSrc
                      }
                    } 
                    // 加载完成但无法获取contentWindow，也要移除iframe
                    document.body.removeChild(tempIframe)
                    
                  }
                  catch (error) {
                    console.log(`iframe ${iframeSrc} 无法获取contentWindow，使用HTML方式:`, error)
                  }
                  
                  // 如果无法获取contentWindow，使用HTML方式
                  const html = await api.getHTML(iframeSrc)
                  // const html = await api.getHTML('https://knowledge.cocorobo.cn/zh-CN/story-telling/a7fa08b8-cf60-11ef-93e3-12e77c4cb76b')
                  console.log('html', html)
                  console.log(`处理幻灯片 ${slideIndex + 1} 中的iframe链接:`, iframeSrc)
                  return {
                    ...element,
                    isHTML: true,
                    url: html
                  }
                }
              }

              // 不是iframe元素或不需要处理，直接返回
              return element
            })
          )

          // 返回更新后的幻灯片
          return {
            ...slide,
            elements: updatedElements
          }
        }

        // 没有元素的幻灯片直接返回
        return slide
      })
    )

    if (hasIframe) {
      console.log('找到iframe元素，更新slides数据')
      // 更新store中的slides数据
      slidesStore.setSlides(updatedSlides)
      console.log('slides数据更新完成')
    }
    else {
      console.log('未找到包含workPage的iframe元素')
    }

    console.log('iframe链接处理完成')
  }
  catch (error) {
    console.error('处理iframe链接时出错:', error)
  }
}

// 导入JSON功能
const importJSON = (jsonData: any) => {
  try {
    console.log('Student importJSON 开始执行')

    const result = readJSON(jsonData, true)

    if (result.success) {
      console.log('Student importJSON 成功，开始重新渲染')

      // 强制重新渲染：先隐藏组件
      showSlideList.value = false

      // 重新计算画布尺寸和缩放比例
      nextTick(() => {
        calculateScale()

        // 延迟500ms后重新显示组件，确保重新渲染完成
        setTimeout(() => {
          showSlideList.value = true
          // 只有当当前页面存在iframe时才获取作业数据
          if (currentSlideHasIframe.value && props.type == '1') {
            getWork()
          }
          selectCourseSLook()
          console.log('组件重新渲染完成')
        }, 500)
      })

      return true
    }

    console.error('Student importJSON 失败:', result.error)
    return false

  }
  catch (error) {
    console.error('Student importJSON 执行失败:', error)
    return false
  }
}

// 导出JSON功能
const exportJSON = () => {
  try {
    console.log('Student exportJSON 开始执行，调用 useImport.exportJSON2')

    // 直接调用 useImport 中的 exportJSON2 函数
    const exportData = exportJSON2()

    if (exportData) {

      return exportData
    }
    console.error('Student exportJSON 失败: exportJSON2 返回空数据')
    return false

  }
  catch (error) {
    console.error('Student exportJSON 执行失败:', error)
    return false
  }
}

// 返回编辑器
const backToEditor = () => {
  // 通过路由跳转到编辑模式
  window.location.href = '/'
}

const submitWork = async (slideIndex: number, atool: string, content: string, type: string) => {
  const res = await api.submitWork({
    uid: props.userid as string,
    cid: props.courseid as string,
    stage: '0',
    task: String(slideIndex), // 转为字符串
    tool: '0',
    atool: atool,
    content: content,
    type: type
  })
  getWork()
  console.log(res)
}
// 文件上传到AWS S3的函数
const uploadFile = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    try {
      // 检查AWS SDK是否可用
      if (!(window as any).AWS) {
        reject(new Error('AWS SDK not loaded'))
        return
      }

      const credentials = {
        accessKeyId: 'AKIATLPEDU37QV5CHLMH',
        secretAccessKey: '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'
      }

      // 配置AWS
      ;(window as any).AWS.config.update(credentials)
      ;(window as any).AWS.config.region = 'cn-northwest-1'

      // 创建S3实例
      const bucket = new (window as any).AWS.S3({ params: { Bucket: 'ccrb' } })

      if (file) {
        // 生成唯一的文件名
        const fileExtension = file.name.split('.').pop()
        const fileName = `${file.name.split('.')[0]}_${Date.now()}.${fileExtension}`

        const params = {
          Key: fileName,
          ContentType: file.type,
          Body: file,
          ACL: 'public-read'
        }

        const options = {
          partSize: 2048 * 1024 * 1024, // 2GB分片
          queueSize: 2,
          leavePartsOnError: true
        }

        bucket
          .upload(params, options)
          .on('httpUploadProgress', (evt: any) => {
            // 这里可以添加进度条逻辑
            const progress = Math.round((evt.loaded * 100) / evt.total)
            console.log(`Uploaded: ${progress}%`)
          })
          .send((err: any, data: any) => {
            if (err) {
              console.error('Upload failed:', err)
              message.error('文件上传失败')
              reject(err)
            }
            else {
              console.log('Upload successful:', data.Location)
              resolve(data.Location)
            }
          })
      }
      else {
        reject(new Error('No file provided'))
      }
    }
    catch (error) {
      console.error('Upload error:', error)
      reject(error)
    }
  })
}
// 作业提交功能（优化版）
const handleHomeworkSubmit = async () => {
  console.log('作业提交按钮被点击')

  // 防抖：如果正在提交中，直接返回
  if (isSubmitting.value) {
    console.log('作业正在提交中，忽略重复点击')
    return
  }

  isSubmitting.value = true

  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 hasSubmitWork = false

    for (let i = 0; i < iframes.length; i++) {
      const iframe = iframes[i] as HTMLIFrameElement
      const iframeSrc = iframe.src
      console.log(`iframe ${i + 1} 链接:`, iframeSrc)

      // 检查iframe链接是否包含workPage
      if (iframeSrc && iframeSrc.includes('workPage')) {
        console.log('找到包含workPage的iframe，尝试执行submitWork')

        try {
          const iframeWindow = iframe.contentWindow as Window & { submitWork?: (...args: any[]) => unknown }

          if (iframeWindow && typeof iframeWindow.submitWork === 'function') {
            console.log('执行iframe中的submitWork方法，参数可变')
            const iframeSlideIndex = slideIndex.value
            const submitArgs = [iframeSlideIndex]

            // 支持同步和异步submitWork
            const result = await iframeWindow.submitWork(...submitArgs)
            if (result instanceof Promise) {
              await result
              console.log('submitWork异步执行完成')
            } 
            else {
              console.log('submitWork同步执行完成')
              message.success('作业提交成功')
              hasSubmitWork = true
            
              // 发送作业提交成功的socket消息
              sendMessage({
                type: 'homework_submitted',
                courseid: props.courseid,
                slideIndex: slideIndex.value,
                userid: props.userid
              })
            }

            break
          } 
          else {
            console.log('iframe中没有找到submitWork方法')
          }
        } 
        catch (error) {
          console.error('访问iframe内容时出错:', error)
        }
      } 
      else if (iframeSrc && (iframeSrc.includes('aichat.cocorobo') || iframeSrc.includes('knowledge.cocorobo'))) {
        console.log('找到包含aichat.cocorobo或knowledge.cocorobo的iframe，尝试执行submitWork')
        // 由于TS类型检查，需通过 any 绕过类型限制
        const iframeWindow = iframe.contentWindow as any
        if (iframeWindow && iframeWindow.exposed_outputs) {
          console.log('执行iframe中的submitWork方法，参数可变')
          const iframeSlideIndex = slideIndex.value
          const Cow = JSON.stringify(iframeWindow.exposed_outputs)
          // 这里假设 submitWork 是全局可用的函数
          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 {
        // message.warning('当前页面暂不支持作业提交')
        console.log('尝试截图当前页面并提交')
        // return
        try {
          // 尝试使用html2canvas，对iframe支持更好
          let imageData: string
          const screenSlides = document.querySelectorAll('.viewer-canvas .screen-slide')
          let iframeElement: HTMLElement | null = null
          if (
            screenSlides &&
            screenSlides[slideIndex.value] &&
            screenSlides[slideIndex.value].querySelector('iframe') &&
            (screenSlides[slideIndex.value].querySelector('iframe') as HTMLIFrameElement).contentWindow &&
            (screenSlides[slideIndex.value].querySelector('iframe') as HTMLIFrameElement).contentWindow!.document &&
            (screenSlides[slideIndex.value].querySelector('iframe') as HTMLIFrameElement).contentWindow!.document.body
          ) {
            iframeElement = (screenSlides[slideIndex.value].querySelector('iframe') as HTMLIFrameElement).contentWindow!.document.body as HTMLElement
          }
          else {
            throw new Error('未能获取到iframe的body元素，无法截图')
          }

          try {
            // 方案1：使用html2canvas的iframe特殊处理
            const html2canvas = await import('html2canvas')
            const canvas = await html2canvas.default(iframeElement, {
              useCORS: true,
              allowTaint: true,
              scale: 1,
              backgroundColor: '#ffffff',
              logging: false,
              // 关键配置：处理iframe内容
              foreignObjectRendering: true,
              removeContainer: true,
              // 特殊处理iframe
              onclone: (clonedDoc, element) => {
                // 在克隆的文档中处理iframe
                const clonedIframes = clonedDoc.querySelectorAll('iframe')
                clonedIframes.forEach((iframe) => {
                  const src = iframe.getAttribute('src')
                  if (src) {
                    // 创建一个包含iframe信息的占位符
                    const placeholder = clonedDoc.createElement('div')
                    placeholder.style.width = iframe.style.width || iframe.getAttribute('width') || '100%'
                    placeholder.style.height = iframe.style.height || iframe.getAttribute('height') || '300px'
                    placeholder.style.backgroundColor = '#f8f9fa'
                    placeholder.style.border = '2px solid #dee2e6'
                    placeholder.style.borderRadius = '8px'
                    placeholder.style.display = 'flex'
                    placeholder.style.flexDirection = 'column'
                    placeholder.style.alignItems = 'center'
                    placeholder.style.justifyContent = 'center'
                    placeholder.style.padding = '20px'
                    placeholder.style.fontFamily = 'Arial, sans-serif'
                    
                    // 创建iframe占位符内容
                    placeholder.innerHTML = `
                      <div style="font-size: 24px; margin-bottom: 10px;">🌐</div>
                      <div style="font-size: 16px; font-weight: bold; color: #495057; margin-bottom: 8px;">iframe内容</div>
                      <div style="font-size: 12px; color: #6c757d; text-align: center; word-break: break-all; max-width: 100%;">
                        ${src.length > 60 ? src.substring(0, 60) + '...' : src}
                      </div>
                      <div style="font-size: 10px; color: #adb5bd; margin-top: 8px;">
                        (跨域限制，无法截图内部内容)
                      </div>
                    `
                    
                    // 替换iframe
                    iframe.parentNode?.replaceChild(placeholder, iframe)
                  }
                })
              }
            })
            imageData = canvas.toDataURL('image/png', 0.95)
            console.log('使用html2canvas iframe特殊处理截图成功')
          }
          catch (html2canvasError) {
            console.log('html2canvas iframe处理失败，尝试html-to-image:', html2canvasError)
            
            try {
              // 方案2：使用html-to-image
              const { toPng } = await import('html-to-image')
              imageData = await toPng(iframeElement, {
                quality: 0.95,
                backgroundColor: '#ffffff',
                // html-to-image的iframe处理
                filter: (node) => {
                  // 过滤掉可能引起问题的元素
                  if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') {
                    return false
                  }
                  return true
                }
              })
              console.log('使用html-to-image截图成功')
            }
            catch (htmlToImageError) {
              console.log('html-to-image也失败了，使用canvas绘制方案:', htmlToImageError)
              
              // 方案3：使用canvas直接绘制iframe占位符
              const canvas = document.createElement('canvas')
              const ctx = canvas.getContext('2d')
              if (ctx) {
                // 设置canvas尺寸
                canvas.width = iframeElement.offsetWidth || 800
                canvas.height = iframeElement.offsetHeight || 600
                
                // 绘制背景
                const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height)
                gradient.addColorStop(0, '#f8f9fa')
                gradient.addColorStop(1, '#e9ecef')
                ctx.fillStyle = gradient
                ctx.fillRect(0, 0, canvas.width, canvas.height)
                
                // 绘制边框
                ctx.strokeStyle = '#dee2e6'
                ctx.lineWidth = 3
                ctx.strokeRect(2, 2, canvas.width - 4, canvas.height - 4)
                
                // 绘制内边框
                ctx.strokeStyle = '#ffffff'
                ctx.lineWidth = 1
                ctx.strokeRect(5, 5, canvas.width - 10, canvas.height - 10)
                
                // 绘制iframe图标
                ctx.fillStyle = '#6c757d'
                ctx.font = 'bold 48px Arial'
                ctx.textAlign = 'center'
                ctx.fillText('', canvas.width / 2, canvas.height / 2 - 40)
                
                // 绘制标题
                ctx.font = 'bold 20px Arial'
                ctx.fillStyle = '#495057'
                ctx.fillText('iframe内容', canvas.width / 2, canvas.height / 2 + 20)
                
                // 绘制URL
                const src = iframeElement.src
                if (src) {
                  ctx.font = '14px Arial'
                  ctx.fillStyle = '#6c757d'
                  const url = src.length > 80 ? src.substring(0, 80) + '...' : src
                  ctx.fillText(url, canvas.width / 2, canvas.height / 2 + 50)
                }
                
                // 绘制提示信息
                ctx.font = '12px Arial'
                ctx.fillStyle = '#adb5bd'
                ctx.fillText('(跨域限制，无法截图内部内容)', canvas.width / 2, canvas.height / 2 + 80)
                
                // 绘制装饰性元素
                ctx.strokeStyle = '#dee2e6'
                ctx.lineWidth = 1
                ctx.setLineDash([5, 5])
                ctx.strokeRect(20, 20, canvas.width - 40, canvas.height - 40)
                ctx.setLineDash([])
                
                imageData = canvas.toDataURL('image/png', 0.95)
                console.log('使用canvas绘制方案截图成功')
              }
              else {
                throw new Error('无法创建canvas上下文')
              }
            }

            // 将base64字符串转换为File对象
            const base64ToFile = (base64String: string, filename: string): File => {
              const arr = base64String.split(',')
              const mime = arr[0].match(/:(.*?);/)?.[1] || 'image/png'
              const bstr = atob(arr[1])
              let n = bstr.length
              const u8arr = new Uint8Array(n)
              while (n--) {
                u8arr[n] = bstr.charCodeAt(n)
              }
              return new File([u8arr], filename, { type: mime })
            }
          
            const imageFile = base64ToFile(imageData, `screenshot_${Date.now()}.png`)
            const imageUrl = await uploadFile(imageFile)
            // 提交截图
            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)
          message.error('截图提交失败')
        }
      }
    }

    if (!hasSubmitWork) {
      message.info('未找到可用的作业提交功能')
      isSubmitting.value = false
    }
  }
  catch (error) {
    console.error('作业提交过程中出错:', error)
    message.error('作业提交失败')
    isSubmitting.value = false
  }
  finally {
    isSubmitting.value = false
  }
}

// 刷新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) {
    return 30 // 全屏时按钮在右侧30px
  }
  if (props.type === '1') {
    // 展开作业区：按钮更靠左；收起时：按钮更靠右侧
    return workPanelCollapsed.value ? 60 : 430
  }
  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) => {
  switch (e.key) {
    case 'ArrowLeft':
      e.preventDefault()
      if (!isFollowModeActive.value || props.type == '1') {
        previousSlide()
      }
      break
    case 'PageUp':
      e.preventDefault()
      if (!isFollowModeActive.value || props.type == '1') {
        previousSlide()
      }
      break
    case 'ArrowRight':
      e.preventDefault()
      if (!isFollowModeActive.value || props.type == '1') {
        nextSlide()
      }
      break
    case 'PageDown':
    case ' ':
      e.preventDefault()
      if (!isFollowModeActive.value || props.type == '1') {
        nextSlide()
      }
      break
    case 'F11':
      e.preventDefault()
      enterFullscreen()
      break
    case 'Escape':
      if (document.fullscreenElement) {
        document.exitFullscreen()
      }
      break
    default:
      break
  }
}

// 事件处理函数
const handleSlidesDataUpdated = () => {
  console.log('收到 slidesDataUpdated 事件')

  // 强制重新渲染：先隐藏组件
  showSlideList.value = false

  nextTick(() => {
    calculateScale()

    // 延迟500ms后重新显示组件，确保重新渲染完成
    setTimeout(() => {
      showSlideList.value = true
      console.log('组件重新渲染完成')

      // 重新处理iframe链接
      processIframeLinks()
    }, 500)

    console.log('slidesDataUpdated 事件处理完成')
  })
}

const handleViewportSizeUpdated = (event: any) => {
  console.log('收到 viewportSizeUpdated 事件:', event.detail)

  // 重新计算缩放比例
  nextTick(() => {
    calculateScale()
    console.log('viewportSizeUpdated 事件处理完成')
  })
}

const getCourseDetail = async () => {
  isLoading.value = true
  try {
    const res = await api.getCourseDetail(props.courseid as string)
    console.log(res)
    const courseData = res[0][0]
    courseDetail.value = courseData
    selectWorksStudent()
    checkIsCreator()
    const pptJSONUrl = JSON.parse(courseData.chapters).pptData ? JSON.parse(courseData.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)
          importJSON(jsonObj)
        }
        catch (e) {
          console.error('解析pptdata.data失败:', e)
        }
      }
    }
  }
  catch (error) {
    console.error('获取课程详情失败:', error)
    message.error('获取课程详情失败')
    isLoading.value = false
  }
  finally {
    isLoading.value = false
    // if (props.type == '2') {
    //   console.log('判断是否是学生进入全屏')
    //   function panFull() {
    //     console.log('判断是否是学生进入全屏111')
    //     if (!document.fullscreenElement) {
    //       setTimeout(() => {
    //         if (!document.fullscreenElement) {
    //           if (document.documentElement.requestFullscreen) {
    //             document.documentElement.requestFullscreen()
    //           }
    //           else if (document.documentElement.mozRequestFullScreen) { // Firefox
    //             document.documentElement.mozRequestFullScreen()
    //           }
    //           else if (document.documentElement.webkitRequestFullscreen) { // Chrome, Safari and Opera
    //             document.documentElement.webkitRequestFullscreen()
    //           }
    //           else if (document.documentElement.msRequestFullscreen) { // IE/Edge
    //             document.documentElement.msRequestFullscreen()
    //           }
    //           panFull()
    //         }
    //       }, 50)
    //     }           
    //   }
    //   nextTick(() => {
    //     setTimeout(() => {
    //       // enterFullscreen(); 
    //       panFull()     
    //     }, 50)
    //   })
    // }
  }
}

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,
      type: props.type,
      isUpdate
    })
    
    if (!props.courseid) {
      console.warn('getWork: courseid 未提供，跳过执行')
      if (!isUpdate) workLoading.value = false
      return
    }
    
    const res = await api.selectSWorks(props.courseid, '0', slideIndex.value.toString())
    console.log('getWork 执行成功，结果:', res)
    const frame = elementList.value.find(element => element.type === ElementTypes.FRAME)
    console.log('frame:', frame)
    const toolType = frame?.toolType ?? ''
    const newWorkArray = props.cid
      ? res[0].filter((work: any) => {
        return props.type == '1' || (props.type == '2' && work.classid.includes(props.cid)) && (work.atool === toolType || !toolType)
      })
      : res[0]
    
    // 如果是更新模式，只有当数据真正变化时才更新
    if (isUpdate) {
      const hasChanged = checkWorkArrayChanged(workArray.value, newWorkArray)
      if (hasChanged) {
        console.log('检测到作业数据变化，更新显示')
        workArray.value = newWorkArray
      }
      else {
        console.log('作业数据无变化，跳过更新')
      }
    }
    else {
      workArray.value = newWorkArray
    }
    
    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
  }
}

const selectWorksStudent = async () => {
  studentLoading.value = true
  try {
    const res = await api.selectWorksStudent(props.oid as string, courseDetail.value.juri as string)
    console.log('selectWorksStudent', res)
    const students = res[0]
    console.log('students', students)
    if (props.cid) {
      studentArray.value = students.filter((student: any) => student.classid.includes(props.cid))
    }
    else {
      studentArray.value = students
    }
  }
  catch (error) {
    console.error('获取学生信息失败:', error)
    message.error('获取学生信息失败')
  }
  finally {
    studentLoading.value = false
  }
}

// 检查作业数组是否发生变化
const checkWorkArrayChanged = (oldArray: WorkItem[], newArray: WorkItem[]): boolean => {
  if (oldArray.length !== newArray.length) return true
  
  // 检查每个作业的 id 和 name 是否一致
  for (let i = 0; i < oldArray.length; i++) {
    const oldWork = oldArray[i]
    const newWork = newArray[i]
    
    if (oldWork.id !== newWork.id || oldWork.name !== newWork.name || oldWork.content !== newWork.content) {
      return true
    }
  }
  
  return false
}

// 查询课程跟随状态
const selectCourseSLook = async () => {
  const res = await api.selectCourseSLook(props.courseid as string)
  console.log('selectCourseSLook', res)
  if (res[0][0].follow == 2) {
    if (props.type == '2') {
      goToSlide(Number(res[0][0].followC))
    }
    isFollowModeActive.value = true
  }
  else {
    isFollowModeActive.value = false
  }
}

// 切换跟随模式
const toggleFollowMode = async () => {
  try {
    const newFollowState = !isFollowModeActive.value
    const sopen = newFollowState ? 2 : 1
    
    // 调用API更新跟随状态
    const res = await api.updateCourseFollow(sopen, props.courseid as string)
    console.log('更新跟随模式状态:', res)
    sendMessage({sopen: newFollowState, courseid: props.courseid, type: 'sopen'})
    
    if (res) {
      isFollowModeActive.value = newFollowState
      message.success(newFollowState ? '跟随模式已开启' : '跟随模式已关闭')
      
      // 如果开启跟随模式，设置当前幻灯片为跟随目标
      if (newFollowState) {
        await api.updateCourseFollowC(slideIndex.value, props.courseid as string)
        console.log('设置当前幻灯片为跟随目标:', slideIndex.value)
      }
    }
    else {
      message.error('操作失败，请重试')
    }
  }
  catch (error) {
    console.error('切换跟随模式失败:', error)
    message.error('操作失败，请重试')
  }
}

// 检查是否为创建人
const checkIsCreator = () => {
  // 这里可以根据实际业务逻辑判断是否为创建人
  // 比如通过props中的userid与课程创建者ID比较
  if (courseDetail.value && props.userid) {
    isCreator.value = courseDetail.value.userid === props.userid
  }
}


/**
 * 初始化消息监听
 */
const messageInit = () => {
  if (docSocket.value && !yMessage.value) {
    console.log('获取message', docSocket.value, yMessage.value)
    yMessage.value = docSocket.value.getArray('message')
    yMessage.value.observe((e: any) => {
      e.changes.added.forEach((i: any) => {
        const message = i.content.getContent()[0]
        console.log('yMessage', message)
        const _nowTime = new Date()
        const _msgTime = new Date(message.timestamp)
        if (
          (_nowTime as any) - (_msgTime as any) <= 1000 * 10 &&
          message.mId !== mId.value
        ) {
          // 10秒内且不是自己发的消息
          getMessages(message)
        }
      })
    })
  }
}

/**
 * 发送消息
 */
const sendMessage = (obj: any) => {
  if (docSocket.value && yMessage.value) {
    const message = obj
    obj.timestamp = new Date().toISOString()
    obj.mId = mId.value
    docSocket.value.transact(() => {
      yMessage.value.push([message])
    })
  }
}

/**
 * 处理收到的消息
 */
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)
  }

}


onMounted(() => {
  document.addEventListener('keydown', handleKeydown)

  // 处理URL参数
  if (props.courseid || props.type) {
    console.log('收到URL参数:', { courseid: props.courseid, type: props.type })

    // 这里可以根据courseid和type进行相应的处理
    // 比如加载特定的课程数据、设置特定的显示模式等
    if (props.courseid) {
      console.log('课程ID:', props.courseid)
      // TODO: 根据courseid加载对应的课程数据
    }

    if (props.type) {
      console.log('类型:', props.type)
      // TODO: 根据type设置特定的显示模式或功能
    }
  }
  getCourseDetail()


  // 计算初始缩放比例
  nextTick(() => {
    calculateScale()

    // 处理iframe链接
    processIframeLinks()
    
    // 初始化时检查并自动切换到可用面板
    autoSwitchToAvailablePanel()
  })

  // 监听窗口大小变化
  window.addEventListener('resize', calculateScale)

  // 监听全屏状态变化
  document.addEventListener('fullscreenchange', handleFullscreenChange)

  // 监听幻灯片数据更新事件（来自useImport的readJSON）
  window.addEventListener('slidesDataUpdated', handleSlidesDataUpdated)

  // 监听视口尺寸更新事件
  window.addEventListener('viewportSizeUpdated', handleViewportSizeUpdated)

  // 将导入导出功能暴露到window上，方便调试和外部调用
  ; (window as any).PPTistStudent = {
    importJSON,
    exportJSON,
    slides: slidesStore.slides,
    currentSlide: computed(() => slidesStore.currentSlide),
    slideIndex: computed(() => slidesStore.slideIndex),
    goToSlide,
    previousSlide,
    nextSlide,
    enterFullscreen,
    toggleLaserPen,
    // 添加URL参数到全局对象中
    courseid: props.courseid,
    type: props.type
  }

  console.log('PPTist Student View 已加载，可通过 window.PPTistStudent 访问功能')
  console.log('URL参数:', { courseid: props.courseid, type: props.type })

  if (api.yweb_socket && !docSocket.value) {
			
    docSocket.value = new Y.Doc()
    providerSocket.value = new WebsocketProvider(api.yweb_socket,
      'PPT' + props.courseid,
      docSocket.value
    )

    providerSocket.value.on('status', (event: any) => {
      console.log('👉', event.status)
      if (event.status === 'connected') {
        console.log('👉连接成功websocket(teachingMode)')
        mId.value = Math.random().toString(36).substr(2, 9)
        messageInit()
      }
    })
  }
})


onUnmounted(() => {
  document.removeEventListener('keydown', handleKeydown)
  window.removeEventListener('resize', calculateScale)
  document.removeEventListener('fullscreenchange', handleFullscreenChange)

  // 移除幻灯片数据更新事件监听器
  window.removeEventListener('slidesDataUpdated', handleSlidesDataUpdated)

  // 移除视口尺寸更新事件监听器
  window.removeEventListener('viewportSizeUpdated', handleViewportSizeUpdated)

  // 移除定时器清理代码，已改用socket监听

  // 清理window上的引用
  if ((window as any).PPTistStudent) {
    delete (window as any).PPTistStudent
    console.log('PPTist Student View 已卸载，window.PPTistStudent 已清理')
  }
})
</script>

<style lang="scss" scoped>
.pptist-student-viewer {
  height: 100vh;
  display: flex;
  background-color: #f5f5f5;

  // 全屏模式样式
  &.fullscreen {
    .layout-content-left {
      display: none; // 全屏时隐藏左侧导航栏
    }

    .layout-content-right {
      display: none; // 全屏时隐藏左侧导航栏
    }

    .viewer-header {
      display: none; // 全屏时隐藏顶部标题栏
    }
  }

  // 激光笔模式样式
  &.laser-pen {
    cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABHNCSVQICAgIfAhkiAAACCJJREFUWIXtmLuO3MYShv/qZl9IzqwXo2BkSAtsIK+z8wwOBcOJ9C56Cr2LlThQcgBnfofVBnswXlgTaLHaIdk3dtcJOKOzd8n2MeDABRDDgKz/m+pudv0N/BN/Luj/kYSZJQBxJR8DKESU/2zuPwTIzAKnpxqHhxUuLir0vYSUAkS0ewA5F7Rtxv7+iNPTEYeHkYjKXwrIzHK9XtultRohaKSkkFIVhqGCEAIxTvm0ZpRSTNOMUGqEUgnGxLX3cblc+t9T2S8GXK1W9dP53OLiwoLZhMtLQ4CiGBVKkchZIOcpn5QMKQuEyKx1YiCZvb0AooD9ff/rZuMPDg7cl+hWn3uAmQWABut1g/PzOnZdTd5bMY6aQtAIQQGQGEd5bYirKgPIZExiY2IKIbK1XpeinzaN2s7b4XPD/iAgM0ucn7fYbNrQ963Juaauq8k5i3E01PcG46iQs0TO1wGlzJAyo6oS2jagqgLGUQNQwTllvJeYzwUz9w8N+b2AzCxwft6i72fBuZkYhnbcbBqKsSbvazhnEIJBzqrEqGQpAlO1AaKShShC6wQpE4UQUNcBKenReyXm8yoIIYwQtNXq7qvkQxVssNm0wbmZuLiYUQgtnGtps2ngfQ3vLaVkEKOmGKcqMtMWkEnKTFonaB3Z+4AQPFmreD6vSAghxpECAFMKY7EoALovBlytVjXW6yb0fSuGoaUQWrq8nKHvW/R9S943xbmavJ+qmNIO8FMFIWXert7A1gYxjprHsSLmaTHt7UF0HYdSilmv82q1ynctnFuAzCzx8aPF+Xltcq7HzaaBcy36vsUwzKjrZhiGRgxDA+8tUjIUgkbOEqVMgEIUkjLDmAjvgwjBI6WKxlHybp5KyVRKMcaMGIb0dLFIzBxvzsdbgOv12i69t7HrpgURY02bTYO+b6nrZui6qZLONdz3jTg5ORDHx0f48OExQpgBAIzp8OjRez46Oi7Pnq1ot5BKETQVgYmosJRj6rrEQNJCxLX3EUB/LyAzC3z8qOGcIe8tOWdpmm81ed9gGJpdJdF1rXz79jucnX1za454P8fZ2ZzOzr6Rx8fvyvPnP38afiEKVVXmqhrJ+wSlIqoqYj73S2s1M7urC0ZcS3x6qhGCDpeXBuOoMY4Gzhl4b4tzNYahgXMNuq4Vb978cCfczTg7+0a8efMDuq6Fcw2GoSnO1fDewjmDcTQYx0kzBI3TU3319euAh4cVUlIEKApBU98bhGAoJSO8N/Dect834u3b73B+/vVn4XZxfv61ePv2O+77Bt5b4b2hlKbcfW8oBE2AQkoKh4fXRvU64MVFhZQqilEhBLX9CCvEqLer1YiTk4MvqtxdlTw5OcAWDDFq5DxphDBtmSlNzcddgMws0fcyDEOFUiQAiZxliVGVGFVJSXEImo6Pj3433Dbo+PiIQ9AlJbXLi5wnrVIm7b6X223wOiAAASkFhBDIWWAcJXKWshQhcpYiZ0k5S3z48PhO9ZcvgV9+ma6XL+8m/PDhMW1ziW1u5Cy3WpO2lOIq11VAAhEhRkLO0z0RgVmAefotRXz6lNyMV6+AxWK6Xr26GzCEGXZb4i7nTifnSXv6Tn7qssTdmf4+cRWQwczQmiHldM/MICogmn6FKDDmzj0Tr18D5+fT9fr13WrGdBCiXMu505Fy0mZmTJYBwPUPdUHOBaUUSFlQVRlS5rzbtqTMJGXGo0fvcXY2vyX+44/T9VA8evSepcy8zcdCFDG1ZBlSTto5FwC3P9RElNG22TTNCCEygAwps9A6Ca2TUCqRMZGPjo4fprg/+OjomIyJQqm0ywspJy0hJu22zVf34+tzcH9/hFIja51gTEJVJUiZoHWEMQFKhfLs2QpPnrz73XRPnrwrz56toFSAMQFaR0g5aRiTWOsEpUbs749XX7u51Y1QKjGQ2JjIbRtgTGClQrE2wFpPbTuU589/xmLx2xfDLRa/lefPf6a2HWCtL9YG3oJy2wY2JjKQoFTC6ekDgIeHEcZEs7cXUFURVTV1wtZ6UdcOTTOgrgfMZn158eKnL6rkkyfvyosXP2E261HXA5pmEHXtYK1HXU9WoKomTWMiDg/j1devbStEVN6/fx+XRIGt9RhHjZQ0Wat4HCsax//1fEQlf//9v8XJyTF9rt1q2+mPtW2PphnY2gHWOrbWcV17ttaDKKy9j4/398u9gACwXC49Pn7UuhQNQI3eT206s2DadptCFEiZqaoS/+tfvnz77X/oRsPKUmYyJpJSAdZ6NM2Aphl4Pu/QND3P5wO0dmo2c5jNHPb3/fKrr/xNnluARJRXq5V/2jQqOKfE1kPsPC8zM1VVLkqNwpiAEAxbq+hGy89SZtq2/MXaIOrasbUDmqZH2/Zo257bdghSOtM07tfNxh/s799yd3d6koODA8fM0ngvw9bgYG9vatOJClfVSFUVYe3UldxhmiBlxtY0kVLTlLHW8Xw+oG17NqYvs1lv6rrHcjkcEN1p5B9ydQPmc2GEoABAdB1TKYWlnDph5wJvbSdPpwvXbCcLUXhrO2FMQF0HttZBa8dtO5TZrDdt26FtewDDfRD3AhJRYeYemKxh2Bqc1HVTm17Xn4y7yFnyDeMurhh33hp3rmuvZjMXpHSmrqehXiz6h04XHjxZIKLMzB0Wi2LW64xhSAwkVFXEOGpo/dmjD2yPPlBVka31mM2caRqH5XLAnz362FUSQLdarfLTxSJpISLmcx8uLw217R8/PLpnzt3S/5KHdvG3Pn67Afr3PMB8APgvOwL+J/5s/BeEBm1u1Gu4+QAAAABJRU5ErkJggg==) 20 20, default !important;
  }
}

.layout-content-left {
  width: 200px;
  height: 100%;
  background-color: #fff;
  border-right: 1px solid #e0e0e0;
  overflow-y: auto;
  transition: width .2s ease;
}
.layout-content-left.collapsed {
  width: 48px;
}
.slide-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
/* 收缩时头部仅显示按钮，并保持按钮在可用宽度内水平居中 */
.layout-content-left.collapsed .slide-header {
  justify-content: center;
  padding: 8px;
}

.layout-content-right {
  width: 400px;
  height: 100%;
  background-color: #fff;
  border-left: 1px solid #e0e0e0;
  overflow-y: auto;
  transition: width .2s ease;
  position: relative;
}

.panel-content {
  margin-right: 52px;
  padding: 0 8px;
  height: calc(100% - 76px);
  overflow: auto;
}
.layout-content-right.collapsed {
  width: 52px;
}
.right-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

/* 侧边导航标签样式 */
.side-nav-tabs {
  position: absolute;
  right: 0;
  top: 60px;
  bottom: 0;
  width: 52px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 8px 0;
  align-items: center;
  background: #fff;
  border-left: 1px solid #e0e0e0;
  z-index: 10;
}

.side-nav-btn {
  width: 45px;
  height: 45px;
  min-height: 45px;
  border: 1px solid #d9d9d9;
  background: #fff;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  gap: 8px;
  overflow: hidden;
  
  &:hover {
    border-color: #1890ff;
    transform: scale(1.02);
  }
  
  &.active {
    border-color: #3681fc;
    background: #3681fc;
    box-shadow: 0 0 0 2px rgba(54, 129, 252, 0.2);
  }
  
  img {
    width: 25px;
    height: 25px;
    object-fit: contain;
    flex-shrink: 0;
  }
  
  span {
    font-size: 12px;
    font-weight: 500;
    color: #333;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  
  &.active span {
    color: #fff;
  }
}

/* 收缩时头部仅显示按钮，并保持按钮在可用宽度内水平居中 */
.layout-content-right.collapsed .right-panel-header {
  justify-content: center;
  padding: 8px;
}

/* 收缩状态下的切换按钮 */
.collapsed-tabs {
  display: flex;
  flex-direction: column;
  gap: 8px;
  // padding: 8px;
  align-items: center;
}

.collapsed-tab-btn {
  width: 32px;
  height: 32px;
  border: 1px solid #d9d9d9;
  background: #fff;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  overflow: hidden;
  
  &:hover {
    border-color: #1890ff;
    transform: scale(1.05);
  }
  
  &.active {
    border-color: #3681fc;
    background: #3681fc;
    box-shadow: 0 0 0 2px rgba(54, 129, 252, 0.2);
  }
  
  img {
    width: 20px;
    height: 20px;
    object-fit: contain;
    transition: transform 0.2s;
  }
  
  &:hover img {
    transform: scale(1.1);
  }
}
.collapse-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 1px solid #d9d9d9;
  border-radius: 8px;
  background: #fff;
  color: #333;
  cursor: pointer;
  line-height: 1;
  font-weight: 700;
}
.collapse-btn:hover {
  border-color: #1890ff;
  color: #1890ff;
}

.homework-title {
  padding: 12px 12px 0 12px;
  color: #333;
  font-size: 14px;
  font-weight: 600;
}
.homework-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  padding: 12px;
}
.homework-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-width: 0;
  height: 35px;
  border: 1px solid #2f80ed;
  color: #2f80ed;
  background: #fff;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  overflow: hidden;
  padding: 0 10px;
  text-align: center;
}
.homework-btn__text {
  display: block;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.homework-btn:hover {
  box-shadow: 0 2px 10px rgba(0,0,0,0.08);
}

.homework-btn.unsubmitted {
  border-color: #d9d9d9;
  color: #999;
  background: #f5f5f5;
  cursor: not-allowed;
}

.homework-btn.unsubmitted:hover {
  box-shadow: none;
  transform: none;
}
.homework-loading {
  padding: 12px;
  color: #666;
  font-size: 13px;
}
.homework-empty {
  padding: 12px;
  color: #999;
  font-size: 13px;
}



.thumbnails {
  padding: 0;
  height: 100%;

  .viewer-header {
    margin-bottom: 16px;

    h3 {
      margin: 0;
      font-size: 16px;
      font-weight: 600;
      color: #333;
    }
  }

  .thumbnail-list {
    width: 100%;
    padding: 0 16px;
    box-sizing: border-box;

    .thumbnail-item {
      position: relative;
      margin-bottom: 12px;
      cursor: pointer;
      border-radius: 8px;
      overflow: hidden;
      transition: all 0.2s ease;
      border: 2px solid rgba(24, 144, 255, 0.2);

      &:hover {
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        border-color: rgba(24, 144, 255, 0.4);
      }

      &.active {
        border: 2px solid #1890ff;
        box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
      }

      .label {
        position: absolute;
        top: 8px;
        left: 8px;
        background-color: rgba(0, 0, 0, 0.6);
        color: #fff;
        padding: 2px 6px;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 600;
        z-index: 1;
      }

      .thumbnail {
        width: 100%;
        height: auto;
      }
    }
  }

  .page-number {
    text-align: center;
    margin-top: 16px;
    padding: 8px;
    background-color: #f0f0f0;
    border-radius: 4px;
    font-size: 14px;
    color: #666;
  }

  .progress-bar {
    margin-top: 12px;
    height: 6px;
    background-color: #f0f0f0;
    border-radius: 3px;
    overflow: hidden;

    .progress-fill {
      height: 100%;
      background: linear-gradient(90deg, #1890ff, #40a9ff);
      border-radius: 3px;
      transition: width 0.3s ease;
    }
  }
}

.layout-content-center {
  flex: 1;
  display: flex;
  flex-direction: column;
  background-color: #000;
}

.viewer-header {
  height: 60px;
  background-color: #fff;
  border-bottom: 1px solid #e0e0e0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 8px;
  transition: transform 0.3s ease;

  &.hidden {
    transform: translateY(-100%);
  }

  .slide-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
  }

  .viewer-controls {
    display: flex;
    gap: 12px;

    button {
      padding: 8px 12px;
      border: 1px solid #d9d9d9;
      border-radius: 6px;
      background-color: #fff;
      color: #333;
      cursor: pointer;
      transition: all 0.2s ease;
      display: flex;
      align-items: center;
      justify-content: center;
      min-width: 40px;
      height: 36px;

      &:hover:not(:disabled) {
        border-color: #1890ff;
        color: #1890ff;
      }

      &:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }

      &.back-btn {
        background-color: #1890ff;
        color: #fff;
        border-color: #1890ff;

        &:hover {
          background-color: #40a9ff;
          border-color: #40a9ff;
        }
      }

      &.follow-active {
        background-color: #3681fc;
        color: #fff !important;
        border-color: #3681fc;

        &:hover {
          background-color: #2d6fd9;
          border-color: #2d6fd9;
          color: #fff !important;
        }
      }

      .control-icon {
        font-size: 16px;
      }
    }
  }
}

.viewer-canvas {
  flex: 1;
  position: relative;
  background-color: rgb(249, 249, 249);
  overflow: hidden;

  // 全屏时隐藏滚动条和边框
  &.fullscreen-mode {
    overflow: hidden !important;
    background-color: transparent !important;
  }
}

.slide-list-wrap {
  position: absolute;
  overflow: hidden;
  background-color: #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.01), 0 0 12px 0 rgba(0, 0, 0, 0.1);
  border-radius: 8px;

  /* 全屏时去掉圆角 */
  .pptist-student-viewer.fullscreen & {
    border-radius: 0;
  }
}

.loading-indicator {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;

  .loading-text {
    color: #666;
    font-size: 14px;
    background-color: rgba(255, 255, 255, 0.9);
    padding: 12px 20px;
    border-radius: 6px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  }
}

// 全屏模式样式
.fullscreen-slide {
  // 使用放映功能的默认样式
}

// 全屏工具按钮样式，直接复制放映功能的样式
.tools-left {
  position: fixed;
  bottom: 8px;
  left: 8px;
  font-size: 25px;
  color: #666;
  z-index: 10;

  .tool-btn {
    opacity: .3;
    cursor: pointer;
    transition: opacity 0.3s;

    &:hover {
      opacity: .95;
    }

    &+.tool-btn {
      margin-left: 8px;
    }
  }
}

.tools-right {
  height: 66px;
  position: fixed;
  bottom: -66px;
  right: 0;
  z-index: 5;
  padding: 8px;
  transition: bottom 0.3s;

  &.visible {
    bottom: 0;
  }

  &::after {
    content: '';
    width: 100%;
    height: 66px;
    position: absolute;
    left: 0;
    top: -66px;
  }

  .content {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 4px;
    font-size: 25px;
    background-color: #fff;
    color: #333;
    padding: 8px 10px;
    box-shadow: 0 2px 12px 0 rgb(56, 56, 56, .2);
    border: 1px solid #e2e6ed;
  }

  .tool-btn {
    cursor: pointer;

    &:hover,
    &.active {
      color: #1890ff;
    }

    &+.tool-btn {
      margin-left: 15px;
    }
  }

  .page-number {
    font-size: 12px;
    padding: 0 12px;
    cursor: pointer;
  }
}

.viewport {
  position: relative;
  width: 100%;
  height: 100%;
  background-color: #fff;
}

.background {
  width: 100%;
  height: 100%;
  background-position: center;
  position: absolute;
}

// 响应式设计
@media (max-width: 768px) {
  .layout-content-left {
    width: 160px;
  }

  .layout-content-right {
    width: 160px;
  }

  .viewer-header {
    padding: 0 16px;

    .slide-title {
      font-size: 16px;
    }

    .viewer-controls button {
      padding: 6px 12px;
      font-size: 14px;
    }
  }
}

/* 作业提交按钮样式 */
.homework-submit-btn {
  position: fixed;
  bottom: 30px;
  z-index: 100;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 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:not(.submitting) {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
  }

  &:active:not(.submitting) {
    transform: translateY(0);
  }

  &.submitting {
    cursor: not-allowed;
    opacity: 0.8;
    background: linear-gradient(135deg, #999 0%, #666 100%);
  }

  .btn-text {
    white-space: nowrap;
  }

  .tool-btn {
    background: transparent;
    color: white;
    width: 20px;
    height: 20px;
    font-size: 16px;

    &:hover {
      background: transparent;
      transform: none;
    }
  }

  .loading-spinner {
    width: 20px;
    height: 20px;
    border: 2px solid rgba(255, 255, 255, 0.3);
    border-top: 2px solid white;
    border-radius: 50%;
    animation: spin 1s linear infinite;
  }
}

/* 刷新网页按钮样式 */
.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;
    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: 1000;

    .loading-spinner {
      width: 40px;
      height: 40px;
      border: 4px solid #f3f3f3;
      border-top: 4px solid #1890ff;
      border-radius: 50%;
      animation: spin 1s linear infinite;
      margin: 0 auto 16px;
  }
}

.loading-content {
    text-align: center;
    color: #666;
}


.loading-text {
    font-size: 14px;
    color: #666;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
</style>