|
@@ -20,6 +20,7 @@ const router = useRouter()
|
|
|
// Check auth status on mount
|
|
// Check auth status on mount
|
|
|
const checkingAuth = ref(true)
|
|
const checkingAuth = ref(true)
|
|
|
const loadingInfo = ref(true)
|
|
const loadingInfo = ref(true)
|
|
|
|
|
+const submitting = ref(false)
|
|
|
|
|
|
|
|
const checkAuthStatus = async (): Promise<boolean> => {
|
|
const checkAuthStatus = async (): Promise<boolean> => {
|
|
|
try {
|
|
try {
|
|
@@ -44,24 +45,26 @@ const checkAuthStatus = async (): Promise<boolean> => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const initPage = async (resetInput = false) => {
|
|
|
|
|
+ const ok = await checkAuthStatus()
|
|
|
|
|
+ if (!ok) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ loadingInfo.value = true
|
|
|
|
|
+ const info = await walletApi.getWithdrawInfo()
|
|
|
|
|
+ applyWithdrawInfo(info, resetInput)
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ console.error('Failed to fetch withdraw info:', error)
|
|
|
|
|
+ showToast({ message: t('wallet.withdraw.apply.toast.fetchInfoFailed') })
|
|
|
|
|
+ }
|
|
|
|
|
+ finally {
|
|
|
|
|
+ loadingInfo.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- (async () => {
|
|
|
|
|
- const ok = await checkAuthStatus()
|
|
|
|
|
- if (!ok) return
|
|
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- loadingInfo.value = true
|
|
|
|
|
- const info = await walletApi.getWithdrawInfo()
|
|
|
|
|
- applyWithdrawInfo(info)
|
|
|
|
|
- }
|
|
|
|
|
- catch (error) {
|
|
|
|
|
- console.error('Failed to fetch withdraw info:', error)
|
|
|
|
|
- showToast({ message: 'Failed to fetch withdraw info' })
|
|
|
|
|
- }
|
|
|
|
|
- finally {
|
|
|
|
|
- loadingInfo.value = false
|
|
|
|
|
- }
|
|
|
|
|
- })()
|
|
|
|
|
|
|
+ void initPage()
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const withdrawInfo = ref<WalletWithdrawInfoVo | null>(null)
|
|
const withdrawInfo = ref<WalletWithdrawInfoVo | null>(null)
|
|
@@ -126,7 +129,9 @@ const canInputBeans = computed(() => {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const beansPlaceholder = computed(() => {
|
|
const beansPlaceholder = computed(() => {
|
|
|
- return canInputBeans.value ? 'Please fill in' : '不满足最低提现金额'
|
|
|
|
|
|
|
+ return canInputBeans.value
|
|
|
|
|
+ ? t('wallet.withdraw.apply.input.placeholder')
|
|
|
|
|
+ : t('wallet.withdraw.apply.input.placeholderDisabled')
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const fromBeansMeasureText = computed(() => {
|
|
const fromBeansMeasureText = computed(() => {
|
|
@@ -135,7 +140,7 @@ const fromBeansMeasureText = computed(() => {
|
|
|
return v
|
|
return v
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-const applyWithdrawInfo = (info: WalletWithdrawInfoVo) => {
|
|
|
|
|
|
|
+const applyWithdrawInfo = (info: WalletWithdrawInfoVo, resetInput = false) => {
|
|
|
withdrawInfo.value = info
|
|
withdrawInfo.value = info
|
|
|
|
|
|
|
|
balanceBeans.value = Number(info.availableBeanAmount) || 0
|
|
balanceBeans.value = Number(info.availableBeanAmount) || 0
|
|
@@ -146,7 +151,7 @@ const applyWithdrawInfo = (info: WalletWithdrawInfoVo) => {
|
|
|
withdrawalFeePercent.value = Number(info.config?.feeRate) || 0
|
|
withdrawalFeePercent.value = Number(info.config?.feeRate) || 0
|
|
|
|
|
|
|
|
// If balance is below minimum, clear any existing input
|
|
// If balance is below minimum, clear any existing input
|
|
|
- if (!canInputBeans.value) {
|
|
|
|
|
|
|
+ if (resetInput || !canInputBeans.value) {
|
|
|
fromBeans.value = ''
|
|
fromBeans.value = ''
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -308,6 +313,7 @@ const calibrateWithdrawCalculate = async (beans: number) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const isSubmitDisabled = computed(() => {
|
|
const isSubmitDisabled = computed(() => {
|
|
|
|
|
+ if (checkingAuth.value || loadingInfo.value || submitting.value) return true
|
|
|
if (!canInputBeans.value) return true
|
|
if (!canInputBeans.value) return true
|
|
|
const v = Number(fromBeans.value)
|
|
const v = Number(fromBeans.value)
|
|
|
if (!fromBeans.value || !Number.isFinite(v) || v <= 0) return true
|
|
if (!fromBeans.value || !Number.isFinite(v) || v <= 0) return true
|
|
@@ -317,11 +323,16 @@ const isSubmitDisabled = computed(() => {
|
|
|
const tipText = computed(() => {
|
|
const tipText = computed(() => {
|
|
|
const minWithdrawalIdr = Number(withdrawInfo.value?.config?.minnum) || 0
|
|
const minWithdrawalIdr = Number(withdrawInfo.value?.config?.minnum) || 0
|
|
|
const feeText = withdrawFeeType.value === 0
|
|
const feeText = withdrawFeeType.value === 0
|
|
|
- ? `Withdrawal fee: ${idrFormat(withdrawalFeeAmount.value, { withSymbol: true })}`
|
|
|
|
|
- : `Withdrawal fee: ${withdrawalFeePercent.value}%`
|
|
|
|
|
|
|
+ ? t('wallet.withdraw.apply.fee.fixed', { fee: idrFormat(withdrawalFeeAmount.value, { withSymbol: true }) })
|
|
|
|
|
+ : t('wallet.withdraw.apply.fee.rate', { rate: withdrawalFeePercent.value })
|
|
|
const { bean, idr } = beanToIdrExchange.value
|
|
const { bean, idr } = beanToIdrExchange.value
|
|
|
|
|
|
|
|
- return `Exchange rate from Beans to IDR: ${bean}:${idr}, Minimum withdrawal amount: ${idrFormat(minWithdrawalIdr, { withSymbol: true })}, ${feeText}`
|
|
|
|
|
|
|
+ return t('wallet.withdraw.apply.tip', {
|
|
|
|
|
+ bean,
|
|
|
|
|
+ idr,
|
|
|
|
|
+ minAmount: idrFormat(minWithdrawalIdr, { withSymbol: true }),
|
|
|
|
|
+ feeText,
|
|
|
|
|
+ })
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const onBack = () => {
|
|
const onBack = () => {
|
|
@@ -391,16 +402,33 @@ const validateBeforeSubmit = (): boolean => {
|
|
|
return true
|
|
return true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const onSubmit = () => {
|
|
|
|
|
|
|
+const onSubmit = async () => {
|
|
|
if (!validateBeforeSubmit()) return
|
|
if (!validateBeforeSubmit()) return
|
|
|
- // Submit API is not provided in the spec; only do local validation for now.
|
|
|
|
|
|
|
+ if (submitting.value) return
|
|
|
|
|
+
|
|
|
|
|
+ const v = Number(fromBeans.value)
|
|
|
|
|
+ if (!Number.isFinite(v) || v <= 0) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ submitting.value = true
|
|
|
|
|
+ await walletApi.withdrawSubmit({ amount: Math.floor(v) })
|
|
|
|
|
+ showToast({ message: t('wallet.withdraw.apply.toast.submitSuccess') })
|
|
|
|
|
+ await initPage(true)
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ console.error('Failed to submit withdraw apply:', error)
|
|
|
|
|
+ // Error message is usually handled by request interceptor toast already
|
|
|
|
|
+ }
|
|
|
|
|
+ finally {
|
|
|
|
|
+ submitting.value = false
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
<template>
|
|
|
<div class="withdraw-apply-page">
|
|
<div class="withdraw-apply-page">
|
|
|
<CommonHeader
|
|
<CommonHeader
|
|
|
- title="Income Swap"
|
|
|
|
|
|
|
+ :title="t('wallet.withdraw.apply.title')"
|
|
|
:disable-default-back="true"
|
|
:disable-default-back="true"
|
|
|
@back="onBack"
|
|
@back="onBack"
|
|
|
/>
|
|
/>
|
|
@@ -444,7 +472,7 @@ const onSubmit = () => {
|
|
|
class="withdraw-apply-balance__all"
|
|
class="withdraw-apply-balance__all"
|
|
|
@click="onWithdrawAll"
|
|
@click="onWithdrawAll"
|
|
|
>
|
|
>
|
|
|
- 全部提现
|
|
|
|
|
|
|
+ {{ t('wallet.withdraw.apply.actions.withdrawAll') }}
|
|
|
</button>
|
|
</button>
|
|
|
</section>
|
|
</section>
|
|
|
|
|
|
|
@@ -452,7 +480,7 @@ const onSubmit = () => {
|
|
|
<section class="withdraw-apply-card">
|
|
<section class="withdraw-apply-card">
|
|
|
<div class="withdraw-apply-card__row withdraw-apply-card__row--top">
|
|
<div class="withdraw-apply-card__row withdraw-apply-card__row--top">
|
|
|
<p class="withdraw-apply-card__label">
|
|
<p class="withdraw-apply-card__label">
|
|
|
- From Beans
|
|
|
|
|
|
|
+ {{ t('wallet.withdraw.apply.labels.fromBeans') }}
|
|
|
</p>
|
|
</p>
|
|
|
|
|
|
|
|
<div class="withdraw-apply-card__right">
|
|
<div class="withdraw-apply-card__right">
|
|
@@ -486,7 +514,7 @@ const onSubmit = () => {
|
|
|
|
|
|
|
|
<div class="withdraw-apply-card__row withdraw-apply-card__row--bottom">
|
|
<div class="withdraw-apply-card__row withdraw-apply-card__row--bottom">
|
|
|
<p class="withdraw-apply-card__label">
|
|
<p class="withdraw-apply-card__label">
|
|
|
- To
|
|
|
|
|
|
|
+ {{ t('wallet.withdraw.apply.labels.to') }}
|
|
|
</p>
|
|
</p>
|
|
|
|
|
|
|
|
<div class="withdraw-apply-card__to">
|
|
<div class="withdraw-apply-card__to">
|
|
@@ -512,7 +540,7 @@ const onSubmit = () => {
|
|
|
:disabled="isSubmitDisabled"
|
|
:disabled="isSubmitDisabled"
|
|
|
@click="onSubmit"
|
|
@click="onSubmit"
|
|
|
>
|
|
>
|
|
|
- With Draw
|
|
|
|
|
|
|
+ {{ submitting ? t('wallet.withdraw.apply.submitting') : t('wallet.withdraw.apply.submit') }}
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|