import dbConnect from "../../lib/dbConnect"; import Prediction from "../../models/Prediction"; import { NextResponse } from "next/server"; import { setCORSHeaders, handleError } from "../../lib/apiUtils"; import { withAuth } from "../../middleware/authMiddleware"; export const GET = withAuth(async (request) => { await dbConnect(); try { const { searchParams } = new URL(request.url); const current = parseInt(searchParams.get("current") || "1"); const pageSize = parseInt(searchParams.get("pageSize") || "10"); const homeTeam = searchParams.get("homeTeam"); const awayTeam = searchParams.get("awayTeam"); const username = searchParams.get("username"); const type = searchParams.get("type"); // 新增type参数来筛选运动类型 let matchStage = {}; // 处理基础筛选条件 if (username) { matchStage.username = { $regex: username, $options: "i" }; } if (type) { matchStage.type = type; } // 处理其他搜索参数 for (const [key, value] of searchParams.entries()) { if ( ["current", "pageSize", "homeTeam", "awayTeam", "username", "type"].includes(key) ) continue; switch (key) { case "user": try { matchStage[key] = new mongoose.Types.ObjectId(value); } catch (error) { console.error(`Invalid ObjectId for user: ${value}`); } break; // 足球预测筛选 case "whoWillWin": matchStage["football.whoWillWin.prediction"] = value; break; case "firstTeamToScore": matchStage["football.firstTeamToScore.prediction"] = value; break; case "totalGoals": matchStage["football.totalGoals.prediction"] = parseInt(value); break; // 篮球预测筛选 case "spread": matchStage["basketball.spread.prediction"] = value; break; case "totalPoints": matchStage["basketball.totalPoints.prediction"] = value; break; default: matchStage[key] = { $regex: value, $options: "i" }; } } let pipeline = [ { $lookup: { from: "users", localField: "user", foreignField: "_id", as: "userInfo", }, }, { $unwind: { path: "$userInfo", preserveNullAndEmptyArrays: true } }, { $addFields: { username: "$userInfo.username", }, }, { $match: matchStage }, { $lookup: { from: "matches", localField: "match", foreignField: "_id", as: "matchDetails", }, }, { $unwind: { path: "$matchDetails", preserveNullAndEmptyArrays: true } }, { $addFields: { matchTime: { $concat: [ { $dateToString: { format: "%Y-%m-%d", date: "$matchDetails.date", }, }, " ", { $ifNull: ["$matchDetails.time", "00:00"] }, ], }, }, }, { $project: { userInfo: 0, }, }, { $sort: { matchTime: -1 } }, ]; if (homeTeam) { pipeline.push({ $match: { "matchDetails.homeTeam.name": homeTeam, }, }); } if (awayTeam) { pipeline.push({ $match: { "matchDetails.awayTeam.name": awayTeam, }, }); } const countPipeline = [...pipeline, { $count: "total" }]; const totalResult = await Prediction.aggregate(countPipeline); const totalCount = totalResult.length > 0 ? totalResult[0].total : 0; pipeline.push({ $skip: (current - 1) * pageSize }); pipeline.push({ $limit: pageSize }); const predictions = await Prediction.aggregate(pipeline); const validPredictions = []; const invalidPredictionIds = []; predictions.forEach((prediction) => { if (prediction.matchDetails) { const formattedPrediction = { matchId: prediction.matchDetails._id, ...prediction, match: undefined, matchDetails: undefined, homeTeam: prediction.matchDetails.homeTeam.name, awayTeam: prediction.matchDetails.awayTeam.name }; // 根据运动类型添加特定信息 if (prediction.type === "football") { formattedPrediction.score = `${prediction.matchDetails.homeTeamScore}:${prediction.matchDetails.awayTeamScore}`; } else if (prediction.type === "basketball") { formattedPrediction.score = `${prediction.matchDetails.homeTeamScore}-${prediction.matchDetails.awayTeamScore}`; } validPredictions.push(formattedPrediction); } else { invalidPredictionIds.push(prediction._id); } }); if (invalidPredictionIds.length > 0) { const deleteResult = await Prediction.deleteMany({ _id: { $in: invalidPredictionIds }, }); console.log(`Deleted ${deleteResult.deletedCount} invalid predictions.`); } const response = NextResponse.json({ success: true, total: totalCount - invalidPredictionIds.length, data: validPredictions, }); return setCORSHeaders(response); } catch (error) { console.error("Error in GET request:", error); return handleError(error); } }); export const POST = withAuth(async (request) => { await dbConnect(); try { const body = await request.json(); const { userId, predictions } = body; if (!userId) { return NextResponse.json( { success: false, error: "请先登录" }, { status: 400 } ); } if ( !predictions || !Array.isArray(predictions) || predictions.length === 0 ) { return NextResponse.json( { success: false, message: "Invalid data format" }, { status: 400 } ); } const createdPredictions = []; for (const pred of predictions) { const { matchId, type, football, basketball } = pred; const existingPrediction = await Prediction.findOne({ user: userId, match: matchId, }); const filter = { user: userId, match: matchId, }; if (existingPrediction) { // 更新预测 if (type === "football" && football) { if (football.whoWillWin) { existingPrediction.football.whoWillWin.prediction = football.whoWillWin.prediction; } if (football.firstTeamToScore) { existingPrediction.football.firstTeamToScore.prediction = football.firstTeamToScore.prediction; if (football.firstTeamToScore.firstTeamToScoreLogo) { existingPrediction.football.firstTeamToScore.firstTeamToScoreLogo = football.firstTeamToScore.firstTeamToScoreLogo; } } if (typeof football.totalGoals?.prediction === "number") { existingPrediction.football.totalGoals.prediction = football.totalGoals.prediction; } } else if (type === "basketball" && basketball) { if (basketball.whoWillWin) { existingPrediction.basketball.whoWillWin.prediction = basketball.whoWillWin.prediction; } if (basketball.spread) { existingPrediction.basketball.spread.prediction = basketball.spread.prediction; } if (basketball.totalPoints) { existingPrediction.basketball.totalPoints.prediction = basketball.totalPoints.prediction; } } // const updatedPrediction = await existingPrediction.save(); const updatedPrediction = await Prediction.findOneAndUpdate( filter, existingPrediction, { new: true, // 返回更新后的数据 upsert: false, // 不存在则不创建新记录 } ); createdPredictions.push(updatedPrediction); } else { // 创建新预测 const newPrediction = new Prediction({ user: userId, match: matchId, type, ...(type === "football" && football && { football: { whoWillWin: { prediction: football.whoWillWin.prediction }, firstTeamToScore: { prediction: football.firstTeamToScore.prediction, firstTeamToScoreLogo: football.firstTeamToScore.firstTeamToScoreLogo, }, totalGoals: { prediction: football.totalGoals.prediction }, }, }), ...(type === "basketball" && basketball && { basketball: { whoWillWin: { prediction: basketball.whoWillWin.prediction }, spread: { prediction: basketball.spread.prediction }, totalPoints: { prediction: basketball.totalPoints.prediction }, }, }), }); // const savedPrediction = await newPrediction.save(); const savedPrediction = await Prediction.findOneAndUpdate( filter, newPrediction, { new: true, // 返回更新后的数据 upsert: true, // 如果不存在则创建新记录 setDefaultsOnInsert: true, // 在插入新记录时,应用模式中的默认值 }); createdPredictions.push(savedPrediction); } } return NextResponse.json({ success: true, data: createdPredictions }); } catch (error) { return handleError(error); } }); export const PUT = withAuth(async (request) => { await dbConnect(); try { const { id, type, football, basketball, ...otherUpdateData } = await request.json(); if (!id) { return NextResponse.json( { success: false, error: "缺少预测ID" }, { status: 400 } ); } const updateData = { ...otherUpdateData, type, ...(type === "football" && football && { football: { whoWillWin: { prediction: football.whoWillWin.prediction }, firstTeamToScore: { prediction: football.firstTeamToScore.prediction, firstTeamToScoreLogo: football.firstTeamToScore.firstTeamToScoreLogo, }, totalGoals: { prediction: football.totalGoals.prediction }, }, }), ...(type === "basketball" && basketball && { basketball: { whoWillWin: { prediction: basketball.whoWillWin.prediction }, spread: { prediction: basketball.spread.prediction }, totalPoints: { prediction: basketball.totalPoints.prediction }, }, }), }; const updatedPrediction = await Prediction.findByIdAndUpdate( id, updateData, { new: true, runValidators: true, } ); if (!updatedPrediction) { return NextResponse.json( { success: false, error: "未找到指定预测" }, { status: 404 } ); } const response = NextResponse.json( { success: true, data: updatedPrediction }, { status: 200 } ); return setCORSHeaders(response); } catch (error) { console.error("更新预测数据时出错:", error); return handleError(error); } }); export const DELETE = withAuth(async (request) => { await dbConnect(); try { const url = new URL(request.url); const id = url.searchParams.get("id"); const ids = url.searchParams.get("ids"); if (!id && !ids) { return NextResponse.json( { success: false, error: "缺少预测ID" }, { status: 400 } ); } let deletedPredictions; let message; if (id) { deletedPredictions = await Prediction.findByIdAndDelete(id); message = deletedPredictions ? "预测已成功删除" : "未找到指定预测"; } else { const idArray = ids.split(","); deletedPredictions = await Prediction.deleteMany({ _id: { $in: idArray }, }); message = `成功删除 ${deletedPredictions.deletedCount} 条预测`; } if ( !deletedPredictions || (Array.isArray(deletedPredictions) && deletedPredictions.length === 0) ) { return setCORSHeaders( NextResponse.json( { success: false, error: "未找到指定预测" }, { status: 404 } ) ); } const response = NextResponse.json( { success: true, message: message }, { status: 200 } ); return setCORSHeaders(response); } catch (error) { console.error("删除预测数据时出错:", error); return handleError(error); } }); export async function OPTIONS() { const response = new NextResponse(null, { status: 204 }); return setCORSHeaders(response); }