“mitao”
2026-04-24 f727ebece6430866b30179001e84adfdca14e9a8
Merge remote-tracking branch 'origin/master'
5个文件已修改
111 ■■■■■ 已修改文件
traditionalApp/pages/courseDetail/courseDetail.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/downloadPlayer/downloadPlayer.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/downloads/downloads.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/liveDetail/liveDetail.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/watchLive/watchLive.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
traditionalApp/pages/courseDetail/courseDetail.vue
@@ -278,6 +278,7 @@
<script setup lang="ts">
import { computed, getCurrentInstance, nextTick, ref } from 'vue'
import { onHide, onLoad, onShow, onUnload } from '@dcloudio/uni-app'
import config from '@/config/index.js'
import {
    favoriteHealthCourse,
    getHealthCourseDetail,
@@ -785,6 +786,16 @@
}
/**
 * 生成课程 H5 分享链接,供微信好友打开页面详情。
 */
function buildCourseShareUrl() {
    if (!courseId.value) {
        return `${config.BASE_URL}/#/pages/healthCourses/healthCourses`
    }
    return `${config.BASE_URL}/#/pages/courseDetail/courseDetail?id=${encodeURIComponent(courseId.value)}`
}
/**
 * 通过微信好友聊天场景分享当前课程。
 */
function shareToWechatSession() {
@@ -806,8 +817,11 @@
            return
        }
        weixinService.send({
            type: 'text',
            type: 0,
            title: courseDetail.value.title.trim() || '养生课程',
            content: buildCourseShareText(),
            href: buildCourseShareUrl(),
            thumbs: courseDetail.value.bannerImages[0] ? [courseDetail.value.bannerImages[0]] : undefined,
            extra: {
                scene: 'WXSceneSession',
            },
traditionalApp/pages/downloadPlayer/downloadPlayer.vue
@@ -77,6 +77,7 @@
    coverImage?: string
    durationText?: string
    savedFilePath?: string
    videoUrl?: string
}
const PLAYER_ID = 'download-video-player'
@@ -91,7 +92,13 @@
let watermarkTimer: ReturnType<typeof setInterval> | null = null
const instance = getCurrentInstance()
const videoSource = computed(() => normalizeText(taskInfo.value?.savedFilePath))
const videoSource = computed(() => {
    const savedFilePath = normalizeText(taskInfo.value?.savedFilePath)
    if (savedFilePath) {
        return savedFilePath
    }
    return normalizeText(taskInfo.value?.videoUrl)
})
const coverImage = computed(() => normalizeText(taskInfo.value?.coverImage) || DEFAULT_COVER)
const title = computed(() => normalizeText(taskInfo.value?.title) || '本地视频')
const subtitle = computed(() => normalizeText(taskInfo.value?.subtitle) || '养生课程')
@@ -113,10 +120,27 @@
    statusBarHeight.value = systemInfo.statusBarHeight || 20
    const clientTaskId = typeof options?.clientTaskId === 'string' ? options.clientTaskId : ''
    const currentUserId = resolveCurrentAppUserId()
    if (!currentUserId || !clientTaskId) {
        return
    const fallbackTaskInfo = {
        clientTaskId: clientTaskId || 'download-player-fallback',
        title: typeof options?.title === 'string' ? decodeURIComponent(options.title) : '',
        subtitle: typeof options?.subtitle === 'string' ? decodeURIComponent(options.subtitle) : '',
        coverImage: typeof options?.coverImage === 'string' ? decodeURIComponent(options.coverImage) : '',
        durationText: typeof options?.durationText === 'string' ? decodeURIComponent(options.durationText) : '',
        savedFilePath: typeof options?.savedFilePath === 'string' ? decodeURIComponent(options.savedFilePath) : '',
        videoUrl: typeof options?.videoUrl === 'string' ? decodeURIComponent(options.videoUrl) : '',
    }
    taskInfo.value = getDownloadTask(currentUserId, clientTaskId) as DownloadTaskItem | null
    if (currentUserId && clientTaskId) {
        taskInfo.value = getDownloadTask(currentUserId, clientTaskId) as DownloadTaskItem | null
    }
    if (!taskInfo.value) {
        taskInfo.value = fallbackTaskInfo
    } else if (!normalizeText(taskInfo.value.savedFilePath) && normalizeText(fallbackTaskInfo.savedFilePath || fallbackTaskInfo.videoUrl)) {
        taskInfo.value = {
            ...taskInfo.value,
            ...fallbackTaskInfo,
            clientTaskId: taskInfo.value.clientTaskId || fallbackTaskInfo.clientTaskId,
        }
    }
    videoContext = uni.createVideoContext(PLAYER_ID, instance?.proxy)
})
traditionalApp/pages/downloads/downloads.vue
@@ -119,6 +119,7 @@
    sourceType: DownloadSourceType
    sortTime: number
    savedFilePath: string
    videoUrl: string
}
const DEFAULT_COURSE_IMAGE = '/static/image/home/class.png'
@@ -237,15 +238,15 @@
        return
    }
    const playableTask = resolvePlayableDownloadTask(currentItem)
    if (!playableTask) {
    if (!playableTask && !normalizeOptionalText(currentItem.videoUrl)) {
        uni.showToast({
            title: '本地文件不存在,请重新下载',
            title: '视频资源不存在,请重新下载',
            icon: 'none',
        })
        return
    }
    uni.navigateTo({
        url: `/pages/downloadPlayer/downloadPlayer?clientTaskId=${encodeURIComponent(playableTask.clientTaskId)}`,
        url: buildDownloadPlayerUrl(currentItem, playableTask),
    })
}
@@ -268,6 +269,22 @@
            && !!normalizeOptionalText(task.savedFilePath)
    }) as LocalDownloadTask | undefined
    return matchedTask || null
}
/**
 * 生成下载播放器页面地址,优先携带本地文件路径,缺失时回退到远程视频地址。
 */
function buildDownloadPlayerUrl(item: DownloadListItem, playableTask: LocalDownloadTask | null) {
    const query = [
        `clientTaskId=${encodeURIComponent(normalizeOptionalText(playableTask?.clientTaskId) || normalizeOptionalText(item.clientTaskId))}`,
        `title=${encodeURIComponent(normalizeOptionalText(playableTask?.title) || item.title)}`,
        `subtitle=${encodeURIComponent(normalizeOptionalText(playableTask?.subtitle) || item.subtitle)}`,
        `coverImage=${encodeURIComponent(normalizeOptionalText(playableTask?.coverImage) || item.image)}`,
        `durationText=${encodeURIComponent(normalizeOptionalText(playableTask?.durationText) || item.duration)}`,
        `savedFilePath=${encodeURIComponent(normalizeOptionalText(playableTask?.savedFilePath) || item.savedFilePath)}`,
        `videoUrl=${encodeURIComponent(normalizeOptionalText(playableTask?.videoUrl) || item.videoUrl)}`,
    ]
    return `/pages/downloadPlayer/downloadPlayer?${query.join('&')}`
}
/**
@@ -370,6 +387,7 @@
            sourceType: 'remoteCompleted',
            sortTime: resolveDateTime(record.downloadedAt),
            savedFilePath: '',
            videoUrl: normalizeOptionalText(record.videoUrl),
        }
    })
}
@@ -399,6 +417,7 @@
            sourceType: 'localTask',
            sortTime: resolveDateTime(item.savedAt || item.updatedAt),
            savedFilePath: normalizeOptionalText(item.savedFilePath),
            videoUrl: normalizeOptionalText(item.videoUrl),
        }
    })
}
@@ -428,6 +447,7 @@
            subtitle: localItem.subtitle || remoteItem.subtitle,
            duration: localItem.duration || remoteItem.duration,
            image: localItem.image || remoteItem.image,
            videoUrl: localItem.videoUrl || remoteItem.videoUrl,
            sortTime: Math.max(localItem.sortTime, remoteItem.sortTime),
        }
    })
traditionalApp/pages/liveDetail/liveDetail.vue
@@ -91,6 +91,7 @@
    import { computed, ref } from 'vue'
    import { onLoad, onShow } from '@dcloudio/uni-app'
    import { getLiveCourseDetail, reserveLiveCourseSession } from './service'
    import config from '@/config/index.js'
    type LiveDisplayStatus = 'NOT_STARTED' | 'LIVING' | 'ENDED'
    type LiveActionStatus = 'RESERVABLE' | 'RESERVED' | 'WATCHABLE' | 'CLOSED'
@@ -341,6 +342,17 @@
    }
    /**
     * 生成直播详情 H5 分享链接,供微信好友直接打开页面。
     */
    function buildLiveShareUrl() {
        const currentCourseId = String(liveDetail.value.courseId || courseId.value || '').trim()
        if (!currentCourseId) {
            return `${config.BASE_URL}/#/pages/home/home`
        }
        return `${config.BASE_URL}/#/pages/liveDetail/liveDetail?id=${encodeURIComponent(currentCourseId)}`
    }
    /**
     * 直接拉起微信好友聊天分享当前直播。
     */
    function shareToWechatSession() {
@@ -362,8 +374,11 @@
                return
            }
            weixinService.send({
                type: 'text',
                type: 0,
                title: liveDetail.value.title?.trim() || '养生直播',
                content: buildLiveShareText(),
                href: buildLiveShareUrl(),
                thumbs: liveDetail.value.displayImage || liveDetail.value.coverImage ? [liveDetail.value.displayImage || liveDetail.value.coverImage] : undefined,
                extra: {
                    scene: 'WXSceneSession',
                },
traditionalApp/pages/watchLive/watchLive.vue
@@ -157,6 +157,7 @@
import { computed, getCurrentInstance, nextTick, ref } from 'vue';
import { onHide, onLoad, onShow, onUnload } from '@dcloudio/uni-app';
import { getLiveCourseDetail, getLiveQuizStatus, submitLiveQuiz, uploadLiveWatchRecord } from './service';
import config from '@/config/index.js';
type LiveActionStatus = 'RESERVABLE' | 'RESERVED' | 'WATCHABLE' | 'CLOSED'
type QuizViewState = 'answering' | 'success' | 'alreadyAwarded' | 'wrong' | 'unopened'
@@ -1204,6 +1205,20 @@
}
/**
 * 生成直播观看页 H5 分享链接,供微信好友直接打开页面。
 */
function buildWatchLiveShareUrl() {
    if (!courseId.value) {
        return `${config.BASE_URL}/#/pages/home/home`
    }
    const queryList = [`courseId=${encodeURIComponent(courseId.value)}`]
    if (activeSessionId.value) {
        queryList.push(`sessionId=${encodeURIComponent(activeSessionId.value)}`)
    }
    return `${config.BASE_URL}/#/pages/watchLive/watchLive?${queryList.join('&')}`
}
/**
 * 直接拉起微信好友聊天分享当前直播。
 */
function shareToWechatSession() {
@@ -1225,8 +1240,11 @@
            return
        }
        weixinService.send({
            type: 'text',
            type: 0,
            title: liveDetail.value.title?.trim() || '直播观看',
            content: buildWatchLiveShareText(),
            href: buildWatchLiveShareUrl(),
            thumbs: liveDetail.value.displayImage || liveDetail.value.coverImage ? [liveDetail.value.displayImage || liveDetail.value.coverImage] : undefined,
            extra: {
                scene: 'WXSceneSession',
            },