엑셀 채점결과 행열 변환 및 채점기준표와 문항 수 동일하게 조정

This commit is contained in:
2025-04-03 17:40:52 +09:00
parent 493aca1ed1
commit b56019f976
23 changed files with 4195 additions and 54 deletions

View File

@@ -12,9 +12,9 @@ const getToday = require('./getToday.js');
const todayDate = getToday();
// --------------------------------------------------------
// const scoringJson = require('./DIC_2503A.json');
const scoringJson = require('./DIC_2503A.json');
// const scoringJson = require('./DIC_2503B.json');
const scoringJson = require('./DIC_2503C.json');
// const scoringJson = require('./DIC_2503C.json');
// const scoringJson = require('./DIC_2503D.json');
// TEST
@@ -23,7 +23,7 @@ const scoringJson = require('./DIC_2503C.json');
// const scoringJson = require('./DIC_2503C_TEST.json');
// const scoringJson = require('./DIC_2503D_TEST.json');
// --------------------------------------------------------
// const answerFilesDir = './output/A/DIC';
const answerFilesDir = './output/A/DIC';
// const answerFilesDir = './output/B/DIC';
// const answerFilesDir = './output/C/DIC';
// const answerFilesDir = './output/D/DIC';
@@ -31,19 +31,19 @@ const scoringJson = require('./DIC_2503C.json');
// TEST
// const answerFilesDir = './output/A/TEST';
// const answerFilesDir = './output/B/TEST';
const answerFilesDir = './output/C/TEST';
// const answerFilesDir = './output/C/TEST';
// const answerFilesDir = './output/D/TEST';
// --------------------------------------------------------
// const outputExcelFile = './'+todayDate+'_DIC_2503A_채점결과.xlsx';
const outputExcelFile = './'+todayDate+'_DIC_2503A_채점결과.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503B_채점결과.xlsx';
// const outputExcelFile = './' + todayDate + '_DIC_2503C_채점결과.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503C_채점결과.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503D_채점결과.xlsx';
// TEST
// const outputExcelFile = './'+todayDate+'_DIC_2503A_TEST.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503B_TEST.xlsx';
const outputExcelFile = './'+todayDate+'_DIC_2503C_TEST.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503C_TEST.xlsx';
// const outputExcelFile = './'+todayDate+'_DIC_2503D_TEST.xlsx';
// --------------------------------------------------------
@@ -118,51 +118,117 @@ studentDirs.forEach(student => {
scoringResultList.push(scoringResult);
});
// Flatten the resultData for better representation in Excel
const flattenedData = scoringResultList.map(student => {
const name = student["0"];
const flattened = { "학생": student["0"] };
// // Flatten the resultData for better representation in Excel
// const flattenedData = scoringResultList.map(student => {
// // const name = student["0"];
// const flattened = { "학생": student["0"] };
// excel에 표시하지 않을 key값들
const exceptKeys = [
"0", // 학생 이름 항상 제외
"1", // psd1
"2", // psd2
]
const exceptSubkeys = [
"videoStartTime",
"openingStartTime",
];
Object.keys(student).forEach(key => {
if (exceptKeys.includes(key)) {
return;
}
Object.keys(student[key]).forEach(subKey => {
if (exceptSubkeys.includes(subKey)) {
return;
// // excel에 표시하지 않을 key값들
// const exceptKeys = [
// "0", // 학생 이름 항상 제외
// // "1", // psd1
// // "2", // psd2
// ]
// const exceptSubkeys = [
// "videoStartTime",
// "openingStartTime",
// ];
// Object.keys(student).forEach(key => {
// if (exceptKeys.includes(key)) {
// return;
// }
// Object.keys(student[key]).forEach(subKey => {
// if (exceptSubkeys.includes(subKey)) {
// return;
// }
// flattened[`${key}-${subKey}`] = student[key][subKey];
// });
// });
// return flattened;
// });
/**
* scoringResultList 배열을 엑셀에 출력하기 위한 데이터 정리 함수
* @param {Array} scoringResultList - 학생별 채점 결과 리스트
* @returns {Array} - 엑셀에 출력할 데이터 배열
*/
function prepareExcelData(scoringResultList) {
return scoringResultList.map(student => {
const flattened = { "학생": student["0"] }; // 학생 이름을 첫 번째 열로 설정
// 제외할 키와 서브키 정의
const exceptKeys = [
"0", // 학생 이름 제외
// "1", // psd1
// "2", // psd2
];
const exceptSubkeys = ["videoStartTime", "openingStartTime"]; // 제외할 서브키
// 학생 데이터 순회
Object.keys(student).forEach(key => {
if (exceptKeys.includes(key)) {
return; // 제외할 키는 건너뜀
}
// 서브키 순회
if (typeof student[key] === "object") {
Object.keys(student[key]).forEach(subKey => {
if (exceptSubkeys.includes(subKey)) {
return; // 제외할 서브키는 건너뜀
}
flattened[`${key}-${subKey}`] = student[key][subKey];
});
} else {
// 서브키가 없는 경우
flattened[key] = student[key];
}
flattened[`${key}_${subKey}`] = student[key][subKey];
});
return flattened;
});
return flattened;
});
}
// console.log(flattenedData);
const flattenedData = prepareExcelData(scoringResultList);
function transposeData(data) {
// 데이터가 없으면 빈 배열 반환
if (data.length === 0) return [];
// 첫 번째 객체의 키(열 제목) 가져오기
const keys = Object.keys(data[0]);
// 행과 열을 변환
const transposed = keys.map(key => {
const row = { "항목": key }; // 각 열 제목을 "항목"으로 설정
data.forEach((item, index) => {
//console.log(data[index]['학생']);
row[data[index]['학생']] = item[key]; // 각 학생의 데이터를 열로 추가
});
return row;
});
return transposed;
}
// const transposedData = transposeData(flattenedData);
const transposedData = transposeData(flattenedData).slice(1);
// 엑셀 파일 생성
const worksheet = XLSX.utils.json_to_sheet(flattenedData);
// const worksheet = XLSX.utils.json_to_sheet(flattenedData);
const worksheet = XLSX.utils.json_to_sheet(transposedData);
const workbook = XLSX.utils.book_new();
// 열 너비 계산
const columnWidths = Object.keys(flattenedData[0]).map(key => {
const maxLength = Math.max(
key.length, // 열 제목의 길이
...flattenedData.map(row => (row[key] ? row[key].toString().length : 0)) // 각 셀의 데이터 길이
);
return { wch: maxLength + 1 }; // 여유 공간 추가
});
// const columnWidths = Object.keys(flattenedData[0]).map(key => {
// const maxLength = Math.max(
// key.length, // 열 제목의 길이
// ...flattenedData.map(row => (row[key] ? row[key].toString().length : 0)) // 각 셀의 데이터 길이
// );
// return { wch: maxLength + 1 }; // 여유 공간 추가
// });
// 열 너비 설정
worksheet['!cols'] = columnWidths;
// worksheet['!cols'] = columnWidths;
// Add the worksheet to the workbook
XLSX.utils.book_append_sheet(workbook, worksheet, '채점 결과');
@@ -246,8 +312,7 @@ function getGmepScore(gmepData, scoringJson, index) {
// const subtitleOrder = type === 'video' ? 2 : type === 'opening' ? 1 : null;
// 2503회 문제오류 처리를 위한 임시 변경
const subtitleOrder = (type === 'video' || type === 'videoIsExist') ? 2 : (type === 'opening' ? 1 : null);
const startTime = type === 'video' ? videoStartTime
: type === 'opening' ? openingStartTime : null;
const startTime = type === 'video' ? videoStartTime : type === 'opening' ? openingStartTime : null;
[ele, ele2, ele3] = [ele, ele2, ele3].map(e => e?.replace(/{subtitleIndex}/g, subtitleIndex));
[ele, ele2, ele3] = [ele, ele2, ele3].map(e => e?.replace(/{subtitleOrder}/g, subtitleOrder));
@@ -478,20 +543,12 @@ function getGmepScore(gmepData, scoringJson, index) {
}
}
/* 현재 문제점 ****************************************************
* ele2 xpath구문을 수행했을때
* /CROwneUnit[position() = //CRTrackList/CRTrackClip[sum(preceding-sibling::CRTrackClip/@Length) = 170]/@ClipIndex + 1]/CRCUnitArr/@Name
* position() = //CRTrackList/CRTrackClip[sum(preceding-sibling::CRTrackClip/@Length) = 170 부분에서
* 시작시간이 170이 아닌 경우 false값이 반환되고 0으로 인식되어
* //CROwneUnit[0]/CRCUnitArr/@Name 의 값이 반환됨
****************************************************************/
// 문제의 타입이 video(동영상자막) 또는 opening(오프닝자막)일 경우
else if (type == "video" || type == "opening") {
const trackClipNode = getTrackClipNode(gmepXmlDoc, type, videoStartTime, openingStartTime);
// 찾으려는 자막이 존재하지 않는 경우
// (2-28) 문항의 경우 오프닝 자막이 없어도 xpath구문의 sum함수 결과값이 0이 반환되는것을 방지
if ( trackClipNode === undefined ) {
if ( trackClipNode === undefined && clipIndex === null ) {
scoringResult[key] = 0;
continue;
}
@@ -678,8 +735,8 @@ function getScore(psdData, scoring, index) {
// value: "Arial"
// result: ["Arial-BoldItalicMT"]
else if (type == "font") {
// console.log(`result ${result}`);
const font = result[0].split('-')[0];
// console.log(`result ${result}`);
// console.log(`font: ${font}`);
scoringResult[key] = result.length > 0 && value === font ? point : 0;
}