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
1 | const modeUrl = { | 1 | const modeUrl = { |
2 | // 开发环境 | 2 | // 开发环境 |
3 | development: { | 3 | development: { |
4 | - baseURL: "/", | 4 | + baseURL: "/api/", |
5 | authBaseURL: "", | 5 | authBaseURL: "", |
6 | $cdn:"" | 6 | $cdn:"" |
7 | }, | 7 | }, |
8 | // 生产环境 | 8 | // 生产环境 |
9 | production: { | 9 | production: { |
10 | - baseURL: "/", | 10 | + baseURL: "/api/", |
11 | authBaseURL: "", | 11 | authBaseURL: "", |
12 | $cdn:"" | 12 | $cdn:"" |
13 | }, | 13 | }, |
src/utils/index.js
@@ -609,6 +609,17 @@ export function getBlob(url) { | @@ -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,10 +878,318 @@ export function formatGradeNameClass(data) { | ||
867 | }); | 878 | }); |
868 | return gradeNameArr; | 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 | var id = options.id; | 1193 | var id = options.id; |
875 | var title = options.title; | 1194 | var title = options.title; |
876 | var lindex = options.lindex; | 1195 | var lindex = options.lindex; |
@@ -880,7 +1199,7 @@ export function tablePrint(options) { | @@ -880,7 +1199,7 @@ export function tablePrint(options) { | ||
880 | var diffNumber = options.diffNumber ?? 0; | 1199 | var diffNumber = options.diffNumber ?? 0; |
881 | var diffStNumber = options.diffStNumber ?? 0; | 1200 | var diffStNumber = options.diffStNumber ?? 0; |
882 | let divs = document.getElementById(id); | 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 | awin.document.getElementsByTagName( | 1203 | awin.document.getElementsByTagName( |
885 | "head" | 1204 | "head" |
886 | )[0].innerHTML = `<style> | 1205 | )[0].innerHTML = `<style> |
@@ -888,16 +1207,15 @@ export function tablePrint(options) { | @@ -888,16 +1207,15 @@ export function tablePrint(options) { | ||
888 | @page { | 1207 | @page { |
889 | size: A4 portrait; | 1208 | size: A4 portrait; |
890 | margin-top: 4mm; | 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 | body { | 1215 | body { |
897 | margin: 2mm; | 1216 | margin: 2mm; |
898 | font-size: 8px; | 1217 | font-size: 8px; |
899 | - } | ||
900 | - | 1218 | + } |
901 | } | 1219 | } |
902 | 1220 | ||
903 | * :not(.tit) { | 1221 | * :not(.tit) { |
@@ -1294,7 +1612,7 @@ export function tablePrint(options) { | @@ -1294,7 +1612,7 @@ export function tablePrint(options) { | ||
1294 | 1612 | ||
1295 | awin.print(); | 1613 | awin.print(); |
1296 | 1614 | ||
1297 | - awin.close() | 1615 | + awin.close(); |
1298 | } | 1616 | } |
1299 | 1617 | ||
1300 | export const cNum = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", | 1618 | export const cNum = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", |
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); |