This commit is contained in:
cao123
2026-09-07 16:50:54 +08:00
parent bb28b8e719
commit b70f00fb53
+94 -132
View File
@@ -13,7 +13,7 @@ const isMobileEnvironment = (): boolean => {
}; };
Page({ Page({
// 页面私有变量,避免触发无效渲染
_wasPlayingBeforeInterrupt: false, _wasPlayingBeforeInterrupt: false,
_pauseVideoHandler: null as any, _pauseVideoHandler: null as any,
_resumeVideoHandler: null as any, _resumeVideoHandler: null as any,
@@ -22,11 +22,8 @@ Page({
_networkStatusChangeHandler: null as any, _networkStatusChangeHandler: null as any,
_videoContext: null as any, _videoContext: null as any,
/**
* 页面的初始数据
*/
data: { data: {
dataList: {}, dataList: {} as any,
nodes: [] as any[], nodes: [] as any[],
eveId: null, eveId: null,
store: {}, store: {},
@@ -41,38 +38,28 @@ Page({
isAppHidden: false, isAppHidden: false,
}, },
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options: any) { async onLoad(options: any) {
const app = getApp<IAppOption>(); const app = getApp<IAppOption>();
wx.hideShareMenu({ menus: ["shareAppMessage"] }); wx.hideShareMenu({ menus: ["shareAppMessage"] });
new UrlParamsHandler(options); new UrlParamsHandler(options);
app.globalData.store = options; app.globalData.store = options;
// 适配底部安全区
let safeBottom = 24; let safeBottom = 24;
try { try {
//@ts-ignore //@ts-ignore
const systemInfo = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync(); const { windowHeight, safeArea } = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync();
safeBottom = Math.abs(systemInfo.windowHeight - systemInfo.safeArea.bottom) + 10; safeBottom = safeArea ? Math.abs(windowHeight - safeArea.bottom) + 10 : 24;
if (safeBottom === 0) safeBottom = 24;
} catch (e) { } } catch (e) { }
this.setData({ this.setData({ safeBottom, store: options });
safeBottom,
store: options,
resumeTime: this.getResumeTime(),
});
this.initSystemListeners(); this.initSystemListeners();
if (!isMobileEnvironment()) { if (!isMobileEnvironment()) {
this.handleEnterError("当前环境不支持观看,请使用手机观看。", "环境不支持"); return this.handleEnterError("当前环境不支持观看,请使用手机观看。", "环境不支持");
return;
} }
const bool = await app.login("video"); if (!(await app.login("video"))) return;
if (!bool) return;
//@ts-ignore 开启防截屏 //@ts-ignore 开启防截屏
if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'hidden' }); if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'hidden' });
@@ -85,10 +72,7 @@ Page({
onHide() { onHide() {
//@ts-ignore //@ts-ignore
if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' }); if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' });
this.flushProgress();
if (this.data.currentTime > 0) {
this.flushProgress();
}
}, },
onUnload() { onUnload() {
@@ -96,11 +80,9 @@ Page({
if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' }); if (wx.setVisualEffectOnCapture) wx.setVisualEffectOnCapture({ visualEffect: 'none' });
this.flushProgress(); this.flushProgress();
try { try { this.pauseVideoBeforeNavigate(); } catch (err) { }
this.pauseVideoBeforeNavigate();
} catch (err) { }
// 卸载时清理所有系统级监听与定时器 // 卸载事件与定时器
if (this._pauseVideoHandler) wx.offAudioInterruptionBegin(this._pauseVideoHandler); if (this._pauseVideoHandler) wx.offAudioInterruptionBegin(this._pauseVideoHandler);
if (this._resumeVideoHandler) wx.offAudioInterruptionEnd(this._resumeVideoHandler); if (this._resumeVideoHandler) wx.offAudioInterruptionEnd(this._resumeVideoHandler);
if (this._appHideHandler) wx.offAppHide(this._appHideHandler); if (this._appHideHandler) wx.offAppHide(this._appHideHandler);
@@ -126,18 +108,16 @@ Page({
wx.onNetworkStatusChange(this._networkStatusChangeHandler); wx.onNetworkStatusChange(this._networkStatusChangeHandler);
this._pauseVideoHandler = () => { this._pauseVideoHandler = () => {
// 来电等系统中断:先落盘进度再暂停
this.flushProgress(); this.flushProgress();
this._wasPlayingBeforeInterrupt = this.data.playing; this._wasPlayingBeforeInterrupt = this.data.playing;
this.pauseVideoBeforeNavigate(); this.pauseVideoBeforeNavigate();
}; };
this._resumeVideoHandler = () => { this._resumeVideoHandler = () => {
const wasPlaying = this._wasPlayingBeforeInterrupt; if (this._wasPlayingBeforeInterrupt && !this.data.isAppHidden) {
this._wasPlayingBeforeInterrupt = false;
if (wasPlaying && !this.data.isAppHidden) {
this.resumeVideoAfterInterrupt(); this.resumeVideoAfterInterrupt();
} }
this._wasPlayingBeforeInterrupt = false;
}; };
this._appHideHandler = () => { this._appHideHandler = () => {
@@ -171,63 +151,12 @@ Page({
this.getVideoContext().play(); this.getVideoContext().play();
}, },
// 统一写进度:interruptedTime 与 currentTime 成对写,保证两者永远一致 // 统一进度落盘(极简版,直接信任内存里的 currentTime)
flushProgress(time?: number) { flushProgress() {
const t = Math.max(time || this.data.currentTime || 0, Number(wx.getStorageSync("currentTime") || 0)); const t = this.data.currentTime;
if (t <= 0) return;
wx.setStorageSync("interruptedTime", t);
wx.setStorageSync("currentTime", t);
},
// 视频元信息就绪后才 seek,否则 seek 会被静默忽略
onPlayerLoadedMetadata() {
this.seekToResumeTime();
},
seekToResumeTime() {
const t = this.getResumeTime();
if (t > 0) { if (t > 0) {
this.getVideoContext().seek(t); wx.setStorageSync("interruptedTime", t);
} wx.setStorageSync("currentTime", t);
},
onPlayerPlay() {
this.setData({ playing: true });
this.seekToResumeTime();
this.startSendProgress();
},
onPlayerPause() {
this.setData({ playing: false });
this.clearSendProgressTimer();
this.flushProgress();
},
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) {
let time = e.detail?.currentTime ?? e.detail?.detail?.currentTime;
if (typeof time === 'number' && time > 0) {
const currentTime = Math.floor(time);
if (currentTime === this.data.currentTime) return;
this.data.currentTime = currentTime;
if (currentTime % 5 === 0) this.flushProgress(currentTime);
} }
}, },
@@ -238,12 +167,54 @@ Page({
return Math.max(interrupted, current); return Math.max(interrupted, current);
}, },
onPlayerPlay() {
this.setData({ playing: true });
// 异步拉取到 fileid 后,初次播放如果存在历史记录,则跳转
if (this.data.resumeTime > 0) {
this.getVideoContext().seek(this.data.resumeTime);
this.setData({ resumeTime: 0 }); // 跳转完立即清空,防止二次跳转
}
this.startSendProgress();
},
onPlayerPause() {
this.setData({ playing: false });
this.clearSendProgressTimer();
this.flushProgress();
},
onPlayerEnded() {
this.setData({ playing: false, resumeTime: 0, currentTime: 0 });
wx.setStorageSync("ended", true);
this.clearSendProgressTimer();
wx.removeStorageSync("interruptedTime");
wx.removeStorageSync("currentTime");
},
onPlayerError(e: any) {
const detail = e?.detail || e || {};
wx.showModal({
title: "播放出错",
content: String(detail.errMsg || detail.message || JSON.stringify(detail) + ',请联系客服'),
showCancel: false,
});
},
onPlayerTimeUpdate(e: any) {
let time = e.detail?.currentTime ?? e.detail?.detail?.currentTime;
if (typeof time === 'number' && time > 0) {
const currentTime = Math.floor(time);
if (currentTime === this.data.currentTime) return; // 避免重复操作
this.data.currentTime = currentTime;
// 逢 5 秒落盘一次
if (currentTime % 5 === 0) this.flushProgress();
}
},
startSendProgress() { startSendProgress() {
this.clearSendProgressTimer(); this.clearSendProgressTimer();
this.sendProgress(); this.sendProgress(); // 启动时先发一次
const timer = setInterval(() => { const timer = setInterval(() => this.sendProgress(), 15000) as unknown as number;
this.sendProgress();
}, 15000) as unknown as number;
this.setData({ sendDurationTimer: timer }); this.setData({ sendDurationTimer: timer });
}, },
@@ -256,21 +227,18 @@ Page({
async sendProgress() { async sendProgress() {
if (!this.data.playing) return; if (!this.data.playing) return;
try { try {
const openId = wx.getStorageSync("openId");
const code = wx.getStorageSync("code"); const code = wx.getStorageSync("code");
const state = wx.getStorageSync("state"); const openId = wx.getStorageSync("openId");
const seeId = wx.getStorageSync("seeId"); const duration = this.data.currentTime + 1; // 时长兜底补偿
// 视频时长兜底补偿
const duration = this.data.currentTime + 1;
const url = code ? `/app/video-watch/inspect` : `/app/watch/inspect`; const params = code
const params = code ? { openId, code, duration } : { openId, state, seeId, duration }; ? { openId, code, duration }
: { openId, state: wx.getStorageSync("state"), seeId: wx.getStorageSync("seeId"), duration };
await request({ await request({
options: { options: {
url, url: code ? `/app/video-watch/inspect` : `/app/watch/inspect`,
data: aesEncrypt(JSON.stringify(params), AES_KEY, AES_IV), data: aesEncrypt(JSON.stringify(params), AES_KEY, AES_IV),
}, },
isLoading: false, isLoading: false,
@@ -280,10 +248,6 @@ Page({
} }
}, },
onAnswerChange() {
this.updateProgress();
},
async search() { async search() {
const app = getApp<IAppOption>(); const app = getApp<IAppOption>();
if (!(await app.checkLoginState())) return; if (!(await app.checkLoginState())) return;
@@ -291,19 +255,21 @@ Page({
const code = wx.getStorageSync("code"); const code = wx.getStorageSync("code");
const params = { openId: wx.getStorageSync("openId"), ...app.globalData.store }; const params = { openId: wx.getStorageSync("openId"), ...app.globalData.store };
const url = code ? `/app/video-watch/details` : `/app/watch/details`;
const data = await request({ const data = await request({
options: { url, method: code ? "GET" : "POST", data: params }, options: {
url: code ? `/app/video-watch/details` : `/app/watch/details`,
method: code ? "GET" : "POST",
data: params
},
}); });
const targetData = code ? data.watch : data.data; const targetData = code ? data.watch : data.data;
if (!targetData.extend?.fileid) { if (!targetData?.extend?.fileid) {
const stateParam = code ? -1 : 5; const stateParam = code ? -1 : 5;
wx.reLaunch({ return wx.reLaunch({
url: `/pages/live/registration/registration?content=${targetData?.content || ''}&state=${stateParam}`, url: `/pages/live/registration/registration?content=${targetData?.content || ''}&state=${stateParam}`,
}); });
return;
} }
this.setData({ this.setData({
@@ -311,13 +277,13 @@ Page({
eveId: targetData.eveId, eveId: targetData.eveId,
nodes: htmlToWxNodes(targetData.content), nodes: htmlToWxNodes(targetData.content),
fileid: targetData.extend.fileid, fileid: targetData.extend.fileid,
resumeTime: this.getResumeTime(), resumeTime: this.getResumeTime(), // 获取到真实视频时,一次性读取恢复点
}); });
this.selectComponent("#tabs")?.resize(); this.selectComponent("#tabs")?.resize();
}, },
updateProgress() { onAnswerChange() {
const quizComponent = this.selectComponent("#quizComponent"); const quizComponent = this.selectComponent("#quizComponent");
if (quizComponent) { if (quizComponent) {
this.setData({ canSubmit: quizComponent.isAllAnswered() }); this.setData({ canSubmit: quizComponent.isAllAnswered() });
@@ -326,9 +292,9 @@ Page({
handleSubmit() { handleSubmit() {
if (!wx.getStorageSync("ended")) { if (!wx.getStorageSync("ended")) {
return wx.showModal({ title: "请先观看完整视频,再答题", showCancel: false, confirmColor: "#FF0000" }); return wx.showModal({ title: "提示", content: "请先观看完整视频,再参与答题", showCancel: false, confirmColor: "#FF0000" });
} }
//@ts-ignore
if (this.data.dataList?.userAnsNum >= this.data.dataList?.answerMax) { if (this.data.dataList?.userAnsNum >= this.data.dataList?.answerMax) {
return wx.showToast({ title: "答题次数已用完", icon: "none", duration: 3000 }); return wx.showToast({ title: "答题次数已用完", icon: "none", duration: 3000 });
} }
@@ -337,10 +303,10 @@ Page({
if (!quizComponent) return wx.showToast({ title: "组件加载失败", icon: "none" }); if (!quizComponent) return wx.showToast({ title: "组件加载失败", icon: "none" });
if (!quizComponent.isAllAnswered()) { if (!quizComponent.isAllAnswered()) {
const progress = quizComponent.getProgress(); const { answered, total } = quizComponent.getProgress();
return wx.showModal({ return wx.showModal({
title: "答题未完成", title: "答题未完成",
content: `您已完成 ${progress.answered}/${progress.total} 题,请完成所有题目后再提交。`, content: `您已完成 ${answered}/${total} 题,请完成所有题目后再提交。`,
showCancel: false, showCancel: false,
}); });
} }
@@ -381,12 +347,11 @@ Page({
confirmText: "立即领取", confirmText: "立即领取",
confirmColor: "#FF0000", confirmColor: "#FF0000",
success: async (res) => { success: async (res) => {
if (res.confirm) { if (!res.confirm) return;
if (redPackage?.packageInfo) { if (redPackage?.packageInfo) {
this.transferRedPacket(redPackage); this.transferRedPacket(redPackage);
} else if (redPackage?.redId) { } else if (redPackage?.redId) {
await this.handleReceive(redPackage.redId); await this.handleReceive(redPackage.redId);
}
} }
}, },
}); });
@@ -401,21 +366,20 @@ Page({
wx.hideLoading(); wx.hideLoading();
return wx.showModal({ content: "你的微信版本过低,请更新至最新版本。", showCancel: false }); return wx.showModal({ content: "你的微信版本过低,请更新至最新版本。", showCancel: false });
} }
try { try {
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
// @ts-ignore //@ts-ignore
wx.requestMerchantTransfer({ wx.requestMerchantTransfer({
mchId: redPackage.mchId, mchId: redPackage.mchId,
appId, appId,
package: redPackage.packageInfo, package: redPackage.packageInfo,
success: () => { success: () => resolve(),
wx.hideLoading();
wx.showToast({ title: "领取成功", icon: "success" });
resolve();
},
fail: (err: any) => reject(new Error(err?.errMsg || "领取失败")), fail: (err: any) => reject(new Error(err?.errMsg || "领取失败")),
}); });
}); });
wx.hideLoading();
wx.showToast({ title: "领取成功", icon: "success" });
} catch (err: any) { } catch (err: any) {
wx.hideLoading(); wx.hideLoading();
wx.showToast({ title: err?.message || "领取失败", icon: "none" }); wx.showToast({ title: err?.message || "领取失败", icon: "none" });
@@ -423,18 +387,16 @@ Page({
}, },
async handleReceive(id: any) { async handleReceive(id: any) {
const { code } = this.data.store as Record<string, any>;
try { try {
wx.showLoading({ title: "领取中" }); wx.showLoading({ title: "领取中" });
await receiveRedPacket( await receiveRedPacket(
{ appId, code, openId: wx.getStorageSync("openId"), redId: id }, { appId, code: wx.getStorageSync("code"), openId: wx.getStorageSync("openId"), redId: id },
'/app/general/receive-red', '/app/general/receive-red',
appId appId
); );
wx.hideLoading(); wx.hideLoading();
} catch (err) { } catch (err) {
wx.hideLoading(); wx.hideLoading();
console.error('领取红包失败:', err);
} }
}, },