feat: 更新 '@capp/eden' 依赖至 0.0.8,优化支付页面表单逻辑和数据处理
This commit is contained in:
@@ -1,24 +1,31 @@
|
||||
<script lang='ts' setup>
|
||||
import type { Treaty } from "@elysiajs/eden";
|
||||
import type { TreatyQuery } from "@/api/types";
|
||||
import type { TreatyBody } from "@/api/types";
|
||||
import { toastController } from "@ionic/vue";
|
||||
import { cardOutline, checkmarkCircleOutline, logoAlipay, personOutline } from "ionicons/icons";
|
||||
import zod from "zod";
|
||||
import { client, safeClient } from "@/api";
|
||||
|
||||
type Receipt = Treaty.Data<typeof client.api.receipt_method.get>["data"][number];
|
||||
type Receipt = TreatyBody<typeof client.api.receipt_method.post>;
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const paymentType = ref<"bank_card" | "alipay">("bank_card");
|
||||
|
||||
const form = ref<Receipt>({
|
||||
fullName: "",
|
||||
type: "bank_card",
|
||||
alipayAccount: "",
|
||||
alipayName: "",
|
||||
bankBranchName: "",
|
||||
bankCardNumber: "",
|
||||
bankName: "",
|
||||
});
|
||||
const isSubmitting = ref(false);
|
||||
const isEditMode = computed(() => !!route.query.id);
|
||||
|
||||
// 银行卡表单验证 Schema
|
||||
const BankSchema = zod.object({
|
||||
name: zod
|
||||
fullName: zod
|
||||
.string()
|
||||
.min(2, "请输入持卡人姓名")
|
||||
.max(20, "姓名长度不能超过20个字符"),
|
||||
@@ -28,12 +35,12 @@ const BankSchema = zod.object({
|
||||
.min(2, "请输入银行名称")
|
||||
.max(50, "银行名称长度不能超过50个字符"),
|
||||
|
||||
bankBranch: zod
|
||||
bankBranchName: zod
|
||||
.string()
|
||||
.min(2, "请输入开户行")
|
||||
.max(100, "开户行长度不能超过100个字符"),
|
||||
|
||||
cardNumber: zod
|
||||
bankCardNumber: zod
|
||||
.string()
|
||||
.min(1, "请输入银行卡号")
|
||||
.regex(/^\d{16,19}$/, "请输入正确的银行卡号(16-19位数字)"),
|
||||
@@ -41,12 +48,11 @@ const BankSchema = zod.object({
|
||||
|
||||
// 支付宝表单验证 Schema
|
||||
const AlipaySchema = zod.object({
|
||||
name: zod
|
||||
fullName: zod
|
||||
.string()
|
||||
.min(2, "请输入真实姓名")
|
||||
.max(20, "姓名长度不能超过20个字符"),
|
||||
|
||||
account: zod
|
||||
alipayAccount: zod
|
||||
.string()
|
||||
.min(1, "请输入支付宝账号")
|
||||
.refine(
|
||||
@@ -71,21 +77,30 @@ async function showToast(message: string, color: "success" | "danger" | "warning
|
||||
}
|
||||
|
||||
// 如果是编辑模式,加载数据
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
if (isEditMode.value) {
|
||||
const id = route.query.id as string;
|
||||
safeClient(client.api.receipt_method({ id }).get());
|
||||
const { data } = await safeClient(client.api.receipt_method({ id }).get());
|
||||
form.value = {
|
||||
fullName: data.value?.fullName,
|
||||
type: data.value?.type,
|
||||
alipayAccount: data.value?.alipayAccount || "",
|
||||
alipayName: data.value?.alipayName || "",
|
||||
bankBranchName: data.value?.bankBranchName || "",
|
||||
bankCardNumber: data.value?.bankCardNumber || "",
|
||||
bankName: data.value?.bankName || "",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
let result;
|
||||
|
||||
if (paymentType.value === "bank_card") {
|
||||
result = BankSchema.safeParse(bankFormData.value);
|
||||
if (form.value.type === "bank_card") {
|
||||
result = BankSchema.safeParse(form.value);
|
||||
}
|
||||
else {
|
||||
result = AlipaySchema.safeParse(alipayFormData.value);
|
||||
result = AlipaySchema.safeParse(form.value);
|
||||
}
|
||||
|
||||
if (!result.success) {
|
||||
@@ -96,17 +111,13 @@ async function handleSubmit() {
|
||||
|
||||
isSubmitting.value = true;
|
||||
try {
|
||||
// TODO: 调用添加/编辑收款方式 API
|
||||
if (isEditMode.value) {
|
||||
await safeClient(client.api.receipt_method.post({ ...formData, type: paymentType.value }));
|
||||
const id = route.query.id as string;
|
||||
await safeClient(client.api.receipt_method({ id }).patch({ ...form.value }));
|
||||
}
|
||||
else {
|
||||
await safeClient(client.api.payment.post({ ...formData, type: paymentType.value }));
|
||||
await safeClient(client.api.receipt_method.post({ ...form.value }));
|
||||
}
|
||||
|
||||
// 模拟 API 调用
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
await showToast(isEditMode.value ? "收款方式修改成功" : "收款方式添加成功", "success");
|
||||
router.back();
|
||||
}
|
||||
@@ -148,16 +159,16 @@ async function handleSubmit() {
|
||||
<div class="type-buttons">
|
||||
<div
|
||||
class="type-button"
|
||||
:class="{ active: paymentType === 'bank_card' }"
|
||||
@click="paymentType = 'bank_card'"
|
||||
:class="{ active: form.type === 'bank_card' }"
|
||||
@click="form.type = 'bank_card'"
|
||||
>
|
||||
<ion-icon :icon="cardOutline" class="type-icon" />
|
||||
<span>银行卡</span>
|
||||
</div>
|
||||
<div
|
||||
class="type-button"
|
||||
:class="{ active: paymentType === 'alipay' }"
|
||||
@click="paymentType = 'alipay'"
|
||||
:class="{ active: form.type === 'alipay' }"
|
||||
@click="form.type = 'alipay'"
|
||||
>
|
||||
<ion-icon :icon="logoAlipay" class="type-icon" />
|
||||
<span>支付宝</span>
|
||||
@@ -166,7 +177,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
|
||||
<!-- 银行卡表单 -->
|
||||
<div v-if="paymentType === 'bank_card'" class="form-card">
|
||||
<div v-if="form.type === 'bank_card'" class="form-card">
|
||||
<div class="space-y-4">
|
||||
<!-- 持卡人姓名 -->
|
||||
<div class="form-item">
|
||||
@@ -176,7 +187,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="bankFormData.name"
|
||||
v-model="form.fullName"
|
||||
type="text"
|
||||
placeholder="请输入持卡人姓名"
|
||||
class="custom-input"
|
||||
@@ -193,7 +204,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="bankFormData.bankName"
|
||||
v-model="form.bankName"
|
||||
type="text"
|
||||
placeholder="例如:中国工商银行"
|
||||
class="custom-input"
|
||||
@@ -210,7 +221,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="bankFormData.bankBranch"
|
||||
v-model="form.bankBranchName"
|
||||
type="text"
|
||||
placeholder="例如:北京朝阳支行"
|
||||
class="custom-input"
|
||||
@@ -227,7 +238,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="bankFormData.cardNumber"
|
||||
v-model="form.bankCardNumber"
|
||||
type="tel"
|
||||
placeholder="请输入银行卡号"
|
||||
class="custom-input"
|
||||
@@ -235,14 +246,6 @@ async function handleSubmit() {
|
||||
/>
|
||||
</ion-item>
|
||||
</div>
|
||||
|
||||
<!-- 设为默认 -->
|
||||
<div class="form-item">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="form-label">设为默认收款方式</label>
|
||||
<ion-toggle v-model="bankFormData.isDefault" color="danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -257,7 +260,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="alipayFormData.name"
|
||||
v-model="form.alipayName"
|
||||
type="text"
|
||||
placeholder="请输入支付宝实名姓名"
|
||||
class="custom-input"
|
||||
@@ -274,7 +277,7 @@ async function handleSubmit() {
|
||||
</div>
|
||||
<ion-item lines="none" class="input-item">
|
||||
<ion-input
|
||||
v-model="alipayFormData.account"
|
||||
v-model="form.alipayAccount"
|
||||
type="text"
|
||||
placeholder="请输入手机号或邮箱"
|
||||
class="custom-input"
|
||||
@@ -284,14 +287,6 @@ async function handleSubmit() {
|
||||
支持手机号或邮箱格式
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设为默认 -->
|
||||
<div class="form-item">
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="form-label">设为默认收款方式</label>
|
||||
<ion-toggle v-model="alipayFormData.isDefault" color="danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang='ts' setup>
|
||||
import type { Treaty } from "@elysiajs/eden";
|
||||
import { alertController, toastController } from "@ionic/vue";
|
||||
import { alertController, onIonViewWillEnter, toastController } from "@ionic/vue";
|
||||
import { addOutline, cardOutline, createOutline, logoAlipay, trashOutline } from "ionicons/icons";
|
||||
import { client, safeClient } from "@/api";
|
||||
|
||||
const router = useRouter();
|
||||
type Receipt = Treaty.Data<typeof client.api.receipt_method.get>["data"][number];
|
||||
|
||||
const { data } = await safeClient(client.api.receipt_method.get({ query: { offset: 0, limit: 20 } }));
|
||||
const { data, execute } = await safeClient(() => client.api.receipt_method.get({ query: { offset: 0, limit: 20 } }), { immediate: true });
|
||||
|
||||
async function showToast(message: string, color: "success" | "danger" | "warning" = "success") {
|
||||
const toast = await toastController.create({
|
||||
@@ -40,12 +40,9 @@ async function handleDelete(payment: Receipt) {
|
||||
text: "删除",
|
||||
role: "destructive",
|
||||
handler: async () => {
|
||||
const index = data.value?.data.findIndex(item => item.id === payment.id);
|
||||
if (index && index > -1) {
|
||||
data.value?.data.splice(index, 1);
|
||||
}
|
||||
await safeClient(client.api.receipt_method({ id: payment.id }).delete());
|
||||
await showToast("删除成功");
|
||||
await execute();
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -61,6 +58,10 @@ function getPaymentIcon(type: Receipt["type"]) {
|
||||
function getPaymentTypeName(type: Receipt["type"]) {
|
||||
return type === "bank_card" ? "银行卡" : "支付宝";
|
||||
}
|
||||
|
||||
onIonViewWillEnter(() => {
|
||||
execute();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -116,22 +117,34 @@ function getPaymentTypeName(type: Receipt["type"]) {
|
||||
</div>
|
||||
|
||||
<div class="payment-details">
|
||||
<div class="detail-row">
|
||||
<span class="label">姓名</span>
|
||||
<span class="value">{{ payment.fullName }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">账号</span>
|
||||
<span class="value">{{ payment.bankCardNumber || payment.alipayAccount }}</span>
|
||||
</div>
|
||||
<div v-if="payment.type === 'bank_card' && payment.bankName" class="detail-row">
|
||||
<span class="label">银行</span>
|
||||
<span class="value">{{ payment.bankName }}</span>
|
||||
</div>
|
||||
<div v-if="payment.type === 'bank_card' && payment.bankBranchName" class="detail-row">
|
||||
<span class="label">开户行</span>
|
||||
<span class="value">{{ payment.bankBranchName }}</span>
|
||||
</div>
|
||||
<template v-if="payment.type === 'bank_card'">
|
||||
<div class="detail-row">
|
||||
<span class="label">姓名</span>
|
||||
<span class="value">{{ payment.fullName }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">账号</span>
|
||||
<span class="value">{{ payment.bankCardNumber }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">银行</span>
|
||||
<span class="value">{{ payment.bankName }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">开户行</span>
|
||||
<span class="value">{{ payment.bankBranchName }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="detail-row">
|
||||
<span class="label">支付宝姓名</span>
|
||||
<span class="value">{{ payment.alipayName }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="label">账号</span>
|
||||
<span class="value">{{ payment.alipayAccount }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -228,7 +241,7 @@ function getPaymentTypeName(type: Receipt["type"]) {
|
||||
|
||||
.payment-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user