Commit ce926d5e338904d6542a7c1c2af6124b1cfe0105
feat : 新增错题组卷
Showing
6 changed files
with
352 additions
and
17 deletions
.gitignore
.vs/slnx.sqlite deleted
No preview for this file type
src/api/apis/apis.js
... | ... | @@ -1049,15 +1049,15 @@ export default { |
1049 | 1049 | }, |
1050 | 1050 | // 获取科目列表 |
1051 | 1051 | getSubjectList(data) { |
1052 | - return defaltService(setUpUrls.subjectList, data); | |
1052 | + return defaltService(setUpUrls.teacherSubjectList, data); | |
1053 | 1053 | }, |
1054 | 1054 | // 获取年级信息 |
1055 | 1055 | getClassList(data) { |
1056 | - return defaltService(setUpUrls.classList, data); | |
1056 | + return defaltService(setUpUrls.teacherClassList, data); | |
1057 | 1057 | }, |
1058 | 1058 | // 获取班级信息 |
1059 | 1059 | getGradeList(data) { |
1060 | - return defaltGetService(setUpUrls.gradeList, data); | |
1060 | + return defaltGetService(setUpUrls.teacherGradeList, data); | |
1061 | 1061 | }, |
1062 | 1062 | // 获取班级信息 |
1063 | 1063 | getWrongQuestionSave(data) { | ... | ... |
src/api/urls/apis.js
... | ... | @@ -496,18 +496,16 @@ export default { |
496 | 496 | listStudentsAndQuestions: "/api_html/teaching/listStudentsAndQuestions", |
497 | 497 | //分页查询授课端日志列表 |
498 | 498 | deviceZipLogList: "/api_html/school/manager/deviceZipLogList", |
499 | - | |
500 | 499 | //获取即时测报表录分情况 |
501 | 500 | getScoreType: "/api_html/teaching/getScoreType", |
502 | - | |
503 | 501 | // 获取错题本列表 |
504 | 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 | 510 | getWrongQuestionSave: "api_html/teaching/wrongQuestion/save", |
513 | 511 | }; | ... | ... |
src/utils/index.js
... | ... | @@ -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 | 882 | }); |
872 | 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 | 1196 | export function tablePrint(options) { |
877 | 1197 | var id = options.id; |
... | ... | @@ -883,22 +1203,23 @@ export function tablePrint(options) { |
883 | 1203 | var diffNumber = options.diffNumber ?? 0; |
884 | 1204 | var diffStNumber = options.diffStNumber ?? 0; |
885 | 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 | 1210 | @media print { |
889 | 1211 | @page { |
890 | 1212 | size: A4 portrait; |
891 | 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 | 1219 | body { |
898 | 1220 | margin: 2mm; |
899 | 1221 | font-size: 8px; |
900 | - } | |
901 | - | |
1222 | + } | |
902 | 1223 | } |
903 | 1224 | |
904 | 1225 | * :not(.tit) { | ... | ... |
src/views/basic/askTestQuestion/index.vue
... | ... | @@ -70,7 +70,9 @@ |
70 | 70 | <el-dropdown-menu slot="dropdown"> |
71 | 71 | <el-dropdown-item |
72 | 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 | 76 | <el-dropdown-item @click.native="_copy(item)">复制</el-dropdown-item> |
75 | 77 | <el-dropdown-item> |
76 | 78 | <el-popconfirm style="color:gray !important;" |
... | ... | @@ -317,6 +319,7 @@ |
317 | 319 | |
318 | 320 | <script> |
319 | 321 | import { setDateRules, downloadFile } from "@/utils"; |
322 | +import { paperPrint } from "@/utils"; | |
320 | 323 | import example from "@/assets/images/example.png"; |
321 | 324 | import example2 from "@/assets/images/example2.png"; |
322 | 325 | import axios from "axios"; |
... | ... | @@ -646,6 +649,18 @@ export default { |
646 | 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 | 664 | _updateQ(item) { |
650 | 665 | |
651 | 666 | var currentClass = this.classList.find(item => item.classId == this.query.class); | ... | ... |