`;
// 값 비교를 위한 배열
const values = [];
serverIds.forEach(id => {
const val = getValueByKey(analysisData[id], key);
values.push(val);
});
// 값들이 모두 같은지 확인
const firstVal = values[0];
const isDiff = !values.every(v => v === firstVal);
if (isDiff) {
row.classList.add('diff-row');
hasDiff = true;
}
if (showDiffOnly && !isDiff) {
return; // Diff Only 모드이고 차이가 없으면 건너뜀
}
values.forEach(val => {
const displayVal = (val === undefined || val === null) ? 'N/A' : val;
const cellClass = (isDiff && val !== firstVal) ? 'diff-highlight' : ''; // 첫번째 서버(기준)와 다르면 강조
rowHtml += `
${displayVal}
`;
});
row.innerHTML = rowHtml;
tbody.appendChild(row);
});
if (showDiffOnly && !hasDiff) {
// 차이점이 하나도 없는데 차이점만 보기 체크된 경우 빈 row가 아니라 메시지 표시가 나을지 고민
// tbody가 비어있음
}
if (tbody.children.length === 0) {
tbody.innerHTML = '
표시할 항목이 없습니다.
';
}
table.appendChild(tbody);
container.appendChild(table);
}
// 헬퍼: 키(Category: Name)로 값 추출
function getValueByKey(data, compositeKey) {
if (!data) return undefined;
const [category, ...rest] = compositeKey.split(': ');
const realKey = rest.join(': '); // 혹시 키 안에 콜론이 있을 경우 복구
if (category === 'BIOS') return data.bios ? data.bios[realKey] : undefined;
if (category === 'iDRAC') return data.idrac ? data.idrac[realKey] : undefined;
if (category === 'System') {
const flatSys = flattenObject(data.system);
return flatSys ? flatSys[realKey] : undefined;
}
return undefined;
}
// 객체 평탄화 (Nested Object -> Flat Key)
function flattenObject(obj, prefix = '') {
if (!obj) return {};
return Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object' && obj[k] !== null) {
Object.assign(acc, flattenObject(obj[k], pre + k));
} else {
acc[pre + k] = obj[k];
}
return acc;
}, {});
}
function downloadReport() {
const table = document.querySelector('.comparison-table');
if (!table) {
alert('다운로드할 데이터가 없습니다. 먼저 분석을 진행해주세요.');
return;
}
let csvContent = "\uFEFF"; // BOM for Excel UTF-8
const rows = table.querySelectorAll('tr');
rows.forEach(row => {
const cols = row.querySelectorAll('th, td');
const rowData = [];
cols.forEach(col => {
// 따옴표 처리 및 텍스트 추출
let text = col.innerText || col.textContent;
text = text.replace(/"/g, '""'); // 따옴표 이스케이프
// 줄바꿈 제거
text = text.replace(/(\r\n|\n|\r)/gm, " ");
if (text.includes(',') || text.includes('"')) {
text = `"${text}"`;
}
rowData.push(text);
});
csvContent += rowData.join(',') + "\r\n";
});
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
const timestamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-');
link.setAttribute('href', url);
link.setAttribute('download', `server_config_comparison_${timestamp}.csv`);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}