finance-calculator/app/api/products/route.ts
2025-06-14 02:55:54 +08:00

180 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from "next/server"
import { auth } from "@/auth"
import { db } from "@/lib/db"
import { z } from "zod"
const createProductSchema = z.object({
principal: z.number().positive("本金必须大于0"),
depositDate: z.string().nullable().optional(),
endDate: z.string().nullable().optional(),
currentNetValue: z.number().nullable().optional(),
annualRate: z.number().nullable().optional(),
currency: z.string().default("RMB"),
notes: z.string().nullable().optional(),
}).refine((data) => {
// 如果有开始时间、结束时间、本金、当前净值,则不需要年化利率(会自动计算)
// 否则至少需要当前净值或年化利率中的一个
const hasCompleteInfo = data.depositDate && data.endDate && data.principal && data.currentNetValue
const hasEitherValue = data.currentNetValue !== null || data.annualRate !== null
return hasCompleteInfo || hasEitherValue
}, {
message: "请提供足够的信息:要么提供当前净值或年化利率,要么提供完整的时间和净值信息",
path: ["currentNetValue", "annualRate"]
})
export async function GET() {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}
const products = await db.financeProduct.findMany({
where: {
userId: session.user.id,
},
orderBy: {
createdAt: "desc",
},
})
return NextResponse.json(products)
} catch (error) {
console.error("Error fetching products:", error)
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
)
}
}
export async function POST(request: NextRequest) {
try {
const session = await auth()
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}
const body = await request.json()
console.log("Received request body:", body)
// 预处理数据将空字符串转换为null
const processedBody = {
...body,
currentNetValue: body.currentNetValue === "" || body.currentNetValue === null ? null : Number(body.currentNetValue),
annualRate: body.annualRate === "" || body.annualRate === null ? null : Number(body.annualRate),
principal: Number(body.principal),
depositDate: body.depositDate || null,
endDate: body.endDate || null,
currency: body.currency || "RMB",
notes: body.notes || null,
}
console.log("Processed request body:", processedBody)
const validatedData = createProductSchema.parse(processedBody)
console.log("Validated data:", validatedData)
// 计算相关字段
let calculatedValues = {
profit: null as number | null,
dailyProfit: null as number | null,
monthlyProfit: null as number | null,
calculatedAnnualRate: null as number | null,
averageAnnualProfit: null as number | null,
}
// 验证日期
let depositDate: Date | null = null
let endDate: Date | null = null
let days = 0
if (validatedData.depositDate && validatedData.endDate) {
depositDate = new Date(validatedData.depositDate)
endDate = new Date(validatedData.endDate)
if (isNaN(depositDate.getTime()) || isNaN(endDate.getTime())) {
return NextResponse.json(
{ error: "无效的日期格式" },
{ status: 400 }
)
}
days = Math.max(1, Math.floor((endDate.getTime() - depositDate.getTime()) / (1000 * 60 * 60 * 24)))
}
// 如果有当前净值,计算收益
if (validatedData.currentNetValue !== null && validatedData.currentNetValue !== undefined) {
calculatedValues.profit = validatedData.currentNetValue - validatedData.principal
}
// 自动计算年化利率(如果没有提供年化利率但有完整信息)
if (!validatedData.annualRate && validatedData.currentNetValue && depositDate && endDate && days > 0) {
const totalReturn = validatedData.currentNetValue - validatedData.principal
const dailyReturn = totalReturn / days
const annualReturn = (dailyReturn * 365) / validatedData.principal
validatedData.annualRate = annualReturn * 100 // 转换为百分比
console.log("Auto-calculated annual rate:", validatedData.annualRate)
}
// 如果有年化利率和日期,计算当前净值(当没有提供当前净值时)
if (validatedData.annualRate && depositDate && endDate && days > 0 && !validatedData.currentNetValue) {
const calculatedNetValue = validatedData.principal * (1 + ((validatedData.annualRate / 100) * days) / 365)
validatedData.currentNetValue = calculatedNetValue
calculatedValues.profit = calculatedNetValue - validatedData.principal
console.log("Auto-calculated net value:", validatedData.currentNetValue)
}
// 计算日收益和月收益
if (calculatedValues.profit !== null && days > 0) {
calculatedValues.dailyProfit = calculatedValues.profit / days
calculatedValues.monthlyProfit = calculatedValues.dailyProfit * 30
calculatedValues.calculatedAnnualRate = ((calculatedValues.dailyProfit * 365) / validatedData.principal) * 100
calculatedValues.averageAnnualProfit = calculatedValues.dailyProfit * 365
}
console.log("Calculated values:", calculatedValues)
const product = await db.financeProduct.create({
data: {
userId: session.user.id,
principal: validatedData.principal,
depositDate: depositDate,
endDate: endDate,
currentNetValue: validatedData.currentNetValue || null,
annualRate: validatedData.annualRate || null,
currency: validatedData.currency,
notes: validatedData.notes,
...calculatedValues,
},
})
console.log("Created product:", product)
return NextResponse.json(product)
} catch (error) {
console.error("Error in POST /api/products:", error)
if (error instanceof z.ZodError) {
console.error("Zod validation errors:", error.errors)
return NextResponse.json(
{
error: "数据验证失败",
details: error.errors.map(err => ({
field: err.path.join('.'),
message: err.message
}))
},
{ status: 400 }
)
}
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
)
}
}