payout.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. <template>
  2. <div class="airwallexPayment">
  3. <s-header :name="$t('airwallex.payout')" :noback="false"></s-header>
  4. <br>
  5. <div class="form-container">
  6. <div id="payout-form-container" class="payout-form-container" style="height: 100%;"></div>
  7. </div>
  8. <div class="button-container">
  9. <van-button type="primary" class="cancel" @click="handleCancel">取消</van-button>
  10. <van-button type="primary" class="register" @click="handleSubmit">继续</van-button>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. import sHeader from "@/components/SimpleHeader";
  16. import { init, createElement } from '@airwallex/payouts-web-sdk';
  17. import { Base64 } from 'js-base64';
  18. import { AIRWALLEX_ADMIN_CLIENTID } from '@/constants/const.js';
  19. import { getAuthCode } from '@/service/airwallex/index';
  20. import { onMounted, ref } from 'vue';
  21. import { styleUrl } from '../../common/js/utils';
  22. import { useRouter, useRoute } from 'vue-router';
  23. export default {
  24. components: { sHeader },
  25. setup() {
  26. const router = useRouter();
  27. const route = useRoute();
  28. const ready = ref(false);
  29. let payoutComponent;
  30. onMounted(async () => {
  31. try {
  32. // 获取从 beneficiary 页面获取到的 beneficiaryId
  33. // const beneficiaryId = router.currentRoute.value.query.beneficiaryId;
  34. const beneficiaryId = route.query.beneficiaryId;
  35. console.log("beneficiaryId >>> " + beneficiaryId);
  36. // generate code_verifier
  37. const codeVerifier = generateCodeVerifier();
  38. // generate code_challenge
  39. const codeChallengeStr = await generateCodeChallengeFromVerifier(codeVerifier);
  40. // getAuthCode 接口参数
  41. const getAuthCodeDTO = {
  42. code_challenge: codeChallengeStr,
  43. scope: [
  44. "w:awx_action:transfers_edit"
  45. ]
  46. };
  47. console.log("getAuthCodeDTO", getAuthCodeDTO);
  48. // generate authCode
  49. const authCodeResponse = await getAuthCode(getAuthCodeDTO);
  50. const authCodeStr = authCodeResponse.data.authorization_code;
  51. await init({
  52. langKey: 'en',
  53. env: 'demo',
  54. authCode: authCodeStr,
  55. clientId: AIRWALLEX_ADMIN_CLIENTID,
  56. codeVerifier: codeVerifier,
  57. });
  58. // 调用 SDK 的 createElement 方法创建付款交易单/收款方模块
  59. payoutComponent = await createElement(eleType, {
  60. defaultValues: {
  61. beneficiary_id: beneficiaryId,
  62. // payment_currency: 'USD',
  63. }
  64. });
  65. payoutComponent.mount('#payout-form-container');
  66. payoutComponent.on('ready', () => {
  67. ready.value = true;
  68. // 添加组件渲染后的逻辑
  69. console.log('组件呈现后的逻辑...');
  70. });
  71. } catch (error) {
  72. console.error(error);
  73. // 处理异常情况
  74. }
  75. });
  76. const handleCancel = async () => {
  77. router.push({
  78. path: '/airwallex',
  79. })
  80. }
  81. const handleSubmit = async () => {
  82. if (ready.value) {
  83. const formResult = await payoutComponent.submit();
  84. // Handle form results
  85. console.log('submit 执行结果:', formResult);
  86. const {
  87. values
  88. } = formResult;
  89. const {
  90. beneficiary_id,
  91. payment_currency,
  92. payment_method,
  93. source_currency,
  94. source_amount,
  95. fee_paid_by,
  96. payment_date,
  97. } = values;
  98. // 校验 values 参数
  99. if (
  100. !beneficiary_id ||
  101. !payment_currency ||
  102. !payment_method ||
  103. !source_currency
  104. // !reason ||
  105. // !reference ||
  106. ) {
  107. throw new Error('缺少必要参数');
  108. }
  109. if (formResult) {
  110. router.push({
  111. path: '/caPayment',
  112. query: {
  113. beneficiary_id: beneficiary_id,
  114. payment_currency: payment_currency,
  115. payment_method: payment_method,
  116. // reason: reason,
  117. // reference: reference,
  118. source_currency: source_currency,
  119. // request_id: request_id,
  120. source_amount: source_amount,
  121. fee_paid_by: fee_paid_by,
  122. payment_date: payment_date,
  123. }
  124. })
  125. }
  126. }
  127. }
  128. // const handleSubmit = async () => {
  129. // if (ready.value) {
  130. // const formResult = await payoutComponent.submit();
  131. // // Handle form results
  132. // console.log('submit 执行结果:', formResult);
  133. // const {
  134. // values, additionalInfo
  135. // } = formResult;
  136. // const {
  137. // beneficiary_id,
  138. // source_currency,
  139. // payment_method,
  140. // payment_currency,
  141. // // source_amount,
  142. // // fee_paid_by,
  143. // // payment_date,
  144. // } = values;
  145. // // 校验 values 参数
  146. // if (
  147. // !beneficiary_id ||
  148. // !payment_currency ||
  149. // !payment_method ||
  150. // // !reason ||
  151. // // !reference ||
  152. // !source_currency
  153. // ) {
  154. // throw new Error('缺少必要参数');
  155. // }
  156. // // const reason = ref(additionalInfo.reason);
  157. // //
  158. // // setTimeout(() => {
  159. // // additionalInfo.value = {
  160. // // reason: {
  161. // // label: "Audiovisual services",
  162. // // value: "audio_visual_services"
  163. // // },
  164. // // // 其他理由...
  165. // // }
  166. // // }, 1000)
  167. // // const reason = additionalInfo.value.additionalInfo
  168. // // const regference = additionalInfo
  169. // // 把这些参数都带去新的页面,然后再去新的页面获取reason 和 sdfsdfs,最后再去请问
  170. // // 构建请求数据对象
  171. // // 后端必须的参数
  172. // // beneficiary_id,
  173. // // payment_currency,
  174. // // payment_method,
  175. // // reason,
  176. // // reference,
  177. // // request_id,
  178. // // source_currency
  179. // const caPaymentReq = {
  180. // beneficiary_id: beneficiary_id,
  181. // payment_currency: payment_currency,
  182. // payment_method: payment_method,
  183. // // reason: reason,
  184. // // reference: reference,
  185. // // request_id: request_id,
  186. // source_currency: source_currency
  187. // }
  188. // // 请求后端接口
  189. // const resultsResp = await createPayment(caPaymentReq);
  190. // console.log("resultResp>>>", resultsResp);
  191. // // if 成功,将
  192. // // if (resultsResp.code === "00000") {
  193. // // router.push({
  194. // // path: '/caPayment',
  195. // // query: { beneficiaryId: beneficiaryId }
  196. // // })
  197. // // }
  198. // }
  199. // };
  200. // 生成 code_verifier
  201. const dec2hex = (dec) => {
  202. return ('0' + dec.toString(16)).slice(-2);
  203. };
  204. const generateCodeVerifier = () => {
  205. // 生成 random length for code_verifier which should be between 43 and 128
  206. const length = Math.random() * (129 - 43) + 43;
  207. const array = new Uint32Array(length / 2);
  208. window.crypto.getRandomValues(array);
  209. return Array.from(array, dec2hex).join('');
  210. };
  211. // 生成 code_challenge
  212. const sha256 = (plain) => {
  213. const encoder = new TextEncoder();
  214. const data = encoder.encode(plain);
  215. return window.crypto.subtle.digest('SHA-256', data);
  216. };
  217. const base64urlencode = (hashed) => {
  218. const bytes = new Uint8Array(hashed);
  219. const base64encoded = Base64.fromUint8Array(bytes, true);
  220. return base64encoded;
  221. };
  222. const generateCodeChallengeFromVerifier = async (codeVerifier) => {
  223. const hashed = await sha256(codeVerifier);
  224. const base64encoded = base64urlencode(hashed);
  225. return base64encoded;
  226. };
  227. // type 字段:payoutForm(可选),beneficiaryForm
  228. const eleType = "payoutForm";
  229. styleUrl("airwallex");
  230. return {
  231. ready,
  232. handleSubmit,
  233. handleCancel
  234. }
  235. }
  236. }
  237. </script>