MarkerGrading.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. <template>
  2. <div class="marker-grading">
  3. <marker-header
  4. ref="MarkerHeader"
  5. @area-change="areaChange"
  6. @step-change="stepChange"
  7. @page-set-change="pageSetChange"
  8. @to-history="toHistory"
  9. @to-standard="toStandard"
  10. @to-statistics="toStatistics"
  11. ></marker-header>
  12. <div
  13. :class="[
  14. 'marker-action',
  15. { 'marker-action-fullscreen': isFullscreenMarking }
  16. ]"
  17. v-show="!multipleGradingList.length"
  18. >
  19. <grade-action
  20. :cur-paper-or-task="curPaper"
  21. :levels="levels"
  22. :params-set="paramsSet"
  23. :key="curPaper.key"
  24. @on-select-level="gradeCurPaper"
  25. @on-pass="passCurPaper"
  26. ref="GradeAction"
  27. v-if="curPaper.id"
  28. ></grade-action>
  29. </div>
  30. <!-- multiple grading action -->
  31. <div class="marker-action" v-show="multipleGradingList.length">
  32. <div class="grade-action">
  33. <div class="action-paper-state">
  34. <p class="paper-state-cont">批量分档</p>
  35. </div>
  36. <div class="action-paper-info">
  37. <p><span>任务密号:</span><span>--</span></p>
  38. </div>
  39. <div class="action-grade-list">
  40. <div
  41. class="action-grade-item"
  42. v-for="(level, index) in levels"
  43. :key="index"
  44. >
  45. <div
  46. :class="[
  47. 'action-grade-item-content',
  48. { 'action-item-content-disabled': multiplebtnClicked }
  49. ]"
  50. @click="multipleSelectLevel(level)"
  51. >
  52. <p>{{ level.name }}</p>
  53. <p>{{ level.minScore }}~{{ level.maxScore }}</p>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="marker-body">
  60. <div :class="markerImageListClasses" v-if="papers.length">
  61. <div
  62. v-for="(paper, index) in papers"
  63. :key="paper.key"
  64. :class="[
  65. 'marker-image-item',
  66. {
  67. 'marker-image-item-act': curPaperIndex === index
  68. }
  69. ]"
  70. >
  71. <div class="marker-image-content">
  72. <marker-image-view
  73. :data="paper"
  74. @to-review="toReview(index)"
  75. @to-select="selectMultiplePaper"
  76. ></marker-image-view>
  77. </div>
  78. </div>
  79. </div>
  80. <div v-else class="marker-image-none">暂无数据</div>
  81. </div>
  82. <!-- MarkerHistory -->
  83. <marker-history
  84. :question-id="filter.questionId"
  85. @on-paper-click="
  86. (index, papers) => {
  87. toViewCarouselPaper(index, papers, 'history');
  88. }
  89. "
  90. ref="MarkerHistory"
  91. ></marker-history>
  92. <!-- MarkerStandard -->
  93. <marker-standard
  94. :question-id="filter.questionId"
  95. :levels="levels"
  96. @on-paper-click="
  97. (index, papers) => {
  98. toViewCarouselPaper(index, papers, 'sample');
  99. }
  100. "
  101. ref="MarkerStandard"
  102. v-if="levels.length && filter.questionId && paramsSet.showSample"
  103. ></marker-standard>
  104. <!-- MarkerStatistics -->
  105. <marker-statistics ref="MarkerStatistics"></marker-statistics>
  106. <!-- image-preview -->
  107. <simple-image-preview
  108. class="grading-operation-image-preview"
  109. :cur-image="curPaper"
  110. @on-prev="toPrevPaper"
  111. @on-next="toNextPaper"
  112. @on-close="isFullscreenMarking = false"
  113. ref="SimpleImagePreview"
  114. ></simple-image-preview>
  115. <!-- carousel paper review -->
  116. <simple-image-preview
  117. class="grading-operation-image-preview"
  118. :cur-image="curPaper"
  119. @on-prev="toCarousePaper('prev')"
  120. @on-next="toCarousePaper('next')"
  121. @on-close="carouseImagePreviewClose"
  122. ref="CarouselPapersPreview"
  123. ></simple-image-preview>
  124. </div>
  125. </template>
  126. <script>
  127. import { mapState, mapMutations } from "vuex";
  128. import MarkerHeader from "./MarkerHeader";
  129. import MarkerImageView from "./MarkerImageView";
  130. import MarkerHistory from "./MarkerHistory";
  131. import MarkerStandard from "./MarkerStandard";
  132. import MarkerStatistics from "./MarkerStatistics";
  133. import GradeAction from "../components/GradeAction";
  134. import SimpleImagePreview from "@/components/SimpleImagePreview";
  135. import {
  136. markerTaskList,
  137. markerLevelTotalStatData,
  138. workLevelList,
  139. paperSelectLevelOrScore,
  140. paperSelectLevelBatch,
  141. paperTaskPass,
  142. getParamsSet
  143. } from "@/api";
  144. export default {
  145. name: "marker-grading",
  146. components: {
  147. MarkerHeader,
  148. MarkerImageView,
  149. MarkerHistory,
  150. MarkerStandard,
  151. MarkerStatistics,
  152. GradeAction,
  153. SimpleImagePreview
  154. },
  155. data() {
  156. return {
  157. filter: {
  158. markerId: this.$ls.get("user").id,
  159. questionId: "",
  160. sort: "randomSeq,asc",
  161. stage: "LEVEL"
  162. },
  163. typeFilter: {
  164. done: {
  165. level: ""
  166. },
  167. undo: {},
  168. reject: {
  169. reject: true
  170. }
  171. },
  172. workId: this.$route.params.workId,
  173. subjectId: this.$route.params.subjectId,
  174. subject: "",
  175. workSubject: {},
  176. curStandardGradeId: "",
  177. levels: [],
  178. papers: [],
  179. curPaper: {},
  180. curPaperIndex: 0,
  181. // multiple grading
  182. multiplebtnClicked: false,
  183. multipleGradingList: [],
  184. // carousel paper review,
  185. carouselType: "",
  186. carouselPapers: [],
  187. curCarouselPaperIndex: 0,
  188. isFullscreenMarking: false
  189. };
  190. },
  191. computed: {
  192. ...mapState("marker", ["paramsSet", "page", "steps", "curStep", "curArea"]),
  193. markerImageListClasses() {
  194. return ["marker-image-list", `marker-image-list-${this.page.size}`];
  195. }
  196. },
  197. created() {
  198. this.subject = this.subjectId.split("-")[1];
  199. this.workSubject = {
  200. workId: this.workId,
  201. subject: this.subject
  202. };
  203. const curUserRoleType = this.$ls.get("user", { role: "" }).role;
  204. this.setCurUserRoleType(curUserRoleType);
  205. this.initData();
  206. },
  207. methods: {
  208. ...mapMutations("marker", [
  209. "setParamSet",
  210. "setPage",
  211. "setSteps",
  212. "setCurArea",
  213. "setCurStep",
  214. "setCurUserRoleType",
  215. "clearState"
  216. ]),
  217. async initData() {
  218. await this.getParamsSetInfo();
  219. await this.getWorkLevels();
  220. },
  221. async getParamsSetInfo() {
  222. const data = await getParamsSet(this.workId);
  223. this.setParamSet(data || {});
  224. },
  225. async getList() {
  226. this.clearMultiplePaper();
  227. const datas = {
  228. ...this.filter,
  229. ...this.typeFilter[this.curStep.type],
  230. workId: this.workId,
  231. page: this.page.current - 1,
  232. size: this.page.size
  233. };
  234. if (this.curStep.type === "done") {
  235. datas.level = this.curStep.name;
  236. datas.sort = "updatedOn,desc";
  237. }
  238. const data = await markerTaskList(datas);
  239. this.papers = data.data.map(paper => {
  240. paper.key = this.$randomCode();
  241. paper.title = `NO.${paper.sn}`;
  242. paper.selected = false;
  243. return paper;
  244. });
  245. this.setPage({
  246. total: data.totalCount,
  247. totalPage: data.pageCount
  248. });
  249. },
  250. async toPage(page) {
  251. this.setPage({
  252. current: page
  253. });
  254. await this.getList();
  255. this.selectPaper(this.curPaperIndex);
  256. },
  257. async getStepLevels() {
  258. const data = await markerLevelTotalStatData(
  259. this.filter.markerId,
  260. this.filter.questionId
  261. );
  262. const undoIndex = data.findIndex(item => item.id === null);
  263. let otherStep = [];
  264. let undo = {
  265. count: 0,
  266. rejected: 0
  267. };
  268. if (undoIndex !== -1) {
  269. undo = { ...data[undoIndex] };
  270. data.splice(undoIndex, 1);
  271. }
  272. otherStep.push({
  273. name: "待评",
  274. count: undo.count,
  275. type: "undo"
  276. });
  277. otherStep.push({
  278. name: "打回",
  279. count: undo.rejected,
  280. type: "reject"
  281. });
  282. let levelStep = data.map(item => {
  283. // 评卷员不展示kdpt
  284. item.kdpt = null;
  285. return {
  286. ...item,
  287. name: item.id,
  288. type: "done"
  289. };
  290. });
  291. this.setSteps({ levelStep, otherStep });
  292. if (!this.curStep.name) {
  293. let curStep = {};
  294. if (undoIndex === -1) {
  295. curStep = levelStep[0];
  296. } else {
  297. const firstStep = otherStep.find(item => item.count);
  298. curStep = firstStep || levelStep[0];
  299. }
  300. this.setCurStep(curStep);
  301. } else {
  302. const curStep = [...levelStep, ...otherStep].find(
  303. item => item.name === this.curStep.name
  304. );
  305. this.setCurStep(curStep);
  306. }
  307. },
  308. updateStepLevel(curStep, curLevel, count) {
  309. if (curStep.type === "done") {
  310. const lpos = this.steps.levelStep.findIndex(
  311. item => item.name === curStep.name
  312. );
  313. this.steps.levelStep[lpos].count -= count;
  314. } else {
  315. const opos = this.steps.otherStep.findIndex(
  316. item => item.type === curStep.type
  317. );
  318. this.steps.otherStep[opos].count -= count;
  319. }
  320. const pos = this.steps.levelStep.findIndex(
  321. item => item.name === curLevel
  322. );
  323. this.steps.levelStep[pos].count += count;
  324. this.steps.levelStep.forEach(item => {
  325. item.percent =
  326. item.finalKdTotal && item.count
  327. ? ((100 * item.count) / item.finalKdTotal).toFixed(3)
  328. : 0;
  329. });
  330. this.setSteps(this.steps);
  331. },
  332. async getWorkLevels() {
  333. const data = await workLevelList(this.workId);
  334. this.levels = data.map(item => {
  335. return {
  336. id: item.id,
  337. name: item.code,
  338. minScore: item.minScore,
  339. maxScore: item.maxScore
  340. };
  341. });
  342. },
  343. async pageSetChange() {
  344. await this.getList();
  345. this.selectPaper(this.curPaperIndex);
  346. },
  347. async stepChange(step) {
  348. this.setCurStep(step);
  349. this.setPage({ current: 1 });
  350. this.isFullscreenMarking = false;
  351. await this.getList();
  352. this.getStepLevels();
  353. if (this.papers.length) {
  354. this.selectPaper(0);
  355. } else {
  356. this.curPaper = {};
  357. }
  358. },
  359. async areaChange(curArea) {
  360. this.setCurArea(curArea);
  361. this.filter.questionId = curArea.id;
  362. await this.getStepLevels();
  363. this.toPage(1);
  364. },
  365. // selectMultiplePaper
  366. selectMultiplePaper(paper) {
  367. if (paper.sample) return;
  368. const curPaper = this.papers.find(p => p.id === paper.id);
  369. curPaper.selected = paper.selected;
  370. this.multipleGradingList = this.papers.filter(paper => paper.selected);
  371. },
  372. clearMultiplePaper() {
  373. this.multipleGradingList = [];
  374. this.papers.forEach(paper => {
  375. paper.selected = false;
  376. });
  377. this.$refs.MarkerHeader.changeAllSelect(false);
  378. },
  379. async multipleSelectLevel(level) {
  380. if (!this.multipleGradingList.length) return;
  381. if (this.multiplebtnClicked) return;
  382. this.multiplebtnClicked = true;
  383. const multipleGradingListCount = this.multipleGradingList.length;
  384. let result = true;
  385. await paperSelectLevelBatch(
  386. this.multipleGradingList.map(item => item.id).join(), // is taskId
  387. level.name,
  388. "LEVEL"
  389. ).catch(() => {
  390. result = false;
  391. });
  392. this.multiplebtnClicked = false;
  393. if (!result) return;
  394. this.multipleGradingList = [];
  395. // this.getStepLevels();
  396. this.updateStepLevel(this.curStep, level.name, multipleGradingListCount);
  397. // update paper list
  398. if (
  399. this.page.current > 1 &&
  400. this.page.current === this.page.totalPage &&
  401. this.papers.length === multipleGradingListCount
  402. ) {
  403. this.setPage({ current: this.page.current - 1 });
  404. }
  405. await this.getList();
  406. this.selectPaper(this.curPaperIndex);
  407. },
  408. // paper view action
  409. toReview(index) {
  410. this.isFullscreenMarking = true;
  411. this.clearMultiplePaper();
  412. this.selectPaper(index);
  413. this.$refs.SimpleImagePreview.open();
  414. },
  415. selectPaper(index) {
  416. let nindex = index;
  417. if (!this.papers.length) {
  418. nindex = 0;
  419. } else if (index > this.papers.length - 1) {
  420. nindex = this.papers.length - 1;
  421. } else if (index < 0) {
  422. nindex = 0;
  423. }
  424. this.curPaperIndex = nindex;
  425. this.curPaper = this.papers[nindex] ? { ...this.papers[nindex] } : {};
  426. },
  427. async toPrevPaper() {
  428. if (this.curPaperIndex === 0) {
  429. if (this.page.current > 1) {
  430. this.setPage({ current: this.page.current - 1 });
  431. this.curPaperIndex = this.page.size - 1;
  432. await this.getList();
  433. } else {
  434. this.$Message.warning("当前已经是第一条数据了");
  435. return;
  436. }
  437. } else {
  438. this.curPaperIndex--;
  439. }
  440. this.selectPaper(this.curPaperIndex);
  441. },
  442. async toNextPaper() {
  443. if (this.curPaperIndex === this.papers.length - 1) {
  444. if (this.page.current === this.page.totalPage) {
  445. this.$Message.warning("当前已经是最后一条数据了");
  446. return;
  447. } else {
  448. this.setPage({ current: this.page.current + 1 });
  449. this.curPaperIndex = 0;
  450. await this.getList();
  451. }
  452. } else {
  453. this.curPaperIndex++;
  454. }
  455. this.selectPaper(this.curPaperIndex);
  456. },
  457. async toActionNextPaper() {
  458. if (this.page.current > 1 && this.papers.length === 1) {
  459. this.setPage({ current: this.page.current - 1 });
  460. this.curPaperIndex = this.page.size;
  461. }
  462. await this.getList();
  463. if (!this.papers.length) this.$refs.SimpleImagePreview.cancel();
  464. this.selectPaper(this.curPaperIndex);
  465. },
  466. async gradeCurPaper(level) {
  467. const paper = await paperSelectLevelOrScore(
  468. this.curPaper.id, // is taskId
  469. level.name,
  470. "LEVEL"
  471. );
  472. if (!paper) return;
  473. if (this.carouselType) {
  474. this.updateStepLevel(
  475. { type: "done", name: this.curPaper.level },
  476. level.name,
  477. 1
  478. );
  479. this.$refs.CarouselPapersPreview.cancel();
  480. this.$refs.MarkerHistory.updatePapers();
  481. } else {
  482. this.updateStepLevel(this.curStep, level.name, 1);
  483. this.toActionNextPaper();
  484. }
  485. },
  486. async passCurPaper() {
  487. await paperTaskPass(this.curPaper.id);
  488. this.toActionNextPaper();
  489. },
  490. // paper carousel
  491. toViewCarouselPaper(paperIndex, papers, type) {
  492. this.carouselType = type;
  493. this.isFullscreenMarking = true;
  494. this.carouselPapers = papers;
  495. this.selectCarouselPaper(paperIndex);
  496. this.$nextTick(() => {
  497. this.$refs.CarouselPapersPreview.open();
  498. });
  499. },
  500. selectCarouselPaper(index) {
  501. this.curCarouselPaperIndex = index;
  502. this.curPaper = { ...this.carouselPapers[index] };
  503. },
  504. toCarousePaper(type) {
  505. // if (this.carouselType === "sample") {
  506. // this.toSampleCarousePaper(type);
  507. // return;
  508. // }
  509. if (type === "prev" && this.curCarouselPaperIndex > 0) {
  510. this.curCarouselPaperIndex--;
  511. } else if (
  512. type === "next" &&
  513. this.curCarouselPaperIndex < this.carouselPapers.length - 1
  514. ) {
  515. this.curCarouselPaperIndex++;
  516. }
  517. this.selectCarouselPaper(this.curCarouselPaperIndex);
  518. },
  519. toSampleCarousePaper(type) {
  520. if (type === "prev") {
  521. this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleLeft();
  522. } else if (type === "next") {
  523. this.$refs.GradeStandardPaper.$refs.PaperCarousel.handleRight();
  524. }
  525. },
  526. carouseImagePreviewClose() {
  527. this.isFullscreenMarking = false;
  528. this.carouselType = "";
  529. this.selectPaper(this.curPaperIndex);
  530. },
  531. // header
  532. toHistory() {
  533. this.$refs.MarkerHistory.open();
  534. },
  535. toStandard() {
  536. this.$refs.MarkerStandard.open();
  537. },
  538. toStatistics() {
  539. this.$refs.MarkerStatistics.open();
  540. }
  541. },
  542. beforeDestroy() {
  543. this.clearState();
  544. }
  545. };
  546. </script>