LibraryDialog.vue 12 KB

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