summaryrefslogtreecommitdiff
path: root/lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx')
-rw-r--r--lib/evaluation/table/periodic-evaluation-finalize-dialogs.tsx109
1 files changed, 90 insertions, 19 deletions
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>