| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- <template>
- <cwg-page-wrapper>
- <view class="page">
- <DynamicForm ref="globalFormRef" :global-form="globalForm" :fields="globalCurrenciesField" :step2="step2"
- type="1">
- <template #top>
- <cwg-input :label="t('global.t2')" v-model:value="globalForm.deductionAccount" fkey="deductionAccount"
- type="select" :columns="loginOptionsSelect" @change="changeLogin" :placeholder="t('placeholder.choose')" />
- </template>
- <template #bottom>
- <view class="form-section">
- <view class="form-item">
- <cwg-input :label="t('global.t6')" v-model:value="globalForm.receiver" fkey="receiver" type="select"
- :columns="receiverUserListSelect" @change="selectReceiver" :placeholder="t('global.t7')" />
- </view>
- <view class="form-item">
- <cwg-input :label="t('global.p1')" v-model:value="globalForm.payoutCurrency" fkey="payoutCurrency"
- type="select" :columns="currencyListSelect" @change="handlePayoutCurrencyChange"
- :disabled="!currencyList.length" :placeholder="t('global.p1')" />
- </view>
- <view class="form-item">
- <cwg-input :label="t('global.p2')" v-model:value="globalForm.payType" fkey="payType" type="select"
- :columns="transferTypeListSelect" @change="handlePayTypeChange"
- :disabled="!globalForm.payoutCurrency || !transferTypeList.length" :placeholder="t('global.p2')" />
- </view>
- <view class="form-item" v-if="payoutMethodListSelect.length">
- <cwg-input :label="t('global.p3')" v-model:value="globalForm.payMethod" fkey="payMethod" type="select"
- :columns="payoutMethodListSelect" @change="handlePayMethodChange"
- :disabled="!globalForm.payType || !payoutMethodList.length" :placeholder="t('global.p3')" />
- </view>
- </view>
- </template>
- <template #transferAmount v-if="globalCurrenciesField.length">
- <view class="form-section">
- <view class="form-item">
- <text class="form-label">
- {{ t("card.Form.f55") }}
- <text class="quota-tip" v-if="exchangeRateData && exchangeRateData.maxQuota">
- ({{ t("global.GlobalOrder.quoteTip") }} {{ exchangeRateData.minQuota }} - {{ exchangeRateData.maxQuota
- }} USD)
- </text>
- </text>
- <cwg-input v-model:value="globalForm.amount" fkey="amount" type="number"
- :placeholder="t('global.placeholder.p4')" @change="handleAmountChange" />
- <text class="form-error" v-if="form__error">{{ form__error }}</text>
- <text class="fee-text" v-if="feeNum">
- {{ `${t("global.GlobalOrder.fee")}:${feeNum}` }} USD
- </text>
- </view>
- <view class="form-item">
- <cwg-input
- :label="t('global.fieldName.' + 'transferAmount' + '.fieldTitle') + ' (' + globalForm.payoutCurrency + ')'"
- v-model:value="globalForm.transferAmount" fkey="transferAmount" :disabled="true"
- :placeholder="t('global.fieldName.' + 'transferAmount' + '.fieldDescription')" />
- </view>
- </view>
- </template>
- <template #tips>
- <view class="tips-section">
- <view class="tips">
- <text class="title">{{ t('global.Tips') }}</text>
- <text>{{ t('global.Tips1') }}</text>
- <text>{{ t('global.Tips2') }}</text>
- <text>{{ t('global.Tips3') }}</text>
- <text>{{ t('global.Tips4') }}</text>
- </view>
- </view>
- </template>
- <template #submit>
- <view class="submit-section cwg-button">
- <u-button type="primary" @click="saveDlobal" class="submit-btn prev-btn">
- <text v-if="$i18n.locale === 'es'">Enviar solicitud</text>
- <text v-else>{{ t('Btn.Submit') }}</text>
- </u-button>
- </view>
- </template>
- </DynamicForm>
- </view>
- </cwg-page-wrapper>
- </template>
- <script setup lang="ts">
- import { ref, onMounted, watch, computed, nextTick } from "vue";
- import _ from "lodash";
- import DynamicForm from "./components/DynamicForm.vue";
- import { showToast } from "@/utils/toast";
- import { onLoad } from '@dcloudio/uni-app'
- import useRouter from "@/hooks/useRouter";
- import { useI18n } from "vue-i18n";
- import { ucardApi } from "@/api/ucard";
- import useCardStore from "@/stores/use-card-store";
- const cardStore = useCardStore();
- import useUserStore from "@/stores/use-user-store";
- const userStore = useUserStore();
- const { t } = useI18n();
- const router = useRouter();
- const currency = ref()
- onLoad((options) => {
- currency.value = options.currency
- })
- // Reactive variables
- const globalForm = ref({
- transferAmount: null,
- payoutCurrency: undefined,
- payType: undefined,
- payMethod: undefined,
- deductionAccount: '',
- amount: undefined,
- receiver: undefined,
- // Other fields go here
- });
- const businessForm = ref({});
- const feeNum = ref(0);
- const exchangeRateData = ref({});
- const form__error = ref('');
- const loginOptions = ref([]);
- const globalCurrenciesDropdown = ref([]);
- const receiverUserList = ref([]);
- const step2 = ref(false);
- const currencyList = ref([]);
- const globalCurrenciesField = ref([]);
- const globalFormRef = ref();
- // Computed properties for select lists
- const loginOptionsSelect = computed(() => {
- return loginOptions.value
- });
- const receiverUserListSelect = computed(() => {
- return receiverUserList.value.map((item: any) => ({
- text: `${item.receiverFirstName} ${item.receiverLastName} / ${item.receiverBankAccountNumber}`,
- value: item.id
- }));
- });
- const currencyListSelect = computed(() => {
- return currencyList.value.map((item: any) => ({
- text: item.payoutCurrency,
- value: item.payoutCurrency
- }));
- });
- const transferTypeListSelect = computed(() => {
- return transferTypeList.value.map((item: any) => ({
- text: item.transferType,
- value: item.transferTypeId
- }));
- });
- const payoutMethodListSelect = computed(() => {
- return payoutMethodList.value.map((item: any) => ({
- text: item.payoutMethodValue,
- value: item.payoutMethodId
- }));
- });
- const transferTypeList = computed(() => {
- return currencyList.value.find((item) => item.payoutCurrency === globalForm.value.payoutCurrency)?.types || [];
- });
- const payoutMethodList = computed(() => {
- return transferTypeList.value.find((item) => item.transferTypeId === globalForm.value.payType)?.methods || [];
- });
- const currentBalance = computed(() => {
- if (!globalForm.value.deductionAccount || !loginOptions.value.length) return 0;
- const target = loginOptions.value.find((item) => item.value === globalForm.value.deductionAccount);
- return target ? Number(target.balance) || 0 : 0;
- });
- const amountDisabled = computed(() => {
- const { payoutCurrency, payType, payMethod } = globalForm.value;
- return !payoutCurrency || !payType || !payMethod;
- });
- // Methods
- const changeLogin = (value: any) => {
- globalForm.value.deductionAccount = value.value;
- if (value.value) {
- step2.value = true;
- }
- };
- const handlePayoutCurrencyChange = (value: any) => {
- globalForm.value.payoutCurrency = value.value;
- selectOption1(1);
- };
- const handlePayTypeChange = (value: any) => {
- globalForm.value.payType = value.value;
- selectOption1(2);
- };
- const handlePayMethodChange = (value: any) => {
- globalForm.value.payMethod = value.value;
- selectOption1(3);
- };
- const handleAmountChange = (value: any) => {
- console.log(value, 'value');
- globalForm.value.amount = value.value;
- globalExchangeRate();
- };
- async function globalExchangeRate() {
- feeNum.value = 0
- const amount = Number(globalForm.value.amount)
- console.log(amount, globalForm.value.amount);
- // 校验金额是否填写
- if (!amount) {
- const msg = t("global.validator.v15")
- // pigeon.MessageError(msg)
- form__error.value = msg
- return
- }
- const { usedQuota, yearTransferAmountQuota, maxQuota, minQuota } = exchangeRateData.value
- // 金额格式校验
- if (!/^(0|([1-9][0-9]*))(\.[\d]{1,2})?$/.test(amount)) {
- const msg = t("global.validator.v15")
- // pigeon.MessageError(msg)
- form__error.value = msg
- return
- }
- // 最小 / 最大额度校验
- if (amount < minQuota || amount > maxQuota) {
- const msg = t("global.validator.v14", { minQuota, maxQuota })
- // pigeon.MessageError(msg)
- form__error.value = msg
- return
- }
- // 余额校验
- if (currentBalance.value && amount > currentBalance.value) {
- const msg = t("global.validator.balanceTip", {
- balance: currentBalance.value,
- })
- // pigeon.MessageError(msg)
- form__error.value = msg
- return
- }
- // 年度额度校验
- if (yearTransferAmountQuota) {
- const add = _.add(usedQuota, amount)
- if (add > yearTransferAmountQuota) {
- const msg = t("global.GlobalOrder.rateTip")
- // pigeon.MessageError(msg)
- form__error.value = msg
- return
- }
- }
- form__error.value = ''
- // 调接口
- const res = await ucardApi.globalExchangeRate({
- amount,
- uniqueId: businessForm.value.uniqueId,
- country: businessForm.value.fieldData.country,
- payoutCurrency: businessForm.value.fieldData.payoutCurrency,
- transferTypeId: businessForm.value.fieldData.transferTypeId,
- payoutMethodId: businessForm.value.fieldData.payoutMethodId,
- })
- console.log(res, 121212121);
- if (res.code === 200) {
- businessForm.value.exchangeRate = res.data
- form__error.value = ''
- // 手续费 (deductionFee ÷ exchangeRate)
- feeNum.value = divideNum(
- res.data.deductionFee,
- businessForm.value.fieldData.exchangeRate
- )
- // 回显转账金额
- globalForm.value.transferAmount = res.data.transferAmount
- console.log(globalForm.value, 121212);
- } else {
- // pigeon.MessageError(res.msg)
- }
- }
- const divideNum = (quote, fee) => {
- return _.floor(_.divide(quote, fee), 2);
- };
- const backActivity = () => {
- // router.push({ path: "/card/index" });
- };
- const selectOption1 = async (type: number) => {
- if (type === 1 || type === 2) {
- const list1 = transferTypeList.value;
- if (list1.length === 1) {
- globalForm.value.payType = list1[0].transferTypeId;
- } else {
- globalForm.value.payType = undefined;
- }
- const list2 = list1[0]?.methods || [];
- if (list2.length === 1) {
- globalForm.value.payMethod = list2[0].payoutMethodId;
- } else {
- globalForm.value.payMethod = undefined;
- }
- }
- globalForm.value.amount = undefined;
- feeNum.value = undefined;
- fetchExchangeRateDebounced();
- };
- // 防抖函数,300ms 内多次触发只执行最后一次
- const fetchExchangeRateDebounced = _.debounce(async () => {
- const { payoutCurrency, payType, payMethod } = globalForm.value;
- if (!payoutCurrency || !payType || !payMethod) return;
- const row = globalCurrenciesDropdown.value.filter(
- (currency: any) =>
- currency.payoutCurrency === payoutCurrency &&
- currency.transferTypeId === payType &&
- currency.payoutMethodId === payMethod
- );
- if (!row[0]) return;
- businessForm.value = { ...businessForm.value, fieldData: row[0] };
- getGlobalCurrenciesField(row[0]);
- try {
- const res = await ucardApi.globalExchangeRate({
- uniqueId: businessForm.value.uniqueId,
- country: row[0].country,
- payoutCurrency: row[0].payoutCurrency,
- transferTypeId: row[0].transferTypeId,
- payoutMethodId: row[0].payoutMethodId,
- });
- if (res.code === 200) {
- exchangeRateData.value = res.data;
- }
- } catch (error) {
- console.error("Error fetching exchange rate:", error);
- }
- }, 500); // 300ms 可根据需要调整
- const getGlobalCurrenciesField = async (row: any) => {
- try {
- const res = await ucardApi.globalCurrenciesField(row);
- if (res.code === 200) {
- setData(res.data || []);
- }
- } catch (error) {
- console.error("Error fetching currencies field:", error);
- }
- };
- const getSenderData = () => {
- const { idType, idNumber } = businessForm.value;
- const senderIdType =
- idType === "PASSPORT"
- ? "1"
- : idType === "GOVERNMENT_ISSUED_ID_CARD"
- ? "2"
- : "";
- const senderIdNumber =
- idType === "PASSPORT"
- ? idNumber
- : idType === "GOVERNMENT_ISSUED_ID_CARD"
- ? idNumber
- : "";
- return {
- senderFirstName: businessForm.value.firstName,
- senderLastName: businessForm.value.lastName,
- senderGender: businessForm.value.gender,
- senderIdType,
- senderIdNumber,
- senderNationality: businessForm.value.nationality,
- senderIdIssueCountry: businessForm.value.senderIdIssueCountry,
- senderDateOfBirth: businessForm.value.birthday,
- senderCountry: businessForm.value.country,
- senderState: businessForm.value.senderState,
- senderRegion: businessForm.value.senderRegion,
- senderCity: businessForm.value.townEnName,
- senderAddress: businessForm.value.address,
- senderZipCode: businessForm.value.postCode,
- senderMobileAreaCode: businessForm.value.areaCode,
- senderMobileNumber: businessForm.value.mobile,
- senderEmail: businessForm.value.email,
- senderOccupation: businessForm.value.occupation,
- transferType: businessForm.value.fieldData.transferTypeId,
- PayoutMethod: businessForm.value.fieldData.payoutMethodId,
- };
- };
- // Function to merge dynamic fields and sender data
- const setData = async (data: any) => {
- const senderData = getSenderData();
- const mergedFields = await Promise.all(
- data.map(async (field: any) => {
- const { fieldName } = field;
- const key = Object.keys(senderData).find(
- (k) => k.toLowerCase() === field.fieldName.toLowerCase()
- );
- const fixedValue = key ? senderData[key] : field.fixedValue;
- if (field.fieldName === "receiverBankCity") {
- try {
- const res = await ucardApi.globalQueryBankCities({
- payoutCurrency: businessForm.value.fieldData.payoutCurrency,
- country: businessForm.value.fieldData.country,
- });
- if (res.code === 200 && Array.isArray(res.data)) {
- field.availableDtos = res.data.map((item: any) => ({
- value: item.bankCitiesValue,
- valueId: item.bankCitiesKey,
- }));
- }
- } catch (e) {
- console.error("Error loading receiverBankCity data:", e);
- }
- }
- // Handle select fields
- if (field.fieldType === "select") {
- let rValue = globalForm.value[fieldName];
- const label = field.availableDtos?.find(
- (item: any) => item.valueId === rValue
- )?.value ?? null;
- globalForm.value[fieldName + "Value"] = label ?? fixedValue;
- }
- return { ...field, fixedValue };
- })
- );
- globalCurrenciesField.value = mergedFields;
- };
- // 选择的收款人
- const selectReceiver = (value: any) => {
- globalForm.value.receiver = value.value;
- const data = receiverUserList.value.find((item: any) => item.id === value.value);
- if (data) {
- globalForm.value = { ...globalForm.value, ...data };
- }
- nextTick(() => {
- // Validation can be triggered here if needed
- });
- };
- // 获取币种列表
- const getGlobalCurrenciesDropdown = () => {
- const res = cardStore.currencyList;
- globalCurrenciesDropdown.value = res || [];
- const data = _.cloneDeep(res);
- const payoutCurrencies = [...new Set(data.map((item: any) => item.payoutCurrency))];
- const array = payoutCurrencies.map((item) => {
- let list = data.filter((item2: any) => item === item2.payoutCurrency);
- let transferTypes = [...new Set(list.map((item: any) => item.transferTypeValue))];
- const types = transferTypes.map((type) => {
- const cur = list.find((item2: any) => item2.transferTypeValue === type);
- let list2 = list
- .filter((item2: any) => item2.transferTypeValue === type)
- .map((item2: any) => ({
- payoutMethodId: item2.payoutMethodId,
- payoutMethodValue: item2.payoutMethodValue,
- }));
- return { transferType: type, transferTypeId: cur.transferTypeId, methods: list2 };
- });
- return { payoutCurrency: item, types };
- });
- currencyList.value = array;
- globalForm.value.payoutCurrency = currency.value
- };
- // 提交订单
- const saveDlobal = async () => {
- const isValid = await globalFormRef.value.validateForm();
- console.log(isValid);
- if (!isValid) {
- return;
- }
- try {
- if (!globalForm.value.deductionAccount) {
- showToast(t('placeholder.choose'));
- return;
- }
- const [cardNumber, deductionAccountType] = globalForm.value.deductionAccount.split(",");
- const otherData = {};
- globalCurrenciesField.value
- .map((item) => ({
- fieldName: item.fieldName,
- fieldType: item.fieldType,
- }))
- .forEach((item) => {
- otherData[item.fieldName] = globalForm.value[item.fieldName];
- if (item.fieldType === "select") {
- const key = item.fieldName + 'Value';
- otherData[key] = globalForm.value[key];
- }
- });
- const params = {
- ...otherData,
- cardNumber,
- amount: globalForm.value.amount,
- deductionAccountType,
- uniqueId: businessForm.value.uniqueId,
- ...businessForm.value.exchangeRate,
- };
- const res = await ucardApi.globalOrdersCreate({ ...params });
- if (res.code === 200) {
- showToast(res.msg);
- backActivity();
- } else {
- showToast(res.msg);
- }
- } catch (error: any) {
- console.error("Error submitting order:", error);
- showToast(error.message || t('common.error'));
- }
- };
- // 收款人list
- const globalReceiverUserList = async ({ uniqueId }: any) => {
- try {
- const res = await ucardApi.globalReceiverUserList({ uniqueId });
- if (res.code === 200) {
- receiverUserList.value = res.data;
- } else {
- showToast(res.msg);
- }
- } catch (error) {
- console.error("Error fetching receiver list:", error);
- showToast(t('common.error'));
- }
- };
- // 付款账户下拉
- const getAccountDropdown = async () => {
- try {
- const res = await ucardApi.cardAccountDropdown();
- if (res.code === 200) {
- loginOptions.value = res.data.map((item: any) => {
- if (item.type === "1") {
- item.text = `${t("global.GlobalOrder.cardNo")} - ${item.cardNumber} ${t("global.GlobalOrder.bal")}: ${item.balance}`;
- } else {
- item.text = `${t("global.GlobalOrder.bagBal")}: ${item.balance}`;
- }
- item.value = `${item.cardNumber},${item.type}`;
- item.disabled = item.balance === 0;
- return item;
- });
- } else {
- showToast(res.msg);
- }
- } catch (error) {
- console.error("Error fetching account dropdown:", error);
- showToast(t('common.error'));
- }
- };
- onMounted(async () => {
- businessForm.value = userStore.userInfo;
- await getAccountDropdown();
- getGlobalCurrenciesDropdown();
- globalReceiverUserList(businessForm.value);
- });
- </script>
- <style lang="scss" scoped>
- @import "@/uni.scss";
- .form-section {
- margin-bottom: px2rpx(20);
- }
- .section-title {
- font-size: px2rpx(16);
- font-weight: bold;
- margin-bottom: px2rpx(15);
- display: block;
- }
- .form-item {
- margin-bottom: px2rpx(15);
- }
- .form-label {
- font-size: var(--font-size-16);
- line-height: px2rpx(24);
- letter-spacing: px2rpx(1);
- color: #474747;
- margin-bottom: px2rpx(4);
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- display: flex;
- align-items: center;
- .required-mark {
- color: red;
- }
- }
- .quota-tip {
- font-size: px2rpx(12);
- color: #999;
- margin-left: px2rpx(5);
-
- }
- .form-error {
- color: #ff0000;
- font-size: px2rpx(12);
- margin-top: px2rpx(5);
- display: block;
- }
- .fee-text {
- font-size: px2rpx(12);
- color: #666;
- margin-top: px2rpx(5);
- display: block;
- }
- .tips-section {
- margin: px2rpx(20) 0;
- }
- .tips {
- background-color: #f5f5f5;
- padding: px2rpx(15);
- border-radius: px2rpx(8);
- }
- .tips .title {
- font-weight: bold;
- margin-bottom: px2rpx(16);
- display: block;
- }
- .tips text {
- display: block;
- margin-bottom: px2rpx(10);
- font-size: px2rpx(13);
- color: #666;
- line-height: px2rpx(20);
- }
- .submit-section {
- margin: px2rpx(20) 0;
- }
- .submit-btn {
- width: 100%;
- }
- </style>
|