Commit ce926d5e338904d6542a7c1c2af6124b1cfe0105

Authored by liufangjia
2 parents 02917cfa cd4095bd

feat : 新增错题组卷

.gitignore
@@ -28,3 +28,4 @@ pnpm-debug.log* @@ -28,3 +28,4 @@ pnpm-debug.log*
28 src/views/portrait/test.vue 28 src/views/portrait/test.vue
29 /src/.vs 29 /src/.vs
30 /.vs 30 /.vs
  31 +/.vs/slnx.sqlite
.vs/slnx.sqlite deleted
No preview for this file type
src/api/apis/apis.js
@@ -1049,15 +1049,15 @@ export default { @@ -1049,15 +1049,15 @@ export default {
1049 }, 1049 },
1050 // 获取科目列表 1050 // 获取科目列表
1051 getSubjectList(data) { 1051 getSubjectList(data) {
1052 - return defaltService(setUpUrls.subjectList, data); 1052 + return defaltService(setUpUrls.teacherSubjectList, data);
1053 }, 1053 },
1054 // 获取年级信息 1054 // 获取年级信息
1055 getClassList(data) { 1055 getClassList(data) {
1056 - return defaltService(setUpUrls.classList, data); 1056 + return defaltService(setUpUrls.teacherClassList, data);
1057 }, 1057 },
1058 // 获取班级信息 1058 // 获取班级信息
1059 getGradeList(data) { 1059 getGradeList(data) {
1060 - return defaltGetService(setUpUrls.gradeList, data); 1060 + return defaltGetService(setUpUrls.teacherGradeList, data);
1061 }, 1061 },
1062 // 获取班级信息 1062 // 获取班级信息
1063 getWrongQuestionSave(data) { 1063 getWrongQuestionSave(data) {
src/api/urls/apis.js
@@ -496,18 +496,16 @@ export default { @@ -496,18 +496,16 @@ export default {
496 listStudentsAndQuestions: "/api_html/teaching/listStudentsAndQuestions", 496 listStudentsAndQuestions: "/api_html/teaching/listStudentsAndQuestions",
497 //分页查询授课端日志列表 497 //分页查询授课端日志列表
498 deviceZipLogList: "/api_html/school/manager/deviceZipLogList", 498 deviceZipLogList: "/api_html/school/manager/deviceZipLogList",
499 -  
500 //获取即时测报表录分情况 499 //获取即时测报表录分情况
501 getScoreType: "/api_html/teaching/getScoreType", 500 getScoreType: "/api_html/teaching/getScoreType",
502 -  
503 // 获取错题本列表 501 // 获取错题本列表
504 wrongQuestionList: "api_html/teaching/wrongQuestion/list", 502 wrongQuestionList: "api_html/teaching/wrongQuestion/list",
505 // 获取科目列表 503 // 获取科目列表
506 - subjectList: "api_html/teaching/subjectList", 504 + teacherSubjectList: "api_html/teaching/subjectList",
507 // 获取年级信息 505 // 获取年级信息
508 - classList: "api_html/teaching/classList", 506 + teacherClassList: "api_html/teaching/classList",
509 // 获取班级信息 507 // 获取班级信息
510 - gradeList: "api_html/teaching/grade",  
511 - // 保存试卷信息 508 + teacherGradeList: "api_html/teaching/grade",
  509 + // 保存接口
512 getWrongQuestionSave: "api_html/teaching/wrongQuestion/save", 510 getWrongQuestionSave: "api_html/teaching/wrongQuestion/save",
513 }; 511 };
src/utils/index.js
@@ -613,6 +613,17 @@ export function getBlob(url) { @@ -613,6 +613,17 @@ export function getBlob(url) {
613 ); 613 );
614 }); 614 });
615 } 615 }
  616 +export function fetchHTML(url) {
  617 + return new Promise((resolve) => {
  618 + resolve(
  619 + service({
  620 + url: url,
  621 + withCredentials: false,
  622 + method: "get"
  623 + })
  624 + );
  625 + });
  626 +}
