From 5f45b517fb0527ad4b6853e504d25e5b90645b49 Mon Sep 17 00:00:00 2001 From: chu eun ju Date: Fri, 12 Dec 2025 17:22:48 +0900 Subject: [PATCH] =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=B0=A8=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/genome/genome.service.ts | 14 +++++++++++--- .../_components/normal-distribution-chart.tsx | 14 ++++++++++++-- frontend/src/app/dashboard/page.tsx | 13 ++++++++++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/backend/src/genome/genome.service.ts b/backend/src/genome/genome.service.ts index 743ef4f..d7bacb8 100644 --- a/backend/src/genome/genome.service.ts +++ b/backend/src/genome/genome.service.ts @@ -594,9 +594,17 @@ export class GenomeService { let rank: number | null = null; const farmData = rankings.find(r => r.farmNo === farmNo); if (farmData) { - // 나보다 높은 점수를 가진 농장 수 + 1 = 내 순위 - const higherCount = rankings.filter(r => r.avgEbv > farmData.avgEbv).length; - rank = higherCount + 1; + // 등지방두께 등 낮을수록 좋은 형질은 순위 계산 반전 + const isNegativeTrait = NEGATIVE_TRAITS.includes(traitName); + if (isNegativeTrait) { + // 나보다 낮은 점수를 가진 농장 수 + 1 = 내 순위 (낮을수록 좋음) + const lowerCount = rankings.filter(r => r.avgEbv < farmData.avgEbv).length; + rank = lowerCount + 1; + } else { + // 나보다 높은 점수를 가진 농장 수 + 1 = 내 순위 (높을수록 좋음) + const higherCount = rankings.filter(r => r.avgEbv > farmData.avgEbv).length; + rank = higherCount + 1; + } } const percentile = rank !== null && totalFarms > 0 ? Math.round((rank / totalFarms) * 100) : null; diff --git a/frontend/src/app/cow/[cowNo]/genome/_components/normal-distribution-chart.tsx b/frontend/src/app/cow/[cowNo]/genome/_components/normal-distribution-chart.tsx index e2cf88a..608c8b8 100644 --- a/frontend/src/app/cow/[cowNo]/genome/_components/normal-distribution-chart.tsx +++ b/frontend/src/app/cow/[cowNo]/genome/_components/normal-distribution-chart.tsx @@ -18,6 +18,9 @@ import { import { genomeApi, TraitRankDto } from "@/lib/api/genome.api" import { useGlobalFilter } from "@/contexts/GlobalFilterContext" +// 낮을수록 좋은 형질 (부호 반전 필요) +const NEGATIVE_TRAITS = ['등지방두께'] + // 카테고리 색상 (모던 & 다이나믹 - 생동감 있는 색상) const CATEGORY_COLORS: Record = { '성장': '#3b82f6', // 블루 @@ -285,8 +288,15 @@ export function NormalDistributionChart({ // "내 개체 중심" 방식: 개체를 0에 고정 // 농가/보은군은 개체 대비 상대 위치로 표시 (음수 = 개체보다 뒤처짐) - const cowVsFarm = baseScore - baseFarmScore // 농가 대비 개체 차이 - const cowVsRegion = baseScore - baseRegionScore // 보은군 대비 개체 차이 + let cowVsFarm = baseScore - baseFarmScore // 농가 대비 개체 차이 + let cowVsRegion = baseScore - baseRegionScore // 보은군 대비 개체 차이 + + // 등지방두께 등 낮을수록 좋은 형질은 부호 반전 + // (개체가 농가보다 낮으면 실제로는 더 좋은 것이므로 양수로 표시) + if (NEGATIVE_TRAITS.includes(chartFilterTrait)) { + cowVsFarm = -cowVsFarm + cowVsRegion = -cowVsRegion + } return { score: 0, // 개체는 항상 0 (중심) diff --git a/frontend/src/app/dashboard/page.tsx b/frontend/src/app/dashboard/page.tsx index 66bf01b..34be54e 100644 --- a/frontend/src/app/dashboard/page.tsx +++ b/frontend/src/app/dashboard/page.tsx @@ -58,6 +58,9 @@ const TRAIT_CATEGORIES: Record = { '비율': ['안심rate', '등심rate', '채끝rate', '목심rate', '앞다리rate', '우둔rate', '설도rate', '사태rate', '양지rate', '갈비rate'], } +// 낮을수록 좋은 형질 (부호 반전 필요) +const NEGATIVE_TRAITS = ['등지방두께'] + export default function DashboardPage() { const router = useRouter() const { user } = useAuthStore() @@ -294,7 +297,15 @@ export default function DashboardPage() { if (traitData) { const farmEpd = traitData.avgEpd ?? 0 const regionEpd = traitData.regionAvgEpd ?? 0 - farmScore = farmEpd - regionEpd // 보은군 대비 차이 + let diff = farmEpd - regionEpd // 보은군 대비 차이 + + // 등지방두께 등 낮을수록 좋은 형질은 부호 반전 + // (농가가 보은군보다 낮으면 실제로는 더 좋은 것이므로 양수로 표시) + if (NEGATIVE_TRAITS.includes(distributionBasis)) { + diff = -diff + } + + farmScore = diff regionScore = 0 // 보은군 = 기준점 (0) originalFarmScore = farmEpd originalRegionScore = regionEpd