Commit d3943e0ddc5d04ef2c3044c7bd9239906828b6ed
1 parent
06869a45
feat:错题打印
Showing
5 changed files
with
345 additions
and
11 deletions
.gitignore
.vs/slnx.sqlite deleted
No preview for this file type
src/config/index.js
src/utils/index.js
... | ... | @@ -609,6 +609,17 @@ export function getBlob(url) { |
609 | 609 | ); |
610 | 610 | }); |
611 | 611 | } |
612 | +export function fetchHTML(url) { | |
613 | + return new Promise((resolve) => { | |
614 | + resolve( | |
615 | + service({ | |
616 | + url: url, | |
617 | + withCredentials: false, | |
618 | + method: "get" | |
619 | + }) | |
620 | + ); | |
621 | + }); | |
622 | +} | |
612 | 623 | /** |
613 | 624 | * 打包压缩下载 |
614 | 625 | */ |
... | ... | @@ -867,10 +878,318 @@ export function formatGradeNameClass(data) { |
867 | 878 | }); |
868 | 879 | return gradeNameArr; |
869 | 880 | } |
870 | -_ | |
871 | 881 | |
872 | -export function tablePrint(options) { | |
882 | +///试卷定制化打印 | |
883 | +export async function paperPrint(paper) { | |
884 | + let printWin = window.open("", "_blank", "width=800,height=600,resizable=no"); | |
885 | + var browser = getBrowserEngine(printWin); | |
886 | + var subjectName = paper.subjectName; | |
887 | + var paperTitle = paper.title; | |
888 | + var paperQuestions = paper.questionList; | |
889 | + function getBrowserEngine(windowParams) { | |
890 | + if (windowParams.navigator.userAgent.indexOf("Edge") > -1) { | |
891 | + return "EdgeHTML"; | |
892 | + } | |
893 | + if (windowParams.navigator.userAgent.indexOf("Edg") > -1) { | |
894 | + return "Blink"; // Microsoft Edge (Chromium) | |
895 | + } | |
896 | + if (windowParams.navigator.userAgent.indexOf("Firefox") > -1) { | |
897 | + return "Gecko"; | |
898 | + } | |
899 | + if (windowParams.navigator.userAgent.indexOf("Trident") > -1) { | |
900 | + return "Trident"; // IE | |
901 | + } | |
902 | + if (/Chrome/.test(windowParams.navigator.userAgent) && /Google Inc/.test(windowParams.navigator.vendor)) { | |
903 | + return 'Google Chrome'; | |
904 | + } | |
905 | + if (/360/.test(windowParams.navigator.userAgent) || /QIHU/.test(windowParams.navigator.userAgent)) { | |
906 | + return '360 Browser'; | |
907 | + } | |
908 | + return "Blink"; // Assume it's Chrome, Safari, or an alternative Blink-based browser | |
909 | + } | |
910 | + function numberToChinese(num) { | |
911 | + const chineseDigits = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]; | |
912 | + const chineseUnits = ["", "十", "百", "千", "万", "亿"]; | |
913 | + | |
914 | + let result = ''; | |
915 | + let unitPos = 0; // 单位的位置 | |
916 | + let zeroFlag = false; // 是否出现过零 | |
917 | + | |
918 | + if (num === 0) { | |
919 | + return chineseDigits[0]; // 特殊情况,0 返回 "零" | |
920 | + } | |
921 | + | |
922 | + // 处理数字,每次取一位并加上单位 | |
923 | + while (num > 0) { | |
924 | + const currentDigit = num % 10; // 取最后一位数字 | |
925 | + if (currentDigit === 0) { | |
926 | + if (!zeroFlag) { | |
927 | + result = chineseDigits[currentDigit] + result; // 只在出现零时添加 | |
928 | + zeroFlag = true; // 标记零已经出现 | |
929 | + } | |
930 | + } else { | |
931 | + result = chineseDigits[currentDigit] + chineseUnits[unitPos] + result; | |
932 | + zeroFlag = false; // 重置零的标记 | |
933 | + } | |
873 | 934 | |
935 | + num = Math.floor(num / 10); // 去掉最后一位数字 | |
936 | + unitPos++; | |
937 | + } | |
938 | + | |
939 | + // 处理 '一十' 和 '一百' 等情况 | |
940 | + if (result.startsWith('一十')) { | |
941 | + result = result.substring(1); // 去掉 '一',例如 '一十' -> '十' | |
942 | + } | |
943 | + | |
944 | + return result; | |
945 | + } | |
946 | + function htmlParseDom(html, getStyleScripts) { | |
947 | + var tempDom = document.createElement('div'); | |
948 | + tempDom.innerHTML = html; | |
949 | + var doms = tempDom.querySelectorAll('p'); | |
950 | + if (getStyleScripts == true) { | |
951 | + var styleDoms = tempDom.querySelectorAll('style'); | |
952 | + var scriptDoms = tempDom.querySelectorAll('script'); | |
953 | + return { | |
954 | + doms: doms, | |
955 | + styles: styleDoms, | |
956 | + scripts: scriptDoms | |
957 | + } | |
958 | + } | |
959 | + return { doms: doms } | |
960 | + } | |
961 | + function generatePageParams() { | |
962 | + const totalHeightPx = Math.max( | |
963 | + printWin.document.documentElement.scrollHeight, // 整个文档高度 | |
964 | + printWin.document.body.scrollHeight // Body 的高度 | |
965 | + ); | |
966 | + const totalHeightMM = totalHeightPx * 25.4 / 96; | |
967 | + // ie浏览器高度 | |
968 | + var A4HeightMM = 287; | |
969 | + if (browser == "Google Chrome") { | |
970 | + A4HeightMM = 297; | |
971 | + } | |
972 | + var pages = Math.ceil(totalHeightMM / A4HeightMM) + 1; | |
973 | + for (var page = 0; page < pages; page++) { | |
974 | + var pageFooteDiv = printWin.document.createElement('div'); | |
975 | + pageFooteDiv.classList.add('page-footer'); | |
976 | + pageFooteDiv.innerText = `${paperTitle} ${subjectName} 第${page + 1}页(共${pages}页)`; | |
977 | + pageFooteDiv.style.top = (page + 1) * A4HeightMM + (page * 5.5) + 'mm'; | |
978 | + printWin.document.body.appendChild(pageFooteDiv); | |
979 | + } | |
980 | + } | |
981 | + // size: A4 portrait; | |
982 | + // size: A3 landscape; | |
983 | + | |
984 | + printWin.document.title = "中天易教"; | |
985 | + const style = printWin.document.createElement('style'); | |
986 | + style.innerHTML = ` | |
987 | + @media print | |
988 | + { | |
989 | + @page { | |
990 | + size: A4 portrait; | |
991 | + height: 300mm; | |
992 | + margin-top:5mm; | |
993 | + margin-bottom:10mm; | |
994 | + margin-left:2mm; | |
995 | + margin-right:2mm; | |
996 | + } | |
997 | + | |
998 | + body { | |
999 | + counter-reset: page-number; /* 重置页码计数器 */ | |
1000 | + } | |
1001 | + | |
1002 | + mn { | |
1003 | + padding-top:2px; | |
1004 | + } | |
1005 | + } | |
1006 | + table tfoot { | |
1007 | + height: 0px; | |
1008 | + display: table-footer-group; | |
1009 | + } | |
1010 | + table thead { | |
1011 | + height: 20px; | |
1012 | + display: table-header-group; | |
1013 | + } | |
1014 | + .student-input { | |
1015 | + text-align:center; | |
1016 | + margin-bottom:10px; | |
1017 | + span | |
1018 | + { | |
1019 | + margin-right:10px; | |
1020 | + } | |
1021 | + } | |
1022 | + .page-left { | |
1023 | + height: 1100px; | |
1024 | + width:30px; | |
1025 | + position:fixed; | |
1026 | + top:0; | |
1027 | + left:0; | |
1028 | + } | |
1029 | + .page-right { | |
1030 | + height:1100px; | |
1031 | + width:30px; | |
1032 | + position:fixed; | |
1033 | + top:0; | |
1034 | + right:0; | |
1035 | + } | |
1036 | + .page-header { | |
1037 | + height:20px; | |
1038 | + width:100%; | |
1039 | + text-align:center; | |
1040 | + position:fixed; | |
1041 | + top:0; | |
1042 | + left:0; | |
1043 | + } | |
1044 | + .page-footer { | |
1045 | + height:20px; | |
1046 | + width:100%; | |
1047 | + text-align:center; | |
1048 | + position: absolute; | |
1049 | + } | |
1050 | + h3,h2 | |
1051 | + { | |
1052 | + margin:3px 0px 3px 0px; | |
1053 | + } | |
1054 | + .title-header | |
1055 | + { | |
1056 | + .title-content { | |
1057 | + text-align:center; | |
1058 | + } | |
1059 | + } | |
1060 | + b | |
1061 | + { | |
1062 | + font-weight:500; | |
1063 | + margin:10px 0px; | |
1064 | + } | |
1065 | + p,table | |
1066 | + { | |
1067 | + font-size:16px; | |
1068 | + margin:0px; | |
1069 | + padding:0px 0px 2px 0px; | |
1070 | + | |
1071 | + margin-block-start:0px; | |
1072 | + margin-block-end: 0px; | |
1073 | + margin-inline-start: 0px; | |
1074 | + margin-inline-end: 0px; | |
1075 | + span,*,image,img,tr,td | |
1076 | + { | |
1077 | + font-size:16px; | |
1078 | + line-height:20px !important; | |
1079 | + } | |
1080 | + img,image | |
1081 | + { | |
1082 | + margin:0px; | |
1083 | + padding:0px; | |
1084 | + transform: scale(0.65); | |
1085 | + transform-origin: center; | |
1086 | + } | |
1087 | + }`; | |
1088 | + | |
1089 | + printWin.document.head.appendChild(style); | |
1090 | + | |
1091 | + const titleBoxDom = printWin.document.createElement('div'); | |
1092 | + titleBoxDom.classList.add('title-header'); | |
1093 | + const titleDom = printWin.document.createElement('h3'); | |
1094 | + titleDom.innerText = paperTitle; | |
1095 | + titleDom.classList.add('title-content'); | |
1096 | + const subjectDom = printWin.document.createElement('h2'); | |
1097 | + subjectDom.innerText = subjectName; | |
1098 | + subjectDom.classList.add('title-content'); | |
1099 | + titleBoxDom.appendChild(titleDom); | |
1100 | + titleBoxDom.appendChild(subjectDom); | |
1101 | + printWin.document.body.appendChild(titleBoxDom); | |
1102 | + | |
1103 | + const studentInputBoxDom = printWin.document.createElement('div'); | |
1104 | + studentInputBoxDom.classList.add('student-input'); | |
1105 | + const studentClassInputDom = printWin.document.createElement('span'); | |
1106 | + studentClassInputDom.innerHTML = '班级:________________'; | |
1107 | + const studentNameInputDom = printWin.document.createElement('span'); | |
1108 | + studentNameInputDom.innerHTML = '姓名:________________'; | |
1109 | + const studentNoInputDom = printWin.document.createElement('span'); | |
1110 | + studentNoInputDom.innerHTML = '学号:________________'; | |
1111 | + studentInputBoxDom.appendChild(studentClassInputDom); | |
1112 | + studentInputBoxDom.appendChild(studentNameInputDom); | |
1113 | + studentInputBoxDom.appendChild(studentNoInputDom); | |
1114 | + printWin.document.body.appendChild(studentInputBoxDom); | |
1115 | + | |
1116 | + const tableDom = printWin.document.createElement('table'); | |
1117 | + const theadDom = printWin.document.createElement('thead'); | |
1118 | + const theadTrDom = printWin.document.createElement('tr'); | |
1119 | + theadTrDom.appendChild(printWin.document.createElement('th')); | |
1120 | + theadTrDom.appendChild(printWin.document.createElement('th')); | |
1121 | + theadTrDom.appendChild(printWin.document.createElement('th')); | |
1122 | + theadDom.appendChild(theadTrDom); | |
1123 | + tableDom.appendChild(theadDom); | |
1124 | + | |
1125 | + const tbodyDom = printWin.document.createElement('tbody'); | |
1126 | + | |
1127 | + for (var iof = 0; iof < paperQuestions.length; iof++) { | |
1128 | + var item = paperQuestions[iof]; | |
1129 | + if (!item || !item.subQuestions) continue; | |
1130 | + | |
1131 | + const tbodyTrDom = printWin.document.createElement('tr'); | |
1132 | + const tbodyLeftAltTdDom = printWin.document.createElement('td'); | |
1133 | + const tbodyContentTdDom = printWin.document.createElement('td'); | |
1134 | + const tbodyRightAltTdDom = printWin.document.createElement('td'); | |
1135 | + | |
1136 | + const questionTitleDom = printWin.document.createElement('div'); | |
1137 | + questionTitleDom.innerText = `${numberToChinese(iof + 1)}、${item.questionTitle}(本节共${item.subQuestions.length}小题,共${item.score}分)`; | |
1138 | + | |
1139 | + tbodyContentTdDom.appendChild(questionTitleDom); | |
1140 | + tbodyTrDom.appendChild(tbodyLeftAltTdDom); | |
1141 | + tbodyTrDom.appendChild(tbodyContentTdDom); | |
1142 | + tbodyTrDom.appendChild(tbodyRightAltTdDom); | |
1143 | + tbodyDom.appendChild(tbodyTrDom); | |
1144 | + | |
1145 | + for (var idof = 0; idof < item.subQuestions.length; idof++) { | |
1146 | + const qTbodyTrDom = printWin.document.createElement('tr'); | |
1147 | + const qTbodyLeftAltTdDom = printWin.document.createElement('td'); | |
1148 | + const qTbodyContentTdDom = printWin.document.createElement('td'); | |
1149 | + const qTbodyRightAltTdDom = printWin.document.createElement('td'); | |
1150 | + | |
1151 | + const questionDom = printWin.document.createElement('div'); | |
1152 | + var subItem = item.subQuestions[idof]; | |
1153 | + var screenshotHtml = await fetchHTML(subItem.screenshot); | |
1154 | + var getStyleScripts = iof == 0 && idof == 0; | |
1155 | + var screenshotObject = htmlParseDom(screenshotHtml, getStyleScripts); | |
1156 | + var screenshotDoms = screenshotObject.doms; | |
1157 | + if (screenshotDoms.length <= 0) continue; | |
1158 | + for (var dom = 0; dom < screenshotDoms.length; dom++) { | |
1159 | + var screenshotDom = screenshotDoms[dom]; | |
1160 | + questionDom.appendChild(screenshotDom); | |
1161 | + } | |
1162 | + qTbodyContentTdDom.appendChild(questionDom); | |
1163 | + qTbodyTrDom.appendChild(qTbodyLeftAltTdDom); | |
1164 | + qTbodyTrDom.appendChild(qTbodyContentTdDom); | |
1165 | + qTbodyTrDom.appendChild(qTbodyRightAltTdDom); | |
1166 | + tbodyDom.appendChild(qTbodyTrDom); | |
1167 | + } | |
1168 | + } | |
1169 | + tableDom.appendChild(tbodyDom); | |
1170 | + printWin.document.body.appendChild(tableDom); | |
1171 | + | |
1172 | + const tfootDom = printWin.document.createElement('tfoot'); | |
1173 | + const tfootTrDom = printWin.document.createElement('tr'); | |
1174 | + tfootTrDom.appendChild(printWin.document.createElement('td')); | |
1175 | + tfootTrDom.appendChild(printWin.document.createElement('td')); | |
1176 | + tfootTrDom.appendChild(printWin.document.createElement('td')); | |
1177 | + tfootDom.appendChild(tfootTrDom); | |
1178 | + tableDom.appendChild(tfootDom); | |
1179 | + // generatePageParams(); | |
1180 | + const iamges = printWin.document.querySelectorAll('img'); | |
1181 | + if (iamges.length >= 1) { | |
1182 | + iamges[iamges.length - 1].onload = function () { | |
1183 | + printWin.print(); | |
1184 | + printWin.close(); | |
1185 | + } | |
1186 | + } else { | |
1187 | + printWin.print(); | |
1188 | + printWin.close(); | |
1189 | + } | |
1190 | +} | |
1191 | + | |
1192 | +export function tablePrint(options) { | |
874 | 1193 | var id = options.id; |
875 | 1194 | var title = options.title; |
876 | 1195 | var lindex = options.lindex; |
... | ... | @@ -880,7 +1199,7 @@ export function tablePrint(options) { |
880 | 1199 | var diffNumber = options.diffNumber ?? 0; |
881 | 1200 | var diffStNumber = options.diffStNumber ?? 0; |
882 | 1201 | let divs = document.getElementById(id); |
883 | - let awin = window.open("中天易教", "_blank"); | |
1202 | + let awin = window.open("中天易教", "_blank", "width=800,height=600,resizable=no"); | |
884 | 1203 | awin.document.getElementsByTagName( |
885 | 1204 | "head" |
886 | 1205 | )[0].innerHTML = `<style> |
... | ... | @@ -888,16 +1207,15 @@ export function tablePrint(options) { |
888 | 1207 | @page { |
889 | 1208 | size: A4 portrait; |
890 | 1209 | margin-top: 4mm; |
891 | - margin-left:2mm; | |
892 | - margin-right:2mm; | |
1210 | + margin-left: 2mm; | |
1211 | + margin-right: 2mm; | |
893 | 1212 | } |
894 | 1213 | |
895 | 1214 | |
896 | 1215 | body { |
897 | 1216 | margin: 2mm; |
898 | 1217 | font-size: 8px; |
899 | - } | |
900 | - | |
1218 | + } | |
901 | 1219 | } |
902 | 1220 | |
903 | 1221 | * :not(.tit) { |
... | ... | @@ -1294,7 +1612,7 @@ export function tablePrint(options) { |
1294 | 1612 | |
1295 | 1613 | awin.print(); |
1296 | 1614 | |
1297 | - awin.close() | |
1615 | + awin.close(); | |
1298 | 1616 | } |
1299 | 1617 | |
1300 | 1618 | export const cNum = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", | ... | ... |
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); | ... | ... |