616 /** 627 /**
617 * 打包压缩下载 628 * 打包压缩下载
618 */ 629 */
@@ -871,7 +882,316 @@ export function formatGradeNameClass(data) { @@ -871,7 +882,316 @@ export function formatGradeNameClass(data) {
871 }); 882 });
872 return gradeNameArr; 883 return gradeNameArr;
873 } 884 }
874 -_; 885 +
  886 +///试卷定制化打印
  887 +export async function paperPrint(paper) {
  888 + let printWin = window.open("", "_blank", "width=800,height=600,resizable=no");
  889 + var browser = getBrowserEngine(printWin);
  890 + var subjectName = paper.subjectName;
  891 + var paperTitle = paper.title;
  892 + var paperQuestions = paper.questionList;
  893 + function getBrowserEngine(windowParams) {
  894 + if (windowParams.navigator.userAgent.indexOf("Edge") > -1) {
  895 + return "EdgeHTML";
  896 + }
  897 + if (windowParams.navigator.userAgent.indexOf("Edg") > -1) {
  898 + return "Blink"; // Microsoft Edge (Chromium)
  899 + }
  900 + if (windowParams.navigator.userAgent.indexOf("Firefox") > -1) {
  901 + return "Gecko";
  902 + }
  903 + if (windowParams.navigator.userAgent.indexOf("Trident") > -1) {
  904 + return "Trident"; // IE
  905 + }
  906 + if (/Chrome/.test(windowParams.navigator.userAgent) && /Google Inc/.test(windowParams.navigator.vendor)) {
  907 + return 'Google Chrome';
  908 + }
  909 + if (/360/.test(windowParams.navigator.userAgent) || /QIHU/.test(windowParams.navigator.userAgent)) {
  910 + return '360 Browser';
  911 + }
  912 + return "Blink"; // Assume it's Chrome, Safari, or an alternative Blink-based browser
  913 + }
  914 + function numberToChinese(num) {
  915 + const chineseDigits = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
  916 + const chineseUnits = ["", "十", "百", "千", "万", "亿"];
  917 +
  918 + let result = '';
  919 + let unitPos = 0; // 单位的位置
  920 + let zeroFlag = false; // 是否出现过零
  921 +
  922 + if (num === 0) {
  923 + return chineseDigits[0]; // 特殊情况,0 返回 "零"
  924 + }
  925 +
  926 + // 处理数字,每次取一位并加上单位
  927 + while (num > 0) {
  928 + const currentDigit = num % 10; // 取最后一位数字
  929 + if (currentDigit === 0) {
  930 + if (!zeroFlag) {
  931 + result = chineseDigits[currentDigit] + result; // 只在出现零时添加
  932 + zeroFlag = true; // 标记零已经出现
  933 + }
  934 + } else {
  935 + result = chineseDigits[currentDigit] + chineseUnits[unitPos] + result;
  936 + zeroFlag = false; // 重置零的标记
  937 + }
  938 +
  939 + num = Math.floor(num / 10); // 去掉最后一位数字
  940 + unitPos++;
  941 + }
  942 +
  943 + // 处理 '一十' 和 '一百' 等情况
  944 + if (result.startsWith('一十')) {
  945 + result = result.substring(1); // 去掉 '一',例如 '一十' -> '十'
  946 + }
  947 +
  948 + return result;
  949 + }
  950 + function htmlParseDom(html, getStyleScripts) {
  951 + var tempDom = document.createElement('div');
  952 + tempDom.innerHTML = html;
  953 + var doms = tempDom.querySelectorAll('p');
  954 + if (getStyleScripts == true) {
  955 + var styleDoms = tempDom.querySelectorAll('style');
  956 + var scriptDoms = tempDom.querySelectorAll('script');
  957 + return {
  958 + doms: doms,
  959 + styles: styleDoms,
  960 + scripts: scriptDoms
  961 + }
  962 + }
  963 + return { doms: doms }
  964 + }
  965 + function generatePageParams() {
  966 + const totalHeightPx = Math.max(
  967 + printWin.document.documentElement.scrollHeight, // 整个文档高度
  968 + printWin.document.body.scrollHeight // Body 的高度
  969 + );
  970 + const totalHeightMM = totalHeightPx * 25.4 / 96;
  971 + // ie浏览器高度
  972 + var A4HeightMM = 287;
  973 + if (browser == "Google Chrome") {
  974 + A4HeightMM = 297;
  975 + }
  976 + var pages = Math.ceil(totalHeightMM / A4HeightMM) + 1;
  977 + for (var page = 0; page < pages; page++) {
  978 + var pageFooteDiv = printWin.document.createElement('div');
  979 + pageFooteDiv.classList.add('page-footer');
  980 + pageFooteDiv.innerText = `${paperTitle} ${subjectName} 第${page + 1}页(共${pages}页)`;
  981 + pageFooteDiv.style.top = (page + 1) * A4HeightMM + (page * 5.5) + 'mm';
  982 + printWin.document.body.appendChild(pageFooteDiv);
  983 + }
  984 + }
  985 + // size: A4 portrait;
  986 + // size: A3 landscape;
  987 +
  988 + printWin.document.title = "中天易教";
  989 + const style = printWin.document.createElement('style');
  990 + style.innerHTML = `
  991 + @media print
  992 + {
  993 + @page {
  994 + size: A4 portrait;
  995 + height: 300mm;
  996 + margin-top:5mm;
  997 + margin-bottom:10mm;
  998 + margin-left:2mm;
  999 + margin-right:2mm;
  1000 + }
  1001 +
  1002 + body {
  1003 + counter-reset: page-number; /* 重置页码计数器 */
  1004 + }
  1005 +
  1006 + mn {
  1007 + padding-top:2px;
  1008 + }
  1009 + }
  1010 + table tfoot {
  1011 + height: 0px;
  1012 + display: table-footer-group;
  1013 + }
  1014 + table thead {
  1015 + height: 20px;
  1016 + display: table-header-group;
  1017 + }
  1018 + .student-input {
  1019 + text-align:center;
  1020 + margin-bottom:10px;
  1021 + span
  1022 + {
  1023 + margin-right:10px;
  1024 + }
  1025 + }
  1026 + .page-left {
  1027 + height: 1100px;
  1028 + width:30px;
  1029 + position:fixed;
  1030 + top:0;
  1031 + left:0;
  1032 + }
  1033 + .page-right {
  1034 + height:1100px;
  1035 + width:30px;
  1036 + position:fixed;
  1037 + top:0;
  1038 + right:0;
  1039 + }
  1040 + .page-header {
  1041 + height:20px;
  1042 + width:100%;
  1043 + text-align:center;
  1044 + position:fixed;
  1045 + top:0;
  1046 + left:0;
  1047 + }
  1048 + .page-footer {
  1049 + height:20px;
  1050 + width:100%;
  1051 + text-align:center;
  1052 + position: absolute;
  1053 + }
  1054 + h3,h2
  1055 + {
  1056 + margin:3px 0px 3px 0px;
  1057 + }
  1058 + .title-header
  1059 + {
  1060 + .title-content {
  1061 + text-align:center;
  1062 + }
  1063 + }
  1064 + b
  1065 + {
  1066 + font-weight:500;
  1067 + margin:10px 0px;
  1068 + }
  1069 + p,table
  1070 + {
  1071 + font-size:16px;
  1072 + margin:0px;
  1073 + padding:0px 0px 2px 0px;
  1074 +
  1075 + margin-block-start:0px;
  1076 + margin-block-end: 0px;
  1077 + margin-inline-start: 0px;
  1078 + margin-inline-end: 0px;
  1079 + span,*,image,img,tr,td
  1080 + {
  1081 + font-size:16px;
  1082 + line-height:20px !important;
  1083 + }
  1084 + img,image
  1085 + {
  1086 + margin:0px;
  1087 + padding:0px;
  1088 + transform: scale(0.65);
  1089 + transform-origin: center;
  1090 + }
  1091 + }`;
  1092 +
  1093 + printWin.document.head.appendChild(style);
  1094 +
  1095 + const titleBoxDom = printWin.document.createElement('div');
  1096 + titleBoxDom.classList.add('title-header');
  1097 + const titleDom = printWin.document.createElement('h3');
  1098 + titleDom.innerText = paperTitle;
  1099 + titleDom.classList.add('title-content');
  1100 + const subjectDom = printWin.document.createElement('h2');
  1101 + subjectDom.innerText = subjectName;
  1102 + subjectDom.classList.add('title-content');
  1103 + titleBoxDom.appendChild(titleDom);
  1104 + titleBoxDom.appendChild(subjectDom);
  1105 + printWin.document.body.appendChild(titleBoxDom);
  1106 +
  1107 + const studentInputBoxDom = printWin.document.createElement('div');
  1108 + studentInputBoxDom.classList.add('student-input');
  1109 + const studentClassInputDom = printWin.document.createElement('span');
  1110 + studentClassInputDom.innerHTML = '班级:________________';
  1111 + const studentNameInputDom = printWin.document.createElement('span');
  1112 + studentNameInputDom.innerHTML = '姓名:________________';
  1113 + const studentNoInputDom = printWin.document.createElement('span');
  1114 + studentNoInputDom.innerHTML = '学号:________________';
  1115 + studentInputBoxDom.appendChild(studentClassInputDom);
  1116 + studentInputBoxDom.appendChild(studentNameInputDom);
  1117 + studentInputBoxDom.appendChild(studentNoInputDom);
  1118 + printWin.document.body.appendChild(studentInputBoxDom);
  1119 +
  1120 + const tableDom = printWin.document.createElement('table');
  1121 + const theadDom = printWin.document.createElement('thead');
  1122 + const theadTrDom = printWin.document.createElement('tr');
  1123 + theadTrDom.appendChild(printWin.document.createElement('th'));
  1124 + theadTrDom.appendChild(printWin.document.createElement('th'));
  1125 + theadTrDom.appendChild(printWin.document.createElement('th'));
  1126 + theadDom.appendChild(theadTrDom);
  1127 + tableDom.appendChild(theadDom);
  1128 +
  1129 + const tbodyDom = printWin.document.createElement('tbody');
  1130 +
  1131 + for (var iof = 0; iof < paperQuestions.length; iof++) {
  1132 + var item = paperQuestions[iof];
  1133 + if (!item || !item.subQuestions) continue;
  1134 +
  1135 + const tbodyTrDom = printWin.document.createElement('tr');
  1136 + const tbodyLeftAltTdDom = printWin.document.createElement('td');
  1137 + const tbodyContentTdDom = printWin.document.createElement('td');
  1138 + const tbodyRightAltTdDom = printWin.document.createElement('td');
  1139 +
  1140 + const questionTitleDom = printWin.document.createElement('div');
  1141 + questionTitleDom.innerText = `${numberToChinese(iof + 1)}、${item.questionTitle}(本节共${item.subQuestions.length}小题,共${item.score}分)`;
  1142 +
  1143 + tbodyContentTdDom.appendChild(questionTitleDom);
  1144 + tbodyTrDom.appendChild(tbodyLeftAltTdDom);
  1145 + tbodyTrDom.appendChild(tbodyContentTdDom);
  1146 + tbodyTrDom.appendChild(tbodyRightAltTdDom);
  1147 + tbodyDom.appendChild(tbodyTrDom);
  1148 +
  1149 + for (var idof = 0; idof < item.subQuestions.length; idof++) {
  1150 + const qTbodyTrDom = printWin.document.createElement('tr');
  1151 + const qTbodyLeftAltTdDom = printWin.document.createElement('td');
  1152 + const qTbodyContentTdDom = printWin.document.createElement('td');
  1153 + const qTbodyRightAltTdDom = printWin.document.createElement('td');
  1154 +
  1155 + const questionDom = printWin.document.createElement('div');
  1156 + var subItem = item.subQuestions[idof];
  1157 + var screenshotHtml = await fetchHTML(subItem.screenshot);
  1158 + var getStyleScripts = iof == 0 && idof == 0;
  1159 + var screenshotObject = htmlParseDom(screenshotHtml, getStyleScripts);
  1160 + var screenshotDoms = screenshotObject.doms;
  1161 + if (screenshotDoms.length <= 0) continue;
  1162 + for (var dom = 0; dom < screenshotDoms.length; dom++) {
  1163 + var screenshotDom = screenshotDoms[dom];
  1164 + questionDom.appendChild(screenshotDom);
  1165 + }
  1166 + qTbodyContentTdDom.appendChild(questionDom);
  1167 + qTbodyTrDom.appendChild(qTbodyLeftAltTdDom);
  1168 + qTbodyTrDom.appendChild(qTbodyContentTdDom);
  1169 + qTbodyTrDom.appendChild(qTbodyRightAltTdDom);
  1170 + tbodyDom.appendChild(qTbodyTrDom);
  1171 + }
  1172 + }
  1173 + tableDom.appendChild(tbodyDom);
  1174 + printWin.document.body.appendChild(tableDom);
  1175 +
  1176 + const tfootDom = printWin.document.createElement('tfoot');
  1177 + const tfootTrDom = printWin.document.createElement('tr');
  1178 + tfootTrDom.appendChild(printWin.document.createElement('td'));
  1179 + tfootTrDom.appendChild(printWin.document.createElement('td'));
  1180 + tfootTrDom.appendChild(printWin.document.createElement('td'));
  1181 + tfootDom.appendChild(tfootTrDom);
  1182 + tableDom.appendChild(tfootDom);
  1183 + // generatePageParams();
  1184 + const iamges = printWin.document.querySelectorAll('img');
  1185 + if (iamges.length >= 1) {
  1186 + iamges[iamges.length - 1].onload = function () {
  1187 + printWin.print();
  1188 + printWin.close();
  1189 + }
  1190 + } else {
  1191 + printWin.print();
  1192 + printWin.close();
  1193 + }
  1194 +}
875 1195
876 export function tablePrint(options) { 1196 export function tablePrint(options) {
877 var id = options.id; 1197 var id = options.id;
@@ -883,22 +1203,23 @@ export function tablePrint(options) { @@ -883,22 +1203,23 @@ export function tablePrint(options) {
883 var diffNumber = options.diffNumber ?? 0; 1203 var diffNumber = options.diffNumber ?? 0;
884 var diffStNumber = options.diffStNumber ?? 0; 1204 var diffStNumber = options.diffStNumber ?? 0;
885 let divs = document.getElementById(id); 1205 let divs = document.getElementById(id);
886 - let awin = window.open("中天易教", "_blank");  
887 - awin.document.getElementsByTagName("head")[0].innerHTML = `<style> 1206 + let awin = window.open("中天易教", "_blank", "width=800,height=600,resizable=no");
  1207 + awin.document.getElementsByTagName(
  1208 + "head"
  1209 + )[0].innerHTML = `<style>
888 @media print { 1210 @media print {
889 @page { 1211 @page {
890 size: A4 portrait; 1212 size: A4 portrait;
891 margin-top: 4mm; 1213 margin-top: 4mm;
892 - margin-left:2mm;  
893 - margin-right:2mm; 1214 + margin-left: 2mm;
  1215 + margin-right: 2mm;
894 } 1216 }
895 1217
896 1218
897 body { 1219 body {
898 margin: 2mm; 1220 margin: 2mm;
899 font-size: 8px; 1221 font-size: 8px;
900 - }  
901 - 1222 + }
902 } 1223 }
903 1224
904 * :not(.tit) { 1225 * :not(.tit) {
src/views/basic/askTestQuestion/index.vue
@@ -70,7 +70,9 @@ @@ -70,7 +70,9 @@
70 <el-dropdown-menu slot="dropdown"> 70 <el-dropdown-menu slot="dropdown">
71 <el-dropdown-item 71 <el-dropdown-item
72 @click.native="_detailQ(item.id)">查看</el-dropdown-item> 72 @click.native="_detailQ(item.id)">查看</el-dropdown-item>
73 - <el-dropdown-item @click.native="_updateQ(item)">修改</el-dropdown-item> 73 + <el-dropdown-item v-if="dataType != 1"
  74 + @click.native="_print(item)">打印</el-dropdown-item>
  75 + <el-dropdown-item @click.native="_updateQ(item)">修改</el-dropdown-item>
74 <el-dropdown-item @click.native="_copy(item)">复制</el-dropdown-item> 76 <el-dropdown-item @click.native="_copy(item)">复制</el-dropdown-item>
75 <el-dropdown-item> 77 <el-dropdown-item>
76 <el-popconfirm style="color:gray !important;" 78 <el-popconfirm style="color:gray !important;"
@@ -317,6 +319,7 @@ @@ -317,6 +319,7 @@
317 319
318 <script> 320 <script>
319 import { setDateRules, downloadFile } from "@/utils"; 321 import { setDateRules, downloadFile } from "@/utils";
  322 +import { paperPrint } from "@/utils";
320 import example from "@/assets/images/example.png"; 323 import example from "@/assets/images/example.png";
321 import example2 from "@/assets/images/example2.png"; 324 import example2 from "@/assets/images/example2.png";
322 import axios from "axios"; 325 import axios from "axios";
@@ -646,6 +649,18 @@ export default { @@ -646,6 +649,18 @@ export default {
646 _delete() { 649 _delete() {
647 650
648 }, 651 },
  652 + async _print(item){
  653 + this.$loading.open();
  654 + const { data, status, info } = await this.$request.tPaperDetail({
  655 + paperId: item.id
  656 + });
  657 + this.$loading.close();
  658 + if (status != 0) {
  659 + this.$message.error(info);
  660 + return;
  661 + }
  662 + await paperPrint(data);
  663 + },
649 _updateQ(item) { 664 _updateQ(item) {
650 665
651 var currentClass = this.classList.find(item => item.classId == this.query.class); 666 var currentClass = this.classList.find(item => item.classId == this.query.class);