TpMain.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <template>
  2. <div class="markmain pull-left" id="student_paper">
  3. <el-tabs :active-name="activeName">
  4. <el-tab-pane label="考生答卷" name="first">
  5. <div v-if="this.examType != 'OFFLINE'">
  6. <div id="main-source" v-if="this.studentPaper.id != ''">
  7. <div
  8. class="paper"
  9. v-if="!this.markSign"
  10. v-html="this.studentPaper.studentSubjectiveHtml"
  11. ></div>
  12. <div class="paper" v-show="this.markSign">
  13. <div class="fixed marktitle signTitle">
  14. <el-button-group class="itemTitle">
  15. <el-button type="info" size="small">
  16. <span class>当前题</span>
  17. </el-button>
  18. <el-button type="info" size="small">
  19. <span class>{{ itemTitle }}</span>
  20. </el-button>
  21. </el-button-group>
  22. <!--
  23. <el-button type="primary" size="small" @click="saveMarkSign">保存轨迹</el-button>
  24. -->
  25. <el-button type="danger" size="small" @click="delMarkSign"
  26. >清除轨迹</el-button
  27. >
  28. <el-button type="danger" size="small" @click="delAllMarkSign"
  29. >清除全部轨迹</el-button
  30. >
  31. </div>
  32. <div>
  33. <canvas id="canvas" width="800px" height="800px"></canvas>
  34. </div>
  35. </div>
  36. </div>
  37. </div>
  38. <div v-if="this.examType == 'OFFLINE'">
  39. <div v-if="this.studentPaper.id != ''">
  40. <div v-html="getPdfUrl()" style="float: left;"></div>
  41. <div
  42. v-if="
  43. this.studentPaper.studentSubjectiveHtml &&
  44. this.studentPaper.studentSubjectiveHtml != '' &&
  45. this.studentPaper.studentSubjectiveHtml.indexOf('.pdf') > -1
  46. "
  47. style="float: right;margin-right: 20px;"
  48. class="no-print"
  49. >
  50. <el-button size="small" type="success" @click="pdfDown()"
  51. >下载</el-button
  52. >
  53. </div>
  54. </div>
  55. </div>
  56. </el-tab-pane>
  57. <template v-if="this.examType == 'OFFLINE'">
  58. <el-tab-pane label="标答" name="second">
  59. <div id="answer-source" v-if="this.examType == 'OFFLINE'">
  60. <div style="float: right;margin-right: 20px;" class="no-print">
  61. <el-button size="small" type="success" @click="printAnswer()"
  62. >打印</el-button
  63. >
  64. </div>
  65. <div
  66. class="paper"
  67. id="answer-content"
  68. v-html="this.answerHtml"
  69. ></div>
  70. </div>
  71. </el-tab-pane>
  72. </template>
  73. </el-tabs>
  74. <el-dialog
  75. title="查看图片"
  76. width="800px"
  77. :visible.sync="picModel"
  78. :close-on-click-modal="false"
  79. @close="closePicModel"
  80. >
  81. <el-button size="mini" icon="el-icon-refresh-left" @click="leftRotate"
  82. >左旋</el-button
  83. >
  84. <el-button size="mini" icon="el-icon-refresh-right" @click="rightRotate"
  85. >右旋</el-button
  86. >
  87. <div class="block-seperator"></div>
  88. <div class="img-div">
  89. <img
  90. v-if="this.picForm.imgUrl != null"
  91. :src="picForm.imgUrl"
  92. height="100%"
  93. width="100%"
  94. :style="{
  95. width: '100%',
  96. transform: 'rotate(' + picForm.rotate + 'deg)'
  97. }"
  98. />
  99. </div>
  100. </el-dialog>
  101. </div>
  102. </template>
  103. <script>
  104. import { Drawing } from "../canvas/mark_sign";
  105. import { EVENTHUB } from "../constants/constants";
  106. import printJS from "print-js";
  107. export default {
  108. data() {
  109. return {
  110. activeName: "first",
  111. drawing: {},
  112. tmpSignScores: this.signScores,
  113. tmpMarkSign: this.markSign,
  114. picModelKey: Math.random(),
  115. picModel: false,
  116. picForm: {
  117. imgUrl: "",
  118. rotate: 0
  119. }
  120. };
  121. },
  122. props: [
  123. "paperMarkSign",
  124. "studentPaper",
  125. "markSign",
  126. "signOption",
  127. "signScores",
  128. "signItem",
  129. "examType",
  130. "answerHtml"
  131. ],
  132. methods: {
  133. rightRotate() {
  134. this.picForm.rotate = this.picForm.rotate + 90;
  135. },
  136. leftRotate() {
  137. this.picForm.rotate = this.picForm.rotate - 90;
  138. },
  139. closePicModel() {
  140. this.picForm.rotate = 0;
  141. this.picModel = false;
  142. this.picForm.imgUrl = null;
  143. this.picModelKey = Math.random();
  144. },
  145. viewPicture(src) {
  146. this.picForm.imgUrl = src;
  147. this.picModel = true;
  148. },
  149. getPdfUrl() {
  150. var url = this.studentPaper.studentSubjectiveHtml;
  151. var content = "";
  152. if (url) {
  153. if (url != "" && url.indexOf(".pdf") > -1) {
  154. content =
  155. "<embed src='" + url + "' width='800px' height='800px'></embed>";
  156. }
  157. if (url != "" && url.indexOf(".zip") > -1) {
  158. content = "<a href='" + url + "'>下载</a>";
  159. }
  160. }
  161. return content;
  162. },
  163. createMarkDraw() {
  164. console.log("create");
  165. var drawing = {};
  166. this.signOption.data = this.studentPaper.studentSubjectiveHtml;
  167. drawing = new Drawing("canvas", this.signOption);
  168. this.drawing = drawing;
  169. },
  170. intMarkDraw() {
  171. console.log("init");
  172. if (this.markSign) {
  173. this.clearScoreLoc();
  174. this.clearScores();
  175. this.setMarkDrawHtml();
  176. this.setSignLocation();
  177. }
  178. },
  179. setMarkDrawHtml() {
  180. this.drawing.setHtml(this.studentPaper.studentSubjectiveHtml);
  181. },
  182. saveMarkSign() {
  183. if (this.drawing.canvas && this.signItem.id) {
  184. localStorage.removeItem(this.paperKey);
  185. localStorage.setItem(this.paperKey, JSON.stringify(this.paperSigns));
  186. this.$notify({
  187. message: "轨迹保存成功",
  188. type: "success"
  189. });
  190. } else {
  191. this.$notify({
  192. message: "请选择给分步骤",
  193. type: "error"
  194. });
  195. }
  196. },
  197. setSignLocation() {
  198. let signStorage = localStorage.getItem(this.paperKey);
  199. console.log("signStorage", signStorage);
  200. if (typeof signStorage == "string") {
  201. let paperSigns = JSON.parse(signStorage);
  202. if (
  203. this.drawing.scoreLoc.length == 0 ||
  204. paperSigns.length > this.drawing.scoreLoc.length
  205. ) {
  206. this.drawing.setLocation(paperSigns, "localStorage");
  207. } else {
  208. this.drawing.setLocation(this.drawing.scoreLoc, "cache");
  209. }
  210. } else {
  211. this.drawing.setLocation(this.drawing.scoreLoc, "cache");
  212. }
  213. this.setSignItemId();
  214. },
  215. setSignItemId() {
  216. var signItem = Object.assign({}, this.signItem);
  217. this.drawing.setItemId(signItem.id);
  218. },
  219. setSignScores() {
  220. let signStorage = localStorage.getItem(this.paperKey);
  221. if (typeof signStorage == "string") {
  222. let paperSigns = JSON.parse(signStorage);
  223. if (paperSigns.length > 0) {
  224. for (let [index, paperSign] of paperSigns.entries()) {
  225. console.log("score index:", index);
  226. if (paperSign.itemId == this.signItem.id) {
  227. this.tmpSignScores.push(paperSign.score);
  228. }
  229. }
  230. }
  231. }
  232. console.log("signScores", this.signScores);
  233. },
  234. delMarkSign() {
  235. if (this.drawing.canvas) {
  236. this.removeItemSign();
  237. this.clearScores();
  238. this.drawing.ResetDrawAll();
  239. this.setSignLocation();
  240. this.$notify({
  241. message: "轨迹清除成功",
  242. type: "success"
  243. });
  244. }
  245. },
  246. removeItemSign() {
  247. let signStorage = localStorage.getItem(this.paperKey);
  248. if (typeof signStorage == "string") {
  249. let paperSigns = JSON.parse(signStorage);
  250. this.removeLS(paperSigns);
  251. this.removeCache();
  252. } else {
  253. this.removeCache();
  254. }
  255. },
  256. removeLS(paperSigns) {
  257. for (let i = paperSigns.length - 1; i >= 0; i--) {
  258. if (paperSigns[i].itemId == this.signItem.id) {
  259. paperSigns.splice(i, 1);
  260. }
  261. }
  262. if (paperSigns.length > 0) {
  263. localStorage.removeItem(this.paperKey);
  264. localStorage.setItem(this.paperKey, JSON.stringify(paperSigns));
  265. } else {
  266. localStorage.removeItem(this.paperKey);
  267. this.clearScoreLoc();
  268. }
  269. },
  270. removeCache() {
  271. for (let i = this.drawing.scoreLoc.length - 1; i >= 0; i--) {
  272. if (this.drawing.scoreLoc[i].itemId == this.signItem.id) {
  273. this.drawing.scoreLoc.splice(i, 1);
  274. }
  275. }
  276. },
  277. delAllMarkSign() {
  278. if (this.drawing.canvas) {
  279. localStorage.removeItem(this.paperKey);
  280. this.clearScores();
  281. this.clearScoreLoc();
  282. this.drawing.ResetDrawAll();
  283. this.$notify({
  284. message: "轨迹全部清除成功",
  285. type: "success"
  286. });
  287. }
  288. },
  289. changeMarkSign() {
  290. if (this.signItem) {
  291. this.drawing.ResetDrawAll();
  292. console.log("paperSign", localStorage.getItem(this.paperKey));
  293. this.setSignLocation();
  294. this.setSignScores();
  295. }
  296. },
  297. //清除分数
  298. clearScores() {
  299. this.tmpSignScores.splice(0, this.tmpSignScores.length);
  300. this.$emit("clearScores");
  301. },
  302. //清除分数坐标
  303. clearScoreLoc() {
  304. this.drawing.clearScoreLoc();
  305. },
  306. //打印
  307. printAnswer() {
  308. printJS({ printable: "answer-content", type: "html" });
  309. },
  310. pdfDown() {
  311. var url = this.studentPaper.studentSubjectiveHtml;
  312. if (url != "undefined" && url != "") {
  313. url = new URL(url);
  314. url = url.pathname;
  315. url = decodeURIComponent(url);
  316. let xhr = new XMLHttpRequest();
  317. xhr.responseType = "blob";
  318. xhr.open("GET", url, true);
  319. xhr.onload = function() {
  320. if (this.status === 200) {
  321. let blob = this.response;
  322. let reader = new FileReader();
  323. reader.readAsDataURL(blob);
  324. reader.onload = function(e) {
  325. let a = document.createElement("a");
  326. a.download = url.substr(url.lastIndexOf("/") + 1);
  327. a.href = e.target.result;
  328. document.body.appendChild(a);
  329. a.click();
  330. a.parentNode.removeChild(a);
  331. };
  332. }
  333. };
  334. xhr.send();
  335. } else {
  336. this.$notify({
  337. message: "离线url为空",
  338. type: "warning"
  339. });
  340. }
  341. }
  342. },
  343. computed: {
  344. itemTitle() {
  345. if (!this.markSign) return "无";
  346. var title = "无";
  347. if (this.signItem.id) {
  348. title =
  349. Number.parseInt(this.signItem.mainNumber) +
  350. 1 +
  351. "(" +
  352. this.signItem.orders +
  353. ")";
  354. }
  355. return title;
  356. },
  357. itemKey() {
  358. if (!this.markSign) return "";
  359. return this.studentPaper.id + "-" + this.signItem.id;
  360. },
  361. paperKey() {
  362. if (!this.markSign) return "";
  363. return this.studentPaper.id;
  364. },
  365. paperSigns() {
  366. if (!this.markSign) return [];
  367. var paperSigns = [];
  368. if (this.drawing.scoreLoc.length > 0) {
  369. for (let scoreLoc of this.drawing.scoreLoc) {
  370. paperSigns.push({
  371. loc: scoreLoc.loc,
  372. score: scoreLoc.score,
  373. itemId: scoreLoc.itemId
  374. });
  375. }
  376. }
  377. return paperSigns;
  378. }
  379. },
  380. watch: {
  381. signItem(val) {
  382. if (this.markSign) {
  383. console.log("signItem", val);
  384. this.changeMarkSign();
  385. }
  386. },
  387. studentPaper() {
  388. if (this.markSign) {
  389. this.intMarkDraw();
  390. }
  391. },
  392. tmpSignScores(val) {
  393. this.$emit("changeSignScores", val);
  394. },
  395. signScores(val) {
  396. this.tmpSignScores = val;
  397. },
  398. markSign() {
  399. this.intMarkDraw();
  400. },
  401. paperSigns(val) {
  402. this.$emit("changePaperSign", val);
  403. }
  404. },
  405. updated() {},
  406. mounted() {
  407. //this.createMarkDraw();
  408. window.viewPicture = this.viewPicture;
  409. },
  410. created() {
  411. EVENTHUB.$on("positionDiv", function(id) {
  412. let o = document.getElementById("student_paper");
  413. o.scrollTop = 0;
  414. var height = 0;
  415. let outObject = document.getElementById("anchor-" + id);
  416. if (outObject) {
  417. if (outObject.currentStyle) {
  418. height = parseInt(outObject.currentStyle["marginTop"]);
  419. } else {
  420. height = parseInt(
  421. document.defaultView.getComputedStyle(outObject, null)["marginTop"]
  422. );
  423. }
  424. var y = document.getElementById("anchor-" + id).offsetTop - height / 2;
  425. o.scrollTop = y - 5;
  426. }
  427. });
  428. }
  429. };
  430. </script>
  431. <style scoped>
  432. .markmain {
  433. width: 74%;
  434. overflow: auto;
  435. max-height: calc(100vh - 65px);
  436. }
  437. .markmain::-webkit-scrollbar {
  438. /*滚动条整体样式*/
  439. width: 8px; /*高宽分别对应横竖滚动条的尺寸*/
  440. }
  441. .markmain::-webkit-scrollbar-thumb {
  442. /*滚动条里面小方块*/
  443. border-radius: 5px;
  444. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  445. background: rgba(0, 0, 0, 0.2);
  446. }
  447. .markmain::-webkit-scrollbar-track {
  448. /*滚动条里面轨道*/
  449. box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  450. border-radius: 0;
  451. background: rgba(0, 0, 0, 0.1);
  452. }
  453. .marktitle {
  454. margin-right: 20px;
  455. margin-bottom: 20px;
  456. }
  457. .signTitle {
  458. margin-left: 35%;
  459. }
  460. .itemTitle {
  461. margin-right: 10px;
  462. }
  463. .titlefont {
  464. font-size: 15px;
  465. }
  466. li {
  467. list-style-type: none;
  468. }
  469. .markbutton {
  470. width: 40px;
  471. height: 40px;
  472. }
  473. img {
  474. width: 100%;
  475. height: 100%;
  476. }
  477. .paper {
  478. width: 90%;
  479. min-height: 600px;
  480. }
  481. .fixed {
  482. position: fixed;
  483. }
  484. .paper >>> .question-item {
  485. border: 1px solid #ccc;
  486. border-radius: 5px;
  487. margin: 10px;
  488. padding: 0 10px;
  489. }
  490. .paper >>> .answer {
  491. border: 1px solid #ccc;
  492. border-radius: 5px;
  493. margin: 10px;
  494. padding: 0 10px;
  495. background: rgb(250, 250, 250);
  496. overflow-wrap: break-word;
  497. }
  498. .paper >>> .right-font {
  499. font-weight: bold;
  500. color: rgb(85, 191, 255);
  501. }
  502. .paper >>> .student-font {
  503. font-weight: bold;
  504. color: black;
  505. }
  506. .paper >>> .max-number {
  507. font-size: 20px;
  508. color: #444444;
  509. }
  510. .paper >>> img.photo-answer {
  511. width: 100px;
  512. padding: 10px;
  513. height: 100px;
  514. }
  515. .paper >>> .photo-answers-block {
  516. width: 350px !important;
  517. }
  518. .paper >>> .photo-answers-block a {
  519. cursor: pointer;
  520. }
  521. .img-div {
  522. text-align: center;
  523. }
  524. </style>