export const dynamic = 'force-dynamic'; import { NextRequest, NextResponse } from 'next/server'; import { supabase } from '@/lib/supabase'; import { determineKRStatus, determineProjectStatus } from '@/lib/kr-utils'; import type { KR, Checkin } from '@/types/database'; export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url); const krId = searchParams.get('kr_id'); const projectId = searchParams.get('project_id'); const userId = searchParams.get('user_id'); const limit = searchParams.get('limit'); let query = supabase .from('checkins') .select(` *, user:users(id, name, avatar_url), kr:krs(id, title, metric_name, unit) `) .order('created_at', { ascending: false }); if (krId) query = query.eq('kr_id', krId); if (projectId) query = query.eq('project_id', projectId); if (userId) query = query.eq('user_id', userId); if (limit) query = query.limit(parseInt(limit)); const { data, error } = await query; if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json(data); } export async function POST(request: NextRequest) { const body = await request.json(); const { kr_id, project_id, user_id, date, current_value, confidence, reason_code, note } = body; if (!kr_id || !project_id || current_value === undefined || confidence === undefined) { return NextResponse.json( { error: 'KR ID、项目ID、当前值和信心度为必填项' }, { status: 400 } ); } const { data: krData, error: krError } = await supabase .from('krs') .select('*') .eq('id', kr_id) .single(); if (krError || !krData) { return NextResponse.json({ error: 'KR不存在' }, { status: 404 }); } const kr = krData as KR; const { data: recentCheckins } = await supabase .from('checkins') .select('*') .eq('kr_id', kr_id) .order('created_at', { ascending: false }) .limit(2); const delta_value = current_value - kr.current_value; const updatedKR: KR = { ...kr, current_value, confidence, reason_code: reason_code || kr.reason_code, note: note || kr.note, }; const newStatus = determineKRStatus(updatedKR, (recentCheckins as Checkin[]) || []); if ((newStatus === 'yellow' || newStatus === 'red') && !reason_code) { return NextResponse.json( { error: '黄色或红色状态必须提供原因代码' }, { status: 400 } ); } const checkinDate = date || new Date().toISOString().split('T')[0]; const { data: checkin, error: checkinError } = await supabase .from('checkins') .insert({ kr_id, project_id, user_id, date: checkinDate, current_value, delta_value, confidence, status_snapshot: newStatus, reason_code, note, }) .select() .single(); if (checkinError) { return NextResponse.json({ error: checkinError.message }, { status: 500 }); } await supabase .from('krs') .update({ current_value, confidence, status: newStatus, reason_code: reason_code || (newStatus === 'green' ? null : kr.reason_code), note: note || kr.note, updated_at: new Date().toISOString(), }) .eq('id', kr_id); const { data: projectKRs } = await supabase .from('krs') .select('status') .eq('project_id', project_id); if (projectKRs) { const projectStatus = determineProjectStatus(projectKRs as KR[]); await supabase .from('projects') .update({ status: projectStatus, updated_at: new Date().toISOString() }) .eq('id', project_id); } return NextResponse.json(checkin, { status: 201 }); }