usePayment.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import { useToast } from './useToast'
  2. import { ref, reactive } from 'vue';
  3. export function usePayment() {
  4. const { Toast } = useToast()
  5. // 支付状态
  6. const paymentLoading = ref(false);
  7. const paymentResult = ref(null);
  8. // 支付配置
  9. const paymentConfig = reactive({
  10. // 支付类型
  11. PAYMENT_TYPES: {
  12. ALIPAY: "alipay",
  13. WECHAT: "weixin",
  14. BALANCE: "balance",
  15. },
  16. // 支付状态
  17. PAYMENT_STATUS: {
  18. SUCCESS: "支付成功",
  19. FAIL: "支付失败",
  20. CANCEL: "用户取消支付",
  21. },
  22. });
  23. /**
  24. * 获取可用的支付渠道
  25. */
  26. const getAvailableChannels = () => {
  27. return new Promise((resolve, reject) => {
  28. // #ifdef APP
  29. uni.getProvider({
  30. service: "payment",
  31. success: (res) => {
  32. console.log("可用支付渠道:", res.provider);
  33. resolve(res.provider);
  34. },
  35. fail: (err) => {
  36. console.error("获取支付渠道失败:", err);
  37. reject(err);
  38. },
  39. });
  40. // #endif
  41. // #ifndef APP
  42. // H5端默认返回所有渠道(实际支付需要调用后端接口)
  43. // resolve(["alipay", "wxpay", "balance"]);
  44. resolve(["balance"]);
  45. // #endif
  46. });
  47. };
  48. /**
  49. * 支付宝支付
  50. * @param {String} orderInfo - 服务器返回的支付宝订单信息字符串
  51. */
  52. const alipayPayment = (orderInfo) => {
  53. return new Promise((resolve, reject) => {
  54. // #ifdef APP
  55. uni.requestPayment({
  56. provider: "alipay",
  57. orderInfo: orderInfo,
  58. success: (res) => {
  59. console.log("支付宝支付成功:", res);
  60. try {
  61. const rawdata = JSON.parse(res.rawdata);
  62. resolve({
  63. status: paymentConfig.PAYMENT_STATUS.SUCCESS,
  64. data: rawdata,
  65. message: "支付成功",
  66. });
  67. } catch (e) {
  68. resolve({
  69. status: paymentConfig.PAYMENT_STATUS.SUCCESS,
  70. data: res,
  71. message: "支付成功",
  72. });
  73. }
  74. },
  75. fail: (err) => {
  76. console.error("支付宝支付失败:", err);
  77. const errorMsg = err.errMsg || "支付失败";
  78. // 判断是否为用户取消
  79. if (errorMsg.includes("cancel") || errorMsg.includes("取消")) {
  80. resolve({
  81. status: paymentConfig.PAYMENT_STATUS.CANCEL,
  82. data: err,
  83. message: "用户取消支付",
  84. });
  85. } else {
  86. reject({
  87. status: paymentConfig.PAYMENT_STATUS.FAIL,
  88. data: err,
  89. message: errorMsg,
  90. });
  91. }
  92. },
  93. });
  94. // #endif
  95. // #ifndef APP
  96. // H5端需要调用后端接口进行支付
  97. console.warn("H5端支付宝支付需要后端配合实现");
  98. reject({
  99. status: paymentConfig.PAYMENT_STATUS.FAIL,
  100. message: "H5端暂不支持支付宝支付",
  101. });
  102. // #endif
  103. });
  104. };
  105. /**
  106. * 微信支付
  107. * @param {Object} orderInfo - 服务器返回的微信支付订单对象
  108. */
  109. const wechatPayment = (orderInfo) => {
  110. return new Promise((resolve, reject) => {
  111. // 验证订单信息
  112. if (!orderInfo || !orderInfo.appid || !orderInfo.partnerid) {
  113. reject({
  114. status: paymentConfig.PAYMENT_STATUS.FAIL,
  115. message: "微信支付订单信息不完整",
  116. });
  117. return;
  118. }
  119. // #ifdef APP-PLUS
  120. uni.requestPayment({
  121. provider: "wxpay",
  122. orderInfo: orderInfo,
  123. success: (res) => {
  124. console.log("微信支付成功:", res);
  125. try {
  126. const rawdata = JSON.parse(res.rawdata || "{}");
  127. resolve({
  128. status: paymentConfig.PAYMENT_STATUS.SUCCESS,
  129. data: rawdata,
  130. message: "支付成功",
  131. });
  132. } catch (e) {
  133. resolve({
  134. status: paymentConfig.PAYMENT_STATUS.SUCCESS,
  135. data: res,
  136. message: "支付成功",
  137. });
  138. }
  139. },
  140. fail: (err) => {
  141. console.error("微信支付失败:", err);
  142. const errorMsg = err.errMsg || "支付失败";
  143. // 判断是否为用户取消
  144. if (errorMsg.includes("cancel") || errorMsg.includes("取消")) {
  145. resolve({
  146. status: paymentConfig.PAYMENT_STATUS.CANCEL,
  147. data: err,
  148. message: "用户取消支付",
  149. });
  150. } else {
  151. reject({
  152. status: paymentConfig.PAYMENT_STATUS.FAIL,
  153. data: err,
  154. message: errorMsg,
  155. });
  156. }
  157. },
  158. });
  159. // #endif
  160. // #ifndef APP
  161. // H5端需要调用后端接口进行支付
  162. console.warn("H5端微信支付需要后端配合实现");
  163. reject({
  164. status: paymentConfig.PAYMENT_STATUS.FAIL,
  165. message: "H5端暂不支持微信支付",
  166. });
  167. // #endif
  168. });
  169. };
  170. /**
  171. * 统一支付方法
  172. * @param {Object} options - 支付配置
  173. * @param {String} options.type - 支付类型 ('alipay' | 'wxpay' | 'balance')
  174. * @param {Object|String} options.orderInfo - 订单信息
  175. * @param {Object} options.params - 其他参数
  176. */
  177. const submitPayment = async (options) => {
  178. const { type, orderInfo, params = {} } = options;
  179. if (paymentLoading.value) {
  180. throw new Error("支付正在进行中,请勿重复提交");
  181. }
  182. paymentLoading.value = true;
  183. paymentResult.value = null;
  184. try {
  185. // 检查支付渠道是否可用
  186. const channels = await getAvailableChannels();
  187. console.log("channels:", channels);
  188. let result = null;
  189. switch (type) {
  190. case paymentConfig.PAYMENT_TYPES.ALIPAY:
  191. if (channels.indexOf('alipay') === -1) {
  192. Toast({title: "设备不支持支付宝支付"})
  193. throw new Error("设备不支持支付宝支付");
  194. }
  195. result = await alipayPayment(orderInfo);
  196. break;
  197. case paymentConfig.PAYMENT_TYPES.WECHAT:
  198. if (channels.indexOf('wxpay') === -1) {
  199. Toast({title: "设备不支持微信支付"})
  200. throw new Error("设备不支持微信支付");
  201. }
  202. result = await wechatPayment(orderInfo);
  203. break;
  204. case paymentConfig.PAYMENT_TYPES.BALANCE:
  205. result = await balancePayment({ ...params, orderInfo });
  206. break;
  207. default:
  208. throw new Error("不支持的支付类型");
  209. }
  210. paymentResult.value = result;
  211. return result;
  212. } catch (error) {
  213. paymentResult.value = error;
  214. throw error;
  215. } finally {
  216. paymentLoading.value = false;
  217. }
  218. };
  219. return {
  220. paymentLoading,
  221. paymentResult,
  222. paymentConfig,
  223. getAvailableChannels,
  224. alipayPayment,
  225. wechatPayment,
  226. submitPayment,
  227. }
  228. }