index.tsx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import request from '@/helpers/request';
  2. import { browser, getUrlCode, moneyFormat } from '@/helpers/utils';
  3. import { goAliAuth, goWechatAuth } from '@/state';
  4. import {
  5. Cell,
  6. CellGroup,
  7. Icon,
  8. Loading,
  9. showConfirmDialog,
  10. showToast
  11. } from 'vant';
  12. import { defineComponent, onMounted, reactive } from 'vue';
  13. import { useRouter, useRoute } from 'vue-router';
  14. import styles from './index.module.less';
  15. export default defineComponent({
  16. name: 'pay-result',
  17. setup() {
  18. const router = useRouter();
  19. const route = useRoute();
  20. const state = reactive({
  21. errorText: '',
  22. browserStatus: false,
  23. code: null as any,
  24. pay_channel: route.query.pay_channel as any,
  25. wxAppId: route.query.wxAppId as any,
  26. paymentType: route.query.paymentType as any,
  27. alipayAppId: route.query.alipayAppId as any,
  28. body: route.query.body as any,
  29. price: route.query.price as any,
  30. orderNo: route.query.orderNo as any,
  31. userId: route.query.userId as any,
  32. payInfo: {} as any,
  33. isYeePay: false // 是否为易宝支付
  34. });
  35. const init = () => {
  36. const query = route.query;
  37. const isYeePay = state.paymentType.indexOf('yeepay') !== -1;
  38. // 判断是否有支付对象
  39. if (!query.orderNo || !query.pay_channel) {
  40. showConfirmDialog({
  41. message: '支付订单信息错误请重新支付',
  42. showCancelButton: false
  43. }).then(() => {
  44. router.back();
  45. });
  46. } else {
  47. // 判断当前浏览器
  48. if (browser().weixin) {
  49. state.browserStatus = true;
  50. getWxPay();
  51. } else if (browser().alipay) {
  52. if (isYeePay) {
  53. let code = getUrlCode('auth_code');
  54. if (code) {
  55. state.code = code; // 赋值code码
  56. state.browserStatus = true;
  57. getPayment();
  58. } else {
  59. goAliAuth(state.alipayAppId);
  60. }
  61. } else {
  62. state.browserStatus = true;
  63. getPayment();
  64. }
  65. } else {
  66. state.errorText = '请在微信或支付宝客户端打开';
  67. document.title = 'ERROR';
  68. }
  69. }
  70. };
  71. const getPayment = async () => {
  72. try {
  73. if (parseFloat(state.price) <= 0) {
  74. showToast('支付金额异常');
  75. return;
  76. }
  77. const payMap: any = {
  78. merOrderNo: state.orderNo,
  79. paymentChannel: state.pay_channel, // 支付渠道
  80. userId: state.userId,
  81. code: state.code
  82. };
  83. // // 判断是否是微信公众号支付
  84. // if (state.pay_channel == 'wx_pub') {
  85. // payMap.code = state.code;
  86. // }
  87. const { data } = await request.post(
  88. '/edu-app/open/userOrder/executePayment',
  89. {
  90. data: {
  91. ...payMap
  92. }
  93. }
  94. );
  95. state.isYeePay = data.paymentVender?.indexOf('yeepay') !== -1;
  96. console.log(data, 'data');
  97. scanCodePay(data.reqParams);
  98. } catch (e) {
  99. //
  100. console.log(e);
  101. // 接口报错也跳转到支付回调页
  102. window.location.replace(
  103. location.origin +
  104. '/classroom-app/#/payment-result?orderNo=' +
  105. state.orderNo
  106. );
  107. }
  108. };
  109. // 由于js的载入是异步的,所以可以通过该方法,当AlipayJSBridgeReady事件发生后,再执行callback方法
  110. const ready = (callback: any) => {
  111. if ((window as any).AlipayJSBridge) {
  112. callback && callback();
  113. } else {
  114. document.addEventListener('AlipayJSBridgeReady', callback, false);
  115. }
  116. };
  117. const tradePay = (tradeNO: any) => {
  118. ready(function () {
  119. // 通过传入交易号唤起快捷调用方式(注意tradeNO大小写严格)
  120. (window as any).AlipayJSBridge.call(
  121. 'tradePay',
  122. {
  123. tradeNO: tradeNO
  124. },
  125. function (data: any) {
  126. if ('9000' == data.resultCode) {
  127. window.location.replace(
  128. location.origin +
  129. '/classroom-app/#/payment-result?orderNo=' +
  130. state.orderNo
  131. );
  132. } else {
  133. window.location.replace(
  134. location.origin +
  135. '/classroom-app/#/payment-result?orderNo=' +
  136. state.orderNo
  137. );
  138. }
  139. //使用的支付宝内置api实现关闭H5
  140. (window as any).AlipayJSBridge.call('closeWebview');
  141. }
  142. );
  143. });
  144. };
  145. const scanCodePay = (data: any) => {
  146. // 判断支付方式 如果是 test 模式 支付用测试url 否则用生产url
  147. if (state.pay_channel == 'alipay_qr') {
  148. if (state.isYeePay) {
  149. tradePay(data.tradeNO);
  150. } else {
  151. const url =
  152. data.prod_mode === 'false'
  153. ? data?.expend?.qrcode_url +
  154. '?payment_id=' +
  155. data.id +
  156. '&pay_channel=' +
  157. data.pay_channel
  158. : data?.expend?.qrcode_url;
  159. window.location.href = url;
  160. }
  161. } else if (state.pay_channel == 'alipay_wap') {
  162. window.location.href = data?.expend?.pay_info;
  163. } else if (state.pay_channel == 'wx_pub') {
  164. const tempPayInfo = state.isYeePay
  165. ? JSON.parse(data.prePayTn)
  166. : data?.expend
  167. ? JSON.parse(data?.expend?.pay_info)
  168. : data;
  169. state.payInfo = tempPayInfo;
  170. if (typeof (window as any).WeixinJSBridge == 'undefined') {
  171. if (document.addEventListener) {
  172. document.addEventListener(
  173. 'WeixinJSBridgeReady',
  174. onBridgeReady,
  175. false
  176. );
  177. } else if ((document as any).attachEvent) {
  178. (document as any)
  179. .attachEvent(
  180. 'WeixinJSBridgeReady',
  181. onBridgeReady
  182. )(document as any)
  183. .attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  184. }
  185. } else {
  186. onBridgeReady();
  187. }
  188. }
  189. };
  190. const onBridgeReady = () => {
  191. const payInfo = state.payInfo;
  192. // let orderNo = state.orderNo
  193. (window as any).WeixinJSBridge.invoke(
  194. 'getBrandWCPayRequest',
  195. {
  196. appId: payInfo.appId, //公众号名称,由商户传入
  197. timeStamp: payInfo.timeStamp, //时间戳,自1970年以来的秒数
  198. nonceStr: payInfo.nonceStr, //随机串
  199. package: payInfo.package || payInfo.packageValue,
  200. signType: payInfo.signType, //微信签名方式:
  201. paySign: payInfo.paySign //微信签名
  202. },
  203. (res: any) => {
  204. // if(res.err_msg == "get_brand_wcpay_request:ok" ){
  205. // 使用以上方式判断前端返回,微信团队郑重提示:
  206. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  207. // } else
  208. if (
  209. res.err_msg == 'get_brand_wcpay_request:cancel' ||
  210. res.err_msg == 'get_brand_wcpay_request:fail'
  211. ) {
  212. window.location.replace(
  213. location.origin +
  214. '/classroom-app/#/payment-result?orderNo=' +
  215. state.orderNo
  216. );
  217. } else {
  218. // 使用以上方式判断前端返回,微信团队郑重提示:
  219. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  220. // alert('支付成功')
  221. window.location.replace(
  222. location.origin +
  223. '/classroom-app/#/payment-result?orderNo=' +
  224. state.orderNo
  225. );
  226. }
  227. }
  228. );
  229. };
  230. const getWxPay = () => {
  231. // 微信公众号支付
  232. //授权
  233. const code = getUrlCode();
  234. if (!code) {
  235. goWechatAuth(state.wxAppId);
  236. } else {
  237. state.code = code;
  238. getPayment();
  239. }
  240. };
  241. onMounted(() => {
  242. init();
  243. });
  244. return () => (
  245. <div class={styles.paywxresult}>
  246. {state.browserStatus && (
  247. <>
  248. <div class={styles.container}>
  249. <CellGroup border={false}>
  250. <Cell
  251. title={'订单金额'}
  252. value={'¥ ' + moneyFormat(state.price)}></Cell>
  253. <Cell title={'订单信息'} value={state.body}></Cell>
  254. </CellGroup>
  255. </div>
  256. <div class={styles['order-loading']}>
  257. <p>{state.pay_channel == 'wx_pub' ? '微信支付' : '支付宝支付'}</p>
  258. <Loading type="spinner" color="#01C1B5" />
  259. </div>
  260. </>
  261. )}
  262. {!state.browserStatus && (
  263. <div class={styles['error-text']}>
  264. {state.errorText && (
  265. <Icon class={styles['error-icon']} name="warning-o" />
  266. )}
  267. {state.errorText}
  268. </div>
  269. )}
  270. </div>
  271. );
  272. }
  273. });