index.vue 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <div v-if="hasTask" class="audit audit-image-check">
  3. <div class="audit-head">
  4. <a-row :gutter="8">
  5. <a-col :span="3">
  6. <span class="head-label">姓名:</span>
  7. <span class="head-cont">{{ curImage?.name }}</span>
  8. </a-col>
  9. <a-col :span="4">
  10. <span class="head-label">考号:</span>
  11. <span class="head-cont">{{ curImage?.examNumber }}</span>
  12. </a-col>
  13. <a-col :span="4">
  14. <span class="head-label">科目:</span>
  15. <span class="head-cont">{{ curImage?.subjectName }}</span>
  16. </a-col>
  17. <a-col :span="3">
  18. <span class="head-label">张数:</span>
  19. <span class="head-cont">{{ curImage?.pageName }}</span>
  20. </a-col>
  21. <a-col :span="5">
  22. <span class="head-label">倒计时:</span>
  23. <span class="head-cont remain-time">{{ remainTime }}秒</span>
  24. <a-button
  25. v-if="loopImageStoped"
  26. class="ant-btn-primary-light"
  27. @click="startImageLoop"
  28. >
  29. <template #icon><PlayCircleOutlined /></template>
  30. 开始
  31. </a-button>
  32. <a-button v-else class="ant-btn-error-light" @click="stopImageLoop">
  33. <template #icon><PauseCircleOutlined /></template>
  34. 暂停
  35. </a-button>
  36. </a-col>
  37. <a-col :span="5">
  38. <a-space>
  39. <a-button :disabled="!prevEnable" @click="getPrevImage">
  40. <template #icon><ArrowLeftOutlined /></template>
  41. 上一个
  42. </a-button>
  43. <span>{{ curImageIndex + 1 }} / {{ imageList.length }}</span>
  44. <a-button @click="getNextImage">
  45. <template #icon><ArrowRightOutlined /></template>
  46. 下一个
  47. </a-button>
  48. </a-space>
  49. </a-col>
  50. </a-row>
  51. </div>
  52. <div class="audit-body">
  53. <img v-if="curImage" :src="getFileUrl(curImage.url)" alt="origin" />
  54. </div>
  55. <div class="audit-topinfo">
  56. <a-space :size="6">
  57. <template #split>
  58. <a-divider type="vertical" style="height: 16px" />
  59. </template>
  60. <span>批次ID:{{ batchInfo.batchId }}</span>
  61. <span>扫描员:{{ batchInfo.deviceName }}</span>
  62. <span>扫描时间:{{ dateFormat(batchInfo.createTime) }}</span>
  63. </a-space>
  64. </div>
  65. </div>
  66. <div v-else class="audit is-wait">
  67. <div>
  68. <img src="@/assets/imgs/bg-wait.png" alt="等待" />
  69. <p>等待审核任务…</p>
  70. </div>
  71. </div>
  72. </template>
  73. <script setup lang="ts">
  74. import { computed, onBeforeUnmount, onMounted, ref } from "vue";
  75. import {
  76. ArrowLeftOutlined,
  77. ArrowRightOutlined,
  78. PlayCircleOutlined,
  79. PauseCircleOutlined,
  80. } from "@ant-design/icons-vue";
  81. import { message } from "ant-design-vue";
  82. import { AuditBatchResult, AuditBatchStudent } from "@/ap/types/audit";
  83. import { imageAuditBatch, imageAuditSave, imageAuditRelease } from "@/ap/audit";
  84. import { useUserStore } from "@/store";
  85. import { dateFormat, getFileUrl } from "@/utils/tool";
  86. import useLoop from "@/hooks/useLoop";
  87. defineOptions({
  88. name: "ImageCheckAudit",
  89. });
  90. interface ImageItem {
  91. url: string;
  92. pageName: string;
  93. name: string;
  94. examNumber: string;
  95. subjectName: string;
  96. }
  97. const userStore = useUserStore();
  98. const imageList = ref<ImageItem[]>([]);
  99. const curImage = ref<ImageItem | null>(null);
  100. const curImageIndex = ref(0);
  101. const batchInfo = ref({} as AuditBatchResult);
  102. const hasTask = ref(false);
  103. const imageCheckLoopTime = computed(() => {
  104. return userStore.imageCheckLoopTime || 0;
  105. });
  106. // 计时
  107. const loopImageStoped = ref(false);
  108. const remainTime = ref(0);
  109. const { start: startLoopRemainTime, stop: stopLoopRemainTime } = useLoop(
  110. updateRemainTime,
  111. 100
  112. );
  113. function updateRemainTime() {
  114. // remainTime.value--;
  115. remainTime.value =
  116. remainTime.value - 0.1 < 0 ? 0 : (remainTime.value * 1000 - 100) / 1000;
  117. if (remainTime.value <= 0) {
  118. stopLoopRemainTime();
  119. // 跳出loop,再开启新的loop
  120. setTimeout(() => {
  121. getNextImage();
  122. });
  123. }
  124. }
  125. function stopImageLoop() {
  126. loopImageStoped.value = true;
  127. stopLoopRemainTime();
  128. }
  129. function startImageLoop() {
  130. loopImageStoped.value = false;
  131. startLoopRemainTime();
  132. }
  133. const prevEnable = computed(() => {
  134. return curImageIndex.value > 0;
  135. });
  136. // 获取批次数据
  137. const { start: startLoopGetData, stop: stopLoopGetData } = useLoop(
  138. getData,
  139. 2000
  140. );
  141. async function getData() {
  142. const res = await imageAuditBatch({ examId: userStore.curExam.id });
  143. if (!res) {
  144. hasTask.value = false;
  145. return;
  146. }
  147. stopLoopGetData();
  148. hasTask.value = true;
  149. batchInfo.value = res;
  150. initImageData();
  151. setCurImage(0);
  152. }
  153. function initImageData() {
  154. if (!hasTask.value) return;
  155. const images: ImageItem[] = [];
  156. batchInfo.value.students.forEach((student) => {
  157. student.papers.forEach((paper, paperIndex) => {
  158. paper.pages.forEach((page, pageIndex) => {
  159. const pageName = `第${paperIndex + 1}张-${
  160. pageIndex === 0 ? "正" : "反"
  161. }面`;
  162. images.push({
  163. url: page,
  164. pageName,
  165. name: student.name,
  166. examNumber: student.examNumber,
  167. subjectName: student.subjectName,
  168. });
  169. });
  170. });
  171. });
  172. imageList.value = images;
  173. }
  174. async function submitBatch() {
  175. await imageAuditSave({
  176. examId: userStore.curExam.id,
  177. batchId: batchInfo.value.batchId,
  178. });
  179. }
  180. async function releaseBatch() {
  181. await imageAuditRelease({ examId: userStore.curExam.id });
  182. }
  183. function setCurImage(index: number) {
  184. curImageIndex.value = index;
  185. curImage.value = imageList.value[curImageIndex.value];
  186. stopLoopRemainTime();
  187. remainTime.value = imageCheckLoopTime.value;
  188. if (!loopImageStoped.value) {
  189. // 开启loop时会调用一次action,所这里提前加1
  190. // remainTime.value++;
  191. startLoopRemainTime();
  192. }
  193. }
  194. async function getNextImage() {
  195. if (curImageIndex.value >= imageList.value.length - 1) {
  196. await submitBatch();
  197. // 获取下一批次
  198. await startLoopGetData();
  199. return;
  200. }
  201. setCurImage(++curImageIndex.value);
  202. }
  203. function getPrevImage() {
  204. if (curImageIndex.value <= 0) return;
  205. setCurImage(--curImageIndex.value);
  206. }
  207. // init
  208. onMounted(async () => {
  209. await releaseBatch();
  210. startLoopGetData();
  211. });
  212. onBeforeUnmount(async () => {
  213. stopLoopGetData();
  214. stopLoopRemainTime();
  215. await releaseBatch();
  216. });
  217. </script>