index.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import request from '@/helpers/request';
  2. import { browser, getHttpOrigin, 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. wxPubAppId: state.wxAppId,
  82. code: state.code
  83. };
  84. // // 判断是否是微信公众号支付
  85. // if (state.pay_channel == 'wx_pub') {
  86. // payMap.code = state.code;
  87. // }
  88. const { data } = await request.post(
  89. '/edu-app/open/userOrder/executePayment',
  90. {
  91. data: {
  92. ...payMap
  93. }
  94. }
  95. );
  96. state.isYeePay = data.paymentVender?.indexOf('yeepay') !== -1;
  97. console.log(data, 'data');
  98. scanCodePay(data.reqParams);
  99. } catch (e) {
  100. //
  101. console.log(e);
  102. // 接口报错也跳转到支付回调页
  103. window.location.replace(
  104. getHttpOrigin() +
  105. '/classroom-app/#/payment-result?orderNo=' +
  106. state.orderNo
  107. );
  108. }
  109. };
  110. // 由于js的载入是异步的,所以可以通过该方法,当AlipayJSBridgeReady事件发生后,再执行callback方法
  111. const ready = (callback: any) => {
  112. if ((window as any).AlipayJSBridge) {
  113. callback && callback();
  114. } else {
  115. document.addEventListener('AlipayJSBridgeReady', callback, false);
  116. }
  117. };
  118. const tradePay = (tradeNO: any) => {
  119. ready(function () {
  120. // 通过传入交易号唤起快捷调用方式(注意tradeNO大小写严格)
  121. (window as any).AlipayJSBridge.call(
  122. 'tradePay',
  123. {
  124. tradeNO: tradeNO
  125. },
  126. function (data: any) {
  127. if ('9000' == data.resultCode) {
  128. window.location.replace(
  129. getHttpOrigin() +
  130. '/classroom-app/#/payment-result?orderNo=' +
  131. state.orderNo
  132. );
  133. } else {
  134. window.location.replace(
  135. getHttpOrigin() +
  136. '/classroom-app/#/payment-result?orderNo=' +
  137. state.orderNo
  138. );
  139. }
  140. //使用的支付宝内置api实现关闭H5
  141. (window as any).AlipayJSBridge.call('closeWebview');
  142. }
  143. );
  144. });
  145. };
  146. const scanCodePay = (data: any) => {
  147. // 判断支付方式 如果是 test 模式 支付用测试url 否则用生产url
  148. if (state.pay_channel == 'alipay_qr') {
  149. if (state.isYeePay) {
  150. tradePay(data.tradeNO);
  151. } else {
  152. const url =
  153. data.prod_mode === 'false'
  154. ? data?.expend?.qrcode_url +
  155. '?payment_id=' +
  156. data.id +
  157. '&pay_channel=' +
  158. data.pay_channel
  159. : data?.expend?.qrcode_url;
  160. window.location.href = url;
  161. }
  162. } else if (state.pay_channel == 'alipay_wap') {
  163. window.location.href = data?.expend?.pay_info;
  164. } else if (state.pay_channel == 'wx_pub') {
  165. const tempPayInfo = state.isYeePay
  166. ? JSON.parse(data.prePayTn)
  167. : data?.expend
  168. ? JSON.parse(data?.expend?.pay_info)
  169. : data;
  170. state.payInfo = tempPayInfo;
  171. if (typeof (window as any).WeixinJSBridge == 'undefined') {
  172. if (document.addEventListener) {
  173. document.addEventListener(
  174. 'WeixinJSBridgeReady',
  175. onBridgeReady,
  176. false
  177. );
  178. } else if ((document as any).attachEvent) {
  179. (document as any)
  180. .attachEvent(
  181. 'WeixinJSBridgeReady',
  182. onBridgeReady
  183. )(document as any)
  184. .attachEvent('onWeixinJSBridgeReady', onBridgeReady);
  185. }
  186. } else {
  187. onBridgeReady();
  188. }
  189. }
  190. };
  191. const onBridgeReady = () => {
  192. const payInfo = state.payInfo;
  193. // let orderNo = state.orderNo
  194. (window as any).WeixinJSBridge.invoke(
  195. 'getBrandWCPayRequest',
  196. {
  197. appId: payInfo.appId, //公众号名称,由商户传入
  198. timeStamp: payInfo.timeStamp, //时间戳,自1970年以来的秒数
  199. nonceStr: payInfo.nonceStr, //随机串
  200. package: payInfo.package || payInfo.packageValue,
  201. signType: payInfo.signType, //微信签名方式:
  202. paySign: payInfo.paySign //微信签名
  203. },
  204. (res: any) => {
  205. // if(res.err_msg == "get_brand_wcpay_request:ok" ){
  206. // 使用以上方式判断前端返回,微信团队郑重提示:
  207. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  208. // } else
  209. if (
  210. res.err_msg == 'get_brand_wcpay_request:cancel' ||
  211. res.err_msg == 'get_brand_wcpay_request:fail'
  212. ) {
  213. window.location.replace(
  214. getHttpOrigin() +
  215. '/classroom-app/#/payment-result?orderNo=' +
  216. state.orderNo
  217. );
  218. } else {
  219. // 使用以上方式判断前端返回,微信团队郑重提示:
  220. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  221. // alert('支付成功')
  222. window.location.replace(
  223. getHttpOrigin() +
  224. '/classroom-app/#/payment-result?orderNo=' +
  225. state.orderNo
  226. );
  227. }
  228. }
  229. );
  230. };
  231. const getWxPay = () => {
  232. // 微信公众号支付
  233. //授权
  234. const code = getUrlCode();
  235. if (!code) {
  236. goWechatAuth(state.wxAppId);
  237. } else {
  238. state.code = code;
  239. getPayment();
  240. }
  241. };
  242. onMounted(() => {
  243. init();
  244. });
  245. return () => (
  246. <div class={styles.paywxresult}>
  247. {state.browserStatus && (
  248. <>
  249. <div class={styles.container}>
  250. <CellGroup border={false}>
  251. <Cell
  252. title={'订单金额'}
  253. value={'¥ ' + moneyFormat(state.price)}></Cell>
  254. <Cell title={'订单信息'} value={state.body}></Cell>
  255. </CellGroup>
  256. </div>
  257. <div class={styles['order-loading']}>
  258. <p>{state.pay_channel == 'wx_pub' ? '微信支付' : '支付宝支付'}</p>
  259. <Loading type="spinner" color="#01C1B5" />
  260. </div>
  261. </>
  262. )}
  263. {!state.browserStatus && (
  264. <div class={styles['error-text']}>
  265. {state.errorText && (
  266. <Icon class={styles['error-icon']} name="warning-o" />
  267. )}
  268. {state.errorText}
  269. </div>
  270. )}
  271. </div>
  272. );
  273. }
  274. });