|
| 1 | +'use server'; |
| 2 | + |
| 3 | +// 使用静态类型推断进行 TypeScript 优先模式验证 https://zod.dev/ |
| 4 | +import { z } from 'zod'; |
| 5 | +import { sql } from '@vercel/postgres'; |
| 6 | +import { revalidatePath } from 'next/cache'; |
| 7 | +import { redirect } from 'next/navigation'; |
| 8 | + |
| 9 | +const FormSchema = z.object({ |
| 10 | + id: z.string(), |
| 11 | + customerId: z.string({ |
| 12 | + invalid_type_error: 'Please select a customer.', |
| 13 | + }), |
| 14 | + amount: z.coerce.number().gt(0, { message: 'Please enter an amount greater than $0.' }), |
| 15 | + status: z.enum(['pending', 'paid'], { |
| 16 | + invalid_type_error: 'Please select an invoice status.', |
| 17 | + }), |
| 18 | + date: z.string(), |
| 19 | +}); |
| 20 | + |
| 21 | +const CreateInvoice = FormSchema.omit({ id: true, date: true }); |
| 22 | +const UpdateInvoice = FormSchema.omit({ id: true, date: true }); |
| 23 | + |
| 24 | +// 错误状态类型定义 |
| 25 | +export type State = { |
| 26 | + errors?: { |
| 27 | + customerId?: string[]; |
| 28 | + amount?: string[]; |
| 29 | + status?: string[]; |
| 30 | + }; |
| 31 | + message?: string | null; |
| 32 | +}; |
| 33 | + |
| 34 | +// 创建发票 |
| 35 | +export async function createInvoice(prevState: State, formData: FormData) { |
| 36 | + |
| 37 | + // const rawFormData1 = Object.fromEntries(formData.entries()) |
| 38 | + // console.log(rawFormData1); |
| 39 | + |
| 40 | + // Validate form using Zod |
| 41 | + // Zod parse()函数更改为safeParse()而不是parse() |
| 42 | + // safeParse()将返回一个包含success或error字段的对象。这将有助于更优雅地处理验证,而无需将此逻辑放入try/catch块中。 |
| 43 | + const validatedFields = CreateInvoice.safeParse({ |
| 44 | + customerId: formData.get('customerId'), |
| 45 | + amount: formData.get('amount'), |
| 46 | + status: formData.get('status'), |
| 47 | + }); |
| 48 | + |
| 49 | + console.log(validatedFields) |
| 50 | + // If form validation fails, return errors early. Otherwise, continue. |
| 51 | + // 在将信息发送到数据库之前,请检查表单字段是否已使用条件正确验证: |
| 52 | + if (!validatedFields.success) { |
| 53 | + return { |
| 54 | + errors: validatedFields.error.flatten().fieldErrors, |
| 55 | + message: 'Missing Fields. Failed to Create Invoice.', |
| 56 | + }; |
| 57 | + } |
| 58 | + // Prepare data for insertion into the database |
| 59 | + const { customerId, amount, status } = validatedFields.data; |
| 60 | + // 通常最好的做法是在数据库中存储以美分为单位的货币值,以消除 JavaScript 浮点错误并确保更高的准确性。让我们将金额转换为美分: |
| 61 | + const amountInCents = amount * 100; |
| 62 | + // 我们为发票的创建日期创建一个格式为“YYYY-MM-DD”的新日期: |
| 63 | + const date = new Date().toISOString().split('T')[0]; |
| 64 | + try { |
| 65 | + // Insert data into the database |
| 66 | + await sql`INSERT INTO invoices (customer_id, amount, status, date) VALUES (${customerId}, ${amountInCents}, ${status}, ${date})`; |
| 67 | + } catch (error) { |
| 68 | + return { |
| 69 | + // If a database error occurs, return a more specific error. |
| 70 | + message: 'Database Error: Failed to Create Invoice.', |
| 71 | + }; |
| 72 | + } |
| 73 | + // 由于您要更新发票路由中显示的数据,因此您希望清除此缓存并向服务器触发新请求。您可以使用 Next.js 中的revalidatePath函数来执行此操作: |
| 74 | + // 数据库更新后, /dashboard/invoices路径将重新验证,并从服务器获取新数据。 |
| 75 | + revalidatePath('/dashboard/invoices'); |
| 76 | + |
| 77 | + // 此时,您还希望将用户重定向回/dashboard/invoices页面。您可以使用 Next.js 中的redirect功能来执行此操作: |
| 78 | + redirect('/dashboard/invoices'); |
| 79 | +} |
| 80 | + |
| 81 | +// 更新发票 |
| 82 | +export async function updateInvoice(id: string, prevState: State, formData: FormData) { |
| 83 | + const validatedFields = UpdateInvoice.safeParse({ |
| 84 | + customerId: formData.get('customerId'), |
| 85 | + amount: formData.get('amount'), |
| 86 | + status: formData.get('status'), |
| 87 | + }); |
| 88 | + |
| 89 | + if (!validatedFields.success) { |
| 90 | + return { |
| 91 | + errors: validatedFields.error.flatten().fieldErrors, |
| 92 | + message: 'Missing Fields. Failed to Update Invoice.', |
| 93 | + }; |
| 94 | + } |
| 95 | + |
| 96 | + const { customerId, amount, status } = validatedFields.data; |
| 97 | + const amountInCents = amount * 100; |
| 98 | + |
| 99 | + try { |
| 100 | + await sql`UPDATE invoices SET customer_id = ${customerId}, amount = ${amountInCents}, status = ${status} WHERE id = ${id}`; |
| 101 | + } catch (error) { |
| 102 | + return { message: 'Database Error: Failed to Update Invoice.' }; |
| 103 | + } |
| 104 | + revalidatePath('/dashboard/invoices'); |
| 105 | + redirect('/dashboard/invoices'); |
| 106 | +} |
| 107 | + |
| 108 | +// 根据主键删除发票 |
| 109 | +export async function deleteInvoice(id: string) { |
| 110 | + throw new Error('Failed to Delete Invoice'); |
| 111 | + |
| 112 | + try { |
| 113 | + await sql`DELETE FROM invoices WHERE id = ${id}`; |
| 114 | + revalidatePath('/dashboard/invoices'); |
| 115 | + return { message: 'Deleted Invoice.' }; |
| 116 | + } catch (error) { |
| 117 | + return { message: 'Database Error: Failed to Delete Invoice.' }; |
| 118 | + } |
| 119 | +} |
0 commit comments