fix: allow optional digital RMB code and inline payment password setup
This commit is contained in:
@@ -2744,6 +2744,16 @@ body {
|
||||
padding: 0 12px;
|
||||
outline: 0;
|
||||
}
|
||||
.m-withdraw-password-notice {
|
||||
margin: 16px 0;
|
||||
color: var(--m-muted);
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
.m-withdraw-confirm .m-withdraw-setup-btn,
|
||||
.m-withdraw-confirm .m-withdraw-back-btn {
|
||||
margin: 8px 0 14px;
|
||||
}
|
||||
|
||||
.m-finance-records {
|
||||
padding-inline: 0;
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
v-model.trim="bank.digital_rmb_code"
|
||||
inputmode="numeric"
|
||||
maxlength="32"
|
||||
placeholder="请输入数字编码"
|
||||
placeholder="请输入数字编码(选填)"
|
||||
/></label>
|
||||
<section class="m-qr-field">
|
||||
<h3>微信二维码</h3>
|
||||
@@ -276,16 +276,26 @@
|
||||
}
|
||||
async function saveBank() {
|
||||
error.value = '';
|
||||
if (
|
||||
!bank.holder_name ||
|
||||
!/^[1-9]\d{14}(?:\d{2}[\dXx])?$/.test(bank.identity_no.replace(/[ -]/g, '')) ||
|
||||
!/^[0-9 -]{8,36}$/.test(bank.account_no) ||
|
||||
!bank.bank_name ||
|
||||
!/^\d{6,32}$/.test(bank.digital_rmb_code.replace(/[ -]/g, '')) ||
|
||||
!bank.wechat_qr_attachment_id ||
|
||||
!bank.alipay_qr_attachment_id
|
||||
) {
|
||||
error.value = '请完整填写绑卡信息并上传微信、支付宝二维码';
|
||||
const identityNo = bank.identity_no.replace(/[ -]/g, '');
|
||||
const accountNo = bank.account_no.replace(/[ -]/g, '');
|
||||
const digitalRMBCode = bank.digital_rmb_code.replace(/[ -]/g, '');
|
||||
const validationError =
|
||||
bank.holder_name.length < 2
|
||||
? '请输入至少 2 个字符的姓名'
|
||||
: !/^[1-9]\d{14}(?:\d{2}[\dXx])?$/.test(identityNo)
|
||||
? '请输入正确的 15 位或 18 位身份证号'
|
||||
: !/^\d{8,32}$/.test(accountNo)
|
||||
? '请输入 8 至 32 位银行卡号'
|
||||
: bank.bank_name.length < 2
|
||||
? '请输入开户行'
|
||||
: digitalRMBCode && !/^\d{6,32}$/.test(digitalRMBCode)
|
||||
? '数字人民币编码须为 6 至 32 位数字,也可留空'
|
||||
: !bank.wechat_qr_attachment_id || !bank.alipay_qr_attachment_id
|
||||
? '请上传微信和支付宝二维码'
|
||||
: '';
|
||||
if (validationError) {
|
||||
error.value = validationError;
|
||||
window.$message?.error(validationError);
|
||||
return;
|
||||
}
|
||||
submitting.value = true;
|
||||
|
||||
@@ -47,12 +47,39 @@
|
||||
:trap-focus="false"
|
||||
@after-enter="focusTradePassword"
|
||||
>
|
||||
<form class="m-withdraw-confirm m-card" @submit.prevent="submitWithdrawal">
|
||||
<form v-if="showTradePasswordSetup" class="m-withdraw-confirm m-card" @submit.prevent="setTradePassword">
|
||||
<h2>设置支付密码</h2>
|
||||
<p class="m-withdraw-password-notice">设置完成后,请返回确认申请。</p>
|
||||
<label>
|
||||
<span>新支付密码</span>
|
||||
<input
|
||||
v-model="setupForm.newTradePassword"
|
||||
type="password"
|
||||
inputmode="numeric"
|
||||
maxlength="6"
|
||||
autocomplete="new-password"
|
||||
placeholder="请输入 6 位数字"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
<span>登录密码确认</span>
|
||||
<input
|
||||
v-model="setupForm.loginPassword"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
placeholder="请输入登录密码"
|
||||
/>
|
||||
</label>
|
||||
<p v-if="setupError" class="m-form-error">{{ setupError }}</p>
|
||||
<button class="m-primary-btn" :disabled="submitting">{{ submitting ? '设置中...' : '确认设置' }}</button>
|
||||
<button class="m-outline-btn m-withdraw-back-btn" type="button" @click="showTradePasswordSetup = false">返回确认申请</button>
|
||||
</form>
|
||||
<form v-else class="m-withdraw-confirm m-card" @submit.prevent="submitWithdrawal">
|
||||
<h2>确认取出</h2>
|
||||
<div><span>申请金额</span><b>{{ money(quote?.request_amount) }}</b></div>
|
||||
<div><span>手续费</span><b>{{ money(quote?.fee_amount) }}</b></div>
|
||||
<div><span>预计到账</span><strong>{{ money(quote?.actual_amount) }}</strong></div>
|
||||
<label>
|
||||
<label v-if="hasTradePassword">
|
||||
<span>支付密码</span>
|
||||
<input
|
||||
ref="tradePasswordInput"
|
||||
@@ -65,8 +92,10 @@
|
||||
placeholder="请输入 6 位支付密码"
|
||||
/>
|
||||
</label>
|
||||
<p v-else class="m-withdraw-password-notice">尚未设置支付密码,请先完成设置。</p>
|
||||
<button v-if="!hasTradePassword" class="m-outline-btn m-withdraw-setup-btn" type="button" @click="openTradePasswordSetup">去设置支付密码</button>
|
||||
<p v-if="actionError" class="m-form-error">{{ actionError }}</p>
|
||||
<button class="m-primary-btn" :disabled="submitting">确认申请</button>
|
||||
<button class="m-primary-btn" :disabled="submitting || !hasTradePassword">确认申请</button>
|
||||
</form>
|
||||
</n-modal>
|
||||
</section>
|
||||
@@ -78,7 +107,7 @@
|
||||
import { ChevronForwardOutline } from '@vicons/ionicons5';
|
||||
import PageHeader from '../components/PageHeader.vue';
|
||||
import AsyncState from '../components/AsyncState.vue';
|
||||
import { errorText, idempotencyKey, money, request } from '../api';
|
||||
import { MobileApiError, errorText, idempotencyKey, money, request } from '../api';
|
||||
import { mobileAssets } from '../assets';
|
||||
|
||||
const router = useRouter();
|
||||
@@ -90,9 +119,13 @@
|
||||
const accounts = ref<any[]>([]);
|
||||
const quote = ref<any>();
|
||||
const showConfirm = ref(false);
|
||||
const showTradePasswordSetup = ref(false);
|
||||
const setupError = ref('');
|
||||
const withdrawalKey = ref('');
|
||||
const tradePasswordInput = ref<HTMLInputElement>();
|
||||
const form = reactive({ paymentAccountId: 0, amountYuan: '', tradePassword: '' });
|
||||
const setupForm = reactive({ newTradePassword: '', loginPassword: '' });
|
||||
const hasTradePassword = computed(() => me.value?.has_trade_password === true);
|
||||
const selectedAccount = computed(() =>
|
||||
accounts.value.find((item) => item.id === form.paymentAccountId)
|
||||
);
|
||||
@@ -112,7 +145,44 @@
|
||||
}
|
||||
async function focusTradePassword() {
|
||||
await nextTick();
|
||||
tradePasswordInput.value?.focus();
|
||||
if (hasTradePassword.value && !showTradePasswordSetup.value) tradePasswordInput.value?.focus();
|
||||
}
|
||||
function openTradePasswordSetup() {
|
||||
setupError.value = '';
|
||||
actionError.value = '';
|
||||
setupForm.newTradePassword = '';
|
||||
setupForm.loginPassword = '';
|
||||
showTradePasswordSetup.value = true;
|
||||
}
|
||||
async function setTradePassword() {
|
||||
if (submitting.value) return;
|
||||
setupError.value = '';
|
||||
if (!/^\d{6}$/.test(setupForm.newTradePassword) || setupForm.loginPassword.length < 6) {
|
||||
setupError.value = '请输入 6 位数字支付密码及登录密码';
|
||||
return;
|
||||
}
|
||||
submitting.value = true;
|
||||
try {
|
||||
await request({
|
||||
url: '/v1/me/trade-password',
|
||||
method: 'PUT',
|
||||
data: {
|
||||
new_trade_password: setupForm.newTradePassword,
|
||||
login_password: setupForm.loginPassword,
|
||||
},
|
||||
});
|
||||
me.value = { ...me.value, has_trade_password: true };
|
||||
setupForm.newTradePassword = '';
|
||||
setupForm.loginPassword = '';
|
||||
form.tradePassword = '';
|
||||
showTradePasswordSetup.value = false;
|
||||
window.$message?.success('支付密码设置成功,请确认申请');
|
||||
await focusTradePassword();
|
||||
} catch (err) {
|
||||
setupError.value = errorText(err);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
async function load() {
|
||||
loading.value = true;
|
||||
@@ -152,6 +222,7 @@
|
||||
});
|
||||
withdrawalKey.value = idempotencyKey();
|
||||
form.tradePassword = '';
|
||||
showTradePasswordSetup.value = false;
|
||||
showConfirm.value = true;
|
||||
} catch (err) {
|
||||
actionError.value = errorText(err);
|
||||
@@ -161,6 +232,10 @@
|
||||
}
|
||||
async function submitWithdrawal() {
|
||||
if (!quote.value || submitting.value) return;
|
||||
if (!hasTradePassword.value) {
|
||||
actionError.value = '请先设置支付密码';
|
||||
return;
|
||||
}
|
||||
if (!/^\d{6}$/.test(form.tradePassword)) {
|
||||
actionError.value = '请输入 6 位支付密码';
|
||||
return;
|
||||
@@ -184,6 +259,9 @@
|
||||
await router.replace('/app/profile/records?tab=withdrawal');
|
||||
} catch (err) {
|
||||
actionError.value = errorText(err);
|
||||
if (err instanceof MobileApiError && err.reason === 'TRADE_PASSWORD_NOT_SET') {
|
||||
me.value = { ...me.value, has_trade_password: false };
|
||||
}
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user