wx.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { ref } from "vue";
  2. import { assign, getUrlParam, storage } from "../utils";
  3. import { service } from "../service";
  4. import { t } from "@/locale";
  5. import { config } from "@/config";
  6. // #ifdef H5
  7. import wx from "weixin-js-sdk";
  8. // #endif
  9. // 微信配置类型
  10. type WxConfig = {
  11. appId: string;
  12. };
  13. // 微信相关功能封装类
  14. export class Wx {
  15. // 微信登录code
  16. code = ref("");
  17. /**
  18. * 获取微信登录code
  19. */
  20. async getCode(): Promise<string> {
  21. return new Promise((resolve) => {
  22. // #ifdef MP-WEIXIN
  23. uni.login({
  24. provider: "weixin",
  25. success: (res) => {
  26. this.code.value = res.code;
  27. resolve(res.code);
  28. }
  29. });
  30. // #endif
  31. // #ifndef MP-WEIXIN
  32. resolve("");
  33. // #endif
  34. });
  35. }
  36. // #ifdef H5
  37. // 公众号配置
  38. mpConfig: WxConfig = {
  39. appId: ""
  40. };
  41. /**
  42. * 判断当前是否为微信浏览器
  43. */
  44. isWxBrowser() {
  45. const ua: string = window.navigator.userAgent.toLowerCase();
  46. if (ua.match(/MicroMessenger/i) != null) {
  47. return true;
  48. } else {
  49. return false;
  50. }
  51. }
  52. /**
  53. * 获取公众号配置信息,并初始化微信JS-SDK
  54. */
  55. getMpConfig() {
  56. if (this.isWxBrowser()) {
  57. service.user.comm
  58. .wxMpConfig({
  59. url: `${location.origin}${location.pathname}`
  60. })
  61. .then((res) => {
  62. wx.config({
  63. debug: config.wx.debug,
  64. jsApiList: ["chooseWXPay"],
  65. ...res
  66. });
  67. // 合并配置到mpConfig
  68. assign(this.mpConfig, res);
  69. });
  70. }
  71. }
  72. /**
  73. * 跳转到微信授权页面
  74. */
  75. mpAuth() {
  76. const { appId } = this.mpConfig;
  77. const redirect_uri = encodeURIComponent(
  78. `${location.origin}${location.pathname}#/pages/user/login`
  79. );
  80. const response_type = "code";
  81. const scope = "snsapi_userinfo";
  82. const state = "STATE";
  83. const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}&state=${state}#wechat_redirect`;
  84. location.href = url;
  85. }
  86. /**
  87. * 公众号登录,获取code
  88. */
  89. mpLogin() {
  90. return new Promise((resolve) => {
  91. const code = getUrlParam("code");
  92. const mpCode = storage.get("mpCode");
  93. // 去除url中的code参数,避免重复
  94. const url = window.location.href.replace(/(\?[^#]*)#/, "#");
  95. window.history.replaceState({}, "", url);
  96. if (code != mpCode) {
  97. storage.set("mpCode", code, 1000 * 60 * 5);
  98. resolve(code);
  99. } else {
  100. resolve(null);
  101. }
  102. });
  103. }
  104. /**
  105. * 公众号微信支付
  106. * @param params 支付参数
  107. */
  108. mpPay(params: wx.IchooseWXPay & { timeStamp: number }): Promise<void> {
  109. return new Promise((resolve, reject) => {
  110. if (!this.isWxBrowser()) {
  111. return reject({ message: t("请在微信浏览器中打开") });
  112. }
  113. wx.chooseWXPay({
  114. ...params,
  115. timestamp: params.timeStamp,
  116. success() {
  117. resolve();
  118. },
  119. complete(e: { errMsg: string }) {
  120. switch (e.errMsg) {
  121. case "chooseWXPay:cancel":
  122. reject({ message: t("已取消支付") });
  123. break;
  124. default:
  125. reject({ message: t("支付失败") });
  126. }
  127. }
  128. });
  129. });
  130. }
  131. // #endif
  132. // #ifdef MP
  133. /**
  134. * 小程序登录,获取用户信息和code
  135. */
  136. miniLogin(): Promise<{
  137. code: string;
  138. iv: string;
  139. encryptedData: string;
  140. signature: string;
  141. rawData: string;
  142. }> {
  143. return new Promise((resolve, reject) => {
  144. // 兼容 Mac,Mac 端需用 getUserInfo
  145. const k = uni.getDeviceInfo().platform === "mac" ? "getUserInfo" : "getUserProfile";
  146. uni[k]({
  147. lang: "zh_CN",
  148. desc: t("授权信息仅用于用户登录"),
  149. success: ({ iv, encryptedData, signature, rawData }) => {
  150. const next = () => {
  151. resolve({
  152. iv,
  153. encryptedData,
  154. signature,
  155. rawData,
  156. code: this.code.value
  157. });
  158. };
  159. // 检查登录状态是否过期
  160. uni.checkSession({
  161. success: () => {
  162. next();
  163. },
  164. fail: () => {
  165. this.getCode().then(() => {
  166. next();
  167. });
  168. }
  169. });
  170. },
  171. fail: (err) => {
  172. console.error(`[useWx.miniLogin] error`, err);
  173. this.getCode();
  174. reject(t("登录授权失败"));
  175. }
  176. });
  177. });
  178. }
  179. /**
  180. * 小程序微信支付
  181. * @param params 支付参数
  182. */
  183. miniPay(params: any): Promise<void> {
  184. return new Promise((resolve, reject) => {
  185. uni.requestPayment({
  186. provider: "wxpay",
  187. ...params,
  188. success() {
  189. resolve();
  190. },
  191. fail() {
  192. reject(t("已取消支付"));
  193. }
  194. });
  195. });
  196. }
  197. // #endif
  198. }
  199. /**
  200. * useWx 钩子函数,后续可扩展
  201. */
  202. export const useWx = (): Wx => {
  203. const wx = new Wx();
  204. onReady(() => {
  205. wx.getCode();
  206. // #ifdef H5
  207. wx.getMpConfig();
  208. // #endif
  209. });
  210. return wx;
  211. };