From 90f79a7a691943a496f67f01c1e493256070e4de Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 7 Jul 2025 01:44:45 +0000
Subject: (대표님) 변경사항 20250707 10시 43분 - unstaged 변경사항 추가
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/evaluation/table/evaluation-details-dialog.tsx | 366 +++++++++++++++++++++
 1 file changed, 366 insertions(+)
 create mode 100644 lib/evaluation/table/evaluation-details-dialog.tsx

(limited to 'lib/evaluation/table/evaluation-details-dialog.tsx')

diff --git a/lib/evaluation/table/evaluation-details-dialog.tsx b/lib/evaluation/table/evaluation-details-dialog.tsx
new file mode 100644
index 00000000..df4ef016
--- /dev/null
+++ b/lib/evaluation/table/evaluation-details-dialog.tsx
@@ -0,0 +1,366 @@
+"use client"
+
+import * as React from "react"
+import { 
+  Eye, 
+  Building2, 
+  User, 
+  Calendar, 
+  CheckCircle2, 
+  Clock, 
+  MessageSquare,
+  Award,
+  FileText
+} from "lucide-react"
+
+import {
+  Dialog,
+  DialogContent,
+  DialogHeader,
+  DialogTitle,
+} from "@/components/ui/dialog"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
+import { Separator } from "@/components/ui/separator"
+import { Skeleton } from "@/components/ui/skeleton"
+import { PeriodicEvaluationView } from "@/db/schema"
+import { getEvaluationDetails, type EvaluationDetailData } from "../service"
+
+interface EvaluationDetailsDialogProps {
+  open: boolean
+  onOpenChange: (open: boolean) => void
+  evaluation: PeriodicEvaluationView | null
+}
+
+// 카테고리별 색상 매핑
+const getCategoryBadgeVariant = (category: string) => {
+  switch (category) {
+    case "quality":
+      return "default"
+    case "delivery": 
+      return "secondary"
+    case "price":
+      return "outline"
+    case "cooperation":
+      return "destructive"
+    default:
+      return "outline"
+  }
+}
+
+// 카테고리명 매핑
+const CATEGORY_LABELS = {
+  "customer-service": "CS",
+  administrator: "관리자", 
+  procurement: "구매",
+  design: "설계",
+  sourcing: "조달",
+  quality: "품질"
+} as const
+
+const CATEGORY_LABELS2 = {
+    bonus: "가점항목",
+    delivery: "납기", 
+    management: "경영현황",
+    penalty: "감점항목",
+    procurement: "구매",
+    quality: "품질"
+  } as const
+
+export function EvaluationDetailsDialog({
+  open,
+  onOpenChange,
+  evaluation,
+}: EvaluationDetailsDialogProps) {
+  const [isLoading, setIsLoading] = React.useState(false)
+  const [evaluationDetails, setEvaluationDetails] = React.useState<{
+    evaluationInfo: any
+    reviewerDetails: EvaluationDetailData[]
+  } | null>(null)
+
+  // 평가 상세 정보 로드
+  React.useEffect(() => {
+    if (open && evaluation?.id) {
+      const loadEvaluationDetails = async () => {
+        try {
+          setIsLoading(true)
+          const details = await getEvaluationDetails(evaluation.id)
+          setEvaluationDetails(details)
+        } catch (error) {
+          console.error("Failed to load evaluation details:", error)
+        } finally {
+          setIsLoading(false)
+        }
+      }
+
+      loadEvaluationDetails()
+    }
+  }, [open, evaluation?.id])
+
+  // 다이얼로그 닫을 때 데이터 리셋
+  React.useEffect(() => {
+    if (!open) {
+      setEvaluationDetails(null)
+    }
+  }, [open])
+
+  if (!evaluation) return null
+
+  return (
+    <Dialog open={open} onOpenChange={onOpenChange}>
+      <DialogContent className="max-w-7xl max-h-[90vh] overflow-y-auto">
+        <DialogHeader className="space-y-4">
+          <DialogTitle className="flex items-center gap-2">
+            <Eye className="h-5 w-5 text-blue-600" />
+            평가 상세
+          </DialogTitle>
+          
+          {/* 평가 기본 정보 */}
+          <Card>
+            <CardHeader>
+              <CardTitle className="flex items-center gap-2 text-lg">
+                <Building2 className="h-5 w-5" />
+                평가 정보
+              </CardTitle>
+            </CardHeader>
+            <CardContent>
+              <div className="flex flex-wrap items-center gap-6 text-sm">
+                {/* 협력업체 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">협력업체:</span>
+                  <span className="font-medium">{evaluation.vendorName}</span>
+                  <span className="text-muted-foreground">({evaluation.vendorCode})</span>
+                </div>
+
+                {/* 평가년도 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">년도:</span>
+                  <span className="font-medium">{evaluation.evaluationYear}년</span>
+                </div>
+
+                {/* 구분 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">구분:</span>
+                  <Badge variant="outline" className="text-xs">
+                    {evaluation.division === "PLANT" ? "해양" : "조선"}
+                  </Badge>
+                </div>
+
+                {/* 진행상태 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">상태:</span>
+                  <Badge variant="secondary" className="text-xs">{evaluation.status}</Badge>
+                </div>
+
+                {/* 평가점수/등급 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">평가점수/등급:</span>
+                  {evaluation.evaluationScore ? (
+                    <div className="flex items-center gap-1">
+                      <span className="font-bold text-blue-600">
+                        {Number(evaluation.evaluationScore).toFixed(1)}점
+                      </span>
+                      {evaluation.evaluationGrade && (
+                        <Badge variant="default" className="text-xs h-5">
+                          {evaluation.evaluationGrade}
+                        </Badge>
+                      )}
+                    </div>
+                  ) : (
+                    <span className="text-muted-foreground">-</span>
+                  )}
+                </div>
+
+                {/* 확정점수/등급 */}
+                <div className="flex items-center gap-2">
+                  <span className="text-muted-foreground">확정점수/등급:</span>
+                  {evaluation.finalScore ? (
+                    <div className="flex items-center gap-1">
+                      <span className="font-bold text-green-600">
+                        {Number(evaluation.finalScore).toFixed(1)}점
+                      </span>
+                      {evaluation.finalGrade && (
+                        <Badge variant="default" className="bg-green-600 text-xs h-5">
+                          {evaluation.finalGrade}
+                        </Badge>
+                      )}
+                    </div>
+                  ) : (
+                    <span className="text-muted-foreground">미확정</span>
+                  )}
+                </div>
+              </div>
+            </CardContent>
+          </Card>
+        </DialogHeader>
+
+        {isLoading ? (
+          <div className="space-y-4">
+            <Card>
+              <CardHeader>
+                <Skeleton className="h-6 w-48" />
+              </CardHeader>
+              <CardContent>
+                <Skeleton className="h-64 w-full" />
+              </CardContent>
+            </Card>
+          </div>
+        ) : evaluationDetails ? (
+          <div className="space-y-6">
+            {/* 통합 평가 테이블 */}
+            <Card>
+              <CardHeader>
+                <CardTitle className="flex items-center gap-2">
+                  <FileText className="h-5 w-5" />
+                  평가 상세 내역
+                </CardTitle>
+              </CardHeader>
+              <CardContent>
+                {evaluationDetails.reviewerDetails.some(r => r.evaluationItems.length > 0) ? (
+                  <Table>
+                    <TableHeader>
+                      <TableRow>
+                        <TableHead className="w-[120px]">담당자</TableHead>
+                        {/* <TableHead className="w-[80px]">상태</TableHead> */}
+                        <TableHead className="w-[100px]">평가부문</TableHead>
+                        <TableHead className="w-[100px]">항목</TableHead>
+                        <TableHead className="w-[150px]">구분</TableHead>
+                        <TableHead className="w-[200px]">범위</TableHead>
+                        <TableHead className="w-[200px]">선택옵션</TableHead>
+                        <TableHead className="w-[80px]">점수</TableHead>
+                        <TableHead className="min-w-[200px]">의견</TableHead>
+                      </TableRow>
+                    </TableHeader>
+                    <TableBody>
+                      {evaluationDetails.reviewerDetails.map((reviewer) =>
+                        reviewer.evaluationItems.map((item, index) => (
+                          <TableRow key={`${reviewer.reviewerEvaluationId}-${item.criteriaId}-${index}`}>
+                            <TableCell>
+                              <div className="space-y-1">
+                                <div className="font-medium text-sm">{reviewer.departmentName}</div>
+                                <div className="text-xs text-muted-foreground">
+                                  {reviewer.reviewerName}
+                                </div>
+                              </div>
+                            </TableCell>
+                            {/* <TableCell>
+                              {reviewer.isCompleted ? (
+                                <Badge variant="default" className="flex items-center gap-1">
+                                  <CheckCircle2 className="h-3 w-3" />
+                                  완료
+                                </Badge>
+                              ) : (
+                                <Badge variant="secondary" className="flex items-center gap-1">
+                                  <Clock className="h-3 w-3" />
+                                  진행중
+                                </Badge>
+                              )}
+                            </TableCell> */}
+                            <TableCell>
+                              <Badge variant={getCategoryBadgeVariant(item.category)}>
+                                {CATEGORY_LABELS[item.category as keyof typeof CATEGORY_LABELS] || item.category}
+                              </Badge>
+                            </TableCell>
+                            <TableCell>
+                                {CATEGORY_LABELS2[item.item as keyof typeof CATEGORY_LABELS2] || item.item}
+                            </TableCell>
+                            <TableCell className="font-medium">
+                              {item.classification}
+                            </TableCell>
+                            <TableCell className="text-sm">
+                              {item.range || "-"}
+                            </TableCell>
+                            <TableCell className="text-sm">
+                              {item.scoreType === "variable" ? (
+                                <Badge variant="outline">직접 입력</Badge>
+                              ) : (
+                                item.selectedDetail || "-"
+                              )}
+                            </TableCell>
+                            <TableCell>
+                              {item.score !== null ? (
+                                <Badge variant="default" className="font-mono">
+                                  {item.score.toFixed(1)}
+                                </Badge>
+                              ) : (
+                                <span className="text-muted-foreground">-</span>
+                              )}
+                            </TableCell>
+                            <TableCell className="text-sm">
+                              {item.comment || (
+                                <span className="text-muted-foreground">의견 없음</span>
+                              )}
+                            </TableCell>
+                          </TableRow>
+                        ))
+                      )}
+                    </TableBody>
+                  </Table>
+                ) : (
+                  <div className="text-center text-muted-foreground py-8">
+                    <FileText className="h-8 w-8 mx-auto mb-2" />
+                    <div>평가 항목이 없습니다</div>
+                  </div>
+                )}
+              </CardContent>
+            </Card>
+
+            {/* 리뷰어별 종합 의견 (있는 경우만) */}
+            {evaluationDetails.reviewerDetails.some(r => r.reviewerComment) && (
+              <Card>
+                <CardHeader>
+                  <CardTitle className="flex items-center gap-2">
+                    <MessageSquare className="h-5 w-5" />
+                    종합 의견
+                  </CardTitle>
+                </CardHeader>
+                <CardContent className="space-y-4">
+                  {evaluationDetails.reviewerDetails
+                    .filter(reviewer => reviewer.reviewerComment)
+                    .map((reviewer) => (
+                      <div key={reviewer.reviewerEvaluationId} className="space-y-2">
+                        <div className="flex items-center gap-2">
+                          <Badge variant="outline">{reviewer.departmentName}</Badge>
+                          <span className="text-sm font-medium">{reviewer.reviewerName}</span>
+                        </div>
+                        <div className="bg-muted p-3 rounded-md text-sm">
+                          {reviewer.reviewerComment}
+                        </div>
+                      </div>
+                    ))}
+                </CardContent>
+              </Card>
+            )}
+
+            {evaluationDetails.reviewerDetails.length === 0 && (
+              <Card>
+                <CardContent className="py-8">
+                  <div className="text-center text-muted-foreground">
+                    <User className="h-8 w-8 mx-auto mb-2" />
+                    <div>배정된 리뷰어가 없습니다</div>
+                  </div>
+                </CardContent>
+              </Card>
+            )}
+          </div>
+        ) : (
+          <Card>
+            <CardContent className="py-8">
+              <div className="text-center text-muted-foreground">
+                평가 상세 정보를 불러올 수 없습니다
+              </div>
+            </CardContent>
+          </Card>
+        )}
+
+        <div className="flex justify-end pt-4">
+          <Button variant="outline" onClick={() => onOpenChange(false)}>
+            닫기
+          </Button>
+        </div>
+      </DialogContent>
+    </Dialog>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

