Files
riwa-ionic/src/views/trade-settings/bank-management/add.vue

187 lines
6.4 KiB
Vue

<script lang='ts' setup>
import type { GenericObject } from "vee-validate";
import { SelectChangeEventDetail, toastController } from "@ionic/vue";
import { toTypedSchema } from "@vee-validate/yup";
import { informationCircle, shieldCheckmark } from "ionicons/icons";
import { ErrorMessage, Field, Form } from "vee-validate";
import * as yup from "yup";
import { client, safeClient } from "@/api";
const { t } = useI18n();
const router = useRouter();
// 银行列表数据
const walletStore = useWalletStore();
const { supportBanks } = storeToRefs(walletStore);
const formInst = useTemplateRef<FormInstance>("formInst");
// 表单验证 Schema
const schema = toTypedSchema(
yup.object({
bankName: yup.string().required(t("bankCard.form.validation.bankRequired")),
accountNumber: yup
.string()
.required(t("bankCard.form.validation.accountNumberRequired")),
accountName: yup.string().required(t("bankCard.form.validation.accountNameRequired")),
}),
);
async function handleSubmit(values: GenericObject) {
try {
await safeClient(() => client.api.bank_account.post(values as any));
const toast = await toastController.create({
message: t("bankCard.messages.addSuccess"),
duration: 2000,
position: "bottom",
color: "success",
});
await toast.present();
router.back();
}
catch (error) {
console.error("添加银行卡失败:", error);
}
}
function handleBankChange(event: any) {
const item = event.detail.value;
const current = supportBanks.value.find(bank => bank.bankCode === item);
formInst.value?.setFieldValue("bankName", current?.nameCn);
formInst.value?.setFieldValue("swiftCode", current?.swiftCode);
formInst.value?.setFieldValue("bankCode", current?.bankCode);
}
// 格式化银行卡号显示
function formatCardNumber(value: string) {
if (!value)
return value;
const numbers = value.replace(/\D/g, "");
return numbers.replace(/(\d{4})(?=\d)/g, "$1 ");
}
</script>
<template>
<IonPage>
<ion-header>
<ion-toolbar class="ui-toolbar">
<ui-back-button slot="start" />
<ion-title>{{ t('bankCard.add') }}</ion-title>
</ion-toolbar>
</ion-header>
<IonContent :fullscreen="true">
<div class="min-h-full">
<div class="p-4">
<!-- 表单说明 -->
<div class="border border-blue-200 dark:border-blue-900 rounded-xl p-4 mb-6">
<div class="flex items-start gap-3">
<ion-icon
:icon="informationCircle"
class="text-blue-500 text-xl mt-0.5 shrink-0"
/>
<div class="text-sm text-blue-700 dark:text-blue-300">
<p class="font-medium mb-1">
{{ t('bankCard.form.tips.title') }}
</p>
<p class="leading-relaxed">
{{ t('bankCard.form.tips.description') }}
</p>
</div>
</div>
</div>
<Form ref="formInst" :validation-schema="schema" class="space-y-5" @submit="handleSubmit">
<div class="space-y-4">
<Field v-slot="{ field }" name="bankCode">
<ion-select class="ui-select" interface="action-sheet" toggle-icon="" v-bind="field" :label="t('bankCard.form.bankName')" :placeholder="t('bankCard.form.bankNamePlaceholder')" @ion-change="handleBankChange">
<ion-select-option v-for="item in supportBanks" :key="item.bankCode" :value="item.bankCode">
{{ item.nameCn }}
</ion-select-option>
</ion-select>
</Field>
<div>
<Field name="accountNumber">
<template #default="{ field }">
<ui-input-label
v-bind="field"
:label="t('bankCard.form.accountNumber')"
:placeholder="t('bankCard.form.accountNumberPlaceholder')"
type="text"
inputmode="numeric"
:maxlength="23"
:helper-text="t('bankCard.form.accountNumberHelper')"
required
@input="(e:any) => field.value = formatCardNumber(e.target.value)"
/>
</template>
</Field>
<ErrorMessage name="accountNumber" class="text-red-500 text-sm mt-1" />
</div>
<div>
<Field name="accountName">
<template #default="{ field }">
<ui-input-label
v-bind="field"
:label="t('bankCard.form.accountName')"
:placeholder="t('bankCard.form.accountNamePlaceholder')"
type="text"
:helper-text="t('bankCard.form.accountNameHelper')"
required
/>
</template>
</Field>
<ErrorMessage name="accountName" class="text-red-500 text-sm mt-1" />
</div>
<div class="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-xl p-4">
<div class="flex gap-3">
<ion-icon
:icon="shieldCheckmark"
class="text-amber-500 text-xl mt-0.5 shrink-0"
/>
<div class="text-sm text-amber-700 dark:text-amber-300">
<p class="font-medium mb-1">
{{ t('bankCard.form.security.title') }}
</p>
<ul class="space-y-1 text-xs leading-relaxed">
<li> {{ t('bankCard.form.security.encryption') }}</li>
<li> {{ t('bankCard.form.security.standard') }}</li>
<li> {{ t('bankCard.form.security.privacy') }}</li>
</ul>
</div>
</div>
</div>
<ion-button type="submit" expand="block">
{{ t('bankCard.form.submit') }}
</ion-button>
</div>
</Form>
</div>
</div>
</IonContent>
</IonPage>
</template>
<style scoped>
/* Tailwind CSS 处理所有样式 */
.ui-select {
--padding-start: 16px;
--padding-end: 16px;
border: 1px solid #d1d5db;
border-radius: 8px;
}
.ui-select.ion-invalid {
border-color: #ef4444;
}
.ion-palette-dark {
.ui-select {
border-color: #4b5563;
}
}
</style>