페이지 수정사항 반영

This commit is contained in:
2025-12-12 08:01:59 +09:00
parent 7d15c9be7c
commit dce58470b6
20 changed files with 1080 additions and 155 deletions

95
backend/check-data.js Normal file
View File

@@ -0,0 +1,95 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
// 1. 해당 개체의 형질 데이터 확인
const cowTraitsResult = await conn.query(
"SELECT trait_name, trait_ebv FROM tb_genome_trait_detail WHERE cow_id = 'KOR002191643715' AND del_dt IS NULL ORDER BY trait_name"
);
const cowTraits = cowTraitsResult.rows;
console.log('=== 개체 KOR002191643715 형질 데이터 ===');
console.log('형질수:', cowTraits.length);
let totalEbv = 0;
cowTraits.forEach(t => {
console.log(t.trait_name + ': ' + t.trait_ebv);
totalEbv += Number(t.trait_ebv || 0);
});
console.log('\n*** 내 개체 EBV 합계(선발지수):', totalEbv.toFixed(2));
// 2. 해당 개체의 농가 확인
const cowInfoResult = await conn.query(
"SELECT gr.fk_farm_no, f.farmer_name FROM tb_genome_request gr JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no LEFT JOIN tb_farm f ON gr.fk_farm_no = f.pk_farm_no WHERE c.cow_id = 'KOR002191643715' AND gr.del_dt IS NULL LIMIT 1"
);
const cowInfo = cowInfoResult.rows;
console.log('\n=== 농가 정보 ===');
console.log('농가번호:', cowInfo[0]?.fk_farm_no, '농장주:', cowInfo[0]?.farmer_name);
const farmNo = cowInfo[0]?.fk_farm_no;
// 3. 같은 농가의 모든 개체 EBV 합계
if (farmNo) {
const farmCowsResult = await conn.query(
`SELECT c.cow_id, SUM(gtd.trait_ebv) as total_ebv, COUNT(*) as trait_count
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.fk_farm_no = $1 AND gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35
ORDER BY total_ebv DESC`,
[farmNo]
);
const farmCows = farmCowsResult.rows;
console.log('\n=== 같은 농가 개체들 EBV 합계 (35형질 전체) ===');
console.log('개체수:', farmCows.length);
let farmSum = 0;
farmCows.forEach(c => {
console.log(c.cow_id + ': ' + Number(c.total_ebv).toFixed(2));
farmSum += Number(c.total_ebv);
});
if (farmCows.length > 0) {
console.log('\n*** 농가 평균:', (farmSum / farmCows.length).toFixed(2));
}
}
// 4. 전체 보은군 평균
const allCowsResult = await conn.query(
`SELECT c.cow_id, SUM(gtd.trait_ebv) as total_ebv
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35`
);
const allCows = allCowsResult.rows;
console.log('\n=== 보은군 전체 통계 ===');
console.log('개체수:', allCows.length);
let regionSum = 0;
allCows.forEach(c => regionSum += Number(c.total_ebv));
if (allCows.length > 0) {
console.log('*** 보은군 평균:', (regionSum / allCows.length).toFixed(2));
}
// 5. 최대/최소 확인
if (allCows.length > 0) {
const maxCow = allCows.reduce((max, c) => Number(c.total_ebv) > Number(max.total_ebv) ? c : max, allCows[0]);
const minCow = allCows.reduce((min, c) => Number(c.total_ebv) < Number(min.total_ebv) ? c : min, allCows[0]);
console.log('\n최대:', maxCow?.cow_id, Number(maxCow?.total_ebv).toFixed(2));
console.log('최소:', minCow?.cow_id, Number(minCow?.total_ebv).toFixed(2));
}
await conn.end();
}
main().catch(console.error);

97
backend/check-data2.js Normal file
View File

@@ -0,0 +1,97 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
// getComparisonAverages가 계산하는 방식 확인
// 농가 1번의 카테고리별 평균 EBV 계산
const farmNo = 1;
// 카테고리 매핑 (백엔드와 동일)
const TRAIT_CATEGORY_MAP = {
'12개월령체중': '성장',
'도체중': '생산', '등심단면적': '생산', '등지방두께': '생산', '근내지방도': '생산',
'체고': '체형', '십자': '체형', '체장': '체형', '흉심': '체형', '흉폭': '체형',
'고장': '체형', '요각폭': '체형', '곤폭': '체형', '좌골폭': '체형', '흉위': '체형',
'안심weight': '무게', '등심weight': '무게', '채끝weight': '무게', '목심weight': '무게',
'앞다리weight': '무게', '우둔weight': '무게', '설도weight': '무게', '사태weight': '무게',
'양지weight': '무게', '갈비weight': '무게',
'안심rate': '비율', '등심rate': '비율', '채끝rate': '비율', '목심rate': '비율',
'앞다리rate': '비율', '우둔rate': '비율', '설도rate': '비율', '사태rate': '비율',
'양지rate': '비율', '갈비rate': '비율',
};
// 농가 1번의 모든 형질 데이터 조회
const result = await conn.query(`
SELECT gtd.trait_name, gtd.trait_ebv
FROM tb_genome_trait_detail gtd
JOIN tb_genome_request gr ON gtd.fk_request_no = gr.pk_request_no
WHERE gr.fk_farm_no = $1
AND gtd.del_dt IS NULL
AND gtd.trait_ebv IS NOT NULL
`, [farmNo]);
const details = result.rows;
console.log('농가 1번 전체 형질 데이터 수:', details.length);
// 카테고리별로 합계 계산
const categoryMap = {};
for (const d of details) {
const category = TRAIT_CATEGORY_MAP[d.trait_name] || '기타';
if (!categoryMap[category]) {
categoryMap[category] = { sum: 0, count: 0 };
}
categoryMap[category].sum += Number(d.trait_ebv);
categoryMap[category].count += 1;
}
console.log('\n=== getComparisonAverages 방식 (카테고리별 평균) ===');
const categories = ['성장', '생산', '체형', '무게', '비율'];
let totalAvgEbv = 0;
for (const cat of categories) {
const data = categoryMap[cat];
const avgEbv = data ? data.sum / data.count : 0;
console.log(`${cat}: 합계=${data?.sum?.toFixed(2)} / 개수=${data?.count} = 평균 ${avgEbv.toFixed(2)}`);
totalAvgEbv += avgEbv;
}
console.log('\n*** farmAvgZ (카테고리 평균의 합/5):', (totalAvgEbv / categories.length).toFixed(2));
// getSelectionIndex 방식 비교
console.log('\n=== getSelectionIndex 방식 (개체별 합계의 평균) ===');
const farmCowsResult = await conn.query(`
SELECT c.cow_id, SUM(gtd.trait_ebv) as total_ebv, COUNT(*) as trait_count
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.fk_farm_no = $1 AND gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35
ORDER BY total_ebv DESC
`, [farmNo]);
const farmCows = farmCowsResult.rows;
let farmSum = 0;
farmCows.forEach(c => farmSum += Number(c.total_ebv));
const farmAvgScore = farmCows.length > 0 ? farmSum / farmCows.length : 0;
console.log(`개체수: ${farmCows.length}`);
console.log(`*** farmAvgScore (개체별 합계의 평균): ${farmAvgScore.toFixed(2)}`);
console.log('\n=================================================');
console.log('farmAvgZ (카테고리 방식):', (totalAvgEbv / categories.length).toFixed(2));
console.log('farmAvgScore (선발지수 방식):', farmAvgScore.toFixed(2));
console.log('=================================================');
await conn.end();
}
main().catch(console.error);

114
backend/check-data3.js Normal file
View File

@@ -0,0 +1,114 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
const farmNo = 1;
const cowId = 'KOR002191643715';
console.log('=======================================================');
console.log('대시보드 vs 개체상세 차트 비교');
console.log('=======================================================\n');
// =====================================================
// 1. 대시보드: getFarmRegionRanking API
// - 농가 평균 = 농가 내 개체들의 선발지수 평균
// - 보은군 평균 = 전체 개체들의 선발지수 평균
// =====================================================
console.log('=== 1. 대시보드 (getFarmRegionRanking) ===');
console.log('보은군 내 농가 위치 차트\n');
// 모든 개체별 선발지수 (35개 형질 EBV 합계)
const allCowsResult = await conn.query(`
SELECT c.cow_id, gr.fk_farm_no, SUM(gtd.trait_ebv) as total_ebv
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id, gr.fk_farm_no
HAVING COUNT(*) = 35
`);
const allCows = allCowsResult.rows;
// 농가별 평균 계산
const farmScoresMap = new Map();
for (const cow of allCows) {
const fNo = cow.fk_farm_no;
if (!farmScoresMap.has(fNo)) {
farmScoresMap.set(fNo, []);
}
farmScoresMap.set(fNo, [...farmScoresMap.get(fNo), Number(cow.total_ebv)]);
}
// 농가별 평균
const farmAverages = [];
for (const [fNo, scores] of farmScoresMap.entries()) {
const avg = scores.reduce((a, b) => a + b, 0) / scores.length;
farmAverages.push({ farmNo: fNo, avgScore: avg, cowCount: scores.length });
}
farmAverages.sort((a, b) => b.avgScore - a.avgScore);
// 보은군 전체 평균 (개체별 합계의 평균)
const regionAvgScore_dashboard = allCows.reduce((sum, c) => sum + Number(c.total_ebv), 0) / allCows.length;
// 농가 1번 평균
const myFarm = farmAverages.find(f => f.farmNo === farmNo);
const farmAvgScore_dashboard = myFarm?.avgScore || 0;
console.log('농가 평균 (개체 선발지수 평균):', farmAvgScore_dashboard.toFixed(2));
console.log('보은군 평균 (개체 선발지수 평균):', regionAvgScore_dashboard.toFixed(2));
console.log('차이 (농가 - 보은군):', (farmAvgScore_dashboard - regionAvgScore_dashboard).toFixed(2));
// =====================================================
// 2. 개체 상세: getSelectionIndex API
// - 내 개체 = 개체의 선발지수 (35개 형질 EBV 합계)
// - 농가 평균 = 같은 농가 개체들의 선발지수 평균
// - 보은군 평균 = 전체 개체들의 선발지수 평균
// =====================================================
console.log('\n=== 2. 개체 상세 (getSelectionIndex) ===');
console.log('농가 및 보은군 내 개체 위치 차트\n');
// 내 개체 선발지수
const myCow = allCows.find(c => c.cow_id === cowId);
const myScore = myCow ? Number(myCow.total_ebv) : 0;
// 같은 농가 개체들의 평균
const farmCows = allCows.filter(c => c.fk_farm_no === farmNo);
const farmAvgScore_detail = farmCows.reduce((sum, c) => sum + Number(c.total_ebv), 0) / farmCows.length;
// 보은군 전체 평균
const regionAvgScore_detail = regionAvgScore_dashboard; // 동일
console.log('내 개체 선발지수:', myScore.toFixed(2));
console.log('농가 평균:', farmAvgScore_detail.toFixed(2));
console.log('보은군 평균:', regionAvgScore_detail.toFixed(2));
console.log('');
console.log('내 개체 vs 농가평균:', (myScore - farmAvgScore_detail).toFixed(2));
console.log('내 개체 vs 보은군평균:', (myScore - regionAvgScore_detail).toFixed(2));
// =====================================================
// 3. 비교 요약
// =====================================================
console.log('\n=======================================================');
console.log('비교 요약');
console.log('=======================================================');
console.log('');
console.log('[대시보드] 농가 vs 보은군 차이:', (farmAvgScore_dashboard - regionAvgScore_dashboard).toFixed(2));
console.log('[개체상세] 개체 vs 농가 차이:', (myScore - farmAvgScore_detail).toFixed(2));
console.log('[개체상세] 개체 vs 보은군 차이:', (myScore - regionAvgScore_detail).toFixed(2));
console.log('');
console.log('=> 대시보드는 농가평균 vs 보은군평균 비교 (차이 작음)');
console.log('=> 개체상세는 개별개체 vs 평균 비교 (개체가 우수하면 차이 큼)');
await conn.end();
}
main().catch(console.error);

126
backend/check-data4.js Normal file
View File

@@ -0,0 +1,126 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
const cowId = 'KOR002191643715';
const farmNo = 1;
console.log('=======================================================');
console.log('선발지수 계산 방식 비교 분석');
console.log('=======================================================\n');
// 1. 해당 개체의 35개 형질 EBV 확인
const traitsResult = await conn.query(`
SELECT trait_name, trait_ebv
FROM tb_genome_trait_detail
WHERE cow_id = $1 AND del_dt IS NULL
ORDER BY trait_name
`, [cowId]);
const traits = traitsResult.rows;
console.log('=== 개체 형질 데이터 ===');
console.log('형질 수:', traits.length);
// EBV 합계
const ebvSum = traits.reduce((sum, t) => sum + Number(t.trait_ebv || 0), 0);
console.log('EBV 합계:', ebvSum.toFixed(2));
// EBV 평균
const ebvAvg = ebvSum / traits.length;
console.log('EBV 평균:', ebvAvg.toFixed(2));
console.log('\n=== 선발지수 계산 방식 비교 ===\n');
// 방식 1: EBV 합계 (getSelectionIndex 방식)
console.log('방식1 - EBV 합계 (weightedSum):', ebvSum.toFixed(2));
// 방식 2: EBV 평균
console.log('방식2 - EBV 평균 (sum/count):', ebvAvg.toFixed(2));
// 농가/보은군 평균도 각 방식으로 계산
console.log('\n=== 농가 평균 계산 방식 비교 ===\n');
// 농가 내 모든 개체
const farmCowsResult = await conn.query(`
SELECT c.cow_id, SUM(gtd.trait_ebv) as sum_ebv, AVG(gtd.trait_ebv) as avg_ebv, COUNT(*) as cnt
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.fk_farm_no = $1 AND gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35
`, [farmNo]);
const farmCows = farmCowsResult.rows;
// 방식 1: 개체별 합계의 평균
const farmSumAvg = farmCows.reduce((sum, c) => sum + Number(c.sum_ebv), 0) / farmCows.length;
console.log('방식1 - 개체별 합계의 평균:', farmSumAvg.toFixed(2));
// 방식 2: 개체별 평균의 평균
const farmAvgAvg = farmCows.reduce((sum, c) => sum + Number(c.avg_ebv), 0) / farmCows.length;
console.log('방식2 - 개체별 평균의 평균:', farmAvgAvg.toFixed(2));
console.log('\n=== 보은군 평균 계산 방식 비교 ===\n');
// 보은군 전체 개체
const allCowsResult = await conn.query(`
SELECT c.cow_id, SUM(gtd.trait_ebv) as sum_ebv, AVG(gtd.trait_ebv) as avg_ebv, COUNT(*) as cnt
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35
`);
const allCows = allCowsResult.rows;
// 방식 1: 개체별 합계의 평균
const regionSumAvg = allCows.reduce((sum, c) => sum + Number(c.sum_ebv), 0) / allCows.length;
console.log('방식1 - 개체별 합계의 평균:', regionSumAvg.toFixed(2));
// 방식 2: 개체별 평균의 평균
const regionAvgAvg = allCows.reduce((sum, c) => sum + Number(c.avg_ebv), 0) / allCows.length;
console.log('방식2 - 개체별 평균의 평균:', regionAvgAvg.toFixed(2));
console.log('\n=======================================================');
console.log('결과 비교');
console.log('=======================================================\n');
console.log('만약 "합계" 방식 사용 시:');
console.log(' 내 개체:', ebvSum.toFixed(2));
console.log(' 농가 평균:', farmSumAvg.toFixed(2));
console.log(' 보은군 평균:', regionSumAvg.toFixed(2));
console.log(' → 내 개체 vs 농가: +', (ebvSum - farmSumAvg).toFixed(2));
console.log(' → 내 개체 vs 보은군: +', (ebvSum - regionSumAvg).toFixed(2));
console.log('\n만약 "평균" 방식 사용 시:');
console.log(' 내 개체:', ebvAvg.toFixed(2));
console.log(' 농가 평균:', farmAvgAvg.toFixed(2));
console.log(' 보은군 평균:', regionAvgAvg.toFixed(2));
console.log(' → 내 개체 vs 농가: +', (ebvAvg - farmAvgAvg).toFixed(2));
console.log(' → 내 개체 vs 보은군: +', (ebvAvg - regionAvgAvg).toFixed(2));
console.log('\n=======================================================');
console.log('리스트 선발지수 확인 (page.tsx의 GENOMIC_TRAITS)');
console.log('=======================================================\n');
// 리스트에서 보여주는 선발지수는 어떻게 계산되나?
// page.tsx:350-356 확인 필요
console.log('리스트의 overallScore 계산식 확인 필요:');
console.log(' - selectionIndex.score 사용 시: 합계 방식');
console.log(' - GENOMIC_TRAITS.reduce / length 사용 시: 평균 방식');
await conn.end();
}
main().catch(console.error);

47
backend/check-data5.js Normal file
View File

@@ -0,0 +1,47 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
const farmNo = 1;
// 농가 내 모든 개체의 선발지수(가중 합계) 조회
const farmCowsResult = await conn.query(`
SELECT c.cow_id, SUM(gtd.trait_ebv) as sum_ebv
FROM tb_genome_request gr
JOIN tb_cow c ON gr.fk_cow_no = c.pk_cow_no
JOIN tb_genome_trait_detail gtd ON gtd.cow_id = c.cow_id AND gtd.del_dt IS NULL
WHERE gr.fk_farm_no = $1 AND gr.del_dt IS NULL AND c.del_dt IS NULL
AND gr.chip_sire_name = '일치'
GROUP BY c.cow_id
HAVING COUNT(*) = 35
ORDER BY sum_ebv DESC
`, [farmNo]);
const farmCows = farmCowsResult.rows;
console.log('=== 농가 1번 개체별 선발지수 (가중 합계) ===\n');
let total = 0;
farmCows.forEach((c, i) => {
const score = Number(c.sum_ebv);
total += score;
console.log(`${i+1}. ${c.cow_id}: ${score.toFixed(2)}`);
});
console.log('\n=== 계산 ===');
console.log('개체 수:', farmCows.length);
console.log('선발지수 총합:', total.toFixed(2));
console.log('농가 평균 = 총합 / 개체수 =', total.toFixed(2), '/', farmCows.length, '=', (total / farmCows.length).toFixed(2));
await conn.end();
}
main().catch(console.error);

66
backend/check-data6.js Normal file
View File

@@ -0,0 +1,66 @@
const { Client } = require('pg');
async function main() {
const conn = new Client({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'turbo123',
database: 'genome_db'
});
await conn.connect();
const cowId = 'KOR002191643715';
console.log('=======================================================');
console.log('리스트 vs 개체상세 선발지수 비교');
console.log('=======================================================\n');
// 해당 개체의 35개 형질 EBV 조회
const traitsResult = await conn.query(`
SELECT trait_name, trait_ebv
FROM tb_genome_trait_detail
WHERE cow_id = $1 AND del_dt IS NULL
ORDER BY trait_name
`, [cowId]);
const traits = traitsResult.rows;
console.log('형질 수:', traits.length);
// 1. 가중 합계 (weight = 1)
let weightedSum = 0;
let totalWeight = 0;
traits.forEach(t => {
const ebv = Number(t.trait_ebv);
const weight = 1;
weightedSum += ebv * weight;
totalWeight += weight;
});
console.log('\n=== 계산 비교 ===');
console.log('가중 합계 (weightedSum):', weightedSum.toFixed(2));
console.log('총 가중치 (totalWeight):', totalWeight);
console.log('');
console.log('리스트 (cow.service.ts) - 가중 합계:', weightedSum.toFixed(2));
console.log('개체상세 (genome.service.ts) - 가중 합계:', weightedSum.toFixed(2));
console.log('\n=== 프론트엔드 가중치 확인 ===');
console.log('프론트엔드에서 weight / 100 정규화 확인 필요');
console.log('예: weight 100 → 1, weight 50 → 0.5');
// 만약 프론트에서 weight/100을 적용한다면?
console.log('\n=== 만약 weight가 0.01로 적용된다면? ===');
let weightedSum2 = 0;
let totalWeight2 = 0;
traits.forEach(t => {
const ebv = Number(t.trait_ebv);
const weight = 0.01; // 1/100
weightedSum2 += ebv * weight;
totalWeight2 += weight;
});
console.log('가중 합계:', weightedSum2.toFixed(2));
await conn.end();
}
main().catch(console.error);

View File

@@ -223,8 +223,24 @@ export class CowService {
*/
private async applyGenomeRanking(
cows: CowModel[],
traitConditions: TraitRankingCondition[],
inputTraitConditions: TraitRankingCondition[],
): Promise<any> {
// 35개 전체 형질 (기본값)
const ALL_TRAITS = [
'12개월령체중',
'도체중', '등심단면적', '등지방두께', '근내지방도',
'체고', '십자', '체장', '흉심', '흉폭', '고장', '요각폭', '좌골폭', '곤폭', '흉위',
'안심weight', '등심weight', '채끝weight', '목심weight', '앞다리weight',
'우둔weight', '설도weight', '사태weight', '양지weight', '갈비weight',
'안심rate', '등심rate', '채끝rate', '목심rate', '앞다리rate',
'우둔rate', '설도rate', '사태rate', '양지rate', '갈비rate',
];
// traitConditions가 비어있으면 35개 전체 형질 사용 (개체상세, 대시보드와 동일)
const traitConditions = inputTraitConditions && inputTraitConditions.length > 0
? inputTraitConditions
: ALL_TRAITS.map(traitNm => ({ traitNm, weight: 1 }));
// 각 개체별로 점수 계산
const cowsWithScore = await Promise.all(
cows.map(async (cow) => {
@@ -260,7 +276,7 @@ export class CowService {
return { entity: { ...cow, unavailableReason: '형질정보없음' }, sortValue: null, details: [] };
}
// Step 4: 가중 평균 계산
// Step 4: 가중 합계 계산
let weightedSum = 0; // 가중치 적용된 EBV 합계
let totalWeight = 0; // 총 가중치
let hasAllTraits = true; // 모든 선택 형질 존재 여부
@@ -290,10 +306,10 @@ export class CowService {
}
}
// Step 6: 최종 점수 계산 (가중 평균)
// Step 6: 최종 점수 계산 (가중 합계)
// 모든 선택 형질이 있어야만 점수 계산
const sortValue = (hasAllTraits && totalWeight > 0)
? weightedSum / totalWeight // 가중 평균 = 가중합 / 총가중치
? weightedSum // 가중 합계 (개체상세, 대시보드와 동일한 방식)
: null;
// Step 7: 응답 데이터 구성