global-order.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. <template>
  2. <cwg-page-wrapper>
  3. <view class="page">
  4. <DynamicForm ref="globalFormRef" :global-form="globalForm" :fields="globalCurrenciesField" :step2="step2"
  5. type="1">
  6. <template #top>
  7. <cwg-input :label="t('global.t2')" v-model:value="globalForm.deductionAccount" fkey="deductionAccount"
  8. type="select" :columns="loginOptionsSelect" @change="changeLogin" :placeholder="t('placeholder.choose')" />
  9. </template>
  10. <template #bottom>
  11. <view class="form-section">
  12. <view class="form-item">
  13. <cwg-input :label="t('global.t6')" v-model:value="globalForm.receiver" fkey="receiver" type="select"
  14. :columns="receiverUserListSelect" @change="selectReceiver" :placeholder="t('global.t7')" />
  15. </view>
  16. <view class="form-item">
  17. <cwg-input :label="t('global.p1')" v-model:value="globalForm.payoutCurrency" fkey="payoutCurrency"
  18. v-model:selectedValueDoc="globalForm['payoutCurrencyValue']" type="select" :columns="currencyListSelect"
  19. @change="handlePayoutCurrencyChange" :disabled="!currencyList.length" :placeholder="t('global.p1')" />
  20. </view>
  21. <view class="form-item">
  22. <cwg-input :label="t('global.p2')" v-model:value="globalForm.payType" fkey="payType" type="select"
  23. v-model:selectedValueDoc="globalForm['transferTypeValue']" :columns="transferTypeListSelect"
  24. @change="handlePayTypeChange" :disabled="!globalForm.payoutCurrency || !transferTypeList.length"
  25. :placeholder="t('global.p2')" />
  26. </view>
  27. <view class="form-item" v-if="payoutMethodListSelect.length">
  28. <cwg-input :label="t('global.p3')" v-model:value="globalForm.payMethod" fkey="payMethod" type="select"
  29. v-model:selectedValueDoc="globalForm['payoutMethodValue']" :columns="payoutMethodListSelect"
  30. @change="handlePayMethodChange" :disabled="!globalForm.payType || !payoutMethodList.length"
  31. :placeholder="t('global.p3')" />
  32. </view>
  33. </view>
  34. </template>
  35. <template #transferAmount v-if="globalCurrenciesField.length">
  36. <view class="form-section">
  37. <view class="form-item">
  38. <text class="form-label">
  39. {{ t("card.Form.f55") }}
  40. <text class="quota-tip" v-if="exchangeRateData && exchangeRateData.maxQuota">
  41. ({{ t("global.GlobalOrder.quoteTip") }} {{ exchangeRateData.minQuota }} - {{ exchangeRateData.maxQuota
  42. }} USD)
  43. </text>
  44. </text>
  45. <cwg-input v-model:value="globalForm.amount" :required="true" fkey="amount" type="number"
  46. :placeholder="t('global.placeholder.p4')" @change="handleAmountChange" />
  47. <text class="form-error" v-if="form__error">{{ form__error }}</text>
  48. <text class="fee-text" v-if="feeNum">
  49. {{ `${t("global.GlobalOrder.fee")}:${feeNum}` }} USD
  50. </text>
  51. </view>
  52. <view class="form-item">
  53. <cwg-input
  54. :label="t('global.fieldName.' + 'transferAmount' + '.fieldTitle') + ' (' + globalForm.payoutCurrency + ')'"
  55. :required="true" v-model:value="globalForm.transferAmount" fkey="transferAmount" :disabled="true"
  56. :placeholder="t('global.fieldName.' + 'transferAmount' + '.fieldDescription')" />
  57. </view>
  58. </view>
  59. </template>
  60. <template #tips>
  61. <view class="tips-section">
  62. <view class="tips">
  63. <text class="title">{{ t('global.Tips') }}</text>
  64. <text>{{ t('global.Tips1') }}</text>
  65. <text>{{ t('global.Tips2') }}</text>
  66. <text>{{ t('global.Tips3') }}</text>
  67. <text>{{ t('global.Tips4') }}</text>
  68. </view>
  69. </view>
  70. </template>
  71. <template #submit>
  72. <view class="submit-section cwg-button">
  73. <u-button type="primary" @click="saveDlobal" class="submit-btn prev-btn">
  74. <text>{{ t('Btn.Submit') }}</text>
  75. </u-button>
  76. </view>
  77. </template>
  78. </DynamicForm>
  79. </view>
  80. <cwg-SuccessPrompt v-model:show="showSuccessPrompt" :title="t('global.title1')" :desc="t('Custom.Withdraw.Des1')"
  81. :btn-click="btnClick" />
  82. </cwg-page-wrapper>
  83. </template>
  84. <script setup lang="ts">
  85. import { ref, onMounted, watch, computed, nextTick } from "vue";
  86. import _ from "lodash";
  87. import DynamicForm from "./components/DynamicForm.vue";
  88. import { showToast } from "@/utils/toast";
  89. import { onLoad, onUnload } from '@dcloudio/uni-app'
  90. import useRouter from "@/hooks/useRouter";
  91. import { useI18n } from "vue-i18n";
  92. import { ucardApi } from "@/api/ucard";
  93. import useCardStore from "@/stores/use-card-store";
  94. import { useKeyboardScroll } from '@/hooks/useKeyboardScroll'
  95. const cardStore = useCardStore();
  96. import useUserStore from "@/stores/use-user-store";
  97. const userStore = useUserStore();
  98. const showSuccessPrompt = ref(false);
  99. const { t } = useI18n();
  100. const router = useRouter();
  101. const currency = ref()
  102. useKeyboardScroll()
  103. onLoad((options) => {
  104. currency.value = options.currency
  105. })
  106. // Reactive variables
  107. const globalForm = ref({
  108. transferAmount: null,
  109. payoutCurrency: undefined,
  110. payType: undefined,
  111. payMethod: undefined,
  112. deductionAccount: '',
  113. amount: undefined,
  114. receiver: undefined,
  115. // Other fields go here
  116. });
  117. const businessForm = ref({});
  118. const feeNum = ref(0);
  119. const exchangeRateData = ref({});
  120. const form__error = ref('');
  121. const loginOptions = ref([]);
  122. const globalCurrenciesDropdown = ref([]);
  123. const receiverUserList = ref([]);
  124. const step2 = ref(false);
  125. const currencyList = ref([]);
  126. const globalCurrenciesField = ref([]);
  127. const globalFormRef = ref();
  128. // Computed properties for select lists
  129. const loginOptionsSelect = computed(() => {
  130. return loginOptions.value
  131. });
  132. const currencyListSelect = computed(() => {
  133. return currencyList.value.map((item: any) => ({
  134. text: item.payoutCurrency,
  135. value: item.payoutCurrency
  136. }));
  137. });
  138. const transferTypeListSelect = computed(() => {
  139. return transferTypeList.value.map((item: any) => ({
  140. text: item.transferType,
  141. value: item.transferTypeId
  142. }));
  143. });
  144. const payoutMethodListSelect = computed(() => {
  145. return payoutMethodList.value.map((item: any) => ({
  146. text: item.payoutMethodValue,
  147. value: item.payoutMethodId
  148. }));
  149. });
  150. const transferTypeList = computed(() => {
  151. return currencyList.value.find((item) => item.payoutCurrency === globalForm.value.payoutCurrency)?.types || [];
  152. });
  153. const payoutMethodList = computed(() => {
  154. return transferTypeList.value.find((item) => item.transferTypeId === globalForm.value.payType)?.methods || [];
  155. });
  156. const currentBalance = computed(() => {
  157. if (!globalForm.value.deductionAccount || !loginOptions.value.length) return 0;
  158. const target = loginOptions.value.find((item) => item.value === globalForm.value.deductionAccount);
  159. return target ? Number(target.balance) || 0 : 0;
  160. });
  161. const amountDisabled = computed(() => {
  162. const { payoutCurrency, payType, payMethod } = globalForm.value;
  163. return !payoutCurrency || !payType || !payMethod;
  164. });
  165. const receiverUserListSelect = computed(() => {
  166. const map = new Map();
  167. receiverUserList.value.forEach(item => {
  168. const cardNumber = item.receiverBankAccountNumber;
  169. if (!cardNumber) return;
  170. if (!map.has(cardNumber)) {
  171. map.set(cardNumber, {
  172. cardNumber,
  173. firstName: '',
  174. lastName: '',
  175. nativeFirstName: '',
  176. nativeLastName: ''
  177. });
  178. }
  179. const target = map.get(cardNumber);
  180. if (!target.firstName && (item.receiverFirstName || item.receiverLastName)) {
  181. target.firstName = item.receiverFirstName || '';
  182. target.lastName = item.receiverLastName || '';
  183. }
  184. if (
  185. !target.nativeFirstName &&
  186. (item.receiverNativeFirstName || item.receiverNativeLastName)
  187. ) {
  188. target.nativeFirstName = item.receiverNativeFirstName || '';
  189. target.nativeLastName = item.receiverNativeLastName || '';
  190. }
  191. });
  192. const result = Array.from(map.values()).map(item => {
  193. const enName = `${item.firstName} ${item.lastName}`.trim();
  194. const nativeName = `${item.nativeFirstName} ${item.nativeLastName}`.trim();
  195. let label = '';
  196. if (enName && nativeName) {
  197. label = `${enName}(${nativeName}) / ${item.cardNumber}`;
  198. } else if (enName) {
  199. label = `${enName} / ${item.cardNumber}`;
  200. } else if (nativeName) {
  201. label = `${nativeName} / ${item.cardNumber}`;
  202. } else {
  203. label = item.cardNumber;
  204. }
  205. return {
  206. value: item.cardNumber,
  207. text: label
  208. };
  209. });
  210. return result
  211. });
  212. // Methods
  213. const changeLogin = (value: any) => {
  214. if (globalForm.value.amount) {
  215. globalExchangeRate()
  216. }
  217. globalForm.value.deductionAccount = value.value;
  218. if (value.value) {
  219. step2.value = true;
  220. }
  221. };
  222. const handlePayoutCurrencyChange = (value: any) => {
  223. globalForm.value.payoutCurrency = value.value;
  224. selectOption1(1);
  225. };
  226. const handlePayTypeChange = (value: any) => {
  227. globalForm.value.payType = value.value;
  228. selectOption1(2);
  229. };
  230. const handlePayMethodChange = (value: any) => {
  231. globalForm.value.payMethod = value.value;
  232. selectOption1(3);
  233. };
  234. const handleAmountChange = (value: any) => {
  235. globalForm.value.amount = value.value;
  236. if (!value.value) return globalForm.value.transferAmount = 0
  237. globalExchangeRate();
  238. };
  239. async function globalExchangeRate() {
  240. feeNum.value = 0
  241. const amount = Number(globalForm.value.amount)
  242. // 校验金额是否填写
  243. if (!amount) {
  244. const msg = t("global.validator.v15")
  245. // pigeon.MessageError(msg)
  246. form__error.value = msg
  247. return
  248. }
  249. const { usedQuota, yearTransferAmountQuota, maxQuota, minQuota } = exchangeRateData.value
  250. // 金额格式校验
  251. if (!/^(0|([1-9][0-9]*))(\.[\d]{1,2})?$/.test(amount)) {
  252. const msg = t("global.validator.v15")
  253. // pigeon.MessageError(msg)
  254. form__error.value = msg
  255. return
  256. }
  257. // 最小 / 最大额度校验
  258. if (amount < minQuota || amount > maxQuota) {
  259. const msg = t("global.validator.v14", { minQuota, maxQuota })
  260. // pigeon.MessageError(msg)
  261. form__error.value = msg
  262. return
  263. }
  264. // 余额校验
  265. if (currentBalance.value && amount > currentBalance.value) {
  266. const msg = t("global.validator.balanceTip", {
  267. balance: currentBalance.value,
  268. })
  269. // pigeon.MessageError(msg)
  270. form__error.value = msg
  271. return
  272. }
  273. // 年度额度校验
  274. if (yearTransferAmountQuota) {
  275. const add = _.add(usedQuota, amount)
  276. if (add > yearTransferAmountQuota) {
  277. const msg = t("global.GlobalOrder.rateTip")
  278. // pigeon.MessageError(msg)
  279. form__error.value = msg
  280. return
  281. }
  282. }
  283. form__error.value = ''
  284. // 调接口
  285. const res = await ucardApi.globalExchangeRate({
  286. amount,
  287. uniqueId: businessForm.value.uniqueId,
  288. country: businessForm.value.fieldData.country,
  289. payoutCurrency: businessForm.value.fieldData.payoutCurrency,
  290. transferTypeId: businessForm.value.fieldData.transferTypeId,
  291. payoutMethodId: businessForm.value.fieldData.payoutMethodId,
  292. })
  293. if (res.code === 200) {
  294. businessForm.value.exchangeRate = res.data
  295. form__error.value = ''
  296. // 手续费 (deductionFee ÷ exchangeRate)
  297. feeNum.value = divideNum(
  298. res.data.deductionFee,
  299. businessForm.value.fieldData.exchangeRate
  300. )
  301. // 回显转账金额
  302. globalForm.value.transferAmount = res.data.transferAmount
  303. } else {
  304. // pigeon.MessageError(res.msg)
  305. }
  306. }
  307. const divideNum = (quote, fee) => {
  308. return _.floor(_.divide(quote, fee), 2);
  309. };
  310. const backActivity = () => {
  311. // router.push({ path: "/card/index" });
  312. };
  313. const selectOption1 = async (type: number, e?: boolean) => {
  314. if (type === 1 || type === 2) {
  315. const list1 = transferTypeList.value;
  316. if (list1.length === 1) {
  317. globalForm.value.payType = list1[0].transferTypeId;
  318. } else {
  319. globalForm.value.payType = undefined;
  320. }
  321. const list2 = list1[0]?.methods || [];
  322. if (list2.length === 1) {
  323. globalForm.value.payMethod = list2[0].payoutMethodId;
  324. } else {
  325. globalForm.value.payMethod = undefined;
  326. }
  327. }
  328. globalForm.value.amount = undefined;
  329. feeNum.value = undefined;
  330. fetchExchangeRateDebounced(type, e);
  331. };
  332. // 防抖函数,300ms 内多次触发只执行最后一次
  333. const fetchExchangeRateDebounced = _.debounce(async (type, e) => {
  334. const { payoutCurrency, payType, payMethod } = globalForm.value;
  335. if (globalForm.value.receiver && !e && type === 1) {
  336. selectReceiver({ value: globalForm.value.receiver }, true)
  337. }
  338. if (!payoutCurrency || !payType || !payMethod) return;
  339. const row = globalCurrenciesDropdown.value.filter(
  340. (currency: any) =>
  341. currency.payoutCurrency === payoutCurrency &&
  342. currency.transferTypeId === payType &&
  343. currency.payoutMethodId === payMethod
  344. );
  345. if (!row[0]) return;
  346. businessForm.value = { ...businessForm.value, fieldData: row[0] };
  347. getGlobalCurrenciesField(row[0]);
  348. try {
  349. const res = await ucardApi.globalExchangeRate({
  350. uniqueId: businessForm.value.uniqueId,
  351. country: row[0].country,
  352. payoutCurrency: row[0].payoutCurrency,
  353. transferTypeId: row[0].transferTypeId,
  354. payoutMethodId: row[0].payoutMethodId,
  355. });
  356. if (res.code === 200) {
  357. exchangeRateData.value = res.data;
  358. }
  359. } catch (error) {
  360. console.error("Error fetching exchange rate:", error);
  361. }
  362. }, 500); // 300ms 可根据需要调整
  363. const getGlobalCurrenciesField = async (row: any) => {
  364. try {
  365. const res = await ucardApi.globalCurrenciesField(row);
  366. if (res.code === 200) {
  367. setData(res.data || []);
  368. }
  369. } catch (error) {
  370. console.error("Error fetching currencies field:", error);
  371. }
  372. };
  373. const getSenderData = () => {
  374. const { idType, idNumber } = businessForm.value;
  375. const senderIdType =
  376. idType === "PASSPORT"
  377. ? "1"
  378. : idType === "GOVERNMENT_ISSUED_ID_CARD"
  379. ? "2"
  380. : "";
  381. const senderIdNumber =
  382. idType === "PASSPORT"
  383. ? idNumber
  384. : idType === "GOVERNMENT_ISSUED_ID_CARD"
  385. ? idNumber
  386. : "";
  387. return {
  388. senderFirstName: businessForm.value.firstName,
  389. senderLastName: businessForm.value.lastName,
  390. senderGender: businessForm.value.gender,
  391. senderIdType,
  392. senderIdNumber,
  393. senderNationality: businessForm.value.nationality,
  394. senderIdIssueCountry: businessForm.value.senderIdIssueCountry,
  395. senderDateOfBirth: businessForm.value.birthday,
  396. senderCountry: businessForm.value.country == "CHN" || businessForm.value.country == "CN" ? '' : businessForm.value.country,
  397. senderState: businessForm.value.senderState,
  398. senderRegion: businessForm.value.senderRegion,
  399. senderCity: businessForm.value.townEnName,
  400. senderAddress: businessForm.value.address,
  401. senderZipCode: businessForm.value.postCode,
  402. senderMobileAreaCode: businessForm.value.areaCode,
  403. senderMobileNumber: businessForm.value.mobile,
  404. senderEmail: businessForm.value.email,
  405. senderBeneficiaryRelationship: '3', // 付款人关系
  406. senderOccupation: businessForm.value.occupation,
  407. transferType: businessForm.value.fieldData.transferTypeId,
  408. PayoutMethod: businessForm.value.fieldData.payoutMethodId,
  409. };
  410. };
  411. function btnClick() {
  412. showSuccessPrompt.value = false;
  413. router.push({ path: "/pages/wallet/index" })
  414. }
  415. // Function to merge dynamic fields and sender data
  416. const setData = async (data: any) => {
  417. const senderData = getSenderData();
  418. // console.log(senderData, 'senderData');
  419. const mergedFields = await Promise.all(
  420. data.map(async (field: any) => {
  421. const { fieldName } = field;
  422. const key = Object.keys(senderData).find(
  423. (k) => k.toLowerCase() === fieldName.toLowerCase()
  424. );
  425. let fixedValue = key ? senderData[key] : field.fixedValue;
  426. // console.log(key, fixedValue, 1222222);
  427. if (fieldName === "receiverBankCity") {
  428. try {
  429. const res = await ucardApi.globalQueryBankCities({
  430. payoutCurrency: businessForm.value.fieldData.payoutCurrency,
  431. country: businessForm.value.fieldData.country,
  432. });
  433. if (res.code === 200 && Array.isArray(res.data)) {
  434. field.availableDtos = res.data.map((item: any) => ({
  435. value: item.bankCitiesValue,
  436. valueId: item.bankCitiesKey,
  437. }));
  438. }
  439. } catch (e) {
  440. console.error("Error loading receiverBankCity data:", e);
  441. }
  442. }
  443. // 如果币种为 CNY,且字段是 senderIdType,则从下拉数据中移除 valueId 为 "2" 的选项
  444. if (
  445. fieldName === "senderIdType" &&
  446. businessForm.value.fieldData &&
  447. businessForm.value.fieldData.payoutCurrency === "CNY" &&
  448. Array.isArray(field.availableDtos)
  449. ) {
  450. field.availableDtos = field.availableDtos.filter(
  451. (item) => String(item.valueId) !== "2"
  452. );
  453. // 如果当前固定值是被移除的 valueId,则清空以避免不可用的默认选中
  454. if (String(fixedValue) === "2") {
  455. fixedValue = null;
  456. }
  457. if (String(field.fixedValue) === "2") {
  458. field.fixedValue = null;
  459. }
  460. }
  461. if (
  462. fieldName === "senderIdNumber" &&
  463. businessForm.value.fieldData &&
  464. businessForm.value.fieldData.payoutCurrency === "CNY"
  465. ) {
  466. // 如果当前固定值是被移除的 valueId,则清空以避免不可用的默认选中
  467. fixedValue = ''
  468. }
  469. // Handle select fields
  470. if (field.fieldType === "select") {
  471. let rValue = globalForm.value[fieldName] || fixedValue;
  472. const label = field.availableDtos?.find(
  473. (item: any) => item.valueId === rValue
  474. ) ?? null;
  475. fixedValue = label?.valueId || fixedValue;
  476. globalForm.value[fieldName + "Value"] = label?.value ?? null;
  477. globalForm.value[fieldName] = fixedValue;
  478. // console.log(field, fixedValue, 'select field');
  479. }
  480. return { ...field, fixedValue };
  481. })
  482. );
  483. globalCurrenciesField.value = mergedFields;
  484. };
  485. // 选择的收款人
  486. const selectReceiver = (a, isCurrencyChange = false) => {
  487. const cardNumber = a.value;
  488. if (!cardNumber) return;
  489. const sameCardList = receiverUserList.value.filter(
  490. (item) => item.receiverBankAccountNumber === cardNumber
  491. );
  492. const receiverFields = cardStore.globalFieldParams.filter(item => item.fieldUserType === 'receiver' && !['transferType', 'payoutMethod', 'payoutCurrency'].includes(item.fieldName)).map(item => item.fieldName)
  493. if (!sameCardList.length) {
  494. receiverFields.forEach(field => {
  495. globalForm.value[field] = undefined;
  496. const valueKey = field + 'Value';
  497. globalForm.value[valueKey] = undefined;
  498. });
  499. return;
  500. }
  501. const { payoutCurrency, payType, payMethod } = globalForm.value;
  502. let matchingData = null;
  503. if (payoutCurrency && payType && payMethod) {
  504. matchingData = sameCardList.find(
  505. (item) =>
  506. item.payoutCurrency === payoutCurrency &&
  507. String(item.payoutMethod) === String(payMethod) &&
  508. String(item.transferType) === String(payType)
  509. );
  510. }
  511. if (!matchingData) {
  512. if (isCurrencyChange) {
  513. receiverFields.forEach(field => {
  514. globalForm.value[field] = undefined;
  515. const valueKey = field + 'Value';
  516. globalForm.value[valueKey] = undefined;
  517. });
  518. return;
  519. }
  520. matchingData = sameCardList[0];
  521. if (matchingData) {
  522. if (!isCurrencyChange) {
  523. globalForm.value.payoutCurrency = matchingData.payoutCurrency;
  524. globalForm.value.payType = String(matchingData.transferType);
  525. globalForm.value.payMethod = String(matchingData.payoutMethod);
  526. selectOption1(3, true);
  527. }
  528. }
  529. } else {
  530. if (!isCurrencyChange) {
  531. selectOption1(3, true);
  532. }
  533. }
  534. if (!matchingData) return;
  535. receiverFields.forEach(field => {
  536. globalForm.value[field] = matchingData[field];
  537. });
  538. };
  539. const getGlobalCurrenciesDropdown = () => {
  540. const res = cardStore.currencyList;
  541. globalCurrenciesDropdown.value = res || [];
  542. const data = _.cloneDeep(res);
  543. const payoutCurrencies = [...new Set(data.map((item: any) => item.payoutCurrency))];
  544. const array = payoutCurrencies.map((item) => {
  545. let list = data.filter((item2: any) => item === item2.payoutCurrency);
  546. let transferTypes = [...new Set(list.map((item: any) => item.transferTypeValue))];
  547. const types = transferTypes.map((type) => {
  548. const cur = list.find((item2: any) => item2.transferTypeValue === type);
  549. let list2 = list
  550. .filter((item2: any) => item2.transferTypeValue === type)
  551. .map((item2: any) => ({
  552. payoutMethodId: item2.payoutMethodId,
  553. payoutMethodValue: item2.payoutMethodValue,
  554. }));
  555. return { transferType: type, transferTypeId: cur.transferTypeId, methods: list2 };
  556. });
  557. return { payoutCurrency: item, types };
  558. });
  559. currencyList.value = array;
  560. globalForm.value.payoutCurrency = currency.value
  561. };
  562. // 提交订单
  563. const saveDlobal = async () => {
  564. const isValid = await globalFormRef.value.validateForm();
  565. if (!isValid) {
  566. return;
  567. }
  568. try {
  569. if (!globalForm.value.amount) {
  570. showToast(t("global.validator.v15"));
  571. return;
  572. }
  573. if (form__error.value) {
  574. showToast(form__error.value);
  575. return
  576. }
  577. if (!globalForm.value.deductionAccount) {
  578. showToast(t('placeholder.choose'));
  579. return;
  580. }
  581. const [cardNumber, deductionAccountType] = globalForm.value.deductionAccount.split(",");
  582. const otherData = {};
  583. globalCurrenciesField.value
  584. .map((item) => ({
  585. fieldName: item.fieldName,
  586. fieldType: item.fieldType,
  587. }))
  588. .forEach((item) => {
  589. otherData[item.fieldName] = globalForm.value[item.fieldName];
  590. if (item.fieldType === "select") {
  591. const key = item.fieldName + 'Value';
  592. otherData[key] = globalForm.value[key];
  593. }
  594. });
  595. const params = {
  596. ...otherData,
  597. cardNumber,
  598. amount: globalForm.value.amount,
  599. deductionAccountType,
  600. uniqueId: businessForm.value.uniqueId,
  601. ...businessForm.value.exchangeRate,
  602. };
  603. const res = await ucardApi.globalOrdersCreate({ ...params });
  604. if (res.code === 200) {
  605. showSuccessPrompt.value = true;
  606. } else {
  607. showToast(res.msg);
  608. }
  609. } catch (error: any) {
  610. console.error("Error submitting order:", error);
  611. showToast(error.message || t('common.error'));
  612. }
  613. };
  614. // 收款人list
  615. const globalReceiverUserList = async ({ uniqueId }: any) => {
  616. try {
  617. const res = await ucardApi.globalReceiverUserList({ uniqueId });
  618. if (res.code === 200) {
  619. receiverUserList.value = res.data;
  620. } else {
  621. showToast(res.msg);
  622. }
  623. } catch (error) {
  624. console.error("Error fetching receiver list:", error);
  625. showToast(t('common.error'));
  626. }
  627. };
  628. // 付款账户下拉
  629. const getAccountDropdown = async () => {
  630. try {
  631. const res = await ucardApi.cardAccountDropdown();
  632. if (res.code === 200) {
  633. loginOptions.value = res.data.map((item: any) => {
  634. if (item.type === "1") {
  635. item.text = `${t("global.GlobalOrder.cardNumber")} - ${item.cardNumber} ${t("global.GlobalOrder.bal")}: ${item.balance}`;
  636. } else {
  637. item.text = `${t("global.GlobalOrder.bagBal")}: ${item.balance}`;
  638. }
  639. item.value = `${item.cardNumber},${item.type}`;
  640. item.disabled = item.balance === 0;
  641. return item;
  642. });
  643. } else {
  644. showToast(res.msg);
  645. }
  646. } catch (error) {
  647. console.error("Error fetching account dropdown:", error);
  648. showToast(t('common.error'));
  649. }
  650. };
  651. // 付款账户下拉
  652. const globalUserDetails = async () => {
  653. try {
  654. const res = await ucardApi.globalUserDetails();
  655. if (res.code === 200) {
  656. businessForm.value = res.data;
  657. }
  658. // console.log(res.data);
  659. } catch (error) {
  660. console.error("Error fetching account dropdown:", error);
  661. showToast(t('common.error'));
  662. }
  663. };
  664. onMounted(async () => {
  665. await globalUserDetails();
  666. await getAccountDropdown();
  667. getGlobalCurrenciesDropdown();
  668. globalReceiverUserList(businessForm.value);
  669. });
  670. </script>
  671. <style lang="scss" scoped>
  672. @import "@/uni.scss";
  673. .form-section {
  674. margin-bottom: px2rpx(20);
  675. }
  676. .section-title {
  677. font-size: px2rpx(16);
  678. font-weight: bold;
  679. margin-bottom: px2rpx(15);
  680. display: block;
  681. }
  682. .form-item {
  683. margin-bottom: px2rpx(15);
  684. }
  685. .form-label {
  686. font-size: var(--font-size-16);
  687. line-height: px2rpx(24);
  688. letter-spacing: px2rpx(1);
  689. color: #474747;
  690. margin-bottom: px2rpx(4);
  691. overflow: hidden;
  692. text-overflow: ellipsis;
  693. white-space: nowrap;
  694. display: flex;
  695. align-items: center;
  696. .required-mark {
  697. color: red;
  698. }
  699. }
  700. .quota-tip {
  701. font-size: px2rpx(12);
  702. color: #999;
  703. margin-left: px2rpx(5);
  704. }
  705. .form-error {
  706. color: #ff0000;
  707. font-size: px2rpx(12);
  708. margin-top: px2rpx(5);
  709. display: block;
  710. }
  711. .fee-text {
  712. font-size: px2rpx(12);
  713. color: #666;
  714. margin-top: px2rpx(5);
  715. display: block;
  716. }
  717. .tips-section {
  718. margin: px2rpx(20) 0;
  719. }
  720. .tips {
  721. background-color: #f5f5f5;
  722. padding: px2rpx(15);
  723. border-radius: px2rpx(8);
  724. }
  725. .tips .title {
  726. font-weight: bold;
  727. margin-bottom: px2rpx(16);
  728. display: block;
  729. }
  730. .tips text {
  731. display: block;
  732. margin-bottom: px2rpx(10);
  733. font-size: px2rpx(13);
  734. color: #666;
  735. line-height: px2rpx(20);
  736. }
  737. .submit-section {
  738. margin: px2rpx(20) 0;
  739. }
  740. .submit-btn {
  741. width: 100%;
  742. }
  743. </style>