feat: 更新 '@capp/eden' 依赖至 0.0.8,优化支付页面表单逻辑和数据处理

This commit is contained in:
2026-01-18 16:39:09 +07:00
parent 2e2386f437
commit 35efe8e178
4 changed files with 88 additions and 80 deletions

14
pnpm-lock.yaml generated
View File

@@ -52,8 +52,8 @@ catalogs:
specifier: 8.0.0
version: 8.0.0
'@capp/eden':
specifier: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz
version: 0.0.7
specifier: http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz
version: 0.0.8
'@cloudflare/workers-types':
specifier: ^4.20260113.0
version: 4.20260116.0
@@ -298,7 +298,7 @@ importers:
version: 8.0.0(@capacitor/core@8.0.0)
'@capp/eden':
specifier: 'catalog:'
version: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))
version: http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))
'@elysiajs/eden':
specifier: 'catalog:'
version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))
@@ -1182,9 +1182,9 @@ packages:
'@capacitor/synapse@1.0.4':
resolution: {integrity: sha512-/C1FUo8/OkKuAT4nCIu/34ny9siNHr9qtFezu4kxm6GY1wNFxrCFWjfYx5C1tUhVGz3fxBABegupkpjXvjCHrw==}
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz':
resolution: {tarball: http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz}
version: 0.0.7
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz':
resolution: {tarball: http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz}
version: 0.0.8
peerDependencies:
'@elysiajs/eden': ^1.4.6
@@ -6903,7 +6903,7 @@ snapshots:
'@capacitor/synapse@1.0.4': {}
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))':
'@capp/eden@http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz(@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)))':
dependencies:
'@elysiajs/eden': 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))

View File

@@ -18,7 +18,7 @@ catalog:
'@capacitor/keyboard': 8.0.0
'@capacitor/share': ^8.0.0
'@capacitor/status-bar': 8.0.0
'@capp/eden': http://192.168.1.2:9538/api/capp-eden-0.0.7.tgz
'@capp/eden': http://192.168.1.2:9538/api/capp-eden-0.0.8.tgz
'@cloudflare/workers-types': ^4.20260113.0
'@elysiajs/eden': ^1.4.6
'@faker-js/faker': ^10.2.0

View File

@@ -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>

View File

@@ -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">
<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 || payment.alipayAccount }}</span>
<span class="value">{{ payment.bankCardNumber }}</span>
</div>
<div v-if="payment.type === 'bank_card' && payment.bankName" class="detail-row">
<div 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">
<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;
}