개체분석 상태 값 수정
This commit is contained in:
@@ -1,43 +1,40 @@
|
||||
'use client'
|
||||
|
||||
import { useSearchParams, useParams, useRouter } from "next/navigation"
|
||||
import { AuthGuard } from "@/components/auth/auth-guard"
|
||||
import { CowNumberDisplay } from "@/components/common/cow-number-display"
|
||||
import { AppSidebar } from "@/components/layout/app-sidebar"
|
||||
import { SiteHeader } from "@/components/layout/site-header"
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import { useMediaQuery } from "@/hooks/use-media-query"
|
||||
import { ComparisonAveragesDto, TraitComparisonAveragesDto, cowApi, genomeApi, geneApi, GeneDetail, GenomeRequestDto, mptApi, MptDto } from "@/lib/api"
|
||||
import { CowDetail } from "@/types/cow.types"
|
||||
import { GenomeTrait } from "@/types/genome.types"
|
||||
import { useGlobalFilter } from "@/contexts/GlobalFilterContext"
|
||||
import {
|
||||
ArrowLeft,
|
||||
ArrowUp,
|
||||
BarChart3,
|
||||
CheckCircle2,
|
||||
Download,
|
||||
Dna,
|
||||
Activity,
|
||||
X,
|
||||
XCircle,
|
||||
Search,
|
||||
} from 'lucide-react'
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { useGlobalFilter } from "@/contexts/GlobalFilterContext"
|
||||
import { useMediaQuery } from "@/hooks/use-media-query"
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import { ComparisonAveragesDto, cowApi, geneApi, GeneDetail, genomeApi, GenomeRequestDto, TraitComparisonAveragesDto } from "@/lib/api"
|
||||
import { getInvalidMessage, getInvalidReason, isExcludedCow, isValidGenomeAnalysis } from "@/lib/utils/genome-analysis-config"
|
||||
import { CowDetail } from "@/types/cow.types"
|
||||
import { GenomeTrait } from "@/types/genome.types"
|
||||
import {
|
||||
Activity,
|
||||
ArrowLeft,
|
||||
BarChart3,
|
||||
CheckCircle2,
|
||||
ChevronUp,
|
||||
Dna,
|
||||
Search,
|
||||
X,
|
||||
XCircle
|
||||
} from 'lucide-react'
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation"
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { CategoryEvaluationCard } from "./genome/_components/category-evaluation-card"
|
||||
import { TraitComparison } from "./genome/_components/genome-integrated-comparison"
|
||||
import { NormalDistributionChart } from "./genome/_components/normal-distribution-chart"
|
||||
import { TraitDistributionCharts } from "./genome/_components/trait-distribution-charts"
|
||||
import { TraitComparison } from "./genome/_components/genome-integrated-comparison"
|
||||
import { CowNumberDisplay } from "@/components/common/cow-number-display"
|
||||
import { isValidGenomeAnalysis, getInvalidReason, getInvalidMessage } from "@/lib/utils/genome-analysis-config"
|
||||
import { AuthGuard } from "@/components/auth/auth-guard"
|
||||
import { MptTable } from "./reproduction/_components/mpt-table"
|
||||
|
||||
// 형질명 → 카테고리 매핑 (한우 35개 형질)
|
||||
const TRAIT_CATEGORY_MAP: Record<string, string> = {
|
||||
@@ -254,6 +251,74 @@ export default function CowOverviewPage() {
|
||||
const [geneSortBy, setGeneSortBy] = useState<'snpName' | 'chromosome' | 'position' | 'snpType' | 'allele1' | 'allele2' | 'remarks'>('snpName')
|
||||
const [geneSortOrder, setGeneSortOrder] = useState<'asc' | 'desc'>('asc')
|
||||
|
||||
// 부 KPN 배지 렌더링 (분석불가/일치/불일치)
|
||||
const renderSireBadge = (chipSireName: string | null | undefined, size: 'sm' | 'lg' = 'lg') => {
|
||||
const sizeClasses = size === 'lg'
|
||||
? 'gap-1.5 text-sm px-3 py-1.5'
|
||||
: 'gap-1 text-xs px-2 py-1'
|
||||
const iconSize = size === 'lg' ? 'w-4 h-4' : 'w-3 h-3'
|
||||
|
||||
// 분석불가 개체 먼저 체크 (EXCLUDED_COW_IDS 또는 DB에서 '분석불가'/'정보없음'으로 저장된 경우)
|
||||
if (isExcludedCow(cow?.cowId) || chipSireName === '분석불가' || chipSireName === '정보없음') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-slate-400 text-white font-semibold rounded-full shrink-0`}>
|
||||
<XCircle className={iconSize} />
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-primary text-primary-foreground font-semibold rounded-full shrink-0`}>
|
||||
<CheckCircle2 className={iconSize} />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-red-500 text-white font-semibold rounded-full shrink-0`}>
|
||||
<XCircle className={iconSize} />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 모 개체 배지 렌더링 (일치/불일치/이력제부재)
|
||||
const renderDamBadge = (chipDamName: string | null | undefined, size: 'sm' | 'lg' = 'lg') => {
|
||||
// 분석불가 개체는 어미 배지 표시 안 함
|
||||
if (isExcludedCow(cow?.cowId)) return null
|
||||
|
||||
const sizeClasses = size === 'lg'
|
||||
? 'gap-1.5 text-sm px-3 py-1.5'
|
||||
: 'gap-1 text-xs px-2 py-1'
|
||||
const iconSize = size === 'lg' ? 'w-4 h-4' : 'w-3 h-3'
|
||||
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-primary text-primary-foreground font-semibold rounded-full shrink-0`}>
|
||||
<CheckCircle2 className={iconSize} />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-red-500 text-white font-semibold rounded-full shrink-0`}>
|
||||
<XCircle className={iconSize} />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className={`flex items-center ${sizeClasses} bg-amber-500 text-white font-semibold rounded-full shrink-0`}>
|
||||
<XCircle className={iconSize} />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 유전자 데이터 지연 로드 함수
|
||||
const loadGeneData = async () => {
|
||||
if (geneDataLoaded || geneDataLoading) return // 이미 로드했거나 로딩 중이면 스킵
|
||||
@@ -264,10 +329,12 @@ export default function CowOverviewPage() {
|
||||
const geneList = geneDataResult || []
|
||||
setGeneData(geneList)
|
||||
setGeneDataLoaded(true)
|
||||
setHasGeneData(geneList.length > 0)
|
||||
} catch (geneErr) {
|
||||
console.error('유전자 데이터 조회 실패:', geneErr)
|
||||
setGeneData([])
|
||||
setGeneDataLoaded(true)
|
||||
setHasGeneData(false)
|
||||
} finally {
|
||||
setGeneDataLoading(false)
|
||||
}
|
||||
@@ -318,6 +385,11 @@ export default function CowOverviewPage() {
|
||||
}
|
||||
setCow(cowDetail)
|
||||
|
||||
// dataStatus에서 데이터 존재 여부 설정 (백엔드에서 가벼운 COUNT 쿼리로 확인)
|
||||
if (cowData.dataStatus) {
|
||||
setHasGeneData(cowData.dataStatus.hasGeneData)
|
||||
}
|
||||
|
||||
// 유전체 데이터 가져오기
|
||||
const genomeDataResult = await genomeApi.findByCowNo(cowNo)
|
||||
setGenomeData(genomeDataResult)
|
||||
@@ -333,9 +405,6 @@ export default function CowOverviewPage() {
|
||||
setGenomeRequest(null)
|
||||
}
|
||||
|
||||
// 유전자(SNP) 데이터는 탭 클릭 시 로드 (지연 로딩)
|
||||
setHasGeneData(true) // 탭은 보여주되, 데이터는 나중에 로드
|
||||
|
||||
// 번식능력 데이터 (현재는 목업 - 추후 API 연동)
|
||||
// TODO: 번식능력 API 연동
|
||||
setHasReproductionData(false)
|
||||
@@ -579,8 +648,8 @@ export default function CowOverviewPage() {
|
||||
>
|
||||
<Dna className="hidden sm:block h-6 w-6 shrink-0" />
|
||||
<span className="font-bold text-sm sm:text-xl">유전자</span>
|
||||
<span className={`text-xs sm:text-sm px-1.5 sm:px-2.5 py-0.5 sm:py-1 rounded font-semibold shrink-0 ${hasGeneData && isValidGenomeAnalysis(genomeRequest?.chipSireName, genomeRequest?.chipDamName, cow?.cowId) ? 'bg-green-500 text-white' : 'bg-slate-300 text-slate-600'}`}>
|
||||
{hasGeneData && isValidGenomeAnalysis(genomeRequest?.chipSireName, genomeRequest?.chipDamName, cow?.cowId) ? '완료' : '미검사'}
|
||||
<span className={`text-xs sm:text-sm px-1.5 sm:px-2.5 py-0.5 sm:py-1 rounded font-semibold shrink-0 ${hasGeneData && !(isExcludedCow(cow?.cowId) || genomeRequest?.chipSireName === '분석불가' || genomeRequest?.chipSireName === '정보없음') ? 'bg-green-500 text-white' : 'bg-slate-300 text-slate-600'}`}>
|
||||
{hasGeneData && !(isExcludedCow(cow?.cowId) || genomeRequest?.chipSireName === '분석불가' || genomeRequest?.chipSireName === '정보없음') ? '완료' : '미검사'}
|
||||
</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
@@ -695,30 +764,7 @@ export default function CowOverviewPage() {
|
||||
<span className="text-2xl font-bold text-foreground break-all">
|
||||
{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}
|
||||
</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-slate-400 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -731,34 +777,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-2xl font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-amber-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
// 정보없음(null/undefined)일 때는 배지 표시 안함
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -770,30 +789,7 @@ export default function CowOverviewPage() {
|
||||
<span className="text-base font-bold text-foreground break-all">
|
||||
{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}
|
||||
</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-slate-400 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
@@ -804,34 +800,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-base font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-amber-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
// 정보없음(null/undefined)일 때는 배지 표시 안함
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1062,30 +1031,7 @@ export default function CowOverviewPage() {
|
||||
</div>
|
||||
<div className="px-5 py-4 flex items-center justify-between gap-3">
|
||||
<span className="text-2xl font-bold text-foreground">{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-slate-400 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1098,34 +1044,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-2xl font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-amber-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
// 정보없음(null/undefined)일 때는 배지 표시 안함
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1135,30 +1054,7 @@ export default function CowOverviewPage() {
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">부 KPN</span>
|
||||
<div className="flex-1 px-4 py-3.5 flex items-center justify-between gap-2">
|
||||
<span className="text-base font-bold text-foreground">{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-slate-400 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
@@ -1169,34 +1065,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-base font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-amber-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
// 정보없음(null/undefined)일 때는 배지 표시 안함
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1333,30 +1202,7 @@ export default function CowOverviewPage() {
|
||||
<span className="text-2xl font-bold text-foreground break-all">
|
||||
{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}
|
||||
</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-slate-400 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -1369,33 +1215,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-2xl font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-primary text-primary-foreground text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-red-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1.5 bg-amber-500 text-white text-sm font-semibold px-3 py-1.5 rounded-full shrink-0">
|
||||
<XCircle className="w-4 h-4" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1407,30 +1227,7 @@ export default function CowOverviewPage() {
|
||||
<span className="text-base font-bold text-foreground break-all">
|
||||
{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}
|
||||
</span>
|
||||
{(() => {
|
||||
const chipSireName = genomeRequest?.chipSireName
|
||||
if (chipSireName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipSireName && chipSireName !== '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-slate-400 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<span>분석불가</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
})()}
|
||||
{renderSireBadge(genomeRequest?.chipSireName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
@@ -1441,33 +1238,7 @@ export default function CowOverviewPage() {
|
||||
) : (
|
||||
<span className="text-base font-bold text-foreground">-</span>
|
||||
)}
|
||||
{(() => {
|
||||
const chipDamName = genomeRequest?.chipDamName
|
||||
if (chipDamName === '일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-primary text-primary-foreground text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<CheckCircle2 className="w-3 h-3" />
|
||||
<span>일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '불일치') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-red-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>불일치</span>
|
||||
</span>
|
||||
)
|
||||
} else if (chipDamName === '이력제부재') {
|
||||
return (
|
||||
<span className="flex items-center gap-1 bg-amber-500 text-white text-xs font-semibold px-2 py-1 rounded-full shrink-0">
|
||||
<XCircle className="w-3 h-3" />
|
||||
<span>이력제부재</span>
|
||||
</span>
|
||||
)
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
})()}
|
||||
{renderDamBadge(genomeRequest?.chipDamName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1477,8 +1248,8 @@ export default function CowOverviewPage() {
|
||||
{/* 유전자 검색 및 필터 섹션 */}
|
||||
<h3 className="text-lg lg:text-xl font-bold text-foreground">유전자 분석 결과</h3>
|
||||
|
||||
{/* 친자확인 결과에 따른 분기 */}
|
||||
{isValidGenomeAnalysis(genomeRequest?.chipSireName, genomeRequest?.chipDamName, cow?.cowId) ? (
|
||||
{/* 유전자 탭 분기: 분석불가/정보없음만 차단, 불일치/이력제부재는 유전자 데이터 표시 */}
|
||||
{!(isExcludedCow(cow?.cowId) || genomeRequest?.chipSireName === '분석불가' || genomeRequest?.chipSireName === '정보없음') ? (
|
||||
<>
|
||||
<div className="flex flex-col gap-3 sm:gap-3 p-3.5 max-sm:p-3 sm:px-4 sm:py-3 rounded-xl bg-slate-50/50 border border-slate-200/50">
|
||||
{/* 검색창 */}
|
||||
@@ -1867,15 +1638,154 @@ export default function CowOverviewPage() {
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Card className="bg-slate-50 border border-border rounded-2xl">
|
||||
<CardContent className="p-8 text-center">
|
||||
<Dna className="h-12 w-12 text-muted-foreground mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-foreground mb-2">유전자 분석 데이터 없음</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
이 개체는 아직 유전자(SNP) 분석이 완료되지 않았습니다.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<>
|
||||
{/* 개체 정보 섹션 */}
|
||||
<h3 className="text-lg lg:text-xl font-bold text-foreground">개체 정보</h3>
|
||||
|
||||
<Card className="bg-white border border-border shadow-sm rounded-2xl overflow-hidden">
|
||||
<CardContent className="p-0">
|
||||
{/* 데스크탑: 가로 그리드 */}
|
||||
<div className="hidden lg:grid lg:grid-cols-4 divide-x divide-border">
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">개체번호</span>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<CowNumberDisplay cowId={cowNo} variant="highlight" className="text-2xl font-bold text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">생년월일</span>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<span className="text-2xl font-bold text-foreground">
|
||||
{cow?.cowBirthDt ? new Date(cow.cowBirthDt).toLocaleDateString('ko-KR') : '-'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">월령</span>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<span className="text-2xl font-bold text-foreground">
|
||||
{cow?.cowBirthDt
|
||||
? `${Math.floor((new Date().getTime() - new Date(cow.cowBirthDt).getTime()) / (1000 * 60 * 60 * 24 * 30.44))}개월`
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">분석일자</span>
|
||||
</div>
|
||||
<div className="px-5 py-4">
|
||||
<span className="text-2xl font-bold text-foreground">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 모바일: 좌우 배치 리스트 */}
|
||||
<div className="lg:hidden divide-y divide-border">
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">개체번호</span>
|
||||
<div className="flex-1 px-4 py-3.5">
|
||||
<CowNumberDisplay cowId={cowNo} variant="highlight" className="text-base font-bold text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">생년월일</span>
|
||||
<span className="flex-1 px-4 py-3.5 text-base font-bold text-foreground">
|
||||
{cow?.cowBirthDt ? new Date(cow.cowBirthDt).toLocaleDateString('ko-KR') : '-'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">월령</span>
|
||||
<span className="flex-1 px-4 py-3.5 text-base font-bold text-foreground">
|
||||
{cow?.cowBirthDt
|
||||
? `${Math.floor((new Date().getTime() - new Date(cow.cowBirthDt).getTime()) / (1000 * 60 * 60 * 24 * 30.44))}개월`
|
||||
: '-'}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">분석일자</span>
|
||||
<span className="flex-1 px-4 py-3.5 text-base font-bold text-foreground">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 혈통정보 섹션 */}
|
||||
<h3 className="text-lg lg:text-xl font-bold text-foreground">혈통정보</h3>
|
||||
|
||||
<Card className="bg-white border border-border shadow-sm rounded-2xl overflow-hidden">
|
||||
<CardContent className="p-0">
|
||||
{/* 데스크탑: 가로 그리드 */}
|
||||
<div className="hidden lg:grid lg:grid-cols-2 divide-x divide-border">
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">부 KPN번호</span>
|
||||
</div>
|
||||
<div className="px-5 py-4 flex items-center justify-between gap-3">
|
||||
<span className="text-2xl font-bold text-foreground">{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}</span>
|
||||
{renderSireBadge(genomeRequest?.chipSireName)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="bg-muted/50 px-5 py-3 border-b border-border">
|
||||
<span className="text-base font-semibold text-muted-foreground">모 개체번호</span>
|
||||
</div>
|
||||
<div className="px-5 py-4 flex items-center justify-between gap-3">
|
||||
{cow?.damCowId && cow.damCowId !== '0' ? (
|
||||
<CowNumberDisplay cowId={cow.damCowId} variant="highlight" className="text-2xl font-bold text-foreground" />
|
||||
) : (
|
||||
<span className="text-2xl font-bold text-foreground">-</span>
|
||||
)}
|
||||
{renderDamBadge(genomeRequest?.chipDamName)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 모바일: 세로 리스트 */}
|
||||
<div className="lg:hidden divide-y divide-border">
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">부 KPN</span>
|
||||
<div className="flex-1 px-4 py-3.5 flex items-center justify-between gap-2">
|
||||
<span className="text-base font-bold text-foreground">{cow?.sireKpn && cow.sireKpn !== '0' ? cow.sireKpn : '-'}</span>
|
||||
{renderSireBadge(genomeRequest?.chipSireName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<span className="w-28 shrink-0 bg-muted/50 px-4 py-3.5 text-base font-medium text-muted-foreground">모 개체번호</span>
|
||||
<div className="flex-1 px-4 py-3.5 flex items-center justify-between gap-2">
|
||||
{cow?.damCowId && cow.damCowId !== '0' ? (
|
||||
<CowNumberDisplay cowId={cow.damCowId} variant="highlight" className="text-base font-bold text-foreground" />
|
||||
) : (
|
||||
<span className="text-base font-bold text-foreground">-</span>
|
||||
)}
|
||||
{renderDamBadge(genomeRequest?.chipDamName, 'sm')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* 유전자 분석 결과 섹션 */}
|
||||
<h3 className="text-lg lg:text-xl font-bold text-foreground">유전자 분석 결과</h3>
|
||||
<Card className="bg-slate-100 border border-slate-300 rounded-2xl">
|
||||
<CardContent className="p-8 text-center">
|
||||
<Dna className="h-12 w-12 text-slate-400 mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-slate-700 mb-2">
|
||||
{genomeRequest ? '유전자 분석 불가' : '유전자 분석불가'}
|
||||
</h3>
|
||||
<p className="text-sm text-slate-500">
|
||||
{genomeRequest
|
||||
? getInvalidMessage(genomeRequest?.chipSireName, genomeRequest?.chipDamName, cow?.cowId).replace('유전체', '유전자')
|
||||
: '이 개체는 아직 유전자(SNP) 분석이 진행되지 않았습니다.'
|
||||
}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
@@ -1955,14 +1865,14 @@ export default function CowOverviewPage() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 플로팅 맨 위로 버튼 */}
|
||||
{/* 플로팅 맨 위로 버튼 - 글래스모피즘 */}
|
||||
{showScrollTop && (
|
||||
<button
|
||||
onClick={scrollToTop}
|
||||
className="fixed bottom-6 right-6 z-50 w-12 h-12 bg-primary text-white rounded-full shadow-lg hover:bg-primary/90 transition-all duration-300 flex items-center justify-center hover:scale-110 active:scale-95"
|
||||
className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-50 w-10 h-10 sm:w-12 sm:h-12 bg-white/80 backdrop-blur-md border border-white/50 text-slate-700 rounded-full shadow-lg hover:bg-white/90 transition-all duration-300 flex items-center justify-center hover:scale-110 active:scale-95"
|
||||
aria-label="맨 위로"
|
||||
>
|
||||
<ArrowUp className="w-6 h-6" />
|
||||
<ChevronUp className="w-5 h-5 sm:w-6 sm:h-6" />
|
||||
</button>
|
||||
)}
|
||||
</SidebarProvider>
|
||||
|
||||
@@ -16,7 +16,7 @@ const MPT_CATEGORIES = [
|
||||
{ name: '단백질 대사', items: ['totalProtein', 'albumin', 'globulin', 'agRatio', 'bun'], color: 'bg-muted/50' },
|
||||
{ name: '간기능', items: ['ast', 'ggt', 'fattyLiverIdx'], color: 'bg-muted/50' },
|
||||
{ name: '미네랄', items: ['calcium', 'phosphorus', 'caPRatio', 'magnesium'], color: 'bg-muted/50' },
|
||||
{ name: '기타', items: ['creatinine'], color: 'bg-muted/50' },
|
||||
{ name: '기타', items: ['creatine'], color: 'bg-muted/50' },
|
||||
]
|
||||
|
||||
// 측정값 상태 판정
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Badge } from "@/components/ui/badge"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import { cowApi, reproApi } from "@/lib/api"
|
||||
import { CowDetail } from "@/types/cow.types"
|
||||
import { ReproMpt } from "@/types/reprompt.types"
|
||||
import { ReproMpt } from "@/types/mpt.types"
|
||||
import { Activity, AlertCircle, CheckCircle } from "lucide-react"
|
||||
import { CowNavigation } from "../_components/navigation"
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
@@ -140,7 +140,7 @@ export default function ReproductionPage() {
|
||||
{ name: '인', value: reproMpt[0].phosphorus, fieldName: 'phosphorus' },
|
||||
{ name: '칼슘/인', value: reproMpt[0].caPRatio, fieldName: 'caPRatio' },
|
||||
{ name: '마그네슘', value: reproMpt[0].magnesium, fieldName: 'magnesium' },
|
||||
{ name: '크레아틴', value: reproMpt[0].creatinine, fieldName: 'creatinine' },
|
||||
{ name: '크레아틴', value: reproMpt[0].creatine, fieldName: 'creatine' },
|
||||
] : []
|
||||
|
||||
const normalItems = mptItems.filter(item => {
|
||||
|
||||
@@ -680,7 +680,7 @@ function MyCowContent() {
|
||||
<div className="flex flex-col gap-3 sm:gap-4">
|
||||
{/* 제목 */}
|
||||
<div>
|
||||
<h1 className="text-3xl max-sm:text-2xl font-bold text-slate-900">개체 목록</h1>
|
||||
<h1 className="text-3xl sm:text-3xl font-bold text-slate-900">개체 목록</h1>
|
||||
<p className="text-base max-sm:text-sm text-slate-500 mt-1">{'농장'} 보유 개체 현황</p>
|
||||
</div>
|
||||
|
||||
@@ -737,12 +737,12 @@ function MyCowContent() {
|
||||
{/* 필터 옵션들 - 모바일: 2행, 데스크톱: 1행 */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 sm:gap-4 border-t border-slate-200/70 pt-3 sm:pt-3">
|
||||
{/* 랭킹/정렬 그룹 */}
|
||||
<div className="grid grid-cols-3 sm:flex sm:items-center gap-2.5 max-sm:gap-2 sm:gap-2">
|
||||
<div className="grid grid-cols-3 sm:flex sm:items-center gap-2.5 max-sm:gap-1.5 sm:gap-2">
|
||||
<Select
|
||||
value={rankingMode}
|
||||
onValueChange={(value: 'gene' | 'genome') => setRankingMode(value)}
|
||||
>
|
||||
<SelectTrigger className="w-full sm:w-[120px] h-10 sm:h-9 text-sm border-slate-200 bg-white">
|
||||
<SelectTrigger className="w-full sm:w-[120px] h-10 sm:h-9 text-xs sm:text-sm px-2 sm:px-3 border-slate-200 bg-white">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -751,7 +751,7 @@ function MyCowContent() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={sortBy} onValueChange={setSortBy}>
|
||||
<SelectTrigger className="w-full sm:w-[110px] h-10 sm:h-9 text-sm border-slate-200 bg-white">
|
||||
<SelectTrigger className="w-full sm:w-[110px] h-10 sm:h-9 text-xs sm:text-sm px-2 sm:px-3 border-slate-200 bg-white">
|
||||
<SelectValue placeholder="정렬" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -765,7 +765,7 @@ function MyCowContent() {
|
||||
value={sortOrder}
|
||||
onValueChange={(value) => setSortOrder(value as 'asc' | 'desc')}
|
||||
>
|
||||
<SelectTrigger className="w-full sm:w-[120px] h-10 sm:h-9 text-sm border-slate-200 bg-white">
|
||||
<SelectTrigger className="w-full sm:w-[120px] h-10 sm:h-9 text-xs sm:text-sm px-2 sm:px-3 border-slate-200 bg-white">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -776,10 +776,10 @@ function MyCowContent() {
|
||||
</div>
|
||||
|
||||
{/* 표시항목 그룹 */}
|
||||
<div className="grid grid-cols-2 sm:flex sm:items-center gap-2.5 max-sm:gap-2 sm:gap-2">
|
||||
<div className="grid grid-cols-2 sm:flex sm:items-center gap-2.5 max-sm:gap-1.5 sm:gap-2">
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" className="h-10 sm:h-9 text-sm justify-between w-full sm:w-[100px] border-slate-200 bg-white">
|
||||
<Button variant="outline" className="h-10 sm:h-9 text-xs sm:text-sm px-2 sm:px-3 justify-between w-full sm:w-[100px] border-slate-200 bg-white">
|
||||
<span>유전자</span>
|
||||
<ChevronsUpDown className="ml-1 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
@@ -843,7 +843,7 @@ function MyCowContent() {
|
||||
</Popover>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" className="h-10 sm:h-9 text-sm justify-between w-full sm:w-[100px] border-slate-200 bg-white">
|
||||
<Button variant="outline" className="h-10 sm:h-9 text-xs sm:text-sm px-2 sm:px-3 justify-between w-full sm:w-[100px] border-slate-200 bg-white">
|
||||
<span>형질</span>
|
||||
<ChevronsUpDown className="ml-1 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
@@ -986,15 +986,15 @@ function MyCowContent() {
|
||||
year: '2-digit',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}) : (
|
||||
}) : cow.unavailableReason ? (
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold ${
|
||||
cow.unavailableReason?.includes('부') ? 'bg-red-100 text-red-700' :
|
||||
cow.unavailableReason?.includes('모') ? 'bg-orange-100 text-orange-700' :
|
||||
cow.unavailableReason.includes('부') ? 'bg-red-100 text-red-700' :
|
||||
cow.unavailableReason.includes('모') ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-slate-100 text-slate-600'
|
||||
}`}>
|
||||
{cow.unavailableReason || '분석불가'}
|
||||
{cow.unavailableReason}
|
||||
</span>
|
||||
)}
|
||||
) : '-'}
|
||||
</td>
|
||||
<td className="cow-table-cell border-r-2 border-r-gray-300 !py-2 !px-0.5">
|
||||
{(cow.genomeScore !== undefined && cow.genomeScore !== null) ? (
|
||||
@@ -1197,15 +1197,15 @@ function MyCowContent() {
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-muted-foreground">{cow.anlysDt ? '분석일' : '분석결과'}</span>
|
||||
<span className="font-medium">
|
||||
{cow.anlysDt ? new Date(cow.anlysDt).toLocaleDateString('ko-KR', { year: '2-digit', month: 'numeric', day: 'numeric' }) : (
|
||||
{cow.anlysDt ? new Date(cow.anlysDt).toLocaleDateString('ko-KR', { year: '2-digit', month: 'numeric', day: 'numeric' }) : cow.unavailableReason ? (
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold ${
|
||||
cow.unavailableReason?.includes('부') ? 'bg-red-100 text-red-700' :
|
||||
cow.unavailableReason?.includes('모') ? 'bg-orange-100 text-orange-700' :
|
||||
cow.unavailableReason.includes('부') ? 'bg-red-100 text-red-700' :
|
||||
cow.unavailableReason.includes('모') ? 'bg-orange-100 text-orange-700' :
|
||||
'bg-slate-100 text-slate-600'
|
||||
}`}>
|
||||
{cow.unavailableReason || '분석불가'}
|
||||
{cow.unavailableReason}
|
||||
</span>
|
||||
)}
|
||||
) : '-'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ const MPT_REFERENCE_VALUES: Record<string, { min: number; max: number; unit: str
|
||||
phosphorus: { min: 4.0, max: 7.5, unit: 'mg/dL', name: '인' },
|
||||
caPRatio: { min: 1.0, max: 2.0, unit: '', name: 'Ca/P 비율' },
|
||||
magnesium: { min: 1.8, max: 2.5, unit: 'mg/dL', name: '마그네슘' },
|
||||
creatinine: { min: 1.0, max: 2.0, unit: 'mg/dL', name: '크레아틴' },
|
||||
creatine: { min: 1.0, max: 2.0, unit: 'mg/dL', name: '크레아틴' },
|
||||
}
|
||||
|
||||
// 카테고리별 항목 그룹핑
|
||||
@@ -63,7 +63,7 @@ const MPT_CATEGORIES = [
|
||||
},
|
||||
{
|
||||
name: '미네랄',
|
||||
items: ['calcium', 'phosphorus', 'caPRatio', 'magnesium', 'creatinine'],
|
||||
items: ['calcium', 'phosphorus', 'caPRatio', 'magnesium', 'creatine'],
|
||||
color: 'bg-purple-500',
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user