diff --git a/src/app/api/projects/[id]/route.ts b/src/app/api/projects/[id]/route.ts new file mode 100644 index 0000000..37e3048 --- /dev/null +++ b/src/app/api/projects/[id]/route.ts @@ -0,0 +1,49 @@ +/** + * GET /api/projects/:id — 상세 정보 (년도, 구분, 유형, 연구기간, 특성화트랙, 지도교수, 연구실, 참여기업, 참여학생) + */ +import { prisma } from '@/lib/db'; +import { requireRole } from '@/lib/auth'; +import { ok, fail, handle } from '@/lib/http'; +import { maskName } from '@/lib/list-filters'; + +type Ctx = { params: { id: string } }; + +export async function GET(_req: Request, { params }: Ctx) { + return handle(async () => { + await requireRole('ADMIN'); + const it = await prisma.project.findUnique({ + where: { id: params.id }, + include: { + company: { select: { id: true, name: true } }, + lab: { select: { professorName: true, labName: true } }, + students: { include: { student: { select: { studentNo: true, nameMasked: true } } } }, + }, + }); + if (!it) return fail('프로젝트를 찾을 수 없습니다.', 404); + + const named = it.students + .filter((s) => !!s.student.nameMasked) + .map((s) => ({ studentNo: s.student.studentNo, nameMasked: s.student.nameMasked as string })); + const raws = it.studentNamesRaw + ? it.studentNamesRaw.split(',').filter(Boolean).map((n) => ({ studentNo: null, nameMasked: maskName(n) })) + : []; + + const row = { + id: it.id, + year: it.year, + dept: it.dept, + category: it.category, + type: it.type, + title: it.title, + period: it.period, + track: it.track, + professorName: it.lab?.professorName ?? null, + labName: it.lab?.labName ?? null, + companyId: it.company?.id ?? null, + companyName: it.company?.name ?? it.companyNameRaw ?? '-', + students: [...named, ...raws], + }; + + return ok(row); + }); +} diff --git a/src/app/students/[studentNo]/page.tsx b/src/app/students/[studentNo]/page.tsx index 433c3ae..8169e13 100644 --- a/src/app/students/[studentNo]/page.tsx +++ b/src/app/students/[studentNo]/page.tsx @@ -1,10 +1,27 @@ 'use client'; +import { useState } from 'react'; import { useRouter } from 'next/navigation'; import useSWR from 'swr'; import PageHeader from '@/components/PageHeader'; import type { StudentDetail, ProgramMap } from '@/lib/student-shape'; +type ProjectDetail = { + id: string; + year: number | null; + dept: string | null; + category: string | null; + type: string | null; + title: string | null; + period: string | null; + track: string | null; + professorName: string | null; + labName: string | null; + companyId: string | null; + companyName: string; + students: { studentNo: string | null; nameMasked: string }[]; +}; + function ProgramGrid({ title, data }: { title: string; data: ProgramMap }) { const entries = ['program1', 'program2', 'program3', 'program4', 'program5'] as (keyof ProgramMap)[]; return ( @@ -24,7 +41,11 @@ function ProgramGrid({ title, data }: { title: string; data: ProgramMap }) { export default function StudentDetailPage({ params }: { params: { studentNo: string } }) { const router = useRouter(); + const [selectedProjectId, setSelectedProjectId] = useState(null); const { data: s, isLoading } = useSWR(`/api/students/${params.studentNo}`); + const { data: projectDetail } = useSWR( + selectedProjectId ? `/api/projects/${selectedProjectId}` : null + ); if (isLoading && !s) return
불러오는 중…
; if (!s) return
학생을 찾을 수 없습니다.
; @@ -94,12 +115,12 @@ export default function StudentDetailPage({ params }: { params: { studentNo: str 연도과제명기간지도교수기업 {s.projects.map((p) => ( - + setSelectedProjectId(p.id)}> {p.year ?? '-'} {p.title || '-'} {p.period || '-'} {p.professorName || '-'} - {p.companyId ? router.push(`/companies/${p.companyId}`)}>{p.companyName} : {p.companyName}} + {p.companyId ? { e.stopPropagation(); router.push(`/companies/${p.companyId}`); }}>{p.companyName} : {p.companyName}} ))} @@ -128,6 +149,50 @@ export default function StudentDetailPage({ params }: { params: { studentNo: str )} + + {selectedProjectId && ( +
+
setSelectedProjectId(null)} /> +
+ {projectDetail ? ( + <> +

{projectDetail.title || '프로젝트 상세'}

+
+
연도{projectDetail.year ?? '-'}
+
구분{projectDetail.category || '-'}{projectDetail.dept ? ` · ${projectDetail.dept}` : ''}
+
유형{projectDetail.type || '-'}
+
연구기간{projectDetail.period || '-'}
+
특성화트랙{projectDetail.track || '-'}
+
지도교수{projectDetail.professorName || '-'}
+
연구실{projectDetail.labName || '-'}
+
참여기업 + {projectDetail.companyId + ? router.push(`/companies/${projectDetail.companyId}`)}>{projectDetail.companyName} + : projectDetail.companyName} +
+
+
+
참여학생 ({projectDetail.students.length}명)
+
+ {projectDetail.students.length + ? projectDetail.students.map((st, i) => ( + st.studentNo + ? { setSelectedProjectId(null); router.push(`/students/${st.studentNo}`); }}>{st.nameMasked} + : {st.nameMasked} + )) + : 기록 없음} +
+
+
+ +
+ + ) : ( +
불러오는 중…
+ )} +
+
+ )} ); }