LibraryDialog.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <template>
  2. <div>
  3. <el-dialog
  4. class="library-dialog page-dialog"
  5. :visible.sync="modalIsShow"
  6. title="数据处理"
  7. :close-on-click-modal="false"
  8. :close-on-press-escape="false"
  9. append-to-body
  10. fullscreen
  11. @open="visibleChange"
  12. @closed="closed"
  13. >
  14. <div class="data-check-body">
  15. <div class="data-check-action part-box">
  16. <div class="data-check-action-form">
  17. <el-button size="mini" type="primary" @click="toSelectTaskStd"
  18. >所有任务考生信息</el-button
  19. >
  20. <div v-if="openCodeOcr">
  21. <el-button
  22. v-if="openCodeOcr"
  23. size="mini"
  24. type="success"
  25. @click="toSetOcrArea"
  26. >设置信息识别区</el-button
  27. >
  28. <el-radio-group v-model="areaType">
  29. <el-radio v-if="openOcr" label="OCR">OCR识别</el-radio>
  30. <el-radio v-if="openBarCode" label="BAR_CODE"
  31. >条码识别</el-radio
  32. >
  33. </el-radio-group>
  34. </div>
  35. <el-divider></el-divider>
  36. <div v-if="openGlobalMatch" class="box-justify mb-2">
  37. <h4>绑定学生</h4>
  38. <div>
  39. <span class="inline-middle mr-1">全局匹配</span>
  40. <el-switch
  41. v-model="globalMatch"
  42. @change="getStudentList"
  43. ></el-switch>
  44. </div>
  45. </div>
  46. <el-input
  47. v-model="studentNameOrNo"
  48. class="width-full"
  49. placeholder="请输入学号/姓名"
  50. clearable
  51. @input="nameOrNoInput"
  52. ></el-input>
  53. </div>
  54. <div class="data-check-action-student">
  55. <el-table ref="TableList" :data="studentList">
  56. <el-table-column
  57. prop="studentName"
  58. label="姓名"
  59. width="80"
  60. ></el-table-column>
  61. <el-table-column
  62. prop="studentCode"
  63. label="学号"
  64. ></el-table-column>
  65. <el-table-column label="操作" width="55">
  66. <template slot-scope="scope">
  67. <el-button
  68. size="mini"
  69. type="primary"
  70. :disabled="loading"
  71. @click="toBind(scope.row)"
  72. >绑定</el-button
  73. >
  74. </template>
  75. </el-table-column>
  76. </el-table>
  77. </div>
  78. </div>
  79. <div v-show="!isSetOcrSet" class="data-check-content part-box">
  80. <div v-if="curPagePapers.length" class="data-check-content-page">
  81. <el-button
  82. :type="curPagePaperIndex === 0 ? 'primary' : 'default'"
  83. :disabled="isSwitchFb"
  84. @click="switchCurPage(0)"
  85. >正面</el-button
  86. >
  87. <el-button
  88. :type="curPagePaperIndex === 1 ? 'primary' : 'default'"
  89. :disabled="isSwitchFb"
  90. @click="switchCurPage(1)"
  91. >反面</el-button
  92. >
  93. <el-button
  94. type="danger"
  95. :disabled="curPage.abnormal"
  96. @click="toAbnormalPaper"
  97. >标记异常</el-button
  98. >
  99. </div>
  100. <image-contain
  101. ref="ImageContain"
  102. :image="curPagePaper"
  103. :show-guide="false"
  104. ></image-contain>
  105. </div>
  106. <div v-if="isSetOcrSet" class="data-check-content part-box">
  107. <ocr-area-set
  108. :image-url="curPagePaper.url"
  109. :setting="ocrArea"
  110. @cancel="isSetOcrSet = false"
  111. @confirm="ocrAreaChange"
  112. ></ocr-area-set>
  113. </div>
  114. </div>
  115. </el-dialog>
  116. <!-- RelateStudentDialog -->
  117. <relate-student-dialog
  118. ref="RelateStudentDialog"
  119. :page-data="curPage"
  120. @confirm="toBind"
  121. ></relate-student-dialog>
  122. <!-- ocr-result -->
  123. <el-dialog
  124. class="page-dialog"
  125. :visible.sync="ocrResultDialogIsShow"
  126. title="OCR识别结果"
  127. top="10vh"
  128. width="500px"
  129. :close-on-click-modal="false"
  130. :close-on-press-escape="false"
  131. append-to-body
  132. >
  133. <div class="part-box part-box-pad mb-0">
  134. <el-table :data="ocrResult">
  135. <el-table-column prop="result" label="结果"></el-table-column>
  136. <el-table-column class-name="action-column" label="操作" width="80">
  137. <template slot-scope="scope">
  138. <el-button
  139. class="btn-primary"
  140. type="text"
  141. @click="selectOcrResule(scope.row)"
  142. >
  143. <span class="cont-link">选择</span>
  144. </el-button>
  145. </template>
  146. </el-table-column>
  147. </el-table>
  148. </div>
  149. <div slot="footer"></div>
  150. </el-dialog>
  151. </div>
  152. </template>
  153. <script>
  154. import timeMixin from "../../../mixins/timeMixin";
  155. import {
  156. paperBindUser,
  157. studentUnbindTaskListPage,
  158. scanTaskStudentListPage,
  159. libraryOcrResult,
  160. abnormalPaper
  161. } from "../api";
  162. import { systemSettingQuery } from "../../base/api";
  163. import ImageContain from "../../../components/ImageContain.vue";
  164. import RelateStudentDialog from "./RelateStudentDialog.vue";
  165. import OcrAreaSet from "./OcrAreaSet.vue";
  166. const initModalForm = {
  167. paperLibraryId: "",
  168. paperScanTaskDetailId: ""
  169. };
  170. export default {
  171. name: "library-dialog",
  172. props: {
  173. mode: {
  174. type: String,
  175. default: "undo",
  176. validate: val => ["undo", "fix"].includes(val)
  177. },
  178. filterData: {
  179. tyep: Object,
  180. default() {
  181. return {};
  182. }
  183. },
  184. student: {
  185. type: Object,
  186. default() {
  187. return {
  188. curPagePaperIndex: 0,
  189. pageList: []
  190. };
  191. }
  192. }
  193. },
  194. components: { ImageContain, RelateStudentDialog, OcrAreaSet },
  195. mixins: [timeMixin],
  196. data() {
  197. return {
  198. modalIsShow: false,
  199. studentNameOrNo: "",
  200. modalForm: { ...initModalForm },
  201. inputSearchDelay: 300,
  202. studentList: [],
  203. courseList: [],
  204. loading: false,
  205. donePageList: [],
  206. undoPageList: [],
  207. curPage: null,
  208. curPagePapers: [],
  209. curPagePaperIndex: 0,
  210. curPagePaper: { url: "" },
  211. lastPaperScanTaskId: "",
  212. isSwitchFb: false,
  213. // ocr
  214. isSetOcrSet: false,
  215. openOcr: false,
  216. openBarCode: false,
  217. openGlobalMatch: false,
  218. globalMatch: false,
  219. areaType: "",
  220. ocrArea: { x: null, y: null, width: null, height: null, rotate: 0 },
  221. ocrResult: [],
  222. ocrResultDialogIsShow: false
  223. };
  224. },
  225. computed: {
  226. IS_UNDO_MODEL() {
  227. return this.mode === "undo";
  228. },
  229. openCodeOcr() {
  230. return this.openBarCode || this.openOcr;
  231. }
  232. },
  233. mounted() {
  234. this.ocrArea = this.$ls.get("ocrArea") || this.ocrArea;
  235. this.getSysSet();
  236. },
  237. methods: {
  238. async visibleChange() {
  239. this.modalForm = { ...initModalForm };
  240. this.studentNameOrNo = "";
  241. this.donePageList = [];
  242. this.undoPageList = [];
  243. this.curPage = null;
  244. this.curPagePapers = [];
  245. this.curPagePaper = { url: "" };
  246. this.lastPaperScanTaskId = "";
  247. if (this.IS_UNDO_MODEL) {
  248. this.curPagePaperIndex = 0;
  249. await this.getUndoPageList();
  250. } else {
  251. this.undoPageList = this.student.pageList;
  252. this.curPagePaperIndex = this.student.curPagePaperIndex;
  253. }
  254. if (!this.undoPageList.length) {
  255. this.$message.error("当前无任务需要处理!");
  256. return;
  257. }
  258. this.getNextPaper();
  259. },
  260. closed() {
  261. this.$emit("closed");
  262. },
  263. cancel() {
  264. this.modalIsShow = false;
  265. },
  266. open() {
  267. this.modalIsShow = true;
  268. },
  269. async getSysSet() {
  270. const data = await systemSettingQuery();
  271. data.forEach(item => {
  272. item.data.forEach(field => {
  273. if (field.code === "openOcr") {
  274. this.openOcr = field.value === "true";
  275. }
  276. if (field.code === "openBarCode") {
  277. this.openBarCode = field.value === "true";
  278. }
  279. if (field.code === "openGlobalMatch") {
  280. this.openGlobalMatch = field.value === "true";
  281. }
  282. });
  283. });
  284. if (this.openOcr) {
  285. this.areaType = "OCR";
  286. } else if (this.openBarCode) {
  287. this.areaType = "BAR_CODE";
  288. }
  289. },
  290. nameOrNoInput() {
  291. this.clearSetTs();
  292. this.addSetTime(() => {
  293. this.getStudentList();
  294. }, this.inputSearchDelay);
  295. },
  296. async getStudentList() {
  297. if (!this.curPage || !this.curPage.paperScanTaskId) return;
  298. const datas = {
  299. paperScanTaskId: this.curPage.paperScanTaskId,
  300. param: this.studentNameOrNo,
  301. globalMatch: this.globalMatch,
  302. pageNumber: 1,
  303. pageSize: 30
  304. };
  305. const data = await scanTaskStudentListPage(datas);
  306. this.studentList = data.records;
  307. },
  308. toSelectTaskStd() {
  309. this.$refs.RelateStudentDialog.open();
  310. },
  311. async switchCurPage(curPagePaperIndex) {
  312. if (this.isSwitchFb) return;
  313. this.curPagePaperIndex = curPagePaperIndex;
  314. this.curPagePaper = {
  315. url: this.curPagePapers[this.curPagePaperIndex]
  316. };
  317. if (this.openCodeOcr) {
  318. this.isSwitchFb = true;
  319. await this.getOrcResult().catch(() => {});
  320. this.isSwitchFb = false;
  321. }
  322. },
  323. async toAbnormalPaper() {
  324. const res = await this.$confirm(`确定要标记当前试卷为异常吗?`, "提示", {
  325. type: "warning"
  326. }).catch(() => {});
  327. if (res !== "confirm") return;
  328. await abnormalPaper(this.curPage.id);
  329. this.$message.success("标记成功!");
  330. this.toNextPaper();
  331. },
  332. async getUndoPageList() {
  333. const data = await studentUnbindTaskListPage({ ...this.filterData });
  334. this.undoPageList.push(...data);
  335. },
  336. async toNextPaper() {
  337. if (!this.undoPageList.length && this.IS_UNDO_MODEL)
  338. await this.getUndoPageList();
  339. if (!this.undoPageList.length) {
  340. this.$message.warning("已全部处理完!");
  341. this.cancel();
  342. return;
  343. }
  344. // 已处理的最多记录10条
  345. if (this.curPage) this.donePageList.push({ ...this.curPage });
  346. if (this.donePageList.length > 10)
  347. this.donePageList = this.donePageList.slice(-10);
  348. this.curPagePaperIndex = 0;
  349. this.getNextPaper();
  350. },
  351. getNextPaper() {
  352. this.curPage = this.undoPageList.shift();
  353. this.curPagePapers = this.curPage.fileUrls;
  354. this.switchCurPage(this.curPagePaperIndex);
  355. if (
  356. !this.openOcr &&
  357. this.lastPaperScanTaskId !== this.curPage.paperScanTaskId
  358. ) {
  359. this.getStudentList();
  360. }
  361. },
  362. toBind(row) {
  363. this.lastPaperScanTaskId = this.curPage.paperScanTaskId;
  364. this.modalForm.paperScanTaskDetailId = row.paperScanTaskDetailId;
  365. this.confirm();
  366. },
  367. async confirm() {
  368. if (this.loading) return;
  369. this.loading = true;
  370. let datas = { ...this.modalForm };
  371. datas.paperLibraryId = this.curPage.id;
  372. const res = await paperBindUser(datas).catch(() => {});
  373. this.loading = false;
  374. if (!res) return;
  375. this.$message.success("绑定成功!");
  376. if (this.IS_UNDO_MODEL) {
  377. this.toNextPaper();
  378. } else {
  379. this.cancel();
  380. }
  381. },
  382. // ocr
  383. toSetOcrArea() {
  384. if (!this.openOcr && !this.openBarCode) return;
  385. this.isSetOcrSet = true;
  386. },
  387. ocrAreaChange(ocrArea) {
  388. Object.keys(ocrArea).forEach(key => {
  389. ocrArea[key] = Math.floor(ocrArea[key]);
  390. });
  391. this.ocrArea = this.$objAssign(this.ocrArea, ocrArea);
  392. this.$ls.set("ocrArea", this.ocrArea);
  393. this.isSetOcrSet = false;
  394. this.getOrcResult();
  395. },
  396. async getOrcResult() {
  397. if (this.ocrArea.x === null) {
  398. this.$message.error("请设置ORC识别区");
  399. this.getStudentList();
  400. return;
  401. }
  402. const res = await libraryOcrResult({
  403. paperLibraryId: this.curPage.id,
  404. index: this.curPagePaperIndex,
  405. type: this.areaType,
  406. ...this.ocrArea
  407. });
  408. if (res && res.length) {
  409. if (res.length === 1) {
  410. this.studentNameOrNo = res[0];
  411. this.getStudentList();
  412. } else {
  413. this.ocrResult = res.map(result => {
  414. return {
  415. result
  416. };
  417. });
  418. this.ocrResultDialogIsShow = true;
  419. }
  420. } else {
  421. this.getStudentList();
  422. }
  423. },
  424. selectOcrResule(cont) {
  425. this.studentNameOrNo = cont.result;
  426. this.getStudentList();
  427. this.ocrResultDialogIsShow = false;
  428. }
  429. }
  430. };
  431. </script>