Files
ruo-shan-cloud-pharmacy/miniprogram/pages/live/video/video.ts
T
2026-08-12 11:47:51 +08:00

437 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// pages/video/video.ts
import UrlParamsHandler from "../../../utils/store";
import { htmlToWxNodes } from "../../../utils/html-to-wx-nodes";
import { request } from "../../../utils/request";
import { version, appversion, appId } from "../../../env";
import { receiveRedPacket } from "../../../utils/util";
const app = getApp<IAppOption>()
const isMobileEnvironment = (): boolean => {
const platform = wx.getSystemInfoSync().platform?.toLowerCase() || '';
return platform !== 'windows' && platform !== 'mac';
};
Page({
/**
* 页面的初始数据
*/
data: {
dataList: {},
nodes: [] as any[],
eveId: null,
store: {},
active: 0,
canSubmit: false,
safeBottom: 0,
initialLoading: false,
},
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options: any) {
const openId = wx.getStorageSync("openId");
if (!openId) {
// 未登录:保持 loading 遮罩,跳转 web-view 授权
const code = options.code || "";
const url = `/pages/webview-auth/index?back=video&code=${code}`
wx.navigateTo({ url });
return;
}
// 已登录(含授权返回):隐藏 loading 遮罩,直接进入页面
this.setData({ initialLoading: true });
wx.hideShareMenu({
menus: ["shareAppMessage"], // 单独禁用好友分享
});
new UrlParamsHandler(options);
// 合并 URL 参数与 globalData.store 中已有的登录信息(来自 webview-auth
app.globalData.store = {
...app.globalData.store,
...options,
};
let safeBottom = 0;
//@ts-ignore
if (wx.getWindowInfo) {
//@ts-ignore
const systemInfo = wx.getWindowInfo();
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;
}
this.setData({
safeBottom: safeBottom,
store: app.globalData.store,
});
if (!isMobileEnvironment()) {
this.handleEnterError(
"当前环境不支持观看,请使用手机观看。",
"环境不支持",
);
return;
}
const bool = await app.login("video");
if (!bool) return;
// 开启防截屏(仅限当前页面生命周期内)
//@ts-ignore
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() {
const openId = wx.getStorageSync("openId");
if (!openId) return;
this.setData({ initialLoading: true });
this.search();
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
// 离开视频页时恢复截屏能力,避免影响其他页面
//@ts-ignore
wx.setVisualEffectOnCapture({
visualEffect: 'none',
});
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
// 卸载时恢复截屏能力
//@ts-ignore
wx.setVisualEffectOnCapture({
visualEffect: 'none',
});
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() { },
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() { },
/**
* 用户点击右上角分享
*/
onShareAppMessage() { },
onChange(event: any) {
this.setData({
active: event.detail.index,
});
},
// 监听答题变化
onAnswerChange() {
this.updateProgress();
},
async search() {
const app = getApp<IAppOption>();
const bool = await app.checkLoginState();
if (!bool) 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/details?version=${version.details}&appVer=${appversion}`,
method: "GET",
data: params,
},
});
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/details?version=${version.details}&appVer=${appversion}`,
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,
});
}
this.selectComponent("#tabs").resize();
},
// 更新答题进度
updateProgress() {
const quizComponent = this.selectComponent("#quizComponent");
if (quizComponent) {
const canSubmit = quizComponent.isAllAnswered();
this.setData({
canSubmit: canSubmit,
});
}
},
handleSubmit(this) {
const ended = wx.getStorageSync("ended") || false;
if (!ended) {
wx.showModal({
title: "请先观看视频,再答题",
showCancel: false,
confirmText: "确定",
confirmColor: "#FF0000",
});
return;
}
//@ts-ignore
if (this.data.dataList?.userAnsNum >= this.data.dataList?.answerMax) {
wx.showToast({
title: "答题次数已用完",
icon: "none",
duration: 6000,
});
return;
}
const quizComponent = this.selectComponent("#quizComponent");
if (!quizComponent) {
wx.showToast({
title: "组件加载失败",
icon: "none",
});
return;
}
const isAllAnswered = quizComponent.isAllAnswered();
if (!isAllAnswered) {
const progress = quizComponent.getProgress();
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;
}
wx.showModal({
title: "确认提交",
content: `您已完成 ${answers.length} 道题目,确定要提交答案吗?`,
success: (res) => {
if (res.confirm) {
this.submitAnswers(answers);
}
},
});
},
async submitAnswers(answers: any[]) {
const code = wx.getStorageSync("code");
const params = {
answers,
openId: wx.getStorageSync("openId"),
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,
},
});
} else {
res = await request({
options: {
url: "/app/watch/interactive",
data: params,
},
});
}
if (res.code !== 200) {
wx.showToast({
title: res.msg || "提交失败",
icon: "none",
duration: 2000,
});
return;
}
const { pass, redPackage } = res.data || {};
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<void>((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<string, any>;
const params = {
appId,
code,
openId: wx.getStorageSync("openId"),
redId: id,
}
try {
await receiveRedPacket(
params,
'/app/general/receive-red',
appId
);
} catch (err) {
console.error('领取红包失败:', err);
}
},
// 跳转前暂停视频播放
pauseVideoBeforeNavigate() {
const video = this.selectComponent("#myVideo") as any;
if (video && video.pauseVideo) {
video.pauseVideo();
}
},
handleCustomReport() {
this.pauseVideoBeforeNavigate();
const { code, state, seeId } = this.data.store as Record<string, any>;
const params: Record<string, string> = {};
if (code) params.code = code;
if (state) params.state = state;
if (seeId) params.seeId = seeId;
wx.navigateTo({
url: `/pages/live/report/report`,
});
},
handleViewHitory() {
this.pauseVideoBeforeNavigate();
const { code, state, seeId } = this.data.store as Record<string, any>;
const params: Record<string, string> = {};
if (code) params.code = code;
if (state) params.state = state;
if (seeId) params.seeId = seeId;
wx.navigateTo({
url: `/pages/live/red-history/red-history`,
});
}
});