<template>
    <view class="course-detail-container" :class="{ 'landscape': isLandscape }" :style="{ paddingTop: !isLandscape ? (navbarHeight + 20) + 'px' : '0' }">
        <!-- 顶部导航栏（横屏时隐藏） -->
        <custom-navbar v-if="!isLandscape" :title="course.courseName || '课程详情'"></custom-navbar>
        
        <!-- 视频播放区域 -->
        <view class="video-container" v-if="courseware && courseware.type === 'video'">
            <video
                id="course-video"
                :key="'video-' + (courseware ? courseware.id : 0)"
                :src="videoUrl"
                :poster="videoPoster"
                :controls="true"
                :show-center-play-btn="true"
                :enable-play-gesture="true"
                :enable-progress-gesture="true"
                :show-fullscreen-btn="true"
                :show-play-btn="true"
                :show-loading="true"
                :object-fit="videoObjectFit"
                :initial-time="initialTime"
                :enable-metadata="true"
                :play-strategy="0"
                :autoplay="false"
                :muted="false"
                :page-gesture="true"
                :enable-auto-rotation="true"
                :show-mute-btn="true"
                :vslide-gesture="true"
                :vslide-gesture-in-fullscreen="true"
                play-btn-position="center"
                class="course-video"
                @play="onVideoPlay"
                @pause="onVideoPause"
                @ended="onVideoEnded"
                @timeupdate="onVideoTimeUpdate"
                @waiting="onVideoWaiting"
                @error="onVideoError"
                @loadedmetadata="onVideoLoadedMetadata"
                @fullscreenchange="onFullscreenChange"
            ></video>
            
            <!-- 视频播放进度条 -->
            <view class="video-progress-bar" v-if="!isLandscape">
                <view class="progress-info">
                    <text class="progress-text">视频进度: {{ videoProgressPercent }}%</text>
                    <text class="time-text">{{ formatTime(videoCurrentTime) }} / {{ formatTime(videoTotalDuration) }}</text>
                </view>
                <view class="progress-track">
                    <view class="progress-active" :style="{ width: videoProgressPercent + '%' }"></view>
                </view>
            </view>
        </view>
        
        <!-- 课件标签切换（多个课件时显示） -->
        <view class="courseware-tabs" v-if="coursewareList.length > 1 && !isLandscape">
            <view 
                v-for="(cw, index) in coursewareList" 
                :key="cw.id"
                class="courseware-tab"
                :class="{ active: currentCoursewareIndex === index }"
                @click="switchCourseware(index)"
            >
                <text class="tab-text">{{ cw.name || cw.title || `课件${index + 1}` }}</text>
            </view>
        </view>
        
        <!-- 图文课件查看区域 -->
        <view class="courseware-container" v-if="courseware && displayType !== 'video'">
            <view class="courseware-viewer">
                <template v-if="displayType === 'pdf'">
                    <view class="pdf-viewer">
                        <view class="pdf-placeholder">
                            <text class="pdf-icon">📄</text>
                            <text class="pdf-text">PDF课件</text>
                            <view class="open-pdf-btn" @click="openPdf">
                                <text class="btn-text">打开课件</text>
                            </view>
                        </view>
                    </view>
                </template>
                <template v-else-if="displayType === 'image'">
                    <scroll-view class="image-viewer" scroll-y="true" :scroll-with-animation="true">
                        <image
                            v-if="imageUrl"
                            :src="imageUrl"
                            mode="widthFix"
                            class="courseware-image"
                            @click="previewImage"
                            @error="onImageError"
                            @load="onImageLoad"
                        ></image>
                        <view v-else class="image-loading">
                            <text>图片加载中...</text>
                        </view>
                    </scroll-view>
                </template>
                <template v-else-if="displayType === 'text'">
                    <view class="text-viewer">
                        <rich-text :nodes="courseware.description || '暂无内容'"></rich-text>
                    </view>
                </template>
                <template v-else>
                    <view class="unknown-viewer">
                        <text class="unknown-icon">📁</text>
                        <text class="unknown-text">暂不支持预览此类型文件</text>
                    </view>
                </template>
            </view>
        </view>
        
        <!-- 课程信息 -->
        <view class="course-info" v-if="!isLandscape">
            <view class="info-header">
                <text class="course-name">{{ course.courseName || '加载中...' }}</text>
            </view>
            <text class="course-desc">{{ course.description || '暂无描述' }}</text>
            
            <!-- 学习进度信息 -->
            <view class="learning-progress" v-if="learningRecord">
                <view class="progress-header">
                    <text class="progress-title">学习进度</text>
                    <text class="progress-percent">{{ courseProgress || 0 }}%</text>
                </view>
                <view class="progress-bar">
                    <view class="progress-fill" :style="{ width: (courseProgress || 0) + '%' }"></view>
                </view>
                <view class="progress-stats">
                    <text>学习时长：{{ formatDuration(learningRecord.totalDuration) }}</text>
                    <text>学习次数：{{ learningRecord.learnCount || 0 }}次</text>
                </view>
            </view>
        </view>
        
    </view>
</template>

<script>
import request from '@/utils/request.js'
import { getCourseInfo } from '@/api/study/course.js'
import { getCoursewareList, getCoursewareDetail } from '@/api/study/courseware.js'
import { getMyRecords, getMyLearningDetails } from '@/api/study/learningRecord.js'
import config from '@/utils/config.js'
import screenStreamClient from '@/utils/screenStream.js'
import progressQueue from '@/utils/progressQueue.js'
import CustomNavbar from '@/components/custom-navbar/custom-navbar.vue'

export default {
    components: {
        CustomNavbar
    },
    data() {
        return {
            courseId: null,
            course: {},
            courseware: null,
            coursewareList: [], // 课件列表
            currentCoursewareIndex: 0, // 当前课件索引
            currentCoursewareId: null, // 当前课件ID（用于判断是否切换课件）
            learningRecord: null,
            learningDetails: [], // 学习详情列表
            courseProgress: 0, // 课程总进度（0-100）
            loading: false,
            isLandscape: false,
            videoId: 'course-video-' + Date.now(),
            videoUrl: '',
            videoPoster: '',
            pdfUrl: '',
            imageUrl: '',
            // 学习进度上报相关
            progressTimer: null,
            progressRefreshTimer: null, // 进度刷新定时器
            lastReportTime: 0,
            reportInterval: 30000, // 每30秒上报一次（减少上报频率）
            reportedNonVideoInSession: null, // 已上报的非视频课件（会话去重）
            videoStartTime: 0,
            videoCurrentTime: 0,
            videoTotalDuration: 0,
            isPlaying: false,
            lastReportedDuration: 0, // 上次已上报的累计时长
            accumulatedDuration: 0, // 累积观看时长（秒）
            currentPlayStartTime: 0, // 当前播放开始时间
            videoObjectFit: 'contain', // 视频显示模式
            videoRetryCount: 0, // 视频重试次数
            initialTime: 0, // 视频初始播放位置（秒）
            // 导航栏高度
            navbarHeight: 0
        }
    },
    mounted() {
        // 计算导航栏总高度（状态栏 + 导航栏）
        const systemInfo = uni.getSystemInfoSync()
        const statusBarHeight = systemInfo.statusBarHeight || 0
        // 导航栏内容高度：88rpx (移动端) 或 80rpx (桌面端)
        const navbarContentHeight = systemInfo.windowWidth >= 768 ? 80 : 88
        // 转换为px（假设1rpx = 0.5px，实际需要根据设备计算）
        const rpxToPx = systemInfo.windowWidth / 750
        this.navbarHeight = statusBarHeight + (navbarContentHeight * rpxToPx)
    },
    onLoad(options) {
        this.courseId = options.id
        this.loadCourseDetail()
    },
    async onShow() {
        // 刷新课件列表、学习记录和进度（每次显示页面时）
        if (this.courseId) {
            console.log('[课程学习] 📊 刷新课件列表、学习记录和进度')
            // 重新加载课件列表（以获取新增的课件）
            await this.loadCoursewareList()
            // 刷新学习记录（包含后端计算的进度）
            await this.loadLearningRecord()
            // 刷新学习详情
            await this.loadLearningDetails()
            // 重新计算进度
            this.calculateCourseProgress()
        }
        
        // 监听屏幕方向变化
        this.checkOrientation()
        this.orientationListener = setInterval(() => {
            this.checkOrientation()
        }, 500)
        
        // 启动实时监控（App环境使用WebSocket+截图方式）
        if (this.courseId) {
            try {
                // 获取用户ID
                const userInfo = uni.getStorageSync('userInfo')
                const userId = userInfo?.userId || userInfo?.id
                
                if (userId) {
                    // App环境：延迟启动，等待plus对象初始化
                    // #ifdef APP-PLUS
                    // 延迟2秒启动，确保plus对象已初始化
                    setTimeout(async () => {
                        try {
                            await screenStreamClient.start(userId, 1000) // 1000ms间隔（1帧/秒），降低频率减少数据量
                            console.log('✅ 实时监控已启动（截图方式）')
                        } catch (error) {
                            console.error('启动实时监控失败:', error)
                        }
                    }, 2000)
                    // #endif
                    
                    // #ifndef APP-PLUS
                    await screenStreamClient.start(userId, 1000) // 1000ms间隔（1帧/秒）
                    console.log('✅ 实时监控已启动（截图方式）')
                    // #endif
                } else {
                    console.warn('无法获取用户ID，跳过实时监控')
                }
            } catch (error) {
                console.error('启动实时监控失败:', error)
                // 不显示错误提示，避免影响用户体验
            }
        }
    },
    onHide() {
        console.log('[课程学习] 页面隐藏，上报当前进度')
        // 页面隐藏时立即上报进度
        if (this.isPlaying) {
            // 先累加当前播放时长
            if (this.currentPlayStartTime) {
                const thisDuration = Math.floor((Date.now() - this.currentPlayStartTime) / 1000)
                this.accumulatedDuration = (this.accumulatedDuration || 0) + thisDuration
            }
            this.reportProgress(true) // 强制立即上报
        }
        this.clearProgressTimer()
        if (this.orientationListener) {
            clearInterval(this.orientationListener)
        }
        // 停止实时监控（页面隐藏时）
        screenStreamClient.stop()
    },
    onUnload() {
        console.log('[课程学习] 页面卸载，上报最终进度')
        // 页面卸载时立即上报最终进度
        if (this.isPlaying || this.accumulatedDuration > 0) {
            // 累加当前播放时长
            if (this.currentPlayStartTime) {
                const thisDuration = Math.floor((Date.now() - this.currentPlayStartTime) / 1000)
                this.accumulatedDuration = (this.accumulatedDuration || 0) + thisDuration
            }
            this.reportProgress(true) // 强制立即上报
        }
        this.clearProgressTimer()
        if (this.orientationListener) {
            clearInterval(this.orientationListener)
        }
        // 停止实时监控（页面卸载时）
        screenStreamClient.stop()
    },
    computed: {
        isPdf() {
            if (!this.courseware) return false
            const fileName = this.courseware.fileName || this.courseware.filePath || ''
            return fileName.toLowerCase().endsWith('.pdf')
        },
        isImage() {
            if (!this.courseware) return false
            const fileName = this.courseware.fileName || this.courseware.filePath || ''
            const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp']
            return imageExts.some(ext => fileName.toLowerCase().endsWith(ext))
        },
        // 计算实际的课件显示类型
        displayType() {
            if (!this.courseware) return null
            if (this.courseware.type === 'video') return 'video'
            if (this.courseware.type === 'image' || this.isImage) return 'image'
            if (this.courseware.type === 'document' && this.isPdf) return 'pdf'
            if (this.courseware.type === 'text') return 'text'
            return 'unknown'
        },
        // 计算视频播放进度百分比
        videoProgressPercent() {
            if (!this.videoTotalDuration || this.videoTotalDuration === 0) {
                return 0
            }
            const percent = Math.floor((this.videoCurrentTime / this.videoTotalDuration) * 100)
            return Math.min(100, Math.max(0, percent))
        }
    },
    methods: {
        checkOrientation() {
            if (typeof window !== 'undefined' && window.orientation !== undefined) {
                const orientation = window.orientation || 0
                this.isLandscape = Math.abs(orientation) === 90
            }
        },
        
        async loadCourseDetail() {
            if (!this.courseId) return
            
            this.loading = true
            try {
                // 加载课程详情（使用封装的API接口）
                const courseResponse = await getCourseInfo(this.courseId)
                if (courseResponse.code === 200) {
                    this.course = courseResponse.data || {}
                    
                    // 加载课件列表
                    await this.loadCoursewareList()
                    
                    // 加载学习记录（包含后端计算的进度）
                    await this.loadLearningRecord()
                    
                    // 加载学习详情
                    await this.loadLearningDetails()
                    this.calculateCourseProgress()
                }
            } catch (error) {
                uni.showToast({
                    title: error.message || '加载失败',
                    icon: 'none'
                })
            } finally {
                this.loading = false
            }
        },
        
        async loadCoursewareList() {
            try {
                // 使用封装的API接口获取课件列表
                const response = await getCoursewareList(this.courseId)
                console.log('课件列表接口响应:', response)
                console.log('课程ID:', this.courseId)
                
                if (response.code === 200) {
                    let data = response.data || []
                    
                    // 如果返回的是单个对象，转换为数组
                    if (!Array.isArray(data)) {
                        console.log('返回的是单个对象，转换为数组')
                        data = [data]
                    }
                    
                    this.coursewareList = data
                    console.log('课件列表数据:', this.coursewareList)
                    console.log('课件数量:', this.coursewareList.length)
                    
                    // 加载学习详情并计算进度
                    await this.loadLearningDetails()
                    this.calculateCourseProgress()
                    
                    // 如果有课件列表，加载第一个课件
                    if (this.coursewareList.length > 0) {
                        this.currentCoursewareIndex = 0
                        const firstCourseware = this.coursewareList[0]
                        console.log('准备加载第一个课件:', firstCourseware)
                        console.log('课件类型:', firstCourseware.type)
                        console.log('课件文件路径:', firstCourseware.filePath)
                        await this.loadCourseware(firstCourseware)
                    } else if (this.course.coursewareId) {
                        // 如果没有课件列表，但课程有coursewareId，尝试加载单个课件
                        console.log('课件列表为空，尝试通过coursewareId加载:', this.course.coursewareId)
                        await this.loadCourseware(this.course.coursewareId)
                    } else {
                        console.warn('没有找到课件数据，courseId:', this.courseId)
                        uni.showToast({
                            title: '该课程暂无课件',
                            icon: 'none'
                        })
                    }
                } else {
                    console.error('课件列表接口返回错误:', response)
                    uni.showToast({
                        title: response.msg || '加载课件列表失败',
                        icon: 'none'
                    })
                }
            } catch (error) {
                console.error('加载课件列表失败:', error)
                console.error('错误详情:', error.stack)
                uni.showToast({
                    title: error.message || '加载课件列表失败',
                    icon: 'none'
                })
                // 如果列表加载失败，尝试加载单个课件
                if (this.course.coursewareId) {
                    await this.loadCourseware(this.course.coursewareId)
                }
            }
        },
        
        async loadCourseware(courseware) {
            // ✅ 防止快速切换导致竞态问题
            if (this.loading) {
                console.log('[课程学习] ⏳ 正在加载中，忽略重复请求')
                return
            }
            
            this.loading = true
            
            try {
                let coursewareData = courseware
                
                // 如果传入的是ID，需要先获取详情
                if (typeof courseware === 'number' || typeof courseware === 'string') {
                    const response = await getCoursewareDetail(courseware)
                    if (response.code === 200) {
                        coursewareData = response.data || {}
                    } else {
                        console.error('获取课件详情失败:', response)
                        this.loading = false
                        return
                    }
                }
                
                console.log('[课程学习] 📦 加载课件数据:', coursewareData)
                console.log('[课程学习] 课件ID:', coursewareData?.id)
                console.log('[课程学习] 课件类型:', coursewareData?.type)
                console.log('[课程学习] 课件文件路径:', coursewareData?.filePath)
                console.log('[课程学习] 课件时长:', coursewareData?.duration)
                
                // ✅ 保存当前课件ID，用于判断是否切换课件
                const previousCoursewareId = this.currentCoursewareId
                this.currentCoursewareId = coursewareData?.id
                this.courseware = coursewareData
                
                console.log('[课程学习] 🔄 课件切换:', previousCoursewareId, '->', this.currentCoursewareId)
                
                // 如果是非视频课件，记录查看进度
                if (this.courseware && this.courseware.type !== 'video') {
                    // 延迟一下，确保课件已加载完成
                    setTimeout(() => {
                        this.reportNonVideoProgress()
                    }, 1000)
                }
                
                // 构建文件URL
                if (this.courseware.filePath) {
                    let filePath = this.courseware.filePath
                    
                    // 确保路径以 / 开头（数据库存储格式：/profile/upload/2025/12/09/xxx.mp4）
                    if (!filePath.startsWith('/')) {
                        filePath = '/' + filePath
                    }
                    
                    // 只对文件名部分进行编码，路径部分保持不变
                    const pathParts = filePath.split('/')
                    const encodedPath = pathParts.map((part, index) => {
                        // 第一个空字符串（因为split会在开头产生空字符串）保持为空
                        if (index === 0) return ''
                        // 只对最后一个部分（文件名）进行编码，其他路径部分保持原样
                        if (index === pathParts.length - 1) {
                            return encodeURIComponent(part)
                        }
                        // 路径部分保持原样
                        return part
                    }).join('/')
                    
                    const fileUrl = config.FILE_BASE_URL + encodedPath
                    console.log('[课程学习] 🔗 URL构建信息:')
                    console.log('  - FILE_BASE_URL:', config.FILE_BASE_URL)
                    console.log('  - 原始filePath:', this.courseware.filePath)
                    console.log('  - 编码后路径:', encodedPath)
                    console.log('  - 完整URL:', fileUrl)
                    
                    // 验证URL格式
                    if (!fileUrl.startsWith('http')) {
                        console.error('[课程学习] ❌ URL格式错误，不是http协议:', fileUrl)
                    }
                    
                    // 测试文件是否可访问（仅在视频时测试）
                    if (this.courseware.type === 'video') {
                        this.testVideoUrl(fileUrl)
                    }
                    
                    if (this.courseware.type === 'video') {
                        // 查找该课件的所有学习详情记录，找出最新的播放位置
                        const coursewareDetails = this.learningDetails.filter(d => d.coursewareId === this.courseware.id)
                        if (coursewareDetails && coursewareDetails.length > 0) {
                            // 按学习时间降序排序，取最新的一条
                            coursewareDetails.sort((a, b) => {
                                const timeA = new Date(a.learnTime || a.createTime).getTime()
                                const timeB = new Date(b.learnTime || b.createTime).getTime()
                                return timeB - timeA  // 降序
                            })
                            const latestDetail = coursewareDetails[0]
                            let lastPosition = latestDetail.videoPosition || 0
                            
                            // 如果上次播放位置接近视频末尾（剩余<5秒），则从头开始
                            // 避免每次都从最后几秒开始然后立即结束
                            if (lastPosition > 0) {
                                // 获取视频总时长（优先使用配置的duration，如果没有则用lastPosition+5作为估算）
                                const estimatedDuration = this.courseware.duration || (lastPosition + 5)
                                const remainingTime = estimatedDuration - lastPosition
                                
                                if (remainingTime < 5) {
                                    // 剩余时间<5秒，从头开始
                                    this.initialTime = 0
                                    console.log('[课程学习] 📝 上次已接近结尾(剩余' + remainingTime + '秒)，从头开始播放')
                                } else {
                                    this.initialTime = lastPosition
                                    console.log('[课程学习] 🔖 恢复上次播放位置:', this.initialTime, '秒 (共', coursewareDetails.length, '条记录)')
                                }
                            } else {
                                this.initialTime = 0
                                console.log('[课程学习] 📝 从头开始播放 (有', coursewareDetails.length, '条记录，但播放位置为0)')
                            }
                        } else {
                            this.initialTime = 0
                            console.log('[课程学习] 📝 从头开始播放 (无学习记录)')
                        }
                        
                        // ✅ 只在课件ID变化时才重新生成videoId（避免不必要的重新渲染）
                        if (!this.videoId || previousCoursewareId !== coursewareData.id) {
                            this.videoId = 'course-video-' + coursewareData.id
                            console.log('[课程学习] 🔄 课件切换，生成新的videoId:', this.videoId)
                        } else {
                            console.log('[课程学习] ℹ️ 相同课件，复用videoId:', this.videoId)
                        }
                        
                        // ✅ 只在URL变化时才更新（避免不必要的重新加载）
                        if (this.videoUrl !== fileUrl) {
                            this.videoUrl = fileUrl
                            console.log('[课程学习] ✅ 视频URL已更新:', this.videoUrl)
                        }
                        console.log('[课程学习] ⏱️ 初始播放位置:', this.initialTime, '秒')
                    } else if (this.displayType === 'image') {
                        // 图片类型（包括type='image'或document类型但文件是图片）
                        this.imageUrl = fileUrl
                        console.log('[课程学习] 🖼️ 设置图片URL:', this.imageUrl)
                        console.log('[课程学习] 📋 课件类型:', this.courseware.type, '显示类型:', this.displayType)
                        // 测试图片是否可访问
                        this.testImageUrl(fileUrl)
                        // 图片课件加载时上报学习进度
                        this.reportNonVideoProgress()
                    } else if (this.displayType === 'pdf') {
                        // PDF类型
                        this.pdfUrl = fileUrl
                        console.log('[课程学习] 📄 设置PDF URL:', this.pdfUrl)
                        // 测试PDF是否可访问
                        this.testPdfUrl(fileUrl)
                        // PDF课件加载时上报学习进度
                        this.reportNonVideoProgress()
                    }
                } else {
                    console.warn('课件没有filePath:', this.courseware)
                }
            } catch (error) {
                console.error('加载课件失败:', error)
                uni.showToast({
                    title: '加载课件失败',
                    icon: 'none'
                })
            } finally {
                // ✅ 无论成功或失败，都重置loading状态
                this.loading = false
                console.log('[课程学习] ✅ 课件加载完成，loading重置')
            }
        },
        
        // 切换课件
        async switchCourseware(index) {
            if (index < 0 || index >= this.coursewareList.length) return
            
            // 切换前先上报当前课件的进度
            if (this.isPlaying) {
                this.reportProgress(true)
            }
            
            this.currentCoursewareIndex = index
            
            // ✅ 重置学习时长统计
            this.accumulatedDuration = 0
            this.currentPlayStartTime = 0
            this.lastReportedDuration = 0
            this.lastReportTime = 0
            this.videoRetryCount = 0  // 重置视频重试计数器
            
            // ✅ 清空视频URL，确保切换时组件重新加载
            this.videoUrl = ''
            this.videoId = ''
            console.log('[课程学习] 切换课件，重置所有状态')
            
            // ✅ 等待DOM更新后再加载新课件
            await this.$nextTick()
            await this.loadCourseware(this.coursewareList[index])
        },
        
        /**
         * 加载学习详情列表
         */
        async loadLearningDetails() {
            try {
                if (!this.courseId) return
                
                const response = await getMyLearningDetails(this.courseId)
                if (response.code === 200) {
                    this.learningDetails = response.data || []
                    console.log('学习详情列表:', this.learningDetails)
                } else {
                    console.error('加载学习详情失败:', response)
                    this.learningDetails = []
                }
            } catch (error) {
                console.error('加载学习详情失败:', error)
                this.learningDetails = []
            }
        },
        
        /**
         * 加载学习记录（包含后端计算的进度）
         */
        async loadLearningRecord() {
            try {
                if (!this.courseId) return
                
                const response = await getMyRecords()
                if (response.code === 200) {
                    const records = response.data || []
                    // 找到当前课程的学习记录
                    const record = records.find(r => r.courseId === this.courseId)
                    if (record) {
                        this.learningRecord = record
                        // ✅ 直接使用后端返回的进度值（已经过精确计算）
                        this.courseProgress = Math.round(record.progress || 0)
                        console.log('[课程学习] ✅✅✅ 使用后端进度（2025-12-05 18:10修复）✅✅✅')
                        console.log('[课程学习] ✅ 学习记录已加载:', {
                            progress: record.progress,
                            courseProgress: this.courseProgress,
                            totalDuration: record.totalDuration,
                            learnCount: record.learnCount
                        })
                        console.log('[课程学习] 📊 最终显示进度:', this.courseProgress + '%')
                    } else {
                        console.log('[课程学习] ℹ️ 当前课程还没有学习记录')
                        this.learningRecord = null
                        this.courseProgress = 0
                    }
                } else {
                    console.error('[课程学习] ❌ 加载学习记录失败:', response)
                    this.learningRecord = null
                    this.courseProgress = 0
                }
            } catch (error) {
                console.error('[课程学习] ❌ 加载学习记录异常:', error)
                this.learningRecord = null
                this.courseProgress = 0
            }
        },
        
        /**
         * 计算课程总进度（已废弃 - 直接使用后端返回的progress）
         * 
         * ⚠️ 已改为使用后端计算的进度值（loadLearningRecord方法中赋值）
         * 前端不再重新计算，避免与后端不一致
         */
        calculateCourseProgress() {
            // ✅ 不再前端计算，直接使用后端返回的 learningRecord.progress
            console.log('[课程学习] ℹ️ 使用后端计算的进度:', this.courseProgress + '%')
            return
            
            /* 已废弃的前端计算逻辑
            if (!this.coursewareList || this.coursewareList.length === 0) {
                this.courseProgress = 0
                console.log('[课程学习] ⚠️ 没有课件列表，进度为0%')
                return
            }
            
            const totalCount = this.coursewareList.length
            let completedCount = 0
            const enableDetailLog = false // 是否输出详细日志（关闭，避免日志刷屏）
            
            // 构建学习详情映射（按课件ID分组，保留视频播放位置最大的记录）
            const detailMap = new Map()
            const realDurationMap = new Map() // 记录推断的真实时长
            
            for (const detail of this.learningDetails) {
                if (detail.coursewareId) {
                    const existing = detailMap.get(detail.coursewareId)
                    if (!existing || 
                        (detail.videoPosition && existing.videoPosition && 
                         detail.videoPosition > existing.videoPosition)) {
                        detailMap.set(detail.coursewareId, detail)
                        
                        // 记录最大播放位置，作为视频的可能真实时长
                        const maxPosition = detail.videoPosition || 0
                        const existingMax = realDurationMap.get(detail.coursewareId) || 0
                        if (maxPosition > existingMax) {
                            realDurationMap.set(detail.coursewareId, maxPosition)
                        }
                    }
                }
            }
            
            // 遍历所有课件，判断是否完成
            if (enableDetailLog) {
                console.log('[课程学习] ⚙️ 开始前端计算课件完成情况...')
            }
            for (const cw of this.coursewareList) {
                const detail = detailMap.get(cw.id)
                
                if (cw.type === 'video') {
                    // 视频：判断是否观看完成
                    if (detail) {
                        const videoPosition = detail.videoPosition || 0
                        const maxPositionFromHistory = realDurationMap.get(cw.id) || 0
                        
                        // 推断视频的真实时长
                        let realDuration = cw.duration // 默认使用配置的时长
                        let durationSource = '配置'
                        
                        // 情况1：配置的duration无效
                        if (!cw.duration || cw.duration <= 0) {
                            realDuration = maxPositionFromHistory + 3 // 使用历史最大位置+3秒缓冲
                            durationSource = '推断'
                        }
                        // 情况2：配置的duration明显过长（历史最大播放位置超过配置时长的50%但不到90%）
                        // 说明用户已经播放到接近或完全结束，但配置的duration偏大
                        else if (maxPositionFromHistory > cw.duration * 0.5 && maxPositionFromHistory < cw.duration * 0.9) {
                            realDuration = maxPositionFromHistory + 3 // 使用历史最大位置+3秒缓冲
                            durationSource = '推断(配置过长)'
                        }
                        
                        // 判断是否完成
                        let isCompleted = false
                        let progress = 0
                        
                        // 特殊判断：如果当前播放位置等于历史最大位置（说明已经播放到视频结尾）
                        // 且播放位置>=3秒（避免误判极短的测试视频）
                        if (videoPosition === maxPositionFromHistory && videoPosition >= 3) {
                            isCompleted = true
                            progress = 100
                        } else {
                            // 常规判断：观看位置 >= 真实时长的90%
                            progress = realDuration > 0 ? Math.floor((videoPosition / realDuration) * 100) : 0
                            isCompleted = realDuration > 0 && videoPosition >= realDuration * 0.9
                        }
                        
                        if (isCompleted) {
                            completedCount++
                            if (enableDetailLog) {
                                console.log(`[课程学习] ✅ 视频课件 ${cw.id}(${cw.name}) 已完成: ${videoPosition}秒 / ${realDuration}秒 (${progress}%) [时长来源:${durationSource}]`)
                            }
                        } else {
                            if (enableDetailLog) {
                                console.log(`[课程学习] ⏳ 视频课件 ${cw.id}(${cw.name}) 未完成: ${videoPosition}秒 / ${realDuration}秒 (${progress}%) [时长来源:${durationSource}]`)
                            }
                        }
                    } else {
                        if (enableDetailLog) {
                            console.log(`[课程学习] ❌ 视频课件 ${cw.id}(${cw.name}) 无学习记录`)
                        }
                    }
                } else {
                    // 图片/PDF：只要有学习详情记录就视为完成
                    if (detail) {
                        completedCount++
                        if (enableDetailLog) {
                            console.log(`[课程学习] ✅ 非视频课件 ${cw.id}(${cw.name}) 已完成`)
                        }
                    } else {
                        if (enableDetailLog) {
                            console.log(`[课程学习] ❌ 非视频课件 ${cw.id}(${cw.name}) 无学习记录`)
                        }
                    }
                }
            }
            
            // 计算进度：已完成课件数 / 总课件数 * 100%
            this.courseProgress = Math.round((completedCount / totalCount) * 100)
            
            // 限制在0-100之间
            if (this.courseProgress > 100) {
                this.courseProgress = 100
            }
            if (this.courseProgress < 0) {
                this.courseProgress = 0
            }
            
            console.log(`[课程学习] 📊 课程进度（完成比例）: ${completedCount}个已完成 / ${totalCount}个总数 = ${this.courseProgress}%`)
            */
        },
        
        // 视频播放事件
        onVideoPlay(e) {
            console.log('[课程学习] ▶️ 视频开始播放')
            console.log('[课程学习] 当前播放位置:', this.videoCurrentTime, '秒')
            console.log('[课程学习] 视频总时长:', this.videoTotalDuration, '秒')
            console.log('[课程学习] 已累积时长:', this.accumulatedDuration, '秒')
            
            this.isPlaying = true
            // 记录本次播放的开始时间（不重置总时长）
            this.currentPlayStartTime = Date.now()
            this.startProgressTimer()
            
            console.log('[课程学习] ✅ 播放状态已设置，定时器已启动')
        },
        
        onVideoPause(e) {
            const playDuration = this.currentPlayStartTime ? Math.floor((Date.now() - this.currentPlayStartTime) / 1000) : 0
            console.log('[课程学习] ⏸️ 视频暂停')
            console.log('[课程学习] 本次播放时长:', playDuration, '秒')
            console.log('[课程学习] 当前位置:', this.videoCurrentTime, '秒')
            
            this.isPlaying = false
            // 累加本次播放时长
            if (this.currentPlayStartTime) {
                const thisDuration = Math.floor((Date.now() - this.currentPlayStartTime) / 1000)
                this.accumulatedDuration = (this.accumulatedDuration || 0) + thisDuration
                console.log('[课程学习] 累积观看时长:', this.accumulatedDuration, '秒')
            }
            this.reportProgress(true) // 暂停时立即上报
            console.log('[课程学习] ✅ 暂停时进度已上报')
        },
        
        onVideoEnded(e) {
            console.log('[课程学习] 🎬 视频播放结束')
            this.isPlaying = false
            
            // 累加最后一次播放时长
            if (this.currentPlayStartTime) {
                const thisDuration = Math.floor((Date.now() - this.currentPlayStartTime) / 1000)
                this.accumulatedDuration = (this.accumulatedDuration || 0) + thisDuration
                console.log('[课程学习] 本次播放时长:', thisDuration, '秒')
            }
            
            console.log('[课程学习] ✅ 最终累积时长:', this.accumulatedDuration, '秒（纯播放时长）')
            
            // 设置视频进度为100%
            if (this.videoTotalDuration > 0) {
                this.videoCurrentTime = this.videoTotalDuration
                console.log('[课程学习] ✅ 视频已播放完毕，设置进度为100%')
            }
            
            // 结束时立即上报，并在上报成功后刷新进度
            this.reportProgress(true)
            
            // 延迟刷新进度，确保后端已处理完成（延长到2秒，确保事务提交）
            setTimeout(async () => {
                await this.loadLearningRecord()
                await this.loadLearningDetails()
                this.calculateCourseProgress()
                console.log('[课程学习] 📊 进度已刷新')
                
                // 如果学习详情还是空的，再尝试一次
                if (this.learningDetails.length === 0) {
                    console.log('[课程学习] ⚠️ 学习详情为空，2秒后重试查询...')
                    setTimeout(async () => {
                        await this.loadLearningDetails()
                        this.calculateCourseProgress()
                        console.log('[课程学习] 📊 重试后进度已刷新，详情数量:', this.learningDetails.length)
                    }, 2000)
                }
            }, 2000)
        },
        
        onVideoTimeUpdate(e) {
            this.videoCurrentTime = e.detail.currentTime
            this.videoTotalDuration = e.detail.duration || this.videoTotalDuration
            
            // 备用进度上报机制：每30秒通过timeupdate上报一次
            // 这是为了兼容某些Android设备上pause/ended事件不触发的情况
            const now = Date.now()
            if (this.isPlaying && this.currentPlayStartTime) {
                const timeSinceLastReport = (now - this.lastReportTime) / 1000
                if (timeSinceLastReport >= 30) {
                    console.log('[课程学习] ⏱️ 通过timeupdate触发备用上报（30秒）')
                    this.reportProgress(false)
                }
            }
        },
        
        onVideoWaiting(e) {
            // 视频缓冲中
            console.log('视频缓冲中...')
        },
        
        onVideoLoadedMetadata(e) {
            // 视频元数据加载完成
            console.log('[课程学习] ✅ 视频元数据加载完成')
            console.log('[课程学习] 视频URL:', this.videoUrl)
            console.log('[课程学习] 视频时长:', e.detail.duration, '秒')
            console.log('[课程学习] 视频宽度:', e.detail.width)
            console.log('[课程学习] 视频高度:', e.detail.height)
            console.log('[课程学习] 课件信息:', this.courseware)
            
            // 如果视频时长存在，更新总时长
            if (e.detail.duration && e.detail.duration > 0) {
                this.videoTotalDuration = e.detail.duration
                console.log('[课程学习] ✅ 视频总时长已设置:', this.videoTotalDuration, '秒')
            } else {
                console.warn('[课程学习] ⚠️ 视频时长为0或未定义')
                // 尝试从课件信息中获取时长
                if (this.courseware && this.courseware.duration) {
                    this.videoTotalDuration = this.courseware.duration
                    console.log('[课程学习] 从课件信息获取时长:', this.videoTotalDuration, '秒')
                }
            }
            
            // 检查视频尺寸，如果宽度或高度为0，可能是黑屏问题
            if (e.detail.width === 0 || e.detail.height === 0) {
                console.warn('[课程学习] ⚠️ 检测到视频尺寸异常（黑屏），重试次数:', this.videoRetryCount)
                
                // 限制重试次数，避免无限循环
                if (this.videoRetryCount < 3) {
                    this.videoRetryCount++
                    console.log('[课程学习] 🔄 第', this.videoRetryCount, '次尝试修复黑屏')
                    
                    // 强制重新加载视频（重新生成videoId）
                    setTimeout(async () => {
                        const currentUrl = this.videoUrl
                        const currentInitialTime = this.initialTime
                        
                        // 重新生成videoId，强制组件重建
                        this.videoId = 'course-video-' + Date.now()
                        this.videoUrl = ''
                        
                        await this.$nextTick()
                        
                        // 恢复视频URL和初始时间
                        this.videoUrl = currentUrl
                        this.initialTime = currentInitialTime
                        
                        console.log('[课程学习] ✅ 已重新加载视频，新videoId:', this.videoId)
                    }, 300)
                } else {
                    console.error('[课程学习] ❌ 已达到最大重试次数，放弃修复')
                    uni.showToast({
                        title: '视频加载异常，请退出重试',
                        icon: 'none',
                        duration: 3000
                    })
                }
            } else {
                // 视频尺寸正常，重置重试计数器
                this.videoRetryCount = 0
                console.log('[课程学习] ✅ 视频尺寸正常，重置重试计数器')
            }
        },
        
        onFullscreenChange(e) {
            console.log('[课程学习] 全屏状态变化:', e.detail)
            
            // 全屏切换时，如果正在播放，累加当前段的时长
            if (this.isPlaying && this.currentPlayStartTime) {
                const thisDuration = Math.floor((Date.now() - this.currentPlayStartTime) / 1000)
                this.accumulatedDuration = (this.accumulatedDuration || 0) + thisDuration
                console.log('[课程学习] 全屏切换时累加时长:', thisDuration, '秒，总计:', this.accumulatedDuration, '秒')
                // 重置当前播放开始时间
                this.currentPlayStartTime = Date.now()
            }
            
            if (e.detail.fullScreen) {
                console.log('[课程学习] ✅ 进入全屏模式，播放状态:', this.isPlaying ? '播放中' : '已暂停')
            } else {
                console.log('[课程学习] ✅ 退出全屏模式，播放状态:', this.isPlaying ? '播放中' : '已暂停')
            }
            
            // 全屏切换后，如果正在播放，立即上报一次进度
            if (this.isPlaying) {
                setTimeout(() => {
                    this.reportProgress(true)
                }, 500)
            }
        },
        
        onVideoError(e) {
            console.error('[课程学习] ❌❌❌ 视频播放错误 ❌❌❌')
            console.error('[课程学习] 错误码:', e.detail?.errCode)
            console.error('[课程学习] 错误信息:', e.detail?.errMsg || e.detail?.message)
            console.error('[课程学习] 视频URL:', this.videoUrl)
            console.error('[课程学习] 课件信息:', this.courseware)
            console.error('[课程学习] 完整错误对象:', JSON.stringify(e.detail || e))
            
            // 根据错误码提供具体的错误信息
            let errorMsg = '视频播放失败'
            if (e.detail?.errCode === -1) {
                errorMsg = '视频文件不存在或无法访问'
            } else if (e.detail?.errCode === -2) {
                errorMsg = '视频格式不支持'
            } else if (e.detail?.errMsg?.includes('404')) {
                errorMsg = '视频文件未找到(404)'
            } else if (e.detail?.errMsg?.includes('403')) {
                errorMsg = '没有权限访问视频文件(403)'
            } else if (e.detail?.errMsg?.includes('timeout')) {
                errorMsg = '视频加载超时，请检查网络'
            }
            
            // 尝试使用原始路径（不编码）或检查是否是编码问题
            if (this.courseware && this.courseware.filePath) {
                let filePath = this.courseware.filePath
                
                // 确保路径以 / 开头（数据库格式：/profile/upload/...）
                if (!filePath.startsWith('/')) {
                    filePath = '/' + filePath
                }
                
                const originalUrl = config.FILE_BASE_URL + filePath
                console.log('尝试原始URL（未编码）:', originalUrl)
                
                // 如果当前URL是编码的，尝试使用未编码的URL
                if (this.videoUrl !== originalUrl) {
                    console.log('尝试切换到未编码的URL')
                    this.videoUrl = originalUrl
                    
                    // 等待一下后重新尝试播放
                    this.$nextTick(() => {
                        setTimeout(() => {
                            const videoContext = uni.createVideoContext('course-video')
                            if (videoContext) {
                                try {
                                    videoContext.play()
                                    videoContext.pause()
                                } catch (err) {
                                    console.error('重新加载视频失败:', err)
                                }
                            }
                        }, 500)
                    })
                } else {
                    uni.showModal({
                        title: '视频播放失败',
                        content: errorMsg + '\n\n服务器: ' + config.FILE_BASE_URL + '\n路径: ' + (this.courseware?.filePath || '未知'),
                        showCancel: false,
                        confirmText: '知道了'
                    })
                }
            } else {
                uni.showModal({
                    title: '视频播放失败',
                    content: errorMsg + '\n\n请检查：\n1. 服务器是否运行\n2. 视频文件是否存在\n3. 网络连接是否正常',
                    showCancel: false,
                    confirmText: '知道了'
                })
            }
        },
        
        // 测试图片URL是否可访问
        async testImageUrl(url) {
            console.log('[课程学习] 🧪 测试图片URL:', url)
            try {
                const res = await uni.request({
                    url: url,
                    method: 'HEAD',
                    timeout: 5000
                })
                
                if (res.statusCode === 200) {
                    console.log('[课程学习] ✅ 图片文件可访问')
                } else if (res.statusCode === 404) {
                    console.error('[课程学习] ❌ 图片文件不存在(404)')
                    uni.showToast({
                        title: '图片文件不存在',
                        icon: 'none'
                    })
                } else {
                    console.warn('[课程学习] ⚠️ 响应码:', res.statusCode)
                }
            } catch (error) {
                console.error('[课程学习] ❌ 图片URL测试失败:', error)
            }
        },
        
        // 图片加载成功
        onImageLoad(e) {
            console.log('[课程学习] ✅ 图片加载成功:', e)
        },
        
        // 图片加载失败
        onImageError(e) {
            console.error('[课程学习] ❌ 图片加载失败:', e)
            console.error('[课程学习] 图片URL:', this.imageUrl)
            uni.showModal({
                title: '图片加载失败',
                content: '无法加载图片，请检查网络连接或联系管理员。\n\nURL: ' + this.imageUrl,
                showCancel: false
            })
        },
        
        // 测试PDF URL是否可访问
        async testPdfUrl(url) {
            console.log('[课程学习] 🧪 测试PDF URL:', url)
            try {
                const res = await uni.request({
                    url: url,
                    method: 'HEAD',
                    timeout: 5000
                })
                
                if (res.statusCode === 200) {
                    console.log('[课程学习] ✅ PDF文件可访问')
                    console.log('[课程学习] Content-Length:', res.header['content-length'] || res.header['Content-Length'])
                } else if (res.statusCode === 404) {
                    console.error('[课程学习] ❌ PDF文件不存在(404)')
                } else {
                    console.warn('[课程学习] ⚠️ 响应码:', res.statusCode)
                }
            } catch (error) {
                console.error('[课程学习] ❌ PDF URL测试失败:', error)
            }
        },
        
        // 测试视频URL是否可访问
        async testVideoUrl(url) {
            console.log('[课程学习] 🧪 测试视频URL可访问性:', url)
            try {
                // 使用HEAD请求测试文件是否存在（不下载文件内容）
                const res = await uni.request({
                    url: url,
                    method: 'HEAD',
                    timeout: 5000
                })
                
                if (res.statusCode === 200) {
                    console.log('[课程学习] ✅ 视频文件可访问')
                    console.log('[课程学习] Content-Type:', res.header['content-type'] || res.header['Content-Type'])
                    console.log('[课程学习] Content-Length:', res.header['content-length'] || res.header['Content-Length'])
                } else if (res.statusCode === 404) {
                    console.error('[课程学习] ❌ 视频文件不存在(404)')
                    console.error('[课程学习] 请检查数据库中的filePath是否正确')
                } else if (res.statusCode === 403) {
                    console.error('[课程学习] ❌ 没有权限访问视频文件(403)')
                } else {
                    console.warn('[课程学习] ⚠️ 意外的响应码:', res.statusCode)
                }
            } catch (error) {
                console.error('[课程学习] ❌ 视频URL测试失败:', error)
                console.error('[课程学习] 可能原因: 服务器未启动或网络不通')
                console.error('[课程学习] 服务器地址:', config.FILE_BASE_URL)
            }
        },
        
        // 开始学习进度定时上报
        startProgressTimer() {
            this.clearProgressTimer()
            this.progressTimer = setInterval(() => {
                if (this.isPlaying) {
                    this.reportProgress()
                }
            }, this.reportInterval)
        },
        
        // 清除定时器
        clearProgressTimer() {
            if (this.progressTimer) {
                clearInterval(this.progressTimer)
                this.progressTimer = null
            }
            if (this.progressRefreshTimer) {
                clearInterval(this.progressRefreshTimer)
                this.progressRefreshTimer = null
            }
        },
        
        // 上报学习进度（使用队列管理器）
        async reportProgress(immediate = false) {
            const now = Date.now()
            // 如果不是立即上报，检查是否到了上报时间
            if (!immediate && now - this.lastReportTime < this.reportInterval) {
                return
            }
            
            // 计算本次播放的时长（如果正在播放）
            let currentSessionDuration = 0
            if (this.isPlaying && this.currentPlayStartTime) {
                currentSessionDuration = Math.floor((now - this.currentPlayStartTime) / 1000)
            }
            
            // 计算总时长：累积时长 + 当前播放时长
            const totalDuration = (this.accumulatedDuration || 0) + currentSessionDuration
            
            // 计算增量时长（本次上报的时长增量）
            const duration = totalDuration - (this.lastReportedDuration || 0)
            
            console.log('[课程学习] 上报进度 - 累积:', this.accumulatedDuration, '当前:', currentSessionDuration, '总计:', totalDuration, '增量:', duration, '强制:', immediate)
            
            // ✅ 如果增量时长太小且不是强制上报，跳过
            // 注意：视频结束时会强制上报（immediate=true），即使增量为0也会上报，以便后端重新计算进度
            if (duration < 1 && !immediate) {
                console.log('[课程学习] ⏭️ 增量时长不足1秒且非强制上报，跳过')
                return
            }
            
            // ✅ 强制上报时即使增量为0也要上报，确保后端更新进度
            if (immediate && duration === 0) {
                console.log('[课程学习] ⚠️ 强制上报但增量为0，仍然上报以触发进度计算')
            }
            
            const videoPosition = Math.floor(this.videoCurrentTime)
            const videoTotalDuration = Math.floor(this.videoTotalDuration)
            
            // 计算当前视频播放进度百分比（仅用于显示，不作为课程总进度）
            let videoProgress = 0
            if (videoTotalDuration > 0) {
                videoProgress = Math.min(100, Math.floor((videoPosition / videoTotalDuration) * 100))
            }
            
            // 添加到上报队列（队列管理器会自动处理网络异常和重连）
            progressQueue.addProgress({
                courseId: this.courseId,
                coursewareId: this.courseware ? this.courseware.id : null, // 添加课件ID
                duration: duration, // 上报增量时长
                videoPosition: videoPosition,
                videoTotalDuration: videoTotalDuration
            }, () => {
                // 上报成功后刷新学习记录、学习详情并重新计算进度（延迟1秒，确保事务提交）
                setTimeout(async () => {
                    await this.loadLearningRecord()
                    await this.loadLearningDetails()
                    this.calculateCourseProgress()
                }, 1000)
            })
            
            // 每隔30秒刷新一次学习进度（从后端获取最新进度）
            if (!this.progressRefreshTimer) {
                this.progressRefreshTimer = setInterval(() => {
                    this.refreshLearningProgress()
                }, 30000) // 30秒刷新一次
            }
            
            this.lastReportTime = now
            this.lastReportedDuration = totalDuration // 更新已上报的累计时长
            
            console.log('[课程学习] ✅ 进度已上报 - courseId:', this.courseId, 'coursewareId:', this.courseware?.id, 'duration:', duration, '秒')
            
            // 更新本地学习记录（注意：课程总进度由后端计算，这里只更新时长和位置）
            if (this.learningRecord) {
                this.learningRecord.totalDuration = (this.learningRecord.totalDuration || 0) + duration
                this.learningRecord.lastVideoPosition = videoPosition
                // 课程总进度不在前端计算，等待后端返回更新
            }
        },
        
        // 刷新学习进度（从后端获取最新进度）
        async refreshLearningProgress() {
            try {
                // 刷新学习记录
                await this.loadLearningRecord()
                
                // 刷新学习详情并重新计算进度
                await this.loadLearningDetails()
                this.calculateCourseProgress()
            } catch (error) {
                console.error('刷新学习进度失败:', error)
            }
        },
        
        // 预览图片
        async previewImage() {
            if (!this.imageUrl) {
                uni.showToast({
                    title: '图片路径为空',
                    icon: 'none'
                })
                return
            }
            
            console.log('[课程学习] 🖼️ 预览图片:', this.imageUrl)
            
            // 记录图片查看进度
            await this.reportNonVideoProgress()
            
            uni.previewImage({
                urls: [this.imageUrl],
                current: this.imageUrl,
                success: () => {
                    console.log('[课程学习] ✅ 图片预览成功')
                },
                fail: (err) => {
                    console.error('[课程学习] ❌ 图片预览失败:', err)
                    uni.showModal({
                        title: '图片预览失败',
                        content: '错误: ' + (err.errMsg || '未知错误') + '\n\nURL: ' + this.imageUrl,
                        showCancel: false
                    })
                }
            })
        },
        
        // 打开PDF（H5用新标签页，App用openDocument）
        async openPdf() {
            if (!this.pdfUrl) {
                uni.showToast({
                    title: 'PDF路径为空',
                    icon: 'none'
                })
                return
            }
            
            console.log('[课程学习] 📄 打开PDF:', this.pdfUrl)
            
            // 记录PDF查看进度
            await this.reportNonVideoProgress()
            
            // #ifdef H5
            window.open(this.pdfUrl, '_blank')
            // #endif
            
            // #ifndef H5
            uni.showLoading({ title: '下载中...' })
            uni.downloadFile({
                url: this.pdfUrl,
                timeout: 60000, // 60秒超时
                success: (res) => {
                    console.log('[课程学习] PDF下载结果:', res.statusCode)
                    uni.hideLoading()
                    if (res.statusCode === 200) {
                        uni.openDocument({
                            filePath: res.tempFilePath,
                            fileType: 'pdf',
                            success: () => {
                                console.log('[课程学习] ✅ 打开PDF成功')
                            },
                            fail: (err) => {
                                console.error('[课程学习] ❌ openDocument错误:', err)
                                uni.showModal({
                                    title: '打开PDF失败',
                                    content: '错误信息: ' + (err.errMsg || '未知错误') + '\n\n请确保设备安装了PDF阅读器',
                                    showCancel: false
                                })
                            }
                        })
                    } else {
                        console.error('[课程学习] ❌ PDF下载失败，状态码:', res.statusCode)
                        uni.showModal({
                            title: 'PDF下载失败',
                            content: 'HTTP状态码: ' + res.statusCode + '\n\nURL: ' + this.pdfUrl,
                            showCancel: false
                        })
                    }
                },
                fail: (err) => {
                    console.error('[课程学习] ❌ 下载PDF错误:', err)
                    uni.hideLoading()
                    uni.showModal({
                        title: 'PDF下载失败',
                        content: '错误: ' + (err.errMsg || '网络错误') + '\n\nURL: ' + this.pdfUrl,
                        showCancel: false
                    })
                }
            })
            // #endif
        },
        
        // 上报非视频课件的学习进度（图片/PDF）
        async reportNonVideoProgress() {
            console.log('[课程学习] 📤 准备上报非视频课件进度')
            console.log('[课程学习] 课件信息:', this.courseware)
            
            if (!this.courseware || !this.courseware.id) {
                console.warn('[课程学习] ⚠️ 课件信息不完整，跳过上报')
                return
            }
            
            // ✅ 会话去重：同一课件在同一会话中只上报一次
            const sessionKey = `nonvideo_${this.courseId}_${this.courseware.id}`
            if (this.reportedNonVideoInSession && this.reportedNonVideoInSession === sessionKey) {
                console.log('[课程学习] ⏭️ 该非视频课件已在本次会话中上报过，跳过')
                return
            }
            
            try {
                console.log('[课程学习] 📤 上报非视频课件进度:', {
                    courseId: this.courseId,
                    coursewareId: this.courseware.id,
                    type: this.courseware.type
                })
                
                // ✅ 上报学习进度（非视频课件，duration为0，不计入学习时长）
                progressQueue.addProgress({
                    courseId: this.courseId,
                    coursewareId: this.courseware.id,
                    duration: 0, // ✅ 图片/PDF不计入学习时长
                    videoPosition: null,
                    videoTotalDuration: null
                }, () => {
                    console.log('[课程学习] ✅ 非视频课件进度上报成功，刷新学习记录和详情')
                    
                    // 标记已上报
                    this.reportedNonVideoInSession = sessionKey
                    
                    // 上报成功后刷新学习记录、学习详情并重新计算进度（延迟1秒，确保事务提交）
                    setTimeout(async () => {
                        await this.loadLearningRecord()
                        await this.loadLearningDetails()
                        this.calculateCourseProgress()
                    }, 1000)
                })
            } catch (error) {
                console.error('[课程学习] ❌ 上报非视频课件进度失败:', error)
            }
        },
        
        // 格式化时长
        formatDuration(seconds) {
            if (!seconds) return '0分钟'
            const hours = Math.floor(seconds / 3600)
            const minutes = Math.floor((seconds % 3600) / 60)
            if (hours > 0) {
                return `${hours}小时${minutes}分钟`
            }
            return `${minutes}分钟`
        },
        
        // 格式化时间（用于视频播放时间显示：分:秒）
        formatTime(seconds) {
            if (!seconds || seconds < 0) return '00:00'
            const min = Math.floor(seconds / 60)
            const sec = Math.floor(seconds % 60)
            return `${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`
        }
    }
}
</script>

<style lang="scss" scoped>
.course-detail-container {
    padding: 20rpx;
    min-height: 100vh;
    background-color: #f8f8f8;
}

/* 横屏样式 */
.course-detail-container.landscape {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
    padding: 0;
    padding-top: 0; // 横屏时不需要导航栏空间
}

/* 视频容器 */
.video-container {
    width: 100%;
    background-color: #000;
    margin-bottom: 20rpx;
    border-radius: 12rpx;
    overflow: hidden;
}

.course-detail-container.landscape .video-container {
    width: 100vw;
    height: 100vh;
    margin-bottom: 0;
    border-radius: 0;
}

.course-video {
    width: 100%;
    height: 400rpx;
    background-color: #000;
    display: block;
}

.course-detail-container.landscape .course-video {
    height: 100vh;
}

/* 视频播放进度条 */
.video-progress-bar {
    padding: 16rpx 20rpx;
    background-color: #fff;
    border-top: 1px solid #eee;
}

.progress-info {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12rpx;
    font-size: 24rpx;
}

.progress-text {
    color: #333;
    font-weight: 500;
}

.time-text {
    color: #999;
    font-size: 22rpx;
}

.progress-track {
    width: 100%;
    height: 8rpx;
    background-color: #e0e0e0;
    border-radius: 4rpx;
    overflow: hidden;
    position: relative;
}

.progress-active {
    height: 100%;
    background: linear-gradient(90deg, #3c9cff 0%, #5cadff 100%);
    border-radius: 4rpx;
    transition: width 0.3s ease;
}

/* 课件容器 */
.courseware-container {
    width: 100%;
    background-color: #fff;
    border-radius: 12rpx;
    margin-bottom: 20rpx;
    overflow: hidden;
}

/* 课件标签切换 */
.courseware-tabs {
    display: flex;
    background: #fff;
    padding: 20rpx;
    margin-bottom: 20rpx;
    border-radius: 12rpx;
    gap: 20rpx;
    overflow-x: auto;
    
    .courseware-tab {
        padding: 12rpx 24rpx;
        border-radius: 20rpx;
        background: #f5f5f5;
        white-space: nowrap;
        transition: all 0.3s;
        
        .tab-text {
            font-size: 26rpx;
            color: #666;
        }
        
        &.active {
            background: rgb(55 140 224);
            
            .tab-text {
                color: #fff;
                font-weight: 500;
            }
        }
    }
}

.courseware-viewer {
    min-height: 600rpx;
    
    .pdf-viewer {
        width: 100%;
        height: 800rpx;
        
        .pdf-placeholder {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100%;
            padding: 60rpx;
            
            .pdf-icon {
                font-size: 120rpx;
                margin-bottom: 30rpx;
            }
            
            .pdf-text {
                font-size: 32rpx;
                color: #666;
                margin-bottom: 40rpx;
            }
            
            .open-pdf-btn {
                background: rgb(55 140 224);
                color: #fff;
                padding: 20rpx 60rpx;
                border-radius: 50rpx;
                font-size: 28rpx;
                font-weight: 500;
                
                .btn-text {
                    color: #fff;
                }
            }
        }
        
        .placeholder {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100%;
            color: #999;
        }
    }
    
    .image-viewer {
        width: 100%;
        height: 70vh;
        background: #f5f5f5;
        
        .courseware-image {
            width: 100%;
            min-height: 200rpx;
        }
        
        .image-loading {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 400rpx;
            color: #999;
            font-size: 28rpx;
        }
    }
    
    .unknown-viewer {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 400rpx;
        background: #f5f5f5;
        
        .unknown-icon {
            font-size: 80rpx;
            margin-bottom: 20rpx;
        }
        
        .unknown-text {
            font-size: 28rpx;
            color: #999;
        }
    }
    
    .text-viewer {
        padding: 30rpx;
    }
}

/* 课程信息 */
.course-info {
    background: #fff;
    border-radius: 16rpx;
    padding: 30rpx;
    margin-bottom: 20rpx;
    
    .info-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20rpx;
    }
    
    .course-name {
        display: block;
        font-size: 36rpx;
        font-weight: bold;
        color: #333;
        margin-bottom: 20rpx;
    }
    
    .course-desc {
        display: block;
        font-size: 28rpx;
        color: #666;
        margin-bottom: 30rpx;
    }
    
    .learning-progress {
        margin-top: 30rpx;
        padding-top: 30rpx;
        border-top: 1rpx solid #f0f0f0;
        
        .progress-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20rpx;
            
            .progress-title {
                font-size: 28rpx;
                font-weight: bold;
                color: #333;
            }
            
            .progress-percent {
                font-size: 32rpx;
                font-weight: bold;
                color: #4caf50;
            }
        }
        
        .progress-bar {
            height: 12rpx;
            background: #f0f0f0;
            border-radius: 6rpx;
            overflow: hidden;
            margin-bottom: 20rpx;
            
            .progress-fill {
                height: 100%;
                background: linear-gradient(90deg, #4caf50, #8bc34a);
                transition: width 0.3s;
            }
        }
        
        .progress-stats {
            display: flex;
            justify-content: space-between;
            font-size: 24rpx;
            color: #999;
        }
    }
}

/* 横屏时隐藏课程信息 */
.course-detail-container.landscape .course-info {
    display: none;
}
</style>
