// 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 = {}; Page({ data: { sdk: null as any, activityId: 0, loading: false, loadingText: "", showError: false, errorTitle: "", errorMessage: "", inviterToken: "", msg: "", userId: "", isLandscape: false, }, async onLoad(options: Record) { 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(); 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, ) { 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({ 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) { const rawActivityId = options.activityId || options.roomId || ""; const activityId = Number(rawActivityId); return Number.isFinite(activityId) ? activityId : 0; }, buildQueryString(params: Record) { return Object.entries(params) .filter(([, value]) => value !== undefined && value !== "") .map( ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`, ) .join("&"); }, cacheRedirectPath(options: Record) { 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(); }, });