Uniapp开发h5 调用微信支付

2025年09月23日 pay

使用 uniapp 开发打包成h5 需要调用微信支付,分两种情况,一种是在浏览器的打开,后台返回一个链接跳转会打开微信来付款,如果是在微信中打开,环境是微信浏览器需要调用微信原后的支付。

支付步骤

  • 创建订单
  • 通过订单号拿到支付需要的参数
  • 通过判断环境发起 web支付还是微信支付

环境判断工具

export const isWxBrowser = () => {
  // 判断是否H5微信环境,true为微信浏览器
  const ua = navigator.userAgent.toLowerCase();
  return ua.includes("micromessenger");
};
export const isIos = () => {
  // 是否IOS true为ios
  let u = navigator.userAgent;
  let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
  return isIOS ? true : false;
};

组装返回的url

const buildReturnUrl = (orderNum) => {
  const baseUrl = window.location.origin;
  const returnUrl = `${baseUrl}/pages/match/buyTicketDetail?orderNum=${orderNum}`;
  return returnUrl;
};

支付判断

通过订单号发起相应的支付

import { isWxBrowser } from "@/utils/env";
const orderPayFn = async (orderNum) => {
  let payParams = {
    detailsId: "0001",
    orderNum,
    transactionType: !isWxBrowser() ? "WX_MWEB" : "WX_JSAPI",//后台规定的两种支付方式
    openId: undefined,//微信原生支付才需要
  };

  if (isWxBrowser()) {
    let currentOpenId = "";

    try {
      currentOpenId = uni.getStorageSync("openId") || "";
    } catch (error) {
      console.log("获取 openId 失败:", error);
    }

    if (!currentOpenId) {
      currentOpenId = openId.value || "";
    }

    payParams.openId = currentOpenId;
  } else {
    payParams.openId = undefined;
  }

  console.log("支付参数:", payParams);
  try {
    let res = await orderPay(payParams);

    if (res.status === 0) {
      if (isWxBrowser()) {
        let data = JSON.parse(res.data);
        console.log("支付数据:", data);

        await callWeixinPay(data, orderNum);
      } else {
        await handleWebPay(res.data, orderNum);
      }
    } else {
      uni.showToast({
        title: res.msg,
        icon: "none",
      });
    }
  } catch (error) {
    console.log(error);
  }
};

h5支付

const handleWebPay = async (payData, orderNum) => {
  const returnUrl = buildReturnUrl(orderNum);
  const redirectUrl = encodeURIComponent(returnUrl);
  const separator = payData.includes("?") ? "&" : "?";
  const payUrlWithRedirect = `${payData}${separator}redirect_url=${redirectUrl}`;
  window.location.href = payUrlWithRedirect;
};

微信支付

支付官方文档:https://pay.weixin.qq.com/doc/v3/merchant/4012791857

获取openId

支付之前需要获取 openId

const getOpenId = async () => {
  try {
    let localOpenId = "";
    try {
      localOpenId = uni.getStorageSync("openId") || "";
    } catch (error) {
      console.log("获取本地 openId 失败:", error);
    }
    if (localOpenId) {
      openId.value = localOpenId;
      console.log("从本地获取到 openId:", localOpenId);
      return localOpenId;
    }

    const urlParams = new URLSearchParams(window.location.search);
    const code = urlParams.get("code");

    if (code) {
      const res = await openIdByWxCode({ code, tokenType: "gz-platform" });
      if (res.status === 0) {
        const newOpenId = res.data;
        uni.setStorageSync("openId", newOpenId);
        openId.value = newOpenId;
        console.log("成功获取并存储 openId:", newOpenId);
        return newOpenId;
      }
    } else if (isWxBrowser()) {
      startWxAuth();
    }

    return null;
  } catch (error) {
    console.error("获取 openId 失败:", error);
    return null;
  }
};

获取授权

在通过 openId 获取静默授权

const startWxAuth = () => {
  try {
    const currentUrl = new URL(window.location.href);
    const currentParams = currentUrl.searchParams;

    const newParams = new URLSearchParams();

    for (const [key, value] of currentParams) {
      if (key !== "code" && key !== "state") {
        newParams.append(key, value);
      }
    }

    const baseUrl = window.location.origin + window.location.pathname;
    const redirectUrl = newParams.toString()
      ? `${baseUrl}?${newParams.toString()}`
      : baseUrl;

    const redirectUri = encodeURIComponent(redirectUrl);

    const appId = WECHAT_APPID;

    const authUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`;

    window.location.href = authUrl;
  } catch (error) {
    console.error("微信授权失败:", error);
    uni.showToast({
      title: "授权失败",
      icon: "none",
    });
  }
};

获取需要在页面加载 的时候 就获取到

onLoad(async (options) => {
  if (isWxBrowser()) {
    await getOpenId();
  }
})

获取订单号

const poserbuyTicket = async () => {
  isBuying.value = true;
  orderParams.value.layoutId = detail.value.layoutId;

  try {
    let res = await buyTicket(orderParams.value);
    if (res.status === 0) {
      await orderPayFn(res.data);
    } else {
      uni.showToast({
        title: res.msg,
        icon: "none",
      });
    }
  } catch (error) {
    console.log(error);
  } finally {
    setTimeout(() => {
      isBuying.value = false;
    }, 2000);
  }
};

微信支付

const callWeixinPay = (payData, orderNum) => {
  const onBridgeReady = () => {
    WeixinJSBridge.invoke(
      "getBrandWCPayRequest",
      {
        appId: payData.appId,
        timeStamp: payData.timeStamp,
        nonceStr: payData.nonceStr,
        package: payData.package,
        signType: payData.signType || "RSA",
        paySign: payData.paySign,
      },
      function (res) {
        console.log("微信支付结果:", res);

        if (res.err_msg == "get_brand_wcpay_request:ok") {
          uni.showToast({
            title: "支付成功",
            icon: "success",
          });

          setTimeout(() => {
            uni.reLaunch({
              url: `/pages/match/buyTicketDetail?orderNum=${orderNum}`,
            });
          }, 1500);
        } else if (res.err_msg == "get_brand_wcpay_request:cancel") {
          uni.showToast({
            title: "支付已取消",
            icon: "none",
          });
          postcancelPay(orderNum);
        } else {
          uni.showToast({
            title: "支付失败",
            icon: "none",
          });
          postcancelPay(orderNum);
        }
      }
    );
  };

  if (typeof WeixinJSBridge == "undefined") {
    if (document.addEventListener) {
      document.addEventListener("WeixinJSBridgeReady", onBridgeReady, false);
    } else if (document.attachEvent) {
      document.attachEvent("WeixinJSBridgeReady", onBridgeReady);
      document.attachEvent("onWeixinJSBridgeReady", onBridgeReady);
    }
  } else {
    onBridgeReady();
  }
};

取消订单

const postcancelPay = async (orderNum) => {
  try {
    let res = await cancelPay(orderNum);
    if (res.status === 0) {
      console.log("取消订单成功");
    }
  } catch (error) {
    console.log("postcancelPay", error);
  }
};

参考文档

CSDN:https://blog.csdn.net/qq_73617452/article/details/147431223

0%