跳转至

微信支付H5支付

h5 页面接入微信支付

需要配置白名单、商户需要关联、还需要配置支付的url等信息

  • 1.判断环境
  • 2.获取code,把code传给后端获取openId
  • 3.通过openIdbizTypemobile等业务信息调去后端接口获取支付信息
  • 4.通过微信方法唤起支付
const WECHAT_APP_ID = "wx8888888"; // appId
const isWeixin = () => /MicroMessenger/i.test(navigator.userAgent);

const initAuth = async () => {
  const code = route.query.code;
  if (code) {
    try {
      const res = await getOpenid({ code });
      const nextOpenid = res.msg || "";
      if (nextOpenid) {
        currentOpenid.value = nextOpenid;
        return nextOpenid;
      }
    } catch (error) {
      // code 失效时重新拉起授权
    }
    triggerAuth();
    return "";
  }
  triggerAuth();
  return "";
};

const triggerAuth = () => {
  const url = new URL(window.location.href);
  url.searchParams.delete("code");
  url.searchParams.delete("state");
  const redirect = encodeURIComponent(url.toString());
  window.location.href =
    `https://open.weixin.qq.com/connect/oauth2/authorize` +
    `?appid=${WECHAT_APP_ID}` +
    `&redirect_uri=${redirect}` +
    `&response_type=code` +
    `&scope=snsapi_base` +
    `&state=weixin_h5#wechat_redirect`;
};

const waitForWeixinBridge = () =>
  new Promise((resolve) => {
    if (window.WeixinJSBridge) {
      resolve(window.WeixinJSBridge);
      return;
    }
    const onReady = () => {
      document.removeEventListener("WeixinJSBridgeReady", onReady);
      resolve(window.WeixinJSBridge);
    };
    document.addEventListener("WeixinJSBridgeReady", onReady, false);
  });

const normalizePayParams = (payload) => {
  if (!payload) {
    return null;
  }
  if (
    !payload.appId ||
    !payload.timeStamp ||
    !payload.nonceStr ||
    !payload.prepayId ||
    !payload.signType ||
    !payload.paySign
  ) {
    return null;
  }
  return {
    appId: payload.appId,
    timeStamp: String(payload.timeStamp),
    nonceStr: payload.nonceStr,
    package: `prepay_id=${payload.prepayId}`,
    signType: payload.signType,
    paySign: payload.paySign,
  };
};

const invokeWeChatPay = async (payParams) => {
  const bridge = await waitForWeixinBridge();
  return new Promise((resolve, reject) => {
    bridge.invoke("getBrandWCPayRequest", payParams, (res) => {
      const errMsg = res?.err_msg || "";
      if (errMsg.includes("ok")) {
        resolve(res);
        return;
      }
      if (errMsg.includes("cancel")) {
        reject(new Error("cancel"));
        return;
      }
      reject(new Error(errMsg || "pay failed"));
    });
  });
};

const stopPayQueryTimer = () => {
  if (payQueryTimer) {
    clearInterval(payQueryTimer);
    payQueryTimer = null;
  }
};

const fillActivationCode = (data) => {
  if (data?.remark) {
    registerForm.value.activationCode = data.remark;
  }
};

const checkPayResult = async (orderSn, silent = false) => {
  if (!orderSn) {
    return false;
  }
  const res = await queryOrderStu({ orderSn });
  const payload = res.data || {};
  if (payload.orderStu) {
    stopPayQueryTimer();
    fillActivationCode(payload);
    if (!silent) {
      proxy.$message.success("支付成功,激活码已自动填充");
    }
    return true;
  }
  return false;
};

const startPayQueryTimer = (orderSn) => {
  stopPayQueryTimer();
  let currentCount = 0;
  payQueryTimer = setInterval(async () => {
    currentCount += 1;
    if (currentCount > 30) {
      stopPayQueryTimer();
      proxy.$message.warning("支付结果查询超时,请稍后手动查询密钥");
      return;
    }
    try {
      await checkPayResult(orderSn);
    } catch (error) {
      if (currentCount >= 30) {
        stopPayQueryTimer();
      }
    }
  }, 3000);
};

const requestH5PayOrder = async (openid) => {
  const res = await buyKey({
    mobile: registerForm.value.username,
    bizType: "ACT_CODE",
    openid,
    payType: "JSAPI",
    source: "H5_weixin",
  });
  return res?.data || {};
};

const handleBuyH5Key = async () => {
  if (!checkBuyKey()) {
    return;
  }
  if (!isWeixin()) {
    proxy.$modal.msgWarning("H5支付请在微信内打开当前页面");
    return;
  }
  h5PayLoading.value = true;
  try {
    let openid = currentOpenid.value;
    if (!openid) {
      await initAuth();
      return;
    }
    const orderInfo = await requestH5PayOrder(openid);
    const orderSn = orderInfo.orderSn;
    if (!orderSn) {
      throw new Error("missing orderSn");
    }
    startPayQueryTimer(orderSn);

    const payParams = normalizePayParams(orderInfo);

    if (payParams) {
      await invokeWeChatPay(payParams);
      await checkPayResult(orderSn);
      return;
    }

    if (orderInfo.codeUrl) {
      window.location.href = orderInfo.codeUrl;
      return;
    }

    proxy.$message.warning("订单已创建,请等待支付参数返回");
  } catch (error) {
    if (error?.message === "cancel") {
      proxy.$message.warning("已取消支付");
    } else {
      proxy.$message.error("发起支付失败,请稍后重试");
    }
    stopPayQueryTimer();
  } finally {
    h5PayLoading.value = false;
  }
};

onMounted(() => {
  // 微信环境 且不是 locahost 才执行
  if (isWeixin() && !location.host.includes("localhost")) {
    initAuth();
  }
});

参考

  1. Q:JSAPI调起支付报错"当前页面的URL未注册"
  2. 配置JSAPI支付授权目录

评论