import { request } from "./request"; export const formatTime = (date: Date) => { const year = date.getFullYear() const month = date.getMonth() + 1 const day = date.getDate() const hour = date.getHours() const minute = date.getMinutes() const second = date.getSeconds() return ( [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') ) } const formatNumber = (n: number) => { const s = n.toString() return s[1] ? s : '0' + s } export function useSecondsToHMS(seconds: number) { const hour = Math.floor(seconds / 3600); const minute = Math.floor((seconds - hour * 3600) / 60); const second = Math.floor(seconds - hour * 3600 - minute * 60); let str = ''; if (hour > 0) str += `${hour.toString().padStart(2, '0')}:`; str += `${minute.toString().padStart(2, '0')}:`; str += `${second.toString().padStart(2, '0')}`; return str; } /**将后端传过来的绝对值px转为相对值rpx, *1rpx为屏幕宽度的750分之1,后台模拟界面写死为375px, *所以1rpx为375/750=0.5px 1px为2rpx */ export function toRpx(px: number): number { return 2 * px } /** * 领取红包并拉起微信转账 * @param data - 动态请求数据对象 * @param url - 请求地址 * @param appId - 当前小程序的 appId (也可选择从接口返回或 getAccountInfoSync 获取) * @returns Promise */ export async function receiveRedPacket(data: any, url: string, appId: string): Promise { wx.showLoading({ title: "领取中", mask: true }); // 建议移除 3s 延迟。如果为了防抖,建议在外部触发点击事件时处理 await new Promise(resolve => setTimeout(resolve, 3000)); try { const res = await request({ options: { url, method: "POST", data }, isLoading: false, }); wx.hideLoading(); if (res.code !== 200) { const title = res.msg || "领取失败"; const duration = res.code === 503 ? 3000 : 1500; wx.showToast({ title, icon: "none", duration }); throw new Error(res.msg || "领取失败"); } const { packageInfo, mchId } = res.data || {}; if (!packageInfo || !mchId) { wx.showToast({ title: "领取失败", icon: "none" }); throw new Error("领取失败"); } if (wx.canIUse?.("requestMerchantTransfer")) { // 把回调式 API 包装成 Promise,让调用方能正确捕获成功/失败 await new Promise((resolve, reject) => { // @ts-ignore wx.requestMerchantTransfer({ mchId, appId, package: 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" }); throw err; } } /** * 异步函数防并发锁 * 直接用 lockPromise 包裹原有的点击逻辑 handleReceiveClick: lockPromise(async function() { await receiveRedPacket(data, url, appId); }) */ /** * 异步函数防并发锁 * @param fn - 需要执行的异步函数 */ export function lockPromise( fn: (this: any, ...args: T) => Promise | R ): (this: any, ...args: T) => Promise { let isLocked = false; return async function (this: any, ...args: T): Promise { // 如果正在执行中,直接返回,返回值为 void if (isLocked) return; isLocked = true; try { // 加上 return,确保原函数的返回值能够被向外传递 return await fn.apply(this, args); } finally { isLocked = false; } }; }