315 lines
8.6 KiB
TypeScript
315 lines
8.6 KiB
TypeScript
// package-live/wxroom/index.ts
|
|
import VolcMiniSdk, { EVENTS } from "../volc-mini-sdk/index";
|
|
import { request } from "../../utils/request";
|
|
import { appId } from "../../env";
|
|
import { aesDecrypt, aesEncrypt } from "../../utils/crypto";
|
|
import { AES_KEY, AES_IV } from "../../env";
|
|
import { receiveRedPacket, lockPromise } from "../../utils/util";
|
|
const WXROOM_REDIRECT_PATH_KEY = "wxroomRedirectPath";
|
|
const WXROOM_PAGE_PATH = "/package-live/wxroom/index";
|
|
|
|
const isMobileEnvironment = (): boolean => {
|
|
const platform = wx.getSystemInfoSync().platform?.toLowerCase() || '';
|
|
return platform !== 'windows' && platform !== 'mac';
|
|
};
|
|
|
|
let pageOptionsCache: Record<string, string | undefined> = {};
|
|
Page({
|
|
data: {
|
|
sdk: null as any,
|
|
activityId: 0,
|
|
loading: false,
|
|
loadingText: "",
|
|
showError: false,
|
|
errorTitle: "",
|
|
errorMessage: "",
|
|
inviterToken: "",
|
|
msg: "",
|
|
userId: "",
|
|
isLandscape: false,
|
|
},
|
|
|
|
async onLoad(options: Record<string, string | undefined>) {
|
|
pageOptionsCache = options || {};
|
|
const activityId = this.getActivityId(options);
|
|
if (!activityId) {
|
|
this.handleEnterError(
|
|
"缺少直播间ID,请重新从正确的直播链接进入。",
|
|
"无法进入直播间",
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (!isMobileEnvironment()) {
|
|
this.handleEnterError(
|
|
"当前环境不支持观看直播,请使用手机观看。",
|
|
"环境不支持",
|
|
);
|
|
return;
|
|
}
|
|
|
|
this.cacheRedirectPath(options);
|
|
this.setData({
|
|
activityId,
|
|
inviterToken: options.inviterToken,
|
|
userId: options.userId,
|
|
isLandscape: String(options.isLandscape) === "true",
|
|
});
|
|
const app = getApp<IAppOption>();
|
|
this.setLoading("正在校验登录状态...");
|
|
const isLogin = app.checkLoginState();
|
|
if (!isLogin) {
|
|
wx.reLaunch({ url: `/package-live/login/login?userId=${options?.userId}&activityId=${activityId}` });
|
|
return;
|
|
};
|
|
|
|
await this.initSdk(activityId, options);
|
|
},
|
|
onHide() {
|
|
// 不销毁SDK,避免接电话返回后重复初始化导致声音重叠
|
|
},
|
|
async initSdk(
|
|
activityId: number,
|
|
options?: Record<string, string | undefined>,
|
|
) {
|
|
if (this.data.sdk) return; // 防止重复实例化SDK
|
|
|
|
try {
|
|
this.clearError();
|
|
this.setLoading("正在获取直播凭证...");
|
|
|
|
const signToken = await this.fetchSignToken();
|
|
if (!signToken) {
|
|
wx.redirectTo({
|
|
url: `/package-live/login/login?userId=${options?.userId}&activityId=${activityId}&show=${true}&msg=${this.data.msg}`
|
|
})
|
|
throw new Error("未获取到直播凭证,请稍后重试");
|
|
}
|
|
|
|
this.setLoading("正在进入直播间...");
|
|
|
|
const sdk = VolcMiniSdk({
|
|
activityId,
|
|
signToken,
|
|
mode: Number(options?.mode || 2) || 2,
|
|
} as any);
|
|
|
|
sdk.on(EVENTS.error, (err: any) => {
|
|
console.log("sdk error", err?.code, err?.message);
|
|
this.handleEnterError(
|
|
err?.message || "直播间加载失败,请稍后重试",
|
|
"直播间加载失败",
|
|
);
|
|
});
|
|
const debugInfo = sdk.getDebugInfo()
|
|
console.log('debugInfo:', debugInfo)
|
|
|
|
//商品卡片,浮动卡片
|
|
sdk.on('floatingCard.click', this.handleFloatingCardClick);
|
|
//商品卡片,购物车
|
|
sdk.on(EVENTS.card.click, (payload: any) => {
|
|
console.log('card.click', payload)
|
|
});
|
|
// 按钮红包功能
|
|
sdk.on(EVENTS.feature.click, (payload: any) => {
|
|
console.log('feature.click', payload)
|
|
});
|
|
sdk.on(EVENTS.luckymoney.withdrawal, (payload: any) => {
|
|
this.handleReceive(payload);
|
|
});
|
|
|
|
sdk.on(EVENTS.activity.status, (status: 1 | 2 | 3 | 4 | 5) => {
|
|
if (status === 4) {
|
|
wx.switchTab({
|
|
url: `/pages/tab-bar/profile/index`
|
|
})
|
|
}
|
|
});
|
|
|
|
this.setData({
|
|
sdk,
|
|
loading: false,
|
|
loadingText: "",
|
|
});
|
|
} catch (error: any) {
|
|
console.error("init wxroom sdk failed:", error);
|
|
this.handleEnterError(
|
|
error?.message || "进入直播间失败,请稍后重试",
|
|
"进入直播间失败",
|
|
);
|
|
}
|
|
},
|
|
|
|
async fetchSignToken() {
|
|
const nickName = wx.getStorageSync("userName") || "微信用户";
|
|
const userIdStr = String(wx.getStorageSync("mbuId") || "");
|
|
const avatarUrl = wx.getStorageSync("avatarUrl") || "";
|
|
|
|
if (!userIdStr) {
|
|
throw new Error("登录信息缺失,请重新登录后再进入直播间");
|
|
}
|
|
|
|
const res = await request<any>({
|
|
options: {
|
|
url: "/app/saas/activity-login",
|
|
method: "POST",
|
|
data: aesEncrypt(JSON.stringify({
|
|
nickName,
|
|
userIdStr,
|
|
avatarUrl,
|
|
userId: this.data.userId,
|
|
inviterToken: this.data.inviterToken,
|
|
activityId: this.data.activityId,
|
|
mpUserId: wx.getStorageSync("userId"),
|
|
}), AES_KEY, AES_IV)
|
|
},
|
|
loadingTitle: "进入直播间",
|
|
isLoading: false,
|
|
});
|
|
const data = JSON.parse(aesDecrypt(res?.data, AES_KEY, AES_IV))
|
|
this.setData({ msg: data?.msg ?? "暂无活动" });
|
|
return (
|
|
data?.signToken || ""
|
|
);
|
|
},
|
|
handleFloatingCardClick: lockPromise(async function (payload: any) {
|
|
if (!payload?.RedirectUrl) return;
|
|
try {
|
|
const res = await request({
|
|
options: {
|
|
url: payload.RedirectUrl,
|
|
method: 'POST',
|
|
},
|
|
});
|
|
if (res.code !== 200) {
|
|
wx.showToast({ title: res.msg || '请求失败', icon: 'none' });
|
|
return;
|
|
}
|
|
const payParams = res.data;
|
|
wx.requestPayment({
|
|
timeStamp: payParams.timeStamp,
|
|
nonceStr: payParams.nonceStr,
|
|
package: payParams.packageVal,
|
|
signType: payParams.signType || 'RSA',
|
|
paySign: payParams.paySign,
|
|
success() {
|
|
wx.showToast({ title: '支付成功', icon: 'success' });
|
|
console.log('支付成功:');
|
|
},
|
|
fail(err) {
|
|
wx.showToast({ title: '支付取消', icon: 'none' });
|
|
console.error('支付失败:', err);
|
|
},
|
|
});
|
|
} catch (err) {
|
|
console.error('floatingCard请求失败:', err);
|
|
}
|
|
}),
|
|
handleReceive: lockPromise(async function (data: any) {
|
|
const params = {
|
|
appId: appId,
|
|
outRewardsId: data.redPacketId,
|
|
openId: wx.getStorageSync("openId"),
|
|
}
|
|
try {
|
|
await receiveRedPacket(
|
|
params,
|
|
'/app/general/receive-red',
|
|
appId
|
|
);
|
|
} catch (err) {
|
|
console.error('领取红包失败:', err);
|
|
}
|
|
}),
|
|
getActivityId(options: Record<string, string | undefined>) {
|
|
const rawActivityId = options.activityId || options.roomId || "";
|
|
const activityId = Number(rawActivityId);
|
|
return Number.isFinite(activityId) ? activityId : 0;
|
|
},
|
|
|
|
buildQueryString(params: Record<string, string | undefined>) {
|
|
return Object.entries(params)
|
|
.filter(([, value]) => value !== undefined && value !== "")
|
|
.map(
|
|
([key, value]) =>
|
|
`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
|
|
)
|
|
.join("&");
|
|
},
|
|
|
|
cacheRedirectPath(options: Record<string, string | undefined>) {
|
|
const query = this.buildQueryString(options);
|
|
const path = query ? `${WXROOM_PAGE_PATH}?${query}` : WXROOM_PAGE_PATH;
|
|
wx.setStorageSync(WXROOM_REDIRECT_PATH_KEY, path);
|
|
},
|
|
|
|
setLoading(text: string) {
|
|
this.setData({
|
|
loading: true,
|
|
loadingText: text,
|
|
showError: false,
|
|
errorTitle: "",
|
|
errorMessage: "",
|
|
});
|
|
},
|
|
|
|
clearError() {
|
|
this.setData({
|
|
showError: false,
|
|
errorTitle: "",
|
|
errorMessage: "",
|
|
});
|
|
},
|
|
|
|
handleEnterError(message: string, title = "无法进入直播间") {
|
|
this.destroySdk();
|
|
this.setData({
|
|
loading: false,
|
|
loadingText: "",
|
|
showError: true,
|
|
errorTitle: title,
|
|
errorMessage: message,
|
|
});
|
|
},
|
|
|
|
retryEnter() {
|
|
const activityId =
|
|
this.data.activityId || this.getActivityId(pageOptionsCache);
|
|
if (!activityId) {
|
|
this.handleEnterError(
|
|
"缺少直播间ID,请重新从正确的直播链接进入。",
|
|
"无法进入直播间",
|
|
);
|
|
return;
|
|
}
|
|
|
|
this.initSdk(activityId, pageOptionsCache);
|
|
},
|
|
|
|
goBack() {
|
|
const pages = getCurrentPages();
|
|
if (pages.length > 1) {
|
|
wx.navigateBack({
|
|
delta: 1,
|
|
});
|
|
return;
|
|
}
|
|
|
|
wx.switchTab({
|
|
url: "/pages/tab-bar/medicine-box/index",
|
|
});
|
|
},
|
|
|
|
destroySdk() {
|
|
this.data.sdk?.destroy?.();
|
|
if (this.data.sdk) {
|
|
this.setData({
|
|
sdk: null,
|
|
});
|
|
}
|
|
},
|
|
|
|
onUnload() {
|
|
this.destroySdk();
|
|
},
|
|
}); |