From de47ffc773d1d5fa6c7187bd7bfc2f8e35b0959c Mon Sep 17 00:00:00 2001 From: cao123 Date: Thu, 3 Sep 2026 16:14:47 +0800 Subject: [PATCH] =?UTF-8?q?vod=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/app.json | 7 +- miniprogram/pages/live/h5Room/index.json | 5 - miniprogram/pages/live/h5Room/index.scss | 112 ----- miniprogram/pages/live/h5Room/index.ts | 108 ---- miniprogram/pages/live/h5Room/index.wxml | 2 - miniprogram/pages/live/room/room.json | 9 - miniprogram/pages/live/room/room.scss | 6 - miniprogram/pages/live/room/room.ts | 75 --- miniprogram/pages/live/room/room.wxml | 4 - miniprogram/pages/live/video/video.json | 5 +- miniprogram/pages/live/video/video.scss | 9 + miniprogram/pages/live/video/video.ts | 605 ++++++++++++----------- miniprogram/pages/live/video/video.wxml | 23 +- miniprogram/pages/live/wxroom/index.json | 5 - miniprogram/pages/live/wxroom/index.scss | 42 -- miniprogram/pages/live/wxroom/index.ts | 26 - miniprogram/pages/live/wxroom/index.wxml | 4 - 17 files changed, 355 insertions(+), 692 deletions(-) delete mode 100644 miniprogram/pages/live/h5Room/index.json delete mode 100644 miniprogram/pages/live/h5Room/index.scss delete mode 100644 miniprogram/pages/live/h5Room/index.ts delete mode 100644 miniprogram/pages/live/h5Room/index.wxml delete mode 100644 miniprogram/pages/live/room/room.json delete mode 100644 miniprogram/pages/live/room/room.scss delete mode 100644 miniprogram/pages/live/room/room.ts delete mode 100644 miniprogram/pages/live/room/room.wxml delete mode 100644 miniprogram/pages/live/wxroom/index.json delete mode 100644 miniprogram/pages/live/wxroom/index.scss delete mode 100644 miniprogram/pages/live/wxroom/index.ts delete mode 100644 miniprogram/pages/live/wxroom/index.wxml diff --git a/miniprogram/app.json b/miniprogram/app.json index 06cdb34..3565e82 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -14,6 +14,12 @@ "pages/live/report/report", "pages/common/red/red" ], + "plugins": { + "myPlugin": { + "version": "0.1.5", + "provider": "wx116d0dd5e6a39ac7" + } + }, "tabBar": { "custom": true, "list": [ @@ -49,7 +55,6 @@ "sdkVersionEnd": "15.255.255" } }, - "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents", "requiredPrivateInfos": [ diff --git a/miniprogram/pages/live/h5Room/index.json b/miniprogram/pages/live/h5Room/index.json deleted file mode 100644 index bd0c1e1..0000000 --- a/miniprogram/pages/live/h5Room/index.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "disableScroll": true, - "navigationBarBackgroundColor": "#FFFFFF", - "usingComponents": {} -} diff --git a/miniprogram/pages/live/h5Room/index.scss b/miniprogram/pages/live/h5Room/index.scss deleted file mode 100644 index e41a66c..0000000 --- a/miniprogram/pages/live/h5Room/index.scss +++ /dev/null @@ -1,112 +0,0 @@ -/* pages/live/h5Room/index.wxss */ -page { - height: 100%; - background: #eaf6ff; - overflow: hidden; -} - -.h5-room { - width: 100%; - min-height: 100vh; - background: #fff; - padding: 0; - box-sizing: border-box; -} - -.h5-room__nav { - position: relative; - width: 100%; - background: linear-gradient(135deg, #edf8ff 0%, #dbeeff 48%, #cae5ff 100%); - box-sizing: border-box; - overflow: hidden; - box-shadow: inset 0 -1px 0 rgba(120, 180, 255, 0.14); -} - -.h5-room__nav-status { - position: relative; - z-index: 2; - width: 100%; - background: transparent; -} - -.h5-room__nav-bg, -.h5-room__nav-grid, -.h5-room__nav-glow, -.h5-room__nav-bubble { - position: absolute; -} - -.h5-room__nav-bg { - top: 0; - right: 0; - bottom: 0; - left: 0; - background: - radial-gradient(circle at 14% 82%, rgba(74, 183, 255, 0.26) 0%, rgba(74, 183, 255, 0) 28%), - radial-gradient(circle at 88% 22%, rgba(93, 255, 240, 0.22) 0%, rgba(93, 255, 240, 0) 20%), - radial-gradient(circle at 76% 84%, rgba(123, 152, 255, 0.18) 0%, rgba(123, 152, 255, 0) 24%), - linear-gradient(135deg, #edf8ff 0%, #dbeeff 48%, #cae5ff 100%); -} - -.h5-room__nav-grid { - top: 0; - right: 0; - bottom: 0; - left: 0; - opacity: 0.42; - background-image: - linear-gradient(rgba(255, 255, 255, 0.32) 1px, transparent 1px), - linear-gradient(90deg, rgba(255, 255, 255, 0.28) 1px, transparent 1px); - background-size: 18px 18px; - background-position: center center; -} - -.h5-room__nav-glow { - border-radius: 999rpx; - background: rgba(255, 255, 255, 0.28); -} - -.h5-room__nav-glow--left { - top: 20rpx; - left: -36rpx; - width: 220rpx; - height: 220rpx; -} - -.h5-room__nav-glow--right { - right: -30rpx; - bottom: -72rpx; - width: 260rpx; - height: 260rpx; - background: rgba(147, 177, 255, 0.2); -} - -.h5-room__nav-bubble { - border-radius: 50%; - background: rgba(71, 170, 255, 0.5); - box-shadow: 0 0 0 10rpx rgba(255, 255, 255, 0.12); -} - -.h5-room__nav-bubble--sm { - top: 22rpx; - right: 184rpx; - width: 12rpx; - height: 12rpx; - background: rgba(89, 187, 255, 0.8); -} - -.h5-room__nav-bubble--md { - top: 66rpx; - left: 112rpx; - width: 18rpx; - height: 18rpx; - background: rgba(79, 165, 255, 0.58); -} - -.h5-room__nav-bubble--lg { - right: 64rpx; - bottom: 18rpx; - width: 28rpx; - height: 28rpx; - background: rgba(120, 157, 255, 0.38); -} diff --git a/miniprogram/pages/live/h5Room/index.ts b/miniprogram/pages/live/h5Room/index.ts deleted file mode 100644 index 36ef4dd..0000000 --- a/miniprogram/pages/live/h5Room/index.ts +++ /dev/null @@ -1,108 +0,0 @@ -// pages/live/h5Room/index.ts -import { appId } from "../../../env"; -Page({ - /** - * 页面的初始数据 - */ - data: { - webViewUrl: "", - webViewHeight: 0, - statusBarHeight: 0, - navBarHeight: 0, - }, - async onLoad(options: any) { - const windowInfo = (wx as any).getWindowInfo - ? (wx as any).getWindowInfo() - : wx.getSystemInfoSync(); - const menuButtonRect = wx.getMenuButtonBoundingClientRect(); - const statusBarHeight = - windowInfo.safeArea?.top || windowInfo.statusBarHeight || 0; - const navBarHeight = menuButtonRect?.top - ? menuButtonRect.bottom + menuButtonRect.top - statusBarHeight - : statusBarHeight + 44; - const webViewHeight = Math.max( - (windowInfo.windowHeight || 0) - navBarHeight, - 0, - ); - - this.setData({ - statusBarHeight, - navBarHeight, - webViewHeight, - }); - const app = getApp(); - const bool = await app.login("room"); - if (!bool) return; - try { - // const baseUrl = "http://localhost:5173/pages/room"; - const baseUrl = "https://live.byteoc.com/1859506470730939/1425285?platform=mobile"; - - const openId = wx.getStorageSync("openId"); - const roomId = options?.roomId; - const params: Record = {}; - if (openId) params.openId = openId; - if (appId) params.appId = appId; - if (roomId) params.roomId = roomId; - - if (options?.extraParams) { - try { - const extraParams = JSON.parse( - decodeURIComponent(options.extraParams), - ); - Object.entries(extraParams).forEach(([key, value]) => { - params[key] = String(value); - }); - } catch (e) { - console.warn("Failed to parse extra parameters"); - } - } - const queryString = Object.entries(params) - .map( - ([key, value]) => - `${encodeURIComponent(key)}=${encodeURIComponent(value)}`, - ) - .join("&"); - const finalUrl = `${baseUrl}?${queryString}`; - this.setData({ - webViewUrl: finalUrl, - }); - } catch (error) { - console.error("Error generating URL:", error); - } - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() {}, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() {}, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() {}, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() {}, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() {}, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() {}, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() {}, -}); diff --git a/miniprogram/pages/live/h5Room/index.wxml b/miniprogram/pages/live/h5Room/index.wxml deleted file mode 100644 index d2c2e08..0000000 --- a/miniprogram/pages/live/h5Room/index.wxml +++ /dev/null @@ -1,2 +0,0 @@ - -pages/live/h5Room/index.wxml \ No newline at end of file diff --git a/miniprogram/pages/live/room/room.json b/miniprogram/pages/live/room/room.json deleted file mode 100644 index 7871bf3..0000000 --- a/miniprogram/pages/live/room/room.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "backgroundTextStyle": "light", - "backgroundColor": "#ffffff", - "navigationBarShareAppMessage": false, - "navigationBarShareTimeline": false, - "usingComponents": { - "liveroom": "/components/liveroom/liveroom" - } -} \ No newline at end of file diff --git a/miniprogram/pages/live/room/room.scss b/miniprogram/pages/live/room/room.scss deleted file mode 100644 index 46b262e..0000000 --- a/miniprogram/pages/live/room/room.scss +++ /dev/null @@ -1,6 +0,0 @@ -/* pages/live/room/room.wxss */ -@import "../../../variables"; -page { - background: #f9f9f9; - height: 100%; -} diff --git a/miniprogram/pages/live/room/room.ts b/miniprogram/pages/live/room/room.ts deleted file mode 100644 index 32c4369..0000000 --- a/miniprogram/pages/live/room/room.ts +++ /dev/null @@ -1,75 +0,0 @@ -// pages/live/room/room.ts -Page({ - /** - * 页面的初始数据 - */ - data: { - joinedGroupId: "", // 已加入的消息组id - windowHeight: "100%", - windowWidth: "100%", - }, - - /** - * 生命周期函数--监听页面加载 - */ - async onLoad(options) { - const app = getApp(); - wx.setStorageSync("joinedGroupId", options.groupId); - - - const bool = await app.login("room"); - if (!bool) return; - this.setData({ - joinedGroupId: options.groupId, - }); - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() {}, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() {}, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() {}, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() {}, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() {}, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() {}, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - const groupId = this.data.joinedGroupId || wx.getStorageSync("joinedGroupId"); - const path = groupId - ? `/pages/live/room/room?groupId=${groupId}` - : "/pages/live/room/room"; - - return { - /* - title: "邀请你进入直播间", - */ - title: "邀请你进入直播间", - path, - imageUrl: "/assets/img/600.jpg", - }; - }, -}); diff --git a/miniprogram/pages/live/room/room.wxml b/miniprogram/pages/live/room/room.wxml deleted file mode 100644 index 5e57358..0000000 --- a/miniprogram/pages/live/room/room.wxml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/miniprogram/pages/live/video/video.json b/miniprogram/pages/live/video/video.json index f077b83..b165e5d 100644 --- a/miniprogram/pages/live/video/video.json +++ b/miniprogram/pages/live/video/video.json @@ -6,9 +6,10 @@ "disableScroll": true, "usingComponents": { "navigation-bar": "/components/navigation-bar/navigation-bar", - "my-video":"/components/my-video/my-video", + "my-video": "/components/my-video/my-video", "van-tab": "@vant/weapp/tab/index", "van-tabs": "@vant/weapp/tabs/index", - "my-quiz":"/components/my-quiz/my-quiz" + "my-quiz":"/components/my-quiz/my-quiz", + "my-player": "plugin://myPlugin/player" } } \ No newline at end of file diff --git a/miniprogram/pages/live/video/video.scss b/miniprogram/pages/live/video/video.scss index 43bac60..bed0a7f 100644 --- a/miniprogram/pages/live/video/video.scss +++ b/miniprogram/pages/live/video/video.scss @@ -142,3 +142,12 @@ rich-content img { height: 80rpx; } } +.cover { + position: absolute; + bottom: 0; + z-index: 998; + height: 20%; + width: 70%; + left: 10%; + background-color: rgba(255, 255, 255, 0.007); +} \ No newline at end of file diff --git a/miniprogram/pages/live/video/video.ts b/miniprogram/pages/live/video/video.ts index 0bb4758..2c1f657 100644 --- a/miniprogram/pages/live/video/video.ts +++ b/miniprogram/pages/live/video/video.ts @@ -3,8 +3,9 @@ import UrlParamsHandler from "../../../utils/store"; import { htmlToWxNodes } from "../../../utils/html-to-wx-nodes"; import { request } from "../../../utils/request"; -import { appId } from "../../../env"; +import { AES_IV, AES_KEY, appId } from "../../../env"; import { receiveRedPacket } from "../../../utils/util"; +import { aesEncrypt } from "../../../utils/crypto"; const isMobileEnvironment = (): boolean => { const platform = wx.getSystemInfoSync().platform?.toLowerCase() || ''; @@ -12,6 +13,15 @@ const isMobileEnvironment = (): boolean => { }; Page({ + + _wasPlayingBeforeInterrupt: false, + _pauseVideoHandler: null as any, + _resumeVideoHandler: null as any, + _appHideHandler: null as any, + _appShowHandler: null as any, + _networkStatusChangeHandler: null as any, + _videoContext: null as any, + /** * 页面的初始数据 */ @@ -20,10 +30,15 @@ Page({ nodes: [] as any[], eveId: null, store: {}, - + fileid: "5001834818839455549", active: 0, canSubmit: false, - safeBottom: 0, + safeBottom: 24, + resumeTime: 0, + playing: false, + currentTime: 0, + sendDurationTimer: 0, + isAppHidden: false, }, /** @@ -31,240 +46,305 @@ Page({ */ async onLoad(options: any) { const app = getApp(); - wx.hideShareMenu({ - menus: ["shareAppMessage"], // 单独禁用好友分享 - }); + wx.hideShareMenu({ menus: ["shareAppMessage"] }); new UrlParamsHandler(options); app.globalData.store = options; - let safeBottom = 0; - //@ts-ignore - if (wx.getWindowInfo) { + + let safeBottom = 24; + try { //@ts-ignore - const systemInfo = wx.getWindowInfo(); - safeBottom = - Math.abs(systemInfo.windowHeight - systemInfo.safeArea.bottom) + 10; + const systemInfo = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync(); + safeBottom = Math.abs(systemInfo.windowHeight - systemInfo.safeArea.bottom) + 10; if (safeBottom === 0) safeBottom = 24; - } else { - const systemInfo = wx.getSystemInfoSync(); - safeBottom = systemInfo.safeArea - ? Math.abs(systemInfo.windowHeight - systemInfo.safeArea.bottom) + 10 - : 24; - } + } catch (e) { } + this.setData({ - safeBottom: safeBottom, + safeBottom, store: options, + resumeTime: this.getResumeTime(), }); + this.initSystemListeners(); + if (!isMobileEnvironment()) { - this.handleEnterError( - "当前环境不支持观看,请使用手机观看。", - "环境不支持", - ); + this.handleEnterError("当前环境不支持观看,请使用手机观看。", "环境不支持"); return; } - // 开启防截屏(仅限当前页面生命周期内) - //@ts-ignore - wx.setVisualEffectOnCapture({ - visualEffect: 'hidden', - }); + const bool = await app.login("video"); + if (!bool) return; + + //@ts-ignore 开启防截屏 + if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'hidden' }); }, - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { }, - handleEnterError(message: string, title = "无法进入") { - wx.showModal({ - title: title, - content: message, - showCancel: false, - confirmText: "确定", - }); - }, - - handleBack() { - wx.switchTab({ - url: "/pages/tab-bar/education/index", - }); - }, - /** - * 生命周期函数--监听页面显示 - */ onShow() { this.search(); }, - /** - * 生命周期函数--监听页面隐藏 - */ onHide() { - // 离开视频页时恢复截屏能力,避免影响其他页面 //@ts-ignore - wx.setVisualEffectOnCapture({ - visualEffect: 'none', - }); + if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' }); + + if (this.data.currentTime > 0) { + wx.setStorageSync("interruptedTime", this.data.currentTime); + } }, - /** - * 生命周期函数--监听页面卸载 - */ onUnload() { - // 卸载时恢复截屏能力 //@ts-ignore - wx.setVisualEffectOnCapture({ - visualEffect: 'none', - }); + if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' }); + + if (this.data.currentTime > 0) { + wx.setStorageSync("interruptedTime", this.data.currentTime); + wx.setStorageSync("currentTime", this.data.currentTime); + } + + try { + this.pauseVideoBeforeNavigate(); + } catch (err) { } + + // 卸载时清理所有系统级监听与定时器 + if (this._pauseVideoHandler) wx.offAudioInterruptionBegin(this._pauseVideoHandler); + if (this._resumeVideoHandler) wx.offAudioInterruptionEnd(this._resumeVideoHandler); + if (this._appHideHandler) wx.offAppHide(this._appHideHandler); + if (this._appShowHandler) wx.offAppShow(this._appShowHandler); + if (this._networkStatusChangeHandler) wx.offNetworkStatusChange(this._networkStatusChangeHandler); + + this.clearSendProgressTimer(); }, - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { }, - onChange(event: any) { - this.setData({ - active: event.detail.index, + this.setData({ active: event.detail.index }); + }, + + initSystemListeners() { + this._networkStatusChangeHandler = (res: any) => { + if (!res.isConnected) { + wx.showToast({ title: '网络连接断开', icon: 'none' }); + this.pauseVideoBeforeNavigate(); + } else if (res.networkType !== 'wifi') { + wx.showToast({ title: '当前为非Wi-Fi环境,请注意流量消耗', icon: 'none' }); + } + }; + wx.onNetworkStatusChange(this._networkStatusChangeHandler); + + this._pauseVideoHandler = () => { + this._wasPlayingBeforeInterrupt = this.data.playing; + this.pauseVideoBeforeNavigate(); + }; + + this._resumeVideoHandler = () => { + const wasPlaying = this._wasPlayingBeforeInterrupt; + this._wasPlayingBeforeInterrupt = false; + if (wasPlaying && !this.data.isAppHidden) { + this.resumeVideoAfterInterrupt(); + } + }; + + this._appHideHandler = () => { + this.setData({ isAppHidden: true }); + this.pauseVideoBeforeNavigate(); + }; + + this._appShowHandler = () => { + this.setData({ isAppHidden: false }); + }; + + wx.onAudioInterruptionBegin(this._pauseVideoHandler); + wx.onAudioInterruptionEnd(this._resumeVideoHandler); + wx.onAppHide(this._appHideHandler); + wx.onAppShow(this._appShowHandler); + }, + + getVideoContext() { + if (!this._videoContext) { + this._videoContext = wx.createVideoContext("myPlayerId", this); + } + return this._videoContext; + }, + + pauseVideoBeforeNavigate() { + this.getVideoContext().pause(); + }, + + resumeVideoAfterInterrupt() { + this.getVideoContext().play(); + }, + + syncResumeTime() { + if (this.data.resumeTime > 0) { + this.getVideoContext().seek(this.data.resumeTime); + } + }, + + onPlayerPlay() { + this.setData({ playing: true, resumeTime: 0 }); + wx.removeStorageSync("interruptedTime"); + this.startSendProgress(); + }, + + onPlayerPause() { + this.setData({ playing: false }); + this.clearSendProgressTimer(); + // 用户主动点击暂停时,存入进度 + if (this.data.currentTime > 0) { + wx.setStorageSync("interruptedTime", this.data.currentTime); + } + }, + + onPlayerEnded() { + this.setData({ playing: false, resumeTime: 0 }); + wx.setStorageSync("ended", true); + this.clearSendProgressTimer(); + wx.removeStorageSync("interruptedTime"); + wx.removeStorageSync("currentTime"); + }, + + onPlayerError(e: any) { + const detail = (e && e.detail) || e || {}; + wx.showModal({ + title: "播放出错", + content: String(detail.errMsg || detail.message || JSON.stringify(detail)), + showCancel: false, }); }, - // 监听答题变化 + // 接收原生组件的时间更新 + onPlayerTimeUpdate(e: any) { + // 兼容 VOD 插件可能多包一层 detail 的情况 + let time = e.detail?.currentTime ?? e.detail?.detail?.currentTime; + if (typeof time === 'number' && time > 0) { + const currentTime = Math.floor(time); + this.data.currentTime = currentTime; // 纯内存更新,不触发无用渲染 + + // 每 5 秒落盘一次 currentTime 作为终极兜底,不要太频繁避免卡顿 + if (currentTime % 5 === 0) { + wx.setStorageSync("currentTime", currentTime); + } + } + }, + + getResumeTime(): number { + if (wx.getStorageSync("ended")) return 0; + const interrupted = Number(wx.getStorageSync("interruptedTime") || 0); + const current = Number(wx.getStorageSync("currentTime") || 0); + return Math.max(interrupted, current); + }, + + startSendProgress() { + this.clearSendProgressTimer(); + this.sendProgress(); + const timer = setInterval(() => { + this.sendProgress(); + }, 15000) as unknown as number; + this.setData({ sendDurationTimer: timer }); + }, + + clearSendProgressTimer() { + if (this.data.sendDurationTimer) { + clearInterval(this.data.sendDurationTimer); + this.setData({ sendDurationTimer: 0 }); + } + }, + + async sendProgress() { + if (!this.data.playing) return; + + try { + const openId = wx.getStorageSync("openId"); + const code = wx.getStorageSync("code"); + const state = wx.getStorageSync("state"); + const seeId = wx.getStorageSync("seeId"); + // 视频时长兜底补偿 + const duration = this.data.currentTime + 1; + + const url = code ? `/app/video-watch/inspect` : `/app/watch/inspect`; + const params = code ? { openId, code, duration } : { openId, state, seeId, duration }; + + await request({ + options: { + url, + data: aesEncrypt(JSON.stringify(params), AES_KEY, AES_IV), + }, + isLoading: false, + }); + } catch (err) { + console.error("上报观看进度失败:", err); + } + }, + onAnswerChange() { this.updateProgress(); }, async search() { const app = getApp(); + if (!(await app.checkLoginState())) return; const code = wx.getStorageSync("code"); - const params = { - openId: wx.getStorageSync("openId"), - ...app.globalData.store, - }; - if (code) { - const data = await request({ - options: { - url: `/app/video-watch/simple-details`, - method: "GET", - data: params, - }, - }); + const params = { openId: wx.getStorageSync("openId"), ...app.globalData.store }; - if (!data.watch.url) { - wx.reLaunch({ - url: `/pages/live/registration/registration?content=${data.watch.content}&state=${-1}`, - }); - } - const nodes = htmlToWxNodes(data.watch.content); - this.setData({ - dataList: data.watch, - eveId: data.watch.eveId, - nodes, - }); - } else { - const data = await request({ - options: { - url: `/app/watch/simple-details`, - data: params, - }, - }); + const url = code ? `/app/video-watch/details` : `/app/watch/details`; + const data = await request({ + options: { url, method: code ? "GET" : "POST", data: params }, + }); - if (!data.data.url) { - wx.reLaunch({ - url: `/pages/live/registration/registration?content=${data.data.content - }&state=${5}`, - }); - } - const nodes = htmlToWxNodes(data.data.content); - this.setData({ - dataList: data.data, - eveId: data.data.eveId, - nodes, + const targetData = code ? data.watch : data.data; + + if (!targetData?.url) { + const stateParam = code ? -1 : 5; + wx.reLaunch({ + url: `/pages/live/registration/registration?content=${targetData?.content || ''}&state=${stateParam}`, }); + return; } - this.selectComponent("#tabs").resize(); + this.setData({ + dataList: targetData, + eveId: targetData.eveId, + nodes: htmlToWxNodes(targetData.content), + }); + + this.syncResumeTime(); + this.selectComponent("#tabs")?.resize(); }, - // 更新答题进度 + updateProgress() { const quizComponent = this.selectComponent("#quizComponent"); if (quizComponent) { - const canSubmit = quizComponent.isAllAnswered(); - this.setData({ - canSubmit: canSubmit, - }); + this.setData({ canSubmit: quizComponent.isAllAnswered() }); } }, - handleSubmit(this) { - const ended = wx.getStorageSync("ended") || false; - if (!ended) { - wx.showModal({ - title: "请先观看视频,再答题", - showCancel: false, - confirmText: "确定", - confirmColor: "#FF0000", - }); - return; + handleSubmit() { + if (!wx.getStorageSync("ended")) { + return wx.showModal({ title: "请先观看完整视频,再答题", showCancel: false, confirmColor: "#FF0000" }); } //@ts-ignore if (this.data.dataList?.userAnsNum >= this.data.dataList?.answerMax) { - wx.showToast({ - title: "答题次数已用完", - icon: "none", - duration: 6000, - }); - return; + return wx.showToast({ title: "答题次数已用完", icon: "none", duration: 3000 }); } + const quizComponent = this.selectComponent("#quizComponent"); + if (!quizComponent) return wx.showToast({ title: "组件加载失败", icon: "none" }); - if (!quizComponent) { - wx.showToast({ - title: "组件加载失败", - icon: "none", - }); - return; - } - - const isAllAnswered = quizComponent.isAllAnswered(); - if (!isAllAnswered) { + if (!quizComponent.isAllAnswered()) { const progress = quizComponent.getProgress(); - wx.showModal({ + return wx.showModal({ title: "答题未完成", content: `您已完成 ${progress.answered}/${progress.total} 题,请完成所有题目后再提交。`, showCancel: false, - confirmText: "继续答题", }); - return; } const answers = quizComponent.getAllAnswers(); - if (!answers || answers.length === 0) { - wx.showToast({ - title: "请先完成答题", - icon: "none", - }); - return; - } + if (!answers?.length) return wx.showToast({ title: "请先完成答题", icon: "none" }); wx.showModal({ title: "确认提交", content: `您已完成 ${answers.length} 道题目,确定要提交答案吗?`, - success: (res) => { - if (res.confirm) { - this.submitAnswers(answers); - } - }, + success: (res) => { if (res.confirm) this.submitAnswers(answers); }, }); }, @@ -276,145 +356,96 @@ Page({ eveId: this.data.eveId, ...this.data.store, }; - wx.showLoading({ - title: "提交中...", - }); - let res = null; - if (code) { - res = await request({ - options: { - url: "/app/video-watch/interactive", - data: params, + wx.showLoading({ title: "提交中..." }); + const url = code ? "/app/video-watch/interactive" : "/app/watch/interactive"; + const res = await request({ options: { url, data: params } }); + wx.hideLoading(); + + if (res.code !== 200) { + return wx.showToast({ title: res.msg || "提交失败", icon: "none", duration: 2000 }); + } + + const { pass, redPackage } = res.data || {}; + if (pass) { + wx.showModal({ + content: "🎉 回答正确,领取红包!", + showCancel: false, + confirmText: "立即领取", + confirmColor: "#FF0000", + success: async (res) => { + if (res.confirm) { + if (redPackage?.packageInfo) { + this.transferRedPacket(redPackage); + } else if (redPackage?.redId) { + await this.handleReceive(redPackage.redId); + } + } }, }); } else { - res = await request({ - options: { - url: "/app/watch/interactive", - data: params, - }, - }); + wx.showToast({ title: "回答错误,与红包擦肩而过", icon: "none", duration: 3000 }); } - - if (res.code !== 200) { - wx.showToast({ - title: res.msg || "提交失败", - icon: "none", - duration: 2000, - }); - return; - } - - const { pass } = res.data || {}; - if (pass) { - wx.showToast({ - title: "提交成功", - icon: "success", - duration: 2000, - }); - } - // if (pass) { - // wx.showModal({ - // content: "🎉 领取红包!", - // showCancel: false, - // confirmText: "立即领取", - // confirmColor: "#FF0000", - // success: async (res) => { - // if (res.confirm) { - // if (redPackage?.packageInfo) { - // try { - // wx.showLoading({ title: "领取中", mask: true }); - // if (wx.canIUse?.("requestMerchantTransfer")) { - // await new Promise((resolve, reject) => { - // // @ts-ignore - // wx.requestMerchantTransfer({ - // mchId: redPackage.mchId, - // appId, - // package: redPackage.packageInfo, - // success: () => { - // wx.showToast({ title: "领取成功", icon: "success" }); - // resolve(); - // }, - // fail: (err: any) => { - // console.error("拉起转账失败:", err); - // wx.showToast({ title: "领取失败", icon: "none" }); - // reject(new Error(err?.errMsg || "领取失败")); - // }, - // }); - // }); - // } else { - // wx.showModal({ - // content: "你的微信版本过低,请更新至最新版本。", - // showCancel: false, - // }); - // throw new Error("微信版本过低"); - // } - // } catch (err: any) { - // wx.hideLoading(); - // const msg = err?.data?.msg || err?.errMsg || err?.message || "领取失败"; - // wx.showToast({ title: msg, icon: "none" }); - // } - // } else { - // await this.handleReceive(redPackage.redId); - // } - // } - // }, - // }); - // } else { - // wx.showToast({ - // title: "回答错误,您与红包擦肩而过", - // icon: "none", - // duration: 6000, - // }); - // } }, - async handleReceive(id: any) { - const { code } = this.data.store as Record; - const params = { - appId, - code, - openId: wx.getStorageSync("openId"), - redId: id, + + async transferRedPacket(redPackage: any) { + wx.showLoading({ title: "领取中", mask: true }); + if (!wx.canIUse?.("requestMerchantTransfer")) { + wx.hideLoading(); + return wx.showModal({ content: "你的微信版本过低,请更新至最新版本。", showCancel: false }); } try { + await new Promise((resolve, reject) => { + // @ts-ignore + wx.requestMerchantTransfer({ + mchId: redPackage.mchId, + appId, + package: redPackage.packageInfo, + success: () => { + wx.hideLoading(); + wx.showToast({ title: "领取成功", icon: "success" }); + resolve(); + }, + fail: (err: any) => reject(new Error(err?.errMsg || "领取失败")), + }); + }); + } catch (err: any) { + wx.hideLoading(); + wx.showToast({ title: err?.message || "领取失败", icon: "none" }); + } + }, + + async handleReceive(id: any) { + const { code } = this.data.store as Record; + try { + wx.showLoading({ title: "领取中" }); await receiveRedPacket( - params, + { appId, code, openId: wx.getStorageSync("openId"), redId: id }, '/app/general/receive-red', appId ); + wx.hideLoading(); } catch (err) { + wx.hideLoading(); console.error('领取红包失败:', err); } }, - // 跳转前暂停视频播放 - pauseVideoBeforeNavigate() { - const video = this.selectComponent("#myVideo") as any; - if (video && video.pauseVideo) { - video.pauseVideo(); - } + + handleEnterError(message: string, title = "无法进入") { + wx.showModal({ title, content: message, showCancel: false }); + }, + + handleBack() { + wx.switchTab({ url: "/pages/tab-bar/course/course" }); }, handleCustomReport() { this.pauseVideoBeforeNavigate(); - const { code, state, seeId } = this.data.store as Record; - const params: Record = {}; - if (code) params.code = code; - if (state) params.state = state; - if (seeId) params.seeId = seeId; - wx.navigateTo({ - url: `/pages/live/report/report`, - }); + wx.navigateTo({ url: `/pages/live/report/report` }); }, + handleViewHitory() { this.pauseVideoBeforeNavigate(); - const { code, state, seeId } = this.data.store as Record; - const params: Record = {}; - if (code) params.code = code; - if (state) params.state = state; - if (seeId) params.seeId = seeId; - wx.navigateTo({ - url: `/pages/live/red-history/red-history`, - }); + wx.navigateTo({ url: `/pages/live/red-history/red-history` }); } -}); +}); \ No newline at end of file diff --git a/miniprogram/pages/live/video/video.wxml b/miniprogram/pages/live/video/video.wxml index 2e3ca6c..ddda9af 100644 --- a/miniprogram/pages/live/video/video.wxml +++ b/miniprogram/pages/live/video/video.wxml @@ -9,8 +9,23 @@ 本视频仅用于科普,无任何恶意引导行为 - - + + + + 提示 @@ -32,8 +47,8 @@ - + \ No newline at end of file diff --git a/miniprogram/pages/live/wxroom/index.json b/miniprogram/pages/live/wxroom/index.json deleted file mode 100644 index b176cdd..0000000 --- a/miniprogram/pages/live/wxroom/index.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "backgroundColor": "#081120", - "disableScroll": true, - "usingComponents": {} -} diff --git a/miniprogram/pages/live/wxroom/index.scss b/miniprogram/pages/live/wxroom/index.scss deleted file mode 100644 index 3f33cbe..0000000 --- a/miniprogram/pages/live/wxroom/index.scss +++ /dev/null @@ -1,42 +0,0 @@ -page { - height: 100%; - background: #081120; -} - -.wxroom-redirect { - width: 100%; - height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 28rpx; - color: #f4f8ff; - background: - radial-gradient(circle at 18% 12%, rgba(83, 214, 255, 0.14), transparent 28%), - linear-gradient(180deg, #0d1b31 0%, #09121f 52%, #050b15 100%); -} - -.wxroom-redirect__spinner { - width: 72rpx; - height: 72rpx; - border-radius: 50%; - border: 6rpx solid rgba(255, 255, 255, 0.1); - border-top-color: #71c1ff; - animation: wxroom-redirect-spin 0.9s linear infinite; -} - -.wxroom-redirect__text { - font-size: 30rpx; - line-height: 1.4; -} - -@keyframes wxroom-redirect-spin { - from { - transform: rotate(0deg); - } - - to { - transform: rotate(360deg); - } -} diff --git a/miniprogram/pages/live/wxroom/index.ts b/miniprogram/pages/live/wxroom/index.ts deleted file mode 100644 index 8c3088b..0000000 --- a/miniprogram/pages/live/wxroom/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -// pages/live/wxroom/index.ts -Page({ - onLoad(options: Record) { - const query = Object.entries(options || {}) - .filter(([, value]) => value !== undefined && value !== "") - .map( - ([key, value]) => - `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`, - ) - .join("&"); - - const target = query - ? `/package-live/wxroom/index?${query}` - : "/package-live/wxroom/index"; - - wx.redirectTo({ - url: target, - fail: () => { - wx.showToast({ - title: "进入直播间失败", - icon: "none", - }); - }, - }); - }, -}); diff --git a/miniprogram/pages/live/wxroom/index.wxml b/miniprogram/pages/live/wxroom/index.wxml deleted file mode 100644 index a82198a..0000000 --- a/miniprogram/pages/live/wxroom/index.wxml +++ /dev/null @@ -1,4 +0,0 @@ - - - 正在进入直播间... -