wx.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import { ref } from "vue";
  2. import { assign, getUrlParam, storage } from "../utils";
  3. import { request } 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. request({
  58. url: "/app/user/common/wxMpConfig",
  59. method: "POST",
  60. data: {
  61. url: `${location.origin}${location.pathname}`
  62. }
  63. }).then((res) => {
  64. if (res != null) {
  65. wx.config({
  66. debug: config.wx.debug,
  67. jsApiList: res.jsApiList || ["chooseWXPay"],
  68. appId: res.appId,
  69. timestamp: res.timestamp,
  70. nonceStr: res.nonceStr,
  71. signature: res.signature,
  72. openTagList: res.openTagList
  73. });
  74. // 合并配置到mpConfig
  75. assign(this.mpConfig, res);
  76. }
  77. });
  78. }
  79. }
  80. /**
  81. * 跳转到微信授权页面
  82. */
  83. mpAuth() {
  84. const { appId } = this.mpConfig;
  85. const redirect_uri = encodeURIComponent(
  86. `${location.origin}${location.pathname}#/pages/user/login`
  87. );
  88. const response_type = "code";
  89. const scope = "snsapi_userinfo";
  90. const state = "STATE";
  91. 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`;
  92. location.href = url;
  93. }
  94. /**
  95. * 公众号登录,获取code
  96. */
  97. mpLogin() {
  98. return new Promise((resolve) => {
  99. const code = getUrlParam("code");
  100. const mpCode = storage.get("mpCode");
  101. // 去除url中的code参数,避免重复
  102. const url = window.location.href.replace(/(\?[^#]*)#/, "#");
  103. window.history.replaceState({}, "", url);
  104. if (code != mpCode) {
  105. storage.set("mpCode", code, 1000 * 60 * 5);
  106. resolve(code);
  107. } else {
  108. resolve(null);
  109. }
  110. });
  111. }
  112. /**
  113. * 公众号微信支付
  114. * @param params 支付参数
  115. */
  116. mpPay(params: wx.IchooseWXPay & { timeStamp: number }): Promise<void> {
  117. return new Promise((resolve, reject) => {
  118. if (!this.isWxBrowser()) {
  119. return reject({ message: t("请在微信浏览器中打开") });
  120. }
  121. wx.chooseWXPay({
  122. ...params,
  123. timestamp: params.timeStamp,
  124. success() {
  125. resolve();
  126. },
  127. complete(e: { errMsg: string }) {
  128. switch (e.errMsg) {
  129. case "chooseWXPay:cancel":
  130. reject({ message: t("已取消支付") });
  131. break;
  132. default:
  133. reject({ message: t("支付失败") });
  134. }
  135. }
  136. });
  137. });
  138. }
  139. // #endif
  140. // #ifdef MP
  141. /**
  142. * 小程序登录,获取用户信息和code
  143. */
  144. miniLogin(): Promise<{
  145. code: string;
  146. iv: string;
  147. encryptedData: string;
  148. signature: string;
  149. rawData: string;
  150. }> {
  151. return new Promise((resolve, reject) => {
  152. // 兼容 Mac,Mac 端需用 getUserInfo
  153. const k = uni.getDeviceInfo().platform === "mac" ? "getUserInfo" : "getUserProfile";
  154. uni[k]({
  155. lang: "zh_CN",
  156. desc: t("授权信息仅用于用户登录"),
  157. success: ({ iv, encryptedData, signature, rawData }) => {
  158. const next = () => {
  159. resolve({
  160. iv,
  161. encryptedData,
  162. signature,
  163. rawData,
  164. code: this.code.value
  165. });
  166. };
  167. // 检查登录状态是否过期
  168. uni.checkSession({
  169. success: () => {
  170. next();
  171. },
  172. fail: () => {
  173. this.getCode().then(() => {
  174. next();
  175. });
  176. }
  177. });
  178. },
  179. fail: (err) => {
  180. console.error(`[useWx.miniLogin] error`, err);
  181. this.getCode();
  182. reject(t("登录授权失败"));
  183. }
  184. });
  185. });
  186. }
  187. /**
  188. * 小程序微信支付
  189. * @param params 支付参数
  190. */
  191. miniPay(params: any): Promise<void> {
  192. return new Promise((resolve, reject) => {
  193. uni.requestPayment({
  194. provider: "wxpay",
  195. ...params,
  196. success() {
  197. resolve();
  198. },
  199. fail() {
  200. reject(t("已取消支付"));
  201. }
  202. });
  203. });
  204. }
  205. // #endif
  206. }
  207. /**
  208. * useWx 钩子函数,后续可扩展
  209. */
  210. export const useWx = (): Wx => {
  211. const wx = new Wx();
  212. onReady(() => {
  213. wx.getCode();
  214. // #ifdef H5
  215. wx.getMpConfig();
  216. // #endif
  217. });
  218. return wx;
  219. };