From 680da9b323db8b8d7cf27c674ab0016ec87bfe81 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 4 Nov 2025 07:48:00 +0000
Subject: (임수민) 구매 점검 테스트 요청사항 수정 (11/02)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../table/periodic-evaluation-finalize-dialogs.tsx | 109 +++++++++++++++++----
 1 file changed, 90 insertions(+), 19 deletions(-)

(limited to 'lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx')

diff --git a/lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx b/lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx
index 84651350..0e9efc8b 100644
--- a/lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx
+++ b/lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx
@@ -54,6 +54,37 @@ const calculateGrade = (score: number):  "A" | "B" | "C" | "D" => {
   return "D"
 }
 
+// 등급에 따른 점수 계산 (등급 변경 시 점수 자동 조정)
+const calculateScoreFromGrade = (grade: "A" | "B" | "C" | "D"): number => {
+  switch (grade) {
+    case "A":
+      return 95 // A등급 최소 점수
+    case "B":
+      return 90 // B등급 최소 점수
+    case "C":
+      return 60 // C등급 최소 점수
+    case "D":
+      return 0 // D등급은 0점으로 설정 (또는 30점 중간값)
+    default:
+      return 0
+  }
+}
+
+// 평가점수 계산 (evaluation-columns.tsx와 동일한 로직)
+const calculateEvaluationScore = (evaluation: PeriodicEvaluationView): number => {
+  const processScore = Number(evaluation.processScore || 0);
+  const priceScore = Number(evaluation.priceScore || 0);
+  const deliveryScore = Number(evaluation.deliveryScore || 0);
+  const selfEvaluationScore = Number(evaluation.selfEvaluationScore || 0);
+  const participationBonus = Number(evaluation.participationBonus || 0);
+  const qualityDeduction = Number(evaluation.qualityDeduction || 0);
+  
+  const totalScore = processScore + priceScore + deliveryScore + selfEvaluationScore;
+  const evaluationScore = totalScore + participationBonus - qualityDeduction;
+  
+  return evaluationScore;
+}
+
 // 개별 평가 스키마
 const evaluationItemSchema = z.object({
   id: z.number(),
@@ -61,8 +92,8 @@ const evaluationItemSchema = z.object({
   vendorCode: z.string(),
   evaluationScore: z.coerce.number().nullable(),
   finalScore: z.coerce.number()
-    .min(0, "점수는 0 이상이어야 합니다"),
-    // .max(100, "점수는 100 이하여야 합니다"),
+    .min(0, "점수는 0 이상이어야 합니다")
+    .max(100, "점수는 100 이하여야 합니다"),
   finalGrade: z.enum(["A", "B", "C", "D"]),
 })
 
@@ -103,14 +134,29 @@ export function FinalizeEvaluationDialog({
   // evaluations가 변경될 때 폼 초기화
   React.useEffect(() => {
     if (evaluations.length > 0) {
-      const formData = evaluations.map(evaluation => ({
-        id: evaluation.id,
-        vendorName: evaluation.vendorName || "",
-        vendorCode: evaluation.vendorCode || "",
-        evaluationScore: evaluation.evaluationScore ? Number(evaluation.evaluationScore) : null,
-        finalScore: Number(evaluation.evaluationScore || 0),
-        finalGrade: calculateGrade(Number(evaluation.evaluationScore || 0)),
-      }))
+      const formData = evaluations.map(evaluation => {
+        // 평가점수 계산 (참고용)
+        const evaluationScore = calculateEvaluationScore(evaluation);
+        
+        // 최종점수가 있으면 우선 사용, 없으면 평가점수 사용
+        const finalScoreValue = evaluation.finalScore 
+          ? Number(evaluation.finalScore) 
+          : (evaluationScore > 0 ? evaluationScore : 0);
+        
+        // 최종등급이 있으면 우선 사용, 없으면 점수 기반으로 계산
+        const finalGradeValue = evaluation.finalGrade 
+          ? evaluation.finalGrade 
+          : calculateGrade(finalScoreValue);
+        
+        return {
+          id: evaluation.id,
+          vendorName: evaluation.vendorName || "",
+          vendorCode: evaluation.vendorCode || "",
+          evaluationScore: evaluationScore > 0 ? evaluationScore : null,
+          finalScore: finalScoreValue,
+          finalGrade: finalGradeValue,
+        };
+      });
       
       form.reset({ evaluations: formData })
     }
@@ -118,13 +164,20 @@ export function FinalizeEvaluationDialog({
 
   // 점수 변경 시 등급 자동 계산
   const handleScoreChange = (index: number, score: number) => {
-    const currentEvaluation = form.getValues(`evaluations.${index}`)
     const newGrade = calculateGrade(score)
+    // form.setValue를 사용하여 리렌더링 최소화
+    form.setValue(`evaluations.${index}.finalGrade`, newGrade, { shouldValidate: false })
+  }
+
+  // 등급 변경 시 점수 자동 조정
+  const handleGradeChange = (index: number, grade: "A" | "B" | "C" | "D") => {
+    const currentEvaluation = form.getValues(`evaluations.${index}`)
+    const newScore = calculateScoreFromGrade(grade)
     
     update(index, {
       ...currentEvaluation,
-      finalScore: score,
-      finalGrade: newGrade,
+      finalScore: newScore,
+      finalGrade: grade,
     })
   }
 
@@ -230,14 +283,26 @@ export function FinalizeEvaluationDialog({
                                   min="0"
                                   max="100"
                                   step="0.1"
-                                  {...field}
+                                  value={field.value ?? ""}
                                   onChange={(e) => {
-                                    const value = parseFloat(e.target.value)
-                                    field.onChange(value)
-                                    if (!isNaN(value)) {
-                                      handleScoreChange(index, value)
+                                    const inputValue = e.target.value
+                                    if (inputValue === "" || inputValue === "-") {
+                                      field.onChange(0)
+                                    } else {
+                                      const numValue = Number(inputValue)
+                                      if (!isNaN(numValue)) {
+                                        // 입력 중에는 제한하지 않고, blur 시에만 제한 적용
+                                        field.onChange(numValue)
+                                      }
                                     }
                                   }}
+                                  onBlur={(e) => {
+                                    const value = Number(e.target.value)
+                                    const clampedValue = isNaN(value) ? 0 : Math.max(0, Math.min(100, value))
+                                    field.onChange(clampedValue)
+                                    handleScoreChange(index, clampedValue)
+                                    field.onBlur()
+                                  }}
                                   className="text-center font-mono"
                                 />
                               </FormControl>
@@ -254,7 +319,13 @@ export function FinalizeEvaluationDialog({
                           render={({ field }) => (
                             <FormItem>
                               <FormControl>
-                                <Select value={field.value} onValueChange={field.onChange}>
+                                <Select 
+                                  value={field.value} 
+                                  onValueChange={(value) => {
+                                    field.onChange(value as "A" | "B" | "C" | "D")
+                                    handleGradeChange(index, value as "A" | "B" | "C" | "D")
+                                  }}
+                                >
                                   <SelectTrigger>
                                     <SelectValue />
                                   </SelectTrigger>
-- 
cgit v1.2.3

