Quellcode durchsuchen

feat: 数据检查完毕

zhangjie vor 9 Monaten
Ursprung
Commit
ea1991141d

+ 224 - 0
src/render/components/ImportBtn/index.vue

@@ -0,0 +1,224 @@
+<template>
+  <a-upload
+    :action="uploadUrl"
+    :headers="headers"
+    :accept="accept"
+    :data="uploadDataDict"
+    :show-upload-list="false"
+    :custom-request="customRequest"
+    :disabled="disabled || loading"
+    :before-upload="handleBeforeUpload"
+    @change="handleFileChange"
+  >
+    <slot>
+      <a-button>
+        <template #icon><ImportOutlined /></template>点击导入
+      </a-button>
+    </slot>
+  </a-upload>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, watch } from "vue";
+import { DownloadOutlined, ImportOutlined } from "@ant-design/icons-vue";
+import { message } from "ant-design-vue";
+import type { UploadProps } from "ant-design-vue";
+
+import type { AxiosError, AxiosProgressEvent } from "axios";
+import { request } from "@/utils/request";
+import { getFileMD5 } from "@/utils/crypto";
+
+defineOptions({
+  name: "ImportBtn",
+});
+
+const props = withDefaults(
+  defineProps<{
+    uploadUrl: string;
+    format?: string[];
+    uploadData?: Record<string, any>;
+    maxSize?: number;
+    disabled?: boolean;
+    uploadFileAlias?: string;
+  }>(),
+  {
+    uploadUrl: "",
+    format: () => ["xls", "xlsx"],
+    uploadData: () => {
+      return {};
+    },
+    maxSize: 20 * 1024 * 1024,
+    uploadFileAlias: "file",
+    disabled: false,
+  }
+);
+
+// interface ResultData {
+//   success: boolean;
+//   message: string;
+// }
+// type UploadSuccessData = ResultData & UploadResultType;
+// const emit = defineEmits<{
+//   uploading: [];
+//   uploadError: [value: ResultData];
+//   uploadSuccess: [value: UploadSuccessData];
+//   validError: [value: ResultData];
+// }>();
+
+const emit = defineEmits([
+  "uploading",
+  "uploadError",
+  "uploadSuccess",
+  "validError",
+]);
+
+const uploadRef = ref();
+const canUpload = ref(false);
+const uploadDataDict = ref({});
+const headers = ref({ md5: "" });
+const result = ref({ success: true, message: "" });
+const loading = ref(false);
+const uploadProgress = ref(0);
+const curFileUid = ref("");
+
+const accept = computed(() => {
+  return props.format.map((el) => `.${el}`).join();
+});
+
+function checkFileFormat(fileType: string) {
+  const fileFormat = fileType.split(".").pop()?.toLocaleLowerCase();
+  return props.format.some((item) => item.toLocaleLowerCase() === fileFormat);
+}
+
+const handleFileChange: UploadProps["onChange"] = ({ file, fileList }) => {
+  if (!fileList.length) {
+    curFileUid.value = "";
+    result.value = {
+      success: true,
+      message: "",
+    };
+    return;
+  }
+
+  if (curFileUid.value !== file.uid) {
+    result.value = {
+      success: true,
+      message: "",
+    };
+  }
+  curFileUid.value = file.uid;
+  canUpload.value = file.status === "uploading";
+};
+
+const handleBeforeUpload: UploadProps["beforeUpload"] = async (file) => {
+  uploadDataDict.value = {
+    ...props.uploadData,
+    filename: file.name,
+  };
+
+  if (file.size > props.maxSize) {
+    handleExceededSize();
+    return Promise.reject(result.value);
+  }
+
+  if (!checkFileFormat(file.name)) {
+    handleFormatError();
+    return Promise.reject(result.value);
+  }
+
+  const md5 = await getFileMD5(file);
+  headers.value.md5 = md5;
+
+  loading.value = true;
+};
+
+interface UploadResultType {
+  hasError: boolean;
+  failRecords: Array<{
+    msg: string;
+    lineNum: number;
+  }>;
+}
+
+const customRequest: UploadProps["customRequest"] = (option) => {
+  const { file, data } = option;
+
+  const formData = new FormData();
+  const paramData: Record<string, any> = data || {};
+  Object.entries(paramData).forEach(([k, v]) => {
+    formData.append(k, v);
+  });
+  formData.append(props.uploadFileAlias, file as File);
+  emit("uploading");
+
+  (
+    request({
+      url: option.action as string,
+      data: formData,
+      headers: option.headers,
+      onUploadProgress: (data: AxiosProgressEvent) => {
+        uploadProgress.value = data.total
+          ? Math.floor((100 * data.loaded) / data.total)
+          : 0;
+      },
+    }) as Promise<UploadResultType>
+  )
+    .then((res) => {
+      // 所有excel导入的特殊处理
+      if (res.hasError) {
+        const failRecords = res.failRecords;
+        const message = failRecords
+          .map((item) => `第${item.lineNum}行:${item.msg}`)
+          .join("。");
+
+        handleError(message);
+        return;
+      }
+      handleSuccess(res);
+    })
+    .catch((error: AxiosError<{ message: string }> | null) => {
+      handleError(error?.response?.data?.message);
+    });
+};
+
+function handleError(message: string | undefined) {
+  canUpload.value = false;
+  loading.value = false;
+  result.value = {
+    success: false,
+    message: message || "上传错误",
+  };
+  emit("uploadError", result.value);
+}
+function handleSuccess(data: UploadResultType) {
+  canUpload.value = false;
+  loading.value = false;
+  result.value = {
+    success: true,
+    message: "上传成功!",
+  };
+  emit("uploadSuccess", {
+    ...result.value,
+    data,
+  });
+}
+
+function handleFormatError() {
+  const content = `只支持文件格式为${props.format.join("/")}`;
+  result.value = {
+    success: false,
+    message: content,
+  };
+  loading.value = false;
+  emit("validError", result.value);
+}
+function handleExceededSize() {
+  const content = `文件大小不能超过${Math.floor(props.maxSize / 1024)}M`;
+  result.value = {
+    success: false,
+    message: content,
+  };
+  loading.value = false;
+  emit("validError", result.value);
+}
+</script>

+ 0 - 97
src/render/components/ImportDialog/index.vue

@@ -330,100 +330,3 @@ function modalOpenHandle() {
   curFileUid.value = "";
 }
 </script>
-
-<style lang="less">
-.import-box {
-  .import-temp {
-    display: flex;
-    justify-content: space-between;
-    margin-bottom: 10px;
-
-    > span {
-      flex-grow: 0;
-      flex-shrink: 0;
-      height: 20px;
-      line-height: 20px;
-      display: block;
-    }
-
-    .temp-btn {
-      flex-grow: 2;
-      text-align: left;
-
-      > a {
-        flex-grow: 2;
-        line-height: 20px;
-        color: var(--color-primary);
-
-        &:hover {
-          text-decoration: underline;
-          opacity: 0.8;
-        }
-      }
-    }
-    .arco-btn {
-      line-height: 20px;
-      height: auto;
-      padding: 0;
-      background: transparent;
-      border: none;
-
-      &:hover {
-        text-decoration: underline;
-        opacity: 0.8;
-      }
-    }
-  }
-  .arco-upload-drag {
-    padding: 40px 0;
-    > div:first-child {
-      height: 54px;
-      background-image: url(assets/images/upload-icon.png);
-      background-size: auto 100%;
-      background-repeat: no-repeat;
-      background-position: center;
-      margin-bottom: 16px;
-    }
-    svg {
-      display: none;
-    }
-  }
-
-  .arco-upload-list-item {
-    margin-top: 8px !important;
-    background-color: var(--color-fill-1);
-    border-radius: var(--border-radius-small);
-    .arco-upload-list-item-operation {
-      margin: 0 12px;
-    }
-
-    .svg-icon {
-      vertical-align: -2px;
-    }
-    .arco-upload-list-item-file-icon {
-      margin-right: 6px;
-      color: inherit;
-    }
-
-    &.arco-upload-list-item-error {
-      .arco-upload-list-item-file-icon {
-        color: var(--color-danger);
-      }
-    }
-  }
-  .arco-upload-progress {
-    > * {
-      display: none;
-    }
-    .arco-upload-icon-success {
-      display: block;
-    }
-  }
-
-  .tips-info {
-    max-height: 100px;
-    overflow: hidden;
-    margin-top: 5px;
-  }
-}
-</style>

+ 20 - 0
src/render/store/modules/dataCheck/index.ts

@@ -16,6 +16,16 @@ interface DataCheckState {
 
 type UpdateFieldParams = Pick<DataCheckOmrFieldEditParams, "field" | "value">;
 
+interface UpdateSheetData {
+  paperIndex: number;
+  paperId?: number;
+  pageIndex: number;
+  uri: string;
+}
+interface UpdateSliceData extends UpdateSheetData {
+  index: number;
+}
+
 export const useDataCheckStore = defineStore("dataCheck", {
   state: (): DataCheckState => ({
     imageType: "ORIGIN",
@@ -49,6 +59,16 @@ export const useDataCheckStore = defineStore("dataCheck", {
       };
       await dataCheckOmrFieldEdit(params).catch(() => {});
     },
+    modifySliceUri(data: UpdateSliceData) {
+      if (!this.curStudent) return;
+      const { uri, pageIndex, index, paperIndex } = data;
+      this.curStudent.papers[paperIndex].pages[pageIndex].sliceUri[index] = uri;
+    },
+    modifySheetUri(data: UpdateSheetData) {
+      if (!this.curStudent) return;
+      const { uri, pageIndex, paperIndex } = data;
+      this.curStudent.papers[paperIndex].pages[pageIndex].sheetUri = uri;
+    },
   },
   persist: {
     storage: sessionStorage,

+ 1 - 1
src/render/views/Audit/ImageCheck/index.vue

@@ -51,7 +51,7 @@
     </div>
     <div class="audit-body">
       <!-- <img src="" alt=""> -->
-      <img src="@/components/ScanImage/data/paper.jpg" />
+      <img src="@/assets/imgs/paper.jpg" />
     </div>
     <div class="audit-topinfo">
       <a-space :size="6">

+ 1 - 1
src/render/views/Audit/InTime/index.vue

@@ -75,7 +75,7 @@
             v-for="(page, pindex) in paper.pages"
             :key="pindex"
             class="paper-img"
-            src="@/components/ScanImage/data/paper.jpg"
+            src="@/assets/imgs/paper.jpg"
           />
           <!-- <img
             v-for="(page, pindex) in paper.pages"

+ 0 - 0
src/render/components/ScanImage/FillAreaSetDialog.vue → src/render/views/DataCheck/ScanImage/FillAreaSetDialog.vue


+ 0 - 0
src/render/components/ScanImage/RecogEditDialog.vue → src/render/views/DataCheck/ScanImage/RecogEditDialog.vue


+ 0 - 0
src/render/components/ScanImage/data/paper.jpg → src/render/views/DataCheck/ScanImage/data/paper.jpg


+ 88 - 27
src/render/components/ScanImage/index.vue → src/render/views/DataCheck/ScanImage/index.vue

@@ -9,6 +9,7 @@
       }"
     >
       <img ref="imgRef" src="./data/paper.jpg" alt="p" @load="initImageSize" />
+      <!-- <img ref="imgRef" :src="curPage?.sheetUri" alt="原图" @load="initImageSize" /> -->
       <div class="img-recogs">
         <div
           v-for="(item, index) in recogBlocks"
@@ -40,7 +41,16 @@
         <li @click="onSetRecogStyle"><BgColorsOutlined /></li>
       </ul>
     </div>
-    <div class="img-change" @click="onChangeImage"><PictureFilled /></div>
+    <import-btn
+      upload-url="/api/admin/scan/answer/sheet/update"
+      :format="['jpg', 'png', 'jpeg']"
+      :upload-data="updateSheetData"
+      @upload-success="updateSheetSuccess"
+    >
+      <a-button class="img-change">
+        <template #icon><PictureFilled /></template>
+      </a-button>
+    </import-btn>
   </div>
 
   <!-- FillAreaSetDialog -->
@@ -63,14 +73,22 @@ import {
   RightOutlined,
   PictureFilled,
 } from "@ant-design/icons-vue";
-import { computed, nextTick, ref, watch } from "vue";
+import { computed, nextTick, ref } from "vue";
 import { objAssign } from "@/utils/tool";
 import { vEleMoveDirective } from "@/directives/eleMove";
-import { ImageRecogData, RecogBlock } from "@/utils/recog/recog";
-import { useUserStore } from "@/store";
+import {
+  parseRecogData,
+  parseDetailSize,
+  RecognizeArea,
+  RecogBlock,
+} from "@/utils/recog/recog";
+import { useUserStore, useDataCheckStore } from "@/store";
 
 import FillAreaSetDialog from "./FillAreaSetDialog.vue";
 import RecogEditDialog from "./RecogEditDialog.vue";
+import ImportBtn from "@/components/ImportBtn/index.vue";
+
+import { objAssign } from "@/utils/tool";
 
 import { omit } from "lodash-es";
 
@@ -78,14 +96,20 @@ defineOptions({
   name: "ScanImage",
 });
 
-const props = defineProps<{
-  imgSrc: string;
-  recogData: ImageRecogData[];
-}>();
-
-const emit = defineEmits(["recogBlockModified", "next", "prev"]);
+const emit = defineEmits(["next", "prev"]);
 
 const userStore = useUserStore();
+const dataCheckStore = useDataCheckStore();
+
+const curPage = computed(() => dataCheckStore.curPage);
+const updateSheetData = computed(() => {
+  if (!curPage.value) return {};
+
+  return {
+    paperId: curPage.value.paperId,
+    pageIndex: curPage.value.pageIndex,
+  };
+});
 
 const elRef = ref();
 const imgRef = ref();
@@ -125,7 +149,7 @@ function initImageSize() {
   imageSize.value = objAssign(imageSize.value, imgSize);
 
   nextTick(() => {
-    parseRecogBlocks();
+    updateRecogList();
   });
 }
 
@@ -174,6 +198,35 @@ function getImageSizePos({
   return imageSize;
 }
 
+// recog data
+const recogList = ref<RecognizeArea[]>([]);
+function updateRecogList() {
+  if (!dataCheckStore.curPage) return;
+
+  const regdata = parseRecogData(dataCheckStore.curPage.recogData);
+  if (!regdata) return;
+
+  recogList.value = [] as RecognizeArea[];
+  let index = 0;
+  regdata.question.forEach((gGroup) => {
+    gGroup.fill_result.forEach((qRecog) => {
+      const result = dataCheckStore.curPage.question[index - 1] || "";
+      qRecog.index = ++index;
+      // TODO: 解析其他数据
+
+      const fileResult = result ? result.split("") : [];
+      const recogItem = parseDetailSize(
+        qRecog,
+        "question",
+        qRecog.index,
+        fileResult
+      );
+      recogList.value.push(recogItem);
+    });
+  });
+
+  parseRecogBlocks();
+}
 // recogBlocks
 const recogBlocks = ref<RecogBlock[]>([]);
 const curRecogBlock = ref<RecogBlock | null>(null);
@@ -185,7 +238,7 @@ function parseRecogBlocks() {
     userStore.recogFillSet;
   const curBorderWidth = Math.max(1, borderWidth * rate);
 
-  recogBlocks.value = props.recogData.map((item) => {
+  recogBlocks.value = recogList.value.map((item) => {
     const nitem: RecogBlock = { ...item };
     nitem.areaImg = "";
 
@@ -228,18 +281,29 @@ function parseRecogBlocks() {
 
 // area click
 const recogEditDialogRef = ref();
-async function onAreaClick(data: RecogBlock) {
+function onAreaClick(data: RecogBlock) {
   curRecogBlock.value = data;
   // TODO:build area src img
-  await nextTick();
-  recogEditDialogRef.value?.open();
+  nextTick(() => {
+    recogEditDialogRef.value?.open();
+  });
 }
 
 async function onRecogEditConfirm(result: string[]) {
   if (!curRecogBlock.value) return;
 
-  curRecogBlock.value.result = result;
-  emit("recogBlockModified", curRecogBlock.value);
+  const data = curRecogBlock.value;
+
+  if (data.type === "question") {
+    const index = data.index - 1;
+    dataCheckStore.curPage.question.splice(index, 1, data.result.join(""));
+    await dataCheckStore.updateField({
+      field: data.type,
+      value: dataCheckStore.curPage.question,
+    });
+    curRecogBlock.value.result = result;
+  }
+  // TODO:
 }
 
 // img action
@@ -277,8 +341,13 @@ function onNext() {
 }
 
 // change image
-function onChangeImage() {
-  // TODO:
+function updateSheetSuccess(data: { url: string }) {
+  if (!curPage.value) return;
+  dataCheckStore.modifySheetUri({
+    paperIndex: curPage.value.paperIndex,
+    pageIndex: curPage.value.pageIndex,
+    uri: data.url,
+  });
 }
 
 // set recog style
@@ -286,14 +355,6 @@ const fillAreaSetDialogRef = ref();
 function onSetRecogStyle() {
   fillAreaSetDialogRef.value?.open();
 }
-
-// watch
-watch(
-  () => props.recogData,
-  (val) => {
-    if (val && imgRef.value) parseRecogBlocks();
-  }
-);
 </script>
 
 <style lang="less" scoped>

+ 1 - 1
src/render/components/SliceImage/CutImageDialog.vue → src/render/views/DataCheck/SliceImage/CutImageDialog.vue

@@ -35,7 +35,7 @@ import { SaveOutlined, CloseOutlined } from "@ant-design/icons-vue";
 import useModal from "@/hooks/useModal";
 import { objAssign } from "@/utils/tool";
 
-import ElementResize from "../ElementResize/index.vue";
+import ElementResize from "@/components/ElementResize/index.vue";
 
 defineOptions({
   name: "CutImageDialog",

+ 56 - 15
src/render/components/SliceImage/index.vue → src/render/views/DataCheck/SliceImage/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="slice-image">
-    <div v-for="item in studentSlice.papers" :key="item.id" class="image-paper">
+    <div v-for="item in curStudent.papers" :key="item.id" class="image-paper">
       <div
         v-for="(page, pindex) in item.pages"
         :key="pindex"
@@ -16,12 +16,22 @@
         >
           <img :src="url" :alt="sindex + 1" />
           <div class="image-action">
-            <a-button class="image-change">
-              <template #icon><PictureFilled /></template>
-            </a-button>
+            <import-btn
+              upload-url="/api/admin/scan/answer/slice/update"
+              :format="['jpg', 'png', 'jpeg']"
+              :upload-data="curSliceInfo"
+              @upload-success="updateSliceSuccess"
+            >
+              <a-button
+                class="image-change"
+                @click="onUpdateSlice(item.number, pindex, sindex)"
+              >
+                <template #icon><PictureFilled /></template>
+              </a-button>
+            </import-btn>
             <a-button
               class="image-slice"
-              @click="onEditSlice(item.id, pindex, sindex)"
+              @click="onEditSlice(item.number, pindex, sindex)"
             >
               <template #icon><NumberOutlined /></template>
             </a-button>
@@ -41,20 +51,22 @@
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import { NumberOutlined, PictureFilled } from "@ant-design/icons-vue";
 import CutImageDialog from "./CutImageDialog.vue";
 import { uploadSlice } from "@/ap/base";
 import { getFileMD5 } from "@/utils/crypto";
+import { useDataCheckStore } from "@/store";
 
 defineOptions({
   name: "SliceImage",
 });
 
-const props = defineProps<{
-  sheetUrl: string;
-  sliceData: StudentSliceData;
-}>();
+const dataCheckStore = useDataCheckStore();
+
+const curStudent = computed(() => {
+  return dataCheckStore.curStudent;
+});
 
 const curSliceSelection = ref<AreaSize>();
 const curSliceInfo = ref({
@@ -69,16 +81,23 @@ function getPageTitle(paperNumber, pageIndex) {
 }
 
 const cutImageDialogRef = ref();
-function onEditSlice(paperId: number, pageIndex: number, index: number) {
-  const paperIndex = props.sliceData.papers.findIndex((p) => p.id === paperId);
-  curSliceInfo.value = { paperIndex, pageIndex, paperId, index };
+function onEditSlice(paperNumber: number, pageIndex: number, index: number) {
+  const paper = curStudent.value.papers[paperNumber - 1];
+  if (!paper) return;
+
+  curSliceInfo.value = {
+    paperIndex: paperNumber - 1,
+    pageIndex,
+    paperId: paper.id as number,
+    index,
+  };
   curSliceSelection.value = undefined;
   cutImageDialogRef.value?.open();
 }
 async function cutImageModified(file: File) {
   const md5 = await getFileMD5(file);
 
-  const { paperId, pageIndex, index, paperIndex } = curSliceInfo.value;
+  const { paperId, pageIndex, index } = curSliceInfo.value;
   const datas = {
     paperId,
     pageIndex,
@@ -89,6 +108,28 @@ async function cutImageModified(file: File) {
   const res = await uploadSlice(datas).catch(() => {});
   if (!res) return;
 
-  props.sliceData.papers[paperIndex].pages[pageIndex].sliceUri[index] = res.uri;
+  dataCheckStore.modifySliceUri({
+    ...curSliceInfo.value,
+    uri: res.uri,
+  });
+}
+
+function onUpdateSlice(paperNumber: number, pageIndex: number, index: number) {
+  const paper = curStudent.value.papers[paperNumber - 1];
+  if (!paper) return;
+
+  curSliceInfo.value = {
+    paperIndex: paperNumber - 1,
+    pageIndex,
+    paperId: paper.id as number,
+    index,
+  };
+}
+
+function updateSliceSuccess(data: { url: string }) {
+  dataCheckStore.modifySliceUri({
+    ...curSliceInfo.value,
+    uri: data.url,
+  });
 }
 </script>

+ 4 - 58
src/render/views/DataCheck/index.vue

@@ -30,11 +30,7 @@
         @next="onNextPage"
         @recog-block-modified="onRecogEditConfirm"
       />
-      <SliceImage
-        v-if="dataCheckStore.curPage && !isOriginImage"
-        :sheet-url="dataCheckStore.curPage.sheetUri"
-        :slice-data="curStudentSlice"
-      />
+      <SliceImage v-if="dataCheckStore.curPage && !isOriginImage" />
     </div>
 
     <CheckAction @search="onSearch" />
@@ -48,22 +44,13 @@ import { CaretLeftOutlined, CaretRightOutlined } from "@ant-design/icons-vue";
 
 import { DataCheckListFilter, DataCheckListItem } from "@/ap/types/dataCheck";
 import { dataCheckList } from "@/ap/dataCheck";
+import { StudentPage } from "./types";
+import { useDataCheckStore } from "@/store";
 
 import SimplePagination from "@/components/SimplePagination/index.vue";
 import ScanImage from "@/components/ScanImage/index.vue";
 import SliceImage from "@/components/SliceImage/index.vue";
 import CheckAction from "./CheckAction.vue";
-import { ImageType } from "@/constants/enumerate";
-import { StudentPage } from "./types";
-import { useDataCheckStore } from "@/store";
-
-import {
-  parseRecogData,
-  parseDetailSize,
-  RecognizeArea,
-  RecogBlock,
-} from "@/utils/recog/recog";
-import { objAssign } from "@/utils/tool";
 
 defineOptions({
   name: "DataCheck",
@@ -105,6 +92,7 @@ function parseStudentPageList(students: DataCheckListItem[]) {
       paper.pages.forEach((page, pageIndex) => {
         dataList.value.push({
           ...page,
+          paperId: paper.id as number,
           pageIndex,
           paperIndex,
           studentIndex,
@@ -166,7 +154,6 @@ function selectPage(index: number) {
     dataCheckStore.curPage.studentIndex
   ] as DataCheckListItem;
   dataCheckStore.setInfo({ curStudent });
-  updateRecogList();
 }
 
 async function onPrevPage() {
@@ -200,45 +187,4 @@ async function onNextPage() {
 
   selectPage(dataCheckStore.curPageIndex + 1);
 }
-
-// recog data
-const recogList = ref<RecognizeArea[]>([]);
-function updateRecogList() {
-  if (!dataCheckStore.curPage) return;
-
-  const regdata = parseRecogData(dataCheckStore.curPage.recogData);
-  if (!regdata) return;
-
-  recogList.value = [] as RecognizeArea[];
-  let index = 0;
-  regdata.question.forEach((gGroup) => {
-    gGroup.fill_result.forEach((qRecog) => {
-      const result = dataCheckStore.curPage.question[index - 1] || "";
-      qRecog.index = ++index;
-      // TODO: 解析其他数据
-
-      const fileResult = result ? result.split("") : [];
-      const recogItem = parseDetailSize(
-        qRecog,
-        "question",
-        qRecog.index,
-        fileResult
-      );
-      recogList.value.push(recogItem);
-    });
-  });
-}
-
-async function onRecogEditConfirm(data: RecogBlock) {
-  if (data.type === "question") {
-    const index = data.index - 1;
-    dataCheckStore.curPage.question.splice(index, 1, data.result.join(""));
-    await dataCheckStore.updateField({
-      field: data.type,
-      value: dataCheckStore.curPage.question,
-    });
-  }
-
-  updateRecogList();
-}
 </script>

+ 1 - 0
src/render/views/DataCheck/types.ts

@@ -4,6 +4,7 @@ export interface StudentPage extends PaperPageItem {
   examId: number;
   studentId: number;
   studentIndex: number;
+  paperId: number;
   paperIndex: number;
   pageIndex: number;
   pagePageIndex: number;

+ 2 - 6
src/render/views/RecognizeCheck/RecognizeImage.vue

@@ -1,14 +1,10 @@
 <template>
   <div ref="arbitrateImgRef" class="arbitrate-img" @scroll="onImgScroll">
-    <img
-      src="@/components/ScanImage/data/paper.jpg"
-      alt="扫描结果"
-      @load="onImgLoad"
-    />
+    <img src="@/assets/imgs/paper.jpg" alt="扫描结果" @load="onImgLoad" />
     <!-- <img :src="imgSrc" alt="扫描结果" @load="onImgLoad" /> -->
   </div>
   <div ref="imgThumbRef" class="arbitrate-img-thumb">
-    <img src="@/components/ScanImage/data/paper.jpg" alt="扫描结果" />
+    <img src="@/assets/imgs/paper.jpg" alt="扫描结果" />
     <!-- <img :src="imgSrc" alt="扫描结果" /> -->
     <div
       class="arbitrate-img-area"

+ 1 - 4
src/render/views/Review/ReviewImage.vue

@@ -12,10 +12,7 @@
         @scroll="onImgScroll"
       >
         <!-- TODO:测试数据 -->
-        <img
-          src="@/components/ScanImage/data/paper.jpg"
-          :alt="`第${index + 1}页`"
-        />
+        <img src="@/assets/imgs/paper.jpg" :alt="`第${index + 1}页`" />
         <!-- <img :src="item.pages[0].sheetUri" :alt="`第${index + 1}页`" /> -->
       </div>
     </div>