usePay.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. import {
  2. ref,
  3. reactive
  4. } from "vue";
  5. import {
  6. orderPayAli,
  7. orderPayWx,
  8. orderCheck,
  9. orderPayApple
  10. } from "@/api/shop";
  11. import {
  12. toast
  13. } from "@/utils/common";
  14. export function usePay(opt = {}) {
  15. const {
  16. createOrderError, // 创建订单失败
  17. checkError, // 校验失败
  18. payError, // 支付失败
  19. paySuccess, //支付成功
  20. applePayError, // 苹果内购失败
  21. } = opt;
  22. const aliData = reactive({
  23. orderId: null, // 订单编号
  24. text: '', // 订单数据
  25. })
  26. const wxData = reactive({
  27. appid: '', // 应用ID(AppID)
  28. mchid: '',
  29. noncestr: '', // 随机字符串
  30. orderId: '',
  31. packageVal: '',
  32. partnerid: '', // 商户号(PartnerID)
  33. pid: '',
  34. prepayid: '', // 预支付交易会话ID
  35. timestamp: '', // 时间戳(单位:秒)
  36. sign: '', // 签名,这里用的 MD5 签名
  37. package: '', // 固定值
  38. })
  39. const appleData = reactive({
  40. chanpinId: null, // 产品ID
  41. paynum: "", // 支付号
  42. receipt: "", // 票据
  43. taocanId: null, // 套餐ID
  44. })
  45. function resetStatus() {
  46. Object.assign(aliData, {
  47. orderId: null, // 订单编号
  48. text: '', // 订单数据
  49. })
  50. Object.assign(wxData, {
  51. appid: '', // 应用ID(AppID)
  52. mchid: '',
  53. noncestr: '', // 随机字符串
  54. orderId: '',
  55. packageVal: '',
  56. partnerid: '', // 商户号(PartnerID)
  57. pid: '',
  58. prepayid: '', // 预支付交易会话ID
  59. timestamp: '', // 时间戳(单位:秒)
  60. sign: '', // 签名,这里用的 MD5 签名
  61. package: '', // 固定值
  62. })
  63. Object.assign(appleData, {
  64. chanpinId: null, // 产品ID
  65. paynum: "", // 支付号
  66. receipt: "", // 票据
  67. taocanId: null, // 套餐ID
  68. })
  69. }
  70. // 支付入口 type:业务类型:wx|ali|apple; options: 入参chanpinId,taocanId,applePid
  71. function OrderPay(type, options) {
  72. // 初始化支付状态
  73. resetStatus();
  74. const {
  75. chanpinId,
  76. taocanId,
  77. applePid, // 苹果商品Id ---> 用来获取支付号+票据
  78. } = options;
  79. if (!chanpinId) {
  80. toast('数据异常,产品信息丢失')
  81. return;
  82. }
  83. if (!taocanId) {
  84. toast('数据异常,套餐信息丢失')
  85. return;
  86. }
  87. if (type == 'wx') {
  88. uni.showLoading({
  89. title: '订单创建中...',
  90. mask: true
  91. });
  92. // 微信
  93. orderPayWx({
  94. chanpinId,
  95. taocanId
  96. }).then(res => {
  97. uni.hideLoading();
  98. if (res.data.code == 0) {
  99. Object.assign(wxData, res.data);
  100. // 开始支付
  101. wxPay(res.data);
  102. } else {
  103. toast('微信订单创建失败')
  104. // 业务异常
  105. createOrderError && createOrderError({
  106. type: 'CreateOrderError',
  107. msg: '业务异常,创建订单返回状态异常',
  108. err: new Error('业务异常,创建订单返回状态异常'),
  109. form: 'wx'
  110. })
  111. }
  112. }).catch(err => {
  113. uni.hideLoading();
  114. toast('创建微信订单失败')
  115. createOrderError && createOrderError({
  116. type: 'CreateOrderError',
  117. msg: '创建微信订单失败',
  118. err,
  119. form: 'wx'
  120. })
  121. })
  122. }
  123. if (type == 'ali') {
  124. uni.showLoading({
  125. title: '订单创建中...',
  126. mask: true
  127. });
  128. // 支付宝
  129. orderPayAli({
  130. chanpinId,
  131. taocanId
  132. }).then(res => {
  133. uni.hideLoading();
  134. if (res.data.code == 0) {
  135. Object.assign(aliData, res.data);
  136. // 开始支付
  137. aliPay(res.data);
  138. } else {
  139. toast('支付宝订单创建失败')
  140. // 业务异常
  141. createOrderError && createOrderError({
  142. type: 'CreateOrderError',
  143. msg: '业务异常,创建订单返回状态异常',
  144. err: new Error('业务异常,创建订单返回状态异常'),
  145. form: 'ali'
  146. })
  147. }
  148. }).catch(err => {
  149. uni.hideLoading();
  150. toast('创建支付宝订单失败')
  151. createOrderError && createOrderError({
  152. type: 'CreateOrderError',
  153. msg: '创建支付宝订单失败',
  154. err,
  155. form: 'ali'
  156. })
  157. })
  158. }
  159. if (type == 'apple') {
  160. if (!applePid) {
  161. toast('数据异常,商品信息丢失')
  162. return;
  163. }
  164. uni.showLoading({
  165. title: '订单创建中...',
  166. mask: true
  167. });
  168. applePay(options)
  169. }
  170. }
  171. // 微信支付
  172. function wxPay(options) {
  173. Object.assign(wxData, options);
  174. try {
  175. uni.requestPayment({
  176. provider: "wxpay",
  177. orderInfo: options,
  178. success: (res) => {
  179. uni.showLoading({
  180. title: '订单支付中...',
  181. mask: true
  182. });
  183. // 校验支付结果
  184. setTimeout(() => OrderCheckWx(), 1000)
  185. },
  186. fail: (err) => {
  187. toast('微信支付失败,请联系管理员')
  188. payError && payError({
  189. type: 'wxPay',
  190. msg: '微信支付失败',
  191. err,
  192. from: 'uni.requestPayment.fail'
  193. })
  194. }
  195. })
  196. } catch (err) {
  197. toast('微信支付环境检测异常')
  198. payError && payError({
  199. type: 'wxPay',
  200. msg: '微信支付API唤起失败',
  201. err,
  202. from: 'uni.requestPayment'
  203. })
  204. }
  205. }
  206. // 校验
  207. function OrderCheckWx() {
  208. orderCheck({
  209. id: wxData.orderId
  210. }).then(res => {
  211. if (res.code == 0 && res.data) {
  212. // 校验通过,支付成功
  213. paySuccessResult();
  214. } else {
  215. setTimeout(() => {
  216. orderCheck({
  217. id: wxData.orderId
  218. }).then(res2 => {
  219. if (res2.code == 0 && res2.data) {
  220. // 校验通过,支付成功
  221. paySuccessResult();
  222. }
  223. }).catch(err1 => {
  224. uni.hideLoading()
  225. toast('支付二次查验失败,请联系管理员')
  226. checkError && checkError({
  227. type: 'OrderCheckWx',
  228. msg: '支付二次查验失败,请联系管理员',
  229. err: err1,
  230. form: 'wx'
  231. })
  232. })
  233. }, 5000)
  234. }
  235. }).catch(err => {
  236. uni.hideLoading()
  237. toast('支付查验失败')
  238. checkError && checkError({
  239. type: 'OrderCheckWx',
  240. msg: '支付查验失败,请联系管理员',
  241. err: err,
  242. form: 'wx'
  243. })
  244. })
  245. }
  246. // 支付宝支付
  247. function aliPay(options) {
  248. Object.assign(aliData, options);
  249. try {
  250. uni.requestPayment({
  251. provider: "alipay",
  252. orderInfo: options.text, //此处为服务器返回的订单信息字符串
  253. success: (res) => {
  254. uni.showLoading({
  255. title: '订单支付中...',
  256. mask: true
  257. });
  258. // 校验支付结果
  259. setTimeout(() => OrderCheckAli(), 1000)
  260. },
  261. fail: (err) => {
  262. toast('支付宝支付失败,请联系管理员')
  263. payError && payError({
  264. type: 'aliPay',
  265. msg: '支付宝支付失败',
  266. err,
  267. from: 'uni.requestPayment.fail'
  268. })
  269. }
  270. })
  271. } catch (err) {
  272. toast('支付宝支付环境检测异常')
  273. payError && payError({
  274. type: 'aliPay',
  275. msg: '支付宝API唤起失败',
  276. err,
  277. from: "uni.requestPayment"
  278. })
  279. }
  280. }
  281. // 校验
  282. function OrderCheckAli() {
  283. orderCheck({
  284. id: aliData.orderId
  285. }).then(res => {
  286. if (res.code == 0 && res.data) {
  287. // 校验通过,支付成功
  288. paySuccessResult();
  289. } else {
  290. setTimeout(() => {
  291. orderCheck({
  292. id: aliData.orderId
  293. }).then(res2 => {
  294. if (res2.code == 0 && res2.data) {
  295. // 校验通过,支付成功
  296. paySuccessResult();
  297. }
  298. }).catch(err1 => {
  299. uni.hideLoading()
  300. toast('支付二次查验失败,请联系管理员')
  301. checkError && checkError({
  302. type: 'OrderCheckAli',
  303. msg: '支付二次查验失败,请联系管理员',
  304. err: err1,
  305. form: 'ali'
  306. })
  307. })
  308. }, 5000)
  309. }
  310. }).catch(err => {
  311. uni.hideLoading()
  312. toast('支付查验失败,请联系管理员')
  313. checkError && checkError({
  314. type: 'OrderCheckAli',
  315. msg: '支付查验失败,请联系管理员',
  316. err: err,
  317. form: 'ali'
  318. })
  319. })
  320. }
  321. // 苹果支付 --- 无需check 直接购买成功
  322. function applePay(options) {
  323. Object.assign(appleData, options)
  324. try {
  325. plus.payment.getChannels(function(channels) {
  326. uni.hideLoading();
  327. // 获取 id 为 'appleiap' 的 channel
  328. // 开通了app应用内支付,在manifest.josn中设置,开通后需打自定议基座
  329. // iapChannel 为应用内支付对象
  330. const iapChannel = channels.find((item) => item.id == "appleiap");
  331. // ids 数组中的项为 App Store Connect 配置的内购买项目产品ID(productId)
  332. if (!iapChannel) {
  333. toast('未找到产品内购信息,请联系管理员')
  334. applePayError &&
  335. applePayError({
  336. type: "applePay",
  337. msg: "内购商品Id丢失,请确认是否已成功配置",
  338. err: new Error("内购商品Id丢失,请确认是否已成功配置"),
  339. from: "apple",
  340. });
  341. return;
  342. }
  343. const ids = [options.applePid];
  344. iapChannel.requestOrder(
  345. ids,
  346. function(e) {
  347. // 获取订单信息成功回调方法
  348. uni.requestPayment({
  349. provider: "appleiap",
  350. orderInfo: {
  351. productid: options.applePid, //产品id,来自于苹果
  352. quantity: 1, //产品数量
  353. manualFinishTransaction: true,
  354. },
  355. success: (e) => {
  356. // 苹果内购成功
  357. const {
  358. transactionIdentifier: paynum,
  359. transactionReceipt: receipt,
  360. } = e;
  361. Object.assign(appleData, {
  362. paynum,
  363. receipt,
  364. });
  365. orderPayApple({
  366. chanpinId: appleData.chanpinId, // 产品ID
  367. paynum: paynum, // 支付号
  368. receipt: receipt, // 票据
  369. taocanId: chanpinId.taocanId, // 套餐ID
  370. })
  371. .then((res) => {
  372. uni.hideLoading();
  373. if (res.code == 0 && res.data) {
  374. // 完成内购
  375. iapChannel.finishTransaction(data
  376. .transactionIdentifier);
  377. // 购买成功
  378. paySuccessResult();
  379. } else {
  380. iapChannel.finishTransaction(data
  381. .transactionIdentifier);
  382. toast("业务异常,订单支付失败,请联系管理员");
  383. applePayError &&
  384. applePayError({
  385. type: "orderPayApple",
  386. msg: "业务异常,订单支付失败",
  387. err: e,
  388. from: "apple",
  389. });
  390. }
  391. })
  392. .catch((err) => {
  393. uni.hideLoading();
  394. toast("订单支付校验失败,请联系管理员");
  395. applePayError &&
  396. applePayError({
  397. type: "orderPayApple",
  398. msg: "订单支付校验失败",
  399. err: err,
  400. from: "apple",
  401. });
  402. });
  403. },
  404. fail: (e) => {
  405. uni.hideLoading();
  406. toast("苹果购买失败,请联系管理员");
  407. applePayError &&
  408. applePayError({
  409. type: "uni.requestPayment",
  410. msg: "苹果内购失败",
  411. err: e,
  412. from: "apple",
  413. });
  414. },
  415. });
  416. },
  417. function(e) {
  418. // 获取订单信息失败回调方法
  419. uni.hideLoading();
  420. toast('内购订单获取失败,请联系管理员')
  421. applePayError &&
  422. applePayError({
  423. type: "uni.requestPayment",
  424. msg: "苹果内购失败",
  425. err: e,
  426. from: "apple",
  427. });
  428. },
  429. );
  430. });
  431. } catch (err) {
  432. toast('支付环境检测异常,请联系管理员')
  433. applePayError &&
  434. applePayError({
  435. type: "uni.requestPayment",
  436. msg: "苹果内购API唤起失败",
  437. err: err,
  438. from: "plus.payment.getChannels",
  439. });
  440. }
  441. }
  442. // 支付成功
  443. function paySuccessResult() {
  444. uni.hideLoading()
  445. toast('支付成功')
  446. paySuccess && paySuccess();
  447. }
  448. return {
  449. OrderPay
  450. }
  451. }
  452. /**
  453. * 错误
  454. * 1. 创建订单错误
  455. * 2. 支付SDK错误
  456. * 3. 支付成功后,后台错误
  457. *
  458. *
  459. *
  460. *
  461. *
  462. *
  463. *
  464. *
  465. *
  466. *
  467. *
  468. *
  469. */