Sfoglia il codice sorgente

1.統測活動決賽名單生成API 追加地理資訊欄位
2.統測活動匯出成績欄位追加

jeff 7 mesi fa
parent
commit
63c1ed10ca

+ 6 - 0
TEAMModelOS.SDK/Models/Service/JointService.cs

@@ -444,6 +444,12 @@ namespace TEAMModelOS.SDK.Models.Service
                                 finalEventCourse.creatorEmail = jointEventCourseRow.creatorEmail;
                                 finalEventCourse.creatorEmail = jointEventCourseRow.creatorEmail;
                                 finalEventCourse.schoolId = jointEventCourseRow.schoolId;
                                 finalEventCourse.schoolId = jointEventCourseRow.schoolId;
                                 finalEventCourse.schoolName = jointEventCourseRow.schoolName;
                                 finalEventCourse.schoolName = jointEventCourseRow.schoolName;
+                                finalEventCourse.countryId = jointEventCourseRow.countryId;
+                                finalEventCourse.countryName = jointEventCourseRow.countryName;
+                                finalEventCourse.provinceId = jointEventCourseRow.provinceId;
+                                finalEventCourse.provinceName = jointEventCourseRow.provinceName;
+                                finalEventCourse.cityId = jointEventCourseRow.cityId;
+                                finalEventCourse.cityName = jointEventCourseRow.cityName;
                                 finalEventCourse.jointScheduleId = finalSchedule.id;
                                 finalEventCourse.jointScheduleId = finalSchedule.id;
                                 classCnt++;
                                 classCnt++;
                                 finalEventCourse.courseLists.Add(new JointEventGroupBase.JointEventGroupCourse()
                                 finalEventCourse.courseLists.Add(new JointEventGroupBase.JointEventGroupCourse()

+ 3 - 1
TEAMModelOS/ClientApp/public/lang/en-US.js

@@ -8076,7 +8076,9 @@ const LANG_EN_US = {
         NoSubjectiveQuestions: 'Evaluation of subjective questions without review',
         NoSubjectiveQuestions: 'Evaluation of subjective questions without review',
         exportScore: 'Export grades',
         exportScore: 'Export grades',
         score: 'Score',
         score: 'Score',
-        totalScore: 'Total Score',
+        totalScore: 'Total score',
+        classAverage: 'Average score',
+        classLostRate: 'Absence rate',
         rank: 'Rank',
         rank: 'Rank',
         item: 'Item',
         item: 'Item',
         classScoreOverview: 'Class overview',
         classScoreOverview: 'Class overview',

+ 2 - 0
TEAMModelOS/ClientApp/public/lang/zh-CN.js

@@ -8078,6 +8078,8 @@ const LANG_ZH_CN = {
         exportScore: '汇出成绩',
         exportScore: '汇出成绩',
         score: '分数',
         score: '分数',
         totalScore: '总分',
         totalScore: '总分',
+        classAverage: '班級平均分',
+        classLostRate: '班級缺考率',
         rank: '排名',
         rank: '排名',
         item: '题目',
         item: '题目',
         classScoreOverview: '所有班级成绩一览',
         classScoreOverview: '所有班级成绩一览',

+ 2 - 0
TEAMModelOS/ClientApp/public/lang/zh-TW.js

@@ -8078,6 +8078,8 @@ const LANG_ZH_TW = {
         exportScore: '匯出成績',
         exportScore: '匯出成績',
         score: '分數',
         score: '分數',
         totalScore: '總分',
         totalScore: '總分',
+        classAverage: '班級平均分',
+        classLostRate: '班級缺考率',
         rank: '排名',
         rank: '排名',
         item: '題目',
         item: '題目',
         classScoreOverview: '所有班級成績一覽',
         classScoreOverview: '所有班級成績一覽',

+ 85 - 57
TEAMModelOS/ClientApp/src/view/htcommunity/htMgtExam.vue

@@ -1143,27 +1143,39 @@ export default {
 		},
 		},
 		//匯出所有活動成績至Excel
 		//匯出所有活動成績至Excel
 		async exportExcel() {
 		async exportExcel() {
-			console.log('勾選匯出成績課程名單', this.importSelection);
+			let classSheet = false; //是否生成各班級作答結果分頁 (目前不生成)
 			this.$api.htcommunity.findSummaryRecords({ data: this.importSelection })
 			this.$api.htcommunity.findSummaryRecords({ data: this.importSelection })
             .then(
             .then(
 				(res) => {
 				(res) => {
                     let scheduleNow = this.propSchedules.find(s => s.id == this.filter.schedule);
                     let scheduleNow = this.propSchedules.find(s => s.id == this.filter.schedule);
 					let groupNow = this.propGroups.find(g => g.id == this.filter.group);
 					let groupNow = this.propGroups.find(g => g.id == this.filter.group);
 					let examNow = this.htEvaListShow[this.curEvaIndex];
 					let examNow = this.htEvaListShow[this.curEvaIndex];
+					let sheetList = []; //分頁名單(分頁名重複防止對策)
 					//分頁1 所有班級成績一覽
 					//分頁1 所有班級成績一覽
                     let navi = [this.$t('htcommunity.eventSchedule') + ':' + scheduleNow.name, this.$t('htcommunity.group') + ':' + groupNow.name, this.$t('htcommunity.eventExam') + ':' + examNow.name, '', '', '', '']
                     let navi = [this.$t('htcommunity.eventSchedule') + ':' + scheduleNow.name, this.$t('htcommunity.group') + ':' + groupNow.name, this.$t('htcommunity.eventExam') + ':' + examNow.name, '', '', '', '']
-                    let title = [this.$t('htcommunity.schoolName'), this.$t('htcommunity.teacher'), this.$t('htcommunity.class'), this.$t('htcommunity.score'), this.$t('htcommunity.rank')];
-                    let key = ['school', 'creator', 'class', 'score', 'rank'];
+                    let title = [this.$t('htcommunity.jointGroup'), this.$t('htcommunity.location'), this.$t('htcommunity.schoolName'), this.$t('htcommunity.teacher'), this.$t('htcommunity.tmid'), this.$t('htcommunity.course'), this.$t('htcommunity.courseGroup'), this.$t('htcommunity.stuNumber'), this.$t('htcommunity.classAverage'), this.$t('htcommunity.classLostRate')];
+                    let key = ['jointGroupName', 'location', 'school', 'creator', 'creatorId', 'course', 'class', 'stuNum', 'score', 'lostRate'];
 					let data = [];
 					let data = [];
 					res.examClassResults.forEach((item) => {
 					res.examClassResults.forEach((item) => {
 						let examId = item.examId;
 						let examId = item.examId;
 						let classId = item.info.id;
 						let classId = item.info.id;
 						let className = item.info.name;
 						let className = item.info.name;
 						let groupInfoNow = this.groupListForExport.find(g => g.groupListId == classId);
 						let groupInfoNow = this.groupListForExport.find(g => g.groupListId == classId);
+						let jointGroupName = groupNow.name;
 						let schoolName = groupInfoNow.schoolName;
 						let schoolName = groupInfoNow.schoolName;
+						let creatorId = groupInfoNow.creatorId;
 						let creatorName = groupInfoNow.creatorName;
 						let creatorName = groupInfoNow.creatorName;
-                        let score = (item.sum.length > 0) ? item.sum.reduce((a, b) => a + b, 0) / item.sum.length : 0;
-						data.push({ school: schoolName, creator: creatorName, class: className, score: score.toFixed(2), rank: 0 });
+						let countryName = groupInfoNow.countryName;
+						let provinceName = groupInfoNow.provinceName;
+						let cityName = groupInfoNow.cityName;
+						let location = groupInfoNow.location;
+						let courseName = groupInfoNow.courseName;
+                        let stuNum = item.studentIds.length;
+						let average = item.average; //平均分數
+						let lostStu = item.status.filter((s) => s == 1).length;
+						let lostRate = (stuNum > 0) ? (lostStu / stuNum) * 100 : 100; //缺考率
+						let score = (item.sum.length > 0) ? item.sum.reduce((a, b) => a + b, 0) / item.sum.length : 0; //總分
+                        data.push({ jointGroupName: jointGroupName, location: location, school: schoolName, creator: creatorName, creatorId: creatorId, course: courseName, class: className, stuNum: stuNum, score: average.toFixed(2), lostRate: lostRate.toFixed(2) });
 					});
 					});
                     var dataSort = data.sort(function (a, b) { return b.score - a.score; });
                     var dataSort = data.sort(function (a, b) { return b.score - a.score; });
 					dataSort.forEach((row, rowIndex) => {
 					dataSort.forEach((row, rowIndex) => {
@@ -1175,58 +1187,64 @@ export default {
 					let ws = XLSX.utils.aoa_to_sheet(arr);
 					let ws = XLSX.utils.aoa_to_sheet(arr);
                     ws = excel.export_auto_width(ws, arr);
                     ws = excel.export_auto_width(ws, arr);
 					let wb = XLSX.utils.book_new();
 					let wb = XLSX.utils.book_new();
-                    let sheetName = scheduleNow.name + ' ' + this.$t('htcommunity.classScoreOverview');
-                    XLSX.utils.book_append_sheet(wb, ws, sheetName);
-
-                    //分頁2~ 各班級學生作答結果
-                    res.examClassResults.forEach((item) => {
-                        let examId = item.examId;
-                        let classId = item.info.id;
-                        let className = item.info.name;
-                        let groupInfoNow = this.groupListForExport.find(g => g.groupListId == classId);
-                        let schoolName = groupInfoNow.schoolName;
-                        let creatorName = groupInfoNow.creatorName;
-                        let naviCls = [this.$t('htcommunity.eventSchedule') + ':' + scheduleNow.name, this.$t('htcommunity.group') + ':' + groupNow.name, this.$t('htcommunity.eventExam') + ':' + examNow.name, this.$t('htcommunity.schoolName') + ':' + schoolName, this.$t('htcommunity.teacher') + ':' + creatorName, this.$t('htcommunity.class') + ':' + className, ''];
-                        let titleCls = [this.$t('htcommunity.student')];
-                        let keyStu = ['stuName'];
-                        for (let i = 0; i < item.studentScores[0].length; i++) {
-                            titleCls.push(this.$t('htcommunity.item') + (i+1));
-                            keyStu.push('item' + i);
-                        }
-                        titleCls.push(this.$t('htcommunity.totalScore'));
-                        titleCls.push(this.$t('htcommunity.rank'));
-                        keyStu.push('total');
-                        keyStu.push('stuRank');
-						let stus = [];
-						item.studentIds.forEach((stuid, idx) => {
-							let stuInfo = res.ufos.find(u => u.id == stuid);
-							if (typeof stuInfo != "undefined") {
-                                let stuName = stuInfo.name;
-                                let stuScores = item.studentScores[idx]; //該學生各題作答結果
-                                let stusRow = {};
-                                stusRow['stuName'] = stuName;
-                                for (let i = 0; i < stuScores.length; i++) {
-                                    let sc = (stuScores[i] >= 0) ? stuScores[i] : 0;
-                                    stusRow['item' + i] = sc;
-                                }
-                                stusRow['total'] = item.sum[idx];
-                                stusRow['stuRank'] = 0;
-                                stus.push(stusRow);
+					let sheetName = scheduleNow.name + ' ' + this.$t('htcommunity.classScoreOverview');
+					if (!sheetList.includes(sheetName)) {
+                        sheetList.push(sheetName)
+                        XLSX.utils.book_append_sheet(wb, ws, sheetName);
+					}
+					//分頁2~ 各班級學生作答結果
+					if (classSheet) {
+						res.examClassResults.forEach((item) => {
+							let examId = item.examId;
+							let classId = item.info.id;
+							let className = item.info.name;
+							let groupInfoNow = this.groupListForExport.find(g => g.groupListId == classId);
+							let schoolName = groupInfoNow.schoolName;
+							let creatorName = groupInfoNow.creatorName;
+							let naviCls = [this.$t('htcommunity.eventSchedule') + ':' + scheduleNow.name, this.$t('htcommunity.group') + ':' + groupNow.name, this.$t('htcommunity.eventExam') + ':' + examNow.name, this.$t('htcommunity.schoolName') + ':' + schoolName, this.$t('htcommunity.teacher') + ':' + creatorName, this.$t('htcommunity.class') + ':' + className, ''];
+							let titleCls = [this.$t('htcommunity.student')];
+							let keyStu = ['stuName'];
+							for (let i = 0; i < item.studentScores[0].length; i++) {
+								titleCls.push(this.$t('htcommunity.item') + (i + 1));
+								keyStu.push('item' + i);
 							}
 							}
-                        });
-                        var stusSort = stus.sort(function (a, b) { return b.total - a.total; });
-                        stusSort.forEach((row, rowIndex) => {
-                            stusSort[rowIndex].stuRank = rowIndex + 1;
-                        });
-                        let arrStu = excel.export_json_to_array(keyStu, stusSort);
-                        arrStu.unshift(titleCls);
-                        arrStu.unshift(naviCls);
-						let wsStu = XLSX.utils.aoa_to_sheet(arrStu);
-                        wsStu = excel.export_auto_width(wsStu, arrStu);
-                        let sheetNameCls = groupNow.name + ' ' + className + '(' + creatorName + ')';
-                        XLSX.utils.book_append_sheet(wb, wsStu, sheetNameCls);
-                    });
-
+							titleCls.push(this.$t('htcommunity.totalScore'));
+							titleCls.push(this.$t('htcommunity.rank'));
+							keyStu.push('total');
+							keyStu.push('stuRank');
+							let stus = [];
+							item.studentIds.forEach((stuid, idx) => {
+								let stuInfo = res.ufos.find(u => u.id == stuid);
+								if (typeof stuInfo != "undefined") {
+									let stuName = stuInfo.name;
+									let stuScores = item.studentScores[idx]; //該學生各題作答結果
+									let stusRow = {};
+									stusRow['stuName'] = stuName;
+									for (let i = 0; i < stuScores.length; i++) {
+										let sc = (stuScores[i] >= 0) ? stuScores[i] : 0;
+										stusRow['item' + i] = sc;
+									}
+									stusRow['total'] = item.sum[idx];
+									stusRow['stuRank'] = 0;
+									stus.push(stusRow);
+								}
+							});
+							var stusSort = stus.sort(function (a, b) { return b.total - a.total; });
+							stusSort.forEach((row, rowIndex) => {
+								stusSort[rowIndex].stuRank = rowIndex + 1;
+							});
+							let arrStu = excel.export_json_to_array(keyStu, stusSort);
+							arrStu.unshift(titleCls);
+							arrStu.unshift(naviCls);
+							let wsStu = XLSX.utils.aoa_to_sheet(arrStu);
+							wsStu = excel.export_auto_width(wsStu, arrStu);
+							let sheetNameCls = groupNow.name + ' ' + className + '(' + creatorName + ')';
+							if (!sheetList.includes(sheetNameCls)) {
+								sheetList.push(sheetNameCls)
+								XLSX.utils.book_append_sheet(wb, wsStu, sheetNameCls);
+							}
+						});
+					}
 					//檔案做成
 					//檔案做成
                     let filename = scheduleNow.name + ' ' + examNow.name + ' ' + this.$t('htcommunity.exportScore');
                     let filename = scheduleNow.name + ' ' + examNow.name + ' ' + this.$t('htcommunity.exportScore');
                     XLSX.writeFile(wb, filename + '.xlsx', {
                     XLSX.writeFile(wb, filename + '.xlsx', {
@@ -1274,6 +1292,9 @@ export default {
 			handler(n) {
 			handler(n) {
 				this.groupListForExport = [];
 				this.groupListForExport = [];
 				n.stuLists.forEach((s) => {
 				n.stuLists.forEach((s) => {
+                    let countryName = (s.countryName != null) ? s.countryName : "";
+                    let provinceName = (s.provinceName != null) ? s.provinceName : "";
+                    let cityName = (s.cityName != null) ? s.cityName : "";
 					s.courseLists.forEach((c) => {
 					s.courseLists.forEach((c) => {
 						c.groupLists.forEach((g) => {
 						c.groupLists.forEach((g) => {
 							let res = {
 							let res = {
@@ -1287,7 +1308,14 @@ export default {
                                 examId: (c.examId != null) ? c.examId : '',
                                 examId: (c.examId != null) ? c.examId : '',
                                 groupListId: g.id,
                                 groupListId: g.id,
 								groupListName: g.name,
 								groupListName: g.name,
-                                teacherName: s.creatorName + ' (' + s.schoolName + ')'
+								teacherName: s.creatorName + ' (' + s.schoolName + ')',
+                                countryId: s.countryId,
+                                countryName: countryName,
+                                provinceId: s.provinceId,
+                                provinceName: provinceName,
+                                cityId: s.cityId,
+                                cityName: cityName,
+                                location: cityName,
 							};
 							};
                             this.groupListForExport.push(res);
                             this.groupListForExport.push(res);
                         });
                         });

+ 1 - 1
TEAMModelOS/Controllers/Common/ExamController.cs

@@ -2356,7 +2356,7 @@ namespace TEAMModelOS.Controllers
                 }
                 }
 
 
                 //取得作答結果
                 //取得作答結果
-                StringBuilder sqlClassResult = new StringBuilder($"SELECT c.id, c.examId, c.subjectId, c.code, c.scIds, c.info ,c.studentIds ,c.studentAnswers, c.studentScores, c.mark, c.sum, c.status FROM c WHERE ");
+                StringBuilder sqlClassResult = new StringBuilder($"SELECT c.id, c.examId, c.subjectId, c.code, c.scIds, c.info ,c.studentIds ,c.studentAnswers, c.studentScores, c.mark, c.sum, c.average, c.status FROM c WHERE ");
                 StringBuilder sqlClassResultWhere = new StringBuilder();
                 StringBuilder sqlClassResultWhere = new StringBuilder();
                 foreach (FindExamClassResultsReqParam param in requestParams)
                 foreach (FindExamClassResultsReqParam param in requestParams)
                 {
                 {

+ 6 - 0
TEAMModelOS/Controllers/Teacher/JointEventController.cs

@@ -1092,6 +1092,12 @@ namespace TEAMModelOS.Controllers.Common
                                 stuListRow.creatorId = stu.creatorId;
                                 stuListRow.creatorId = stu.creatorId;
                                 stuListRow.creatorName = stu.creatorName;
                                 stuListRow.creatorName = stu.creatorName;
                                 stuListRow.creatorEmail = stu.creatorEmail;
                                 stuListRow.creatorEmail = stu.creatorEmail;
+                                stuListRow.countryId = stu.countryId;
+                                stuListRow.countryName = stu.countryName;
+                                stuListRow.provinceId = stu.provinceId;
+                                stuListRow.provinceName = stu.provinceName;
+                                stuListRow.cityId = stu.cityId;
+                                stuListRow.cityName = stu.cityName;
                                 stuListRow.schoolId = stu.schoolId;
                                 stuListRow.schoolId = stu.schoolId;
                                 stuListRow.schoolName = stu.schoolName;
                                 stuListRow.schoolName = stu.schoolName;
                                 stuListRow.courseLists = Newtonsoft.Json.JsonConvert.DeserializeObject<List<JointEventGroupBase.JointEventGroupCourse>>(Newtonsoft.Json.JsonConvert.SerializeObject(stu.courseLists));
                                 stuListRow.courseLists = Newtonsoft.Json.JsonConvert.DeserializeObject<List<JointEventGroupBase.JointEventGroupCourse>>(Newtonsoft.Json.JsonConvert.SerializeObject(stu.courseLists));