zhangjie 11 сар өмнө
parent
commit
b5de06589e

+ 64 - 0
src/components/base/FileTypeSelect.vue

@@ -0,0 +1,64 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="file-type-select"
+    :placeholder="placeholder"
+    filterable
+    :clearable="clearable"
+    :disabled="disabled"
+    @change="select"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.id"
+      :value="item.name"
+      :label="item.name"
+    >
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+import { fileTypeQuery } from "../../modules/client/api";
+
+export default {
+  name: "file-type-select",
+  props: {
+    value: { type: [Number, String], default: "" },
+    placeholder: { type: String, default: "请选择" },
+    disabled: { type: Boolean, default: false },
+    clearable: { type: Boolean, default: true },
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: "",
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    async search() {
+      this.optionList = [];
+      const res = await fileTypeQuery();
+      this.optionList = res;
+    },
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit(
+        "change",
+        this.optionList.find((item) => item.name === this.selected)
+      );
+    },
+  },
+};
+</script>

+ 87 - 0
src/components/base/RoomClassSelect.vue

@@ -0,0 +1,87 @@
+<template>
+  <el-select
+    v-model="selected"
+    class="room-class-select"
+    :placeholder="placeholder"
+    filterable
+    :clearable="clearable"
+    :disabled="disabled"
+    @change="select"
+  >
+    <el-option
+      v-for="item in optionList"
+      :key="item.id"
+      :value="item.name"
+      :label="item.name"
+    >
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+import { roomQuery, classQuery } from "../../modules/client/api";
+
+export default {
+  name: "room-class-select",
+  props: {
+    value: { type: [Number, String], default: "" },
+    placeholder: { type: String, default: "请选择" },
+    disabled: { type: Boolean, default: false },
+    clearable: { type: Boolean, default: true },
+    type: { type: String, default: "room" },
+    filterData: {
+      type: Object,
+      default() {
+        return {
+          examId: "",
+          courseCode: "",
+        };
+      },
+    },
+  },
+  data() {
+    return {
+      optionList: [],
+      selected: "",
+    };
+  },
+  watch: {
+    value: {
+      immediate: true,
+      handler(val) {
+        this.selected = val;
+      },
+    },
+    "filterData.courseCode": {
+      handler(val, oldval) {
+        console.log(val);
+        if (val !== oldval) {
+          this.search();
+          this.$emit("input", "");
+          this.$emit("change", {});
+        }
+      },
+    },
+  },
+  created() {
+    this.search();
+  },
+  methods: {
+    async search() {
+      this.optionList = [];
+      if (!this.filterData.courseCode) return;
+
+      const func = this.type === "room" ? roomQuery : classQuery;
+      const res = await func(this.filterData);
+      this.optionList = res;
+    },
+    select() {
+      this.$emit("input", this.selected);
+      this.$emit(
+        "change",
+        this.optionList.find((item) => item.name === this.selected)
+      );
+    },
+  },
+};
+</script>

+ 14 - 0
src/modules/client/api.js

@@ -12,6 +12,20 @@ export const commonExamQuery = (data) => {
 export const commonCourseQuery = (datas) => {
 export const commonCourseQuery = (datas) => {
   return $postParam("/api/admin/common/course/query", datas);
   return $postParam("/api/admin/common/course/query", datas);
 };
 };
+// 文件类型
+export const fileTypeQuery = () => {
+  return $postParam("/api/admin/common/course/query", {});
+};
+// 考场
+export const roomQuery = (datas) => {
+  // examId,courseCode
+  return $postParam("/api/admin/common/room/query", datas);
+};
+// 班级
+export const classQuery = (datas) => {
+  // examId,courseCode
+  return $postParam("/api/admin/common/class/query", datas);
+};
 
 
 // scan
 // scan
 export const uploadImage = (isFormal, datas, config = {}) => {
 export const uploadImage = (isFormal, datas, config = {}) => {

+ 104 - 0
src/modules/client/components/SelectBatchNoDialog.vue

@@ -0,0 +1,104 @@
+<template>
+  <el-dialog
+    class="ocr-area-dialog"
+    :visible.sync="modalIsShow"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    append-to-body
+    @opened="dialogOpened"
+  >
+    <el-form
+      ref="modalFormComp"
+      :model="modalForm"
+      :rules="rules"
+      :key="modalForm.id"
+      label-width="100px"
+    >
+      <el-form-item prop="serialNo" label="批次号:">
+        <el-select
+          v-model.trim="modalForm.code"
+          filterable
+          placeholder="编码"
+          :disabled="!!originCode"
+        >
+          <el-option
+            v-for="item in codes"
+            :key="item"
+            :label="code"
+            :value="code"
+          ></el-option>
+        </el-select>
+        <el-input-number
+          v-model="modalForm.serialNo"
+          placeholder="请输入编号"
+          :min="1"
+          :max="9999"
+          :step="1"
+          step-strictly
+          :controls="false"
+        ></el-input-number>
+      </el-form-item>
+    </el-form>
+
+    <div slot="footer">
+      <el-button type="primary" @click="confirm">确定</el-button>
+      <el-button @click="cancel">取消</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name: "select-batch-no-dialog",
+  data() {
+    return {
+      modalIsShow: false,
+      modalForm: { code: "", serialNo: 1 },
+      originCode: "",
+      codes: "abcdefghijklmnopqrstuvwxyz".toUpperCase().split(""),
+      rules: {
+        serialNo: [
+          {
+            required: true,
+            message: "请输入批次号",
+            trigger: "change",
+          },
+        ],
+      },
+    };
+  },
+  methods: {
+    cancel() {
+      this.modalIsShow = false;
+    },
+    open() {
+      this.modalIsShow = true;
+    },
+    dialogOpened() {
+      const batchNo = this.$ls.get("batchNo", "");
+      if (batchNo) {
+        this.modalForm.code = batchNo[0];
+        this.modalForm.serialNo = Number(batchNo.substring(1) || "0") + 1;
+      } else {
+        this.modalForm.code = "";
+        this.modalForm.serialNo = 1;
+      }
+      this.originCode = this.modalForm.code;
+
+      this.$nextTick(() => {
+        this.$refs.modalFormComp.clearValidate();
+      });
+    },
+    async confirm() {
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      const batchNo = `${this.modalForm.code}${this.modalForm.serialNo}`;
+
+      this.$ls.set("batchNo", batchNo);
+      this.$emit("confirm", batchNo);
+      this.cancel();
+    },
+  },
+};
+</script>

+ 362 - 3
src/modules/client/views/ScanOther.vue

@@ -1,13 +1,372 @@
 <template>
 <template>
-  <div class="scan-other">scan-other</div>
+  <div class="scan-other">
+    <div class="part-box part-box-filter part-box-flex">
+      <el-form
+        ref="modalFormComp"
+        :model="modalForm"
+        :rules="rules"
+        label-position="left"
+        label-width="85px"
+        inline
+      >
+        <el-form-item prop="roomOrClass" label="考场/班级:">
+          <room-class-select
+            v-model="modalForm.roomOrClass"
+            placeholder="请选择考场/班级"
+            :disabled="isScaning"
+          >
+          </room-class-select>
+        </el-form-item>
+        <el-form-item prop="fileType" label="文件类型:">
+          <file-type-select
+            v-model="modalForm.fileType"
+            placeholder="请选择文件类型"
+            :disabled="isScaning"
+          >
+          </file-type-select>
+        </el-form-item>
+      </el-form>
+      <div class="part-box-action">
+        <el-button :disabled="!canClear" type="danger" @click="clearStage"
+          >清空</el-button
+        >
+        <el-button
+          :disabled="!canSave"
+          :loading="saving"
+          type="primary"
+          @click="toSave"
+          >保存</el-button
+        >
+        <el-button
+          type="primary"
+          :loading="scanStatus === 'SCAN'"
+          :disabled="!canScan"
+          @click="toScan"
+        >
+          {{ statusDesc[scanStatus] }}
+        </el-button>
+      </div>
+    </div>
+
+    <div class="part-box part-box-pad">
+      <el-table ref="TableList" size="medium" :data="dataList">
+        <el-table-column
+          prop="文件名"
+          label="任务名称"
+          min-width="300"
+        ></el-table-column>
+        <el-table-column
+          prop="roomOrClass"
+          label="考场/班级"
+          min-width="160"
+        ></el-table-column>
+        <el-table-column
+          prop="fileType"
+          label="文件类型"
+          width="160"
+        ></el-table-column>
+      </el-table>
+    </div>
+
+    <!-- SelectBatchNoDialog -->
+    <select-batch-no-dialog
+      ref="SelectBatchNoDialog"
+      @confirm="saveScanData"
+    ></select-batch-no-dialog>
+  </div>
 </template>
 </template>
 
 
 <script>
 <script>
+import {
+  getPreUploadFiles,
+  saveOutputImage,
+  clearDir,
+  getDirScanFile,
+} from "../../../plugins/imageOcr";
+import db from "../../../plugins/db";
+import { evokeScanner } from "../../../plugins/scanner";
+
+import FileTypeSelect from "@/components/base/FileTypeSelect.vue";
+import RoomClassSelect from "@/components/base/RoomClassSelect.vue";
+import SelectBatchNoDialog from "../components/SelectBatchNoDialog.vue";
+
+import timeMixins from "@/mixins/setTimeMixins";
+import log4js from "@/plugins/logger";
+import { randomCode } from "@/plugins/utils";
+import { getStageDir } from "@/plugins/env";
+const logger = log4js.getLogger("scan");
+
 export default {
 export default {
   name: "scan-other",
   name: "scan-other",
+  components: { RoomClassSelect, FileTypeSelect, SelectBatchNoDialog },
+  mixins: [timeMixins],
   data() {
   data() {
-    return {};
+    return {
+      task: this.$ls.get("task", {}),
+      scanStatus: "INIT",
+      scanStageList: [],
+      statusDesc: {
+        INIT: "开始扫描",
+        SCAN: "扫描中",
+        FINISH: "继续扫描",
+      },
+      user: this.$ls.get("user", {}),
+      saving: false,
+      maxCacheCount: 120,
+      scanCount: 0,
+      modalForm: {
+        roomOrClass: "",
+        fileType: "",
+      },
+      rules: {
+        roomOrClass: [
+          {
+            required: true,
+            message: "请选择考场/班级",
+            trigger: "change",
+          },
+        ],
+        fileType: [
+          {
+            required: true,
+            message: "请选择文件类型",
+            trigger: "change",
+          },
+        ],
+      },
+      // 非等待模式:delayMode:0
+      looping: false,
+      stageDir: getStageDir(),
+    };
+  },
+  computed: {
+    paperCount() {
+      return this.scanStageList.length;
+    },
+    canSave() {
+      return this.scanStatus === "FINISH" && this.paperCount > 0;
+    },
+    canScan() {
+      return (
+        this.scanStatus !== "SCAN" && this.paperCount <= this.maxCacheCount
+      );
+    },
+    canClear() {
+      return this.paperCount > 0;
+    },
+    isScaning() {
+      return this.scanStatus === "SCAN";
+    },
+    IS_DELAY_MODE() {
+      return this.GLOBAL.delayMode === 1;
+    },
+  },
+  beforeDestroy() {
+    this.stopLoopScaningFile();
+  },
+  methods: {
+    initData() {
+      this.scanStageList = [];
+      this.scanStatus = "INIT";
+      this.scanCount = 0;
+    },
+    clearFiles() {
+      clearDir(this.stageDir);
+    },
+    async goBackHandle() {
+      if (this.scanStageList.length) {
+        const res = await this.$confirm(
+          `当前存在未保存的扫描数据,确定要退出吗?`,
+          "警告",
+          {
+            type: "warning",
+          }
+        ).catch(() => {});
+        if (res !== "confirm") return;
+      }
+
+      logger.info(`99退出扫描`);
+    },
+    // scan
+    async toScan() {
+      if (!this.canScan) {
+        this.$message.error("已超过最大缓存数量,请先保存数据再继续扫描!");
+        return;
+      }
+
+      const valid = await this.$refs.modalFormComp.validate().catch(() => {});
+      if (!valid) return;
+
+      if (this.scanStatus === "INIT") {
+        this.startTask();
+      } else {
+        this.continueTask();
+      }
+    },
+    startTask() {
+      logger.info(`01开始扫描`);
+      this.continueTask();
+    },
+    continueTask() {
+      this.scanStatus = "SCAN";
+      if (this.IS_DELAY_MODE) {
+        this.evokeScanExe();
+      } else {
+        this.evokeScanExeNotDelay();
+      }
+    },
+    async evokeScanExe() {
+      logger.info("02唤起扫描仪");
+      await evokeScanner(this.GLOBAL.input).catch((error) => {
+        console.error(error);
+      });
+
+      // 缓存已扫描的数据
+      const res = getPreUploadFiles(this.GLOBAL.input, true);
+      if (!res.succeed) {
+        logger.error(`03扫描仪停止,故障:${res.errorMsg}`);
+        this.$message.error(res.errorMsg);
+        this.scanStatus = "FINISH";
+        return;
+      }
+      logger.info(`03扫描仪停止,扫描数:${res.data.length}`);
+      await this.stageScanImage(res.data);
+      this.scanStatus = "FINISH";
+      logger.info(`03-1完成条码解析`);
+    },
+    async evokeScanExeNotDelay() {
+      logger.info("02唤起扫描仪");
+      this.looping = true;
+      this.loopScaningFile();
+
+      await evokeScanner(this.GLOBAL.input).catch((error) => {
+        console.error(error);
+      });
+      this.stopLoopScaningFile();
+      await this.getScaningFile();
+
+      const scanCount = this.scanStageList.length - this.scanCount;
+      this.scanCount = this.scanStageList.length;
+
+      // 已扫描的数据
+      const res = getPreUploadFiles(this.GLOBAL.input);
+      this.scanStatus = "FINISH";
+      if (!res.succeed) {
+        logger.error(
+          `03扫描仪停止,扫描数:${scanCount},故障:${res.errorMsg}`
+        );
+        this.$message.error(res.errorMsg);
+        return;
+      }
+      logger.info(`03扫描仪停止,扫描数:${scanCount}`);
+    },
+    async stageScanImage(imageList) {
+      for (let i = 0, len = imageList.length; i < len; i++) {
+        const fileInfo = {
+          id: randomCode(16),
+          taskId: this.task.id,
+          schoolId: this.task.schoolId,
+          semesterId: this.task.semesterId,
+          examId: this.task.examId,
+          courseCode: this.task.courseCode,
+          courseName: this.task.courseName,
+          frontOriginImgPath: imageList[i].frontFile,
+          versoOriginImgPath: imageList[i].versoFile,
+          isFormal: 0,
+          studentName: "",
+          studentCode: "",
+          ocrArea: "",
+          fileType: this.modalForm.fileType,
+          roomOrClass: this.modalForm.roomOrClass,
+          batchNo: "",
+          clientUserId: this.user.id,
+          clientUsername: this.user.loginName,
+          clientUserLoginTime: this.user.loginTime,
+        };
+
+        this.scanStageList.push(fileInfo);
+      }
+    },
+    async saveScanItem(fileInfo) {
+      const ouputImageList = saveOutputImage(
+        [fileInfo.frontOriginImgPath, fileInfo.versoOriginImgPath],
+        {
+          courseCode: this.task.courseCode,
+        }
+      );
+
+      fileInfo.frontOriginImgPath = ouputImageList[0];
+      fileInfo.versoOriginImgPath = ouputImageList[1];
+
+      await db.saveUploadInfo(fileInfo);
+    },
+    toSave() {
+      if (!this.scanStageList.length) {
+        this.$message.error("当前无要保存的数据!");
+        return;
+      }
+
+      this.$refs.selectBatchNoDialog.open();
+    },
+    async saveScanData(batchNo) {
+      if (this.saving) return;
+      this.saving = true;
+
+      // TODO: 使用批量保存,有时间再做
+      logger.info(`04-1开始保存数据`);
+      for (let i = 0, len = this.scanStageList.length; i < len; i++) {
+        const fileInfo = this.scanStageList[i];
+        fileInfo.batchNo = batchNo;
+
+        let res = true;
+        await this.saveScanItem(fileInfo).catch((err) => {
+          res = false;
+          console.error(err);
+          logger.error(`04-1保存数据错误,${err}`);
+        });
+        if (!res) {
+          this.saving = false;
+          this.$message.error("保存数据错误,请重新尝试!");
+          return Promise.reject();
+        }
+      }
+
+      this.$message.success("保存成功!");
+      this.saving = false;
+      logger.info(`04-2保存数据成功`);
+      this.clearFiles();
+      this.initData();
+    },
+    // delay mode
+    // 实时获取扫描图片
+    async loopScaningFile() {
+      this.clearSetTs();
+      if (!this.looping) return;
+      await this.getScaningFile();
+
+      this.addSetTime(this.loopScaningFile, 1 * 1000);
+    },
+    stopLoopScaningFile() {
+      this.clearSetTs();
+      this.looping = false;
+    },
+    async getScaningFile() {
+      const newScanFiles = getDirScanFile(this.GLOBAL.input);
+      await this.stageScanImage(newScanFiles);
+    },
+    // table action
+    async clearStage() {
+      const res = await this.$confirm(`确定要清空所有数据吗?`, "警告", {
+        type: "warning",
+      }).catch(() => {});
+      if (res !== "confirm") return;
+
+      this.clearFiles();
+      this.initData();
+
+      logger.info(`99数据清空`);
+      this.$message.success("数据已清空!");
+    },
   },
   },
-  methods: {},
 };
 };
 </script>
 </script>

+ 22 - 4
src/modules/client/views/ScanPaper.vue

@@ -85,6 +85,11 @@
       :datas="selectList"
       :datas="selectList"
       @confirm="bindConfirm"
       @confirm="bindConfirm"
     ></manual-bind-dialog>
     ></manual-bind-dialog>
+    <!-- SelectBatchNoDialog -->
+    <select-batch-no-dialog
+      ref="SelectBatchNoDialog"
+      @confirm="saveScanData"
+    ></select-batch-no-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -103,6 +108,8 @@ import { evokeScanner } from "../../../plugins/scanner";
 import ImageContain from "@/components/ImageContain.vue";
 import ImageContain from "@/components/ImageContain.vue";
 import ScanResultTable from "../components/ScanResultTable.vue";
 import ScanResultTable from "../components/ScanResultTable.vue";
 import ManualBindDialog from "../components/ManualBindDialog.vue";
 import ManualBindDialog from "../components/ManualBindDialog.vue";
+import SelectBatchNoDialog from "../components/SelectBatchNoDialog.vue";
+
 import timeMixins from "@/mixins/setTimeMixins";
 import timeMixins from "@/mixins/setTimeMixins";
 import { getStudentInfo } from "../api";
 import { getStudentInfo } from "../api";
 import log4js from "@/plugins/logger";
 import log4js from "@/plugins/logger";
@@ -113,7 +120,12 @@ const logger = log4js.getLogger("scan");
 export default {
 export default {
   name: "scan-paper",
   name: "scan-paper",
   mixins: [timeMixins],
   mixins: [timeMixins],
-  components: { ImageContain, ScanResultTable, ManualBindDialog },
+  components: {
+    ImageContain,
+    ScanResultTable,
+    ManualBindDialog,
+    SelectBatchNoDialog,
+  },
   data() {
   data() {
     return {
     return {
       task: this.$ls.get("task", {}),
       task: this.$ls.get("task", {}),
@@ -305,6 +317,9 @@ export default {
           studentName: "",
           studentName: "",
           studentCode: "",
           studentCode: "",
           ocrArea: ocrAreaContent,
           ocrArea: ocrAreaContent,
+          fileType: "答题卡",
+          roomOrClass: "",
+          batchNo: "",
           clientUserId: this.user.id,
           clientUserId: this.user.id,
           clientUsername: this.user.loginName,
           clientUsername: this.user.loginName,
           clientUserLoginTime: this.user.loginTime,
           clientUserLoginTime: this.user.loginTime,
@@ -389,7 +404,7 @@ export default {
 
 
       await db.saveUploadInfo(fileInfo);
       await db.saveUploadInfo(fileInfo);
     },
     },
-    async toSave() {
+    toSave() {
       if (this.errorStageList.length) {
       if (this.errorStageList.length) {
         this.$message.error("还有异常数据未处理!");
         this.$message.error("还有异常数据未处理!");
         return;
         return;
@@ -399,7 +414,9 @@ export default {
         this.$message.error("当前无要保存的数据!");
         this.$message.error("当前无要保存的数据!");
         return;
         return;
       }
       }
-
+      this.$refs.selectBatchNoDialog.open();
+    },
+    async saveScanData(batchNo) {
       if (this.saving) return;
       if (this.saving) return;
       this.saving = true;
       this.saving = true;
 
 
@@ -408,6 +425,7 @@ export default {
       logger.info(`04-1开始保存数据`);
       logger.info(`04-1开始保存数据`);
       for (let i = 0, len = datas.length; i < len; i++) {
       for (let i = 0, len = datas.length; i < len; i++) {
         const fileInfo = datas[i];
         const fileInfo = datas[i];
+        fileInfo.batchNo = batchNo;
 
 
         let res = true;
         let res = true;
         await this.saveScanItem(fileInfo).catch((err) => {
         await this.saveScanItem(fileInfo).catch((err) => {
@@ -443,7 +461,7 @@ export default {
     },
     },
     async getScaningFile() {
     async getScaningFile() {
       const newScanFiles = getDirScanFile(this.GLOBAL.input);
       const newScanFiles = getDirScanFile(this.GLOBAL.input);
-      await this.stageScanImage(newScanFiles, true);
+      await this.stageScanImage(newScanFiles);
     },
     },
     // table action
     // table action
     toBind() {
     toBind() {

+ 22 - 1
src/plugins/db.js

@@ -60,7 +60,7 @@ function serializeWhere(params) {
 
 
 // scan
 // scan
 function saveUploadInfo(params) {
 function saveUploadInfo(params) {
-  const sql = `INSERT INTO scan (taskId, schoolId, semesterId, examId, courseCode, courseName, frontOriginImgPath, versoOriginImgPath, studentCode, ocrArea, isFormal, clientUserId, clientUsername, clientUserLoginTime, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
+  const sql = `INSERT INTO scan (taskId, schoolId, semesterId, examId, courseCode, courseName, frontOriginImgPath, versoOriginImgPath, studentCode, ocrArea,fileType,roomOrClass,batchNo, isFormal, clientUserId, clientUsername, clientUserLoginTime, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
   const datas = [
   const datas = [
     params.taskId,
     params.taskId,
     params.schoolId,
     params.schoolId,
@@ -72,6 +72,9 @@ function saveUploadInfo(params) {
     params.versoOriginImgPath,
     params.versoOriginImgPath,
     params.studentCode,
     params.studentCode,
     params.ocrArea,
     params.ocrArea,
+    params.fileType,
+    params.roomOrClass,
+    params.batchNo,
     params.isFormal,
     params.isFormal,
     params.clientUserId,
     params.clientUserId,
     params.clientUsername,
     params.clientUsername,
@@ -90,6 +93,23 @@ function saveUploadInfo(params) {
   });
   });
 }
 }
 
 
+function batchSaveUploadInfo(datas) {
+  return new Promise((resolve, reject) => {
+    const sql = `INSERT INTO scan (taskId, schoolId, semesterId, examId, courseCode, courseName, frontOriginImgPath, versoOriginImgPath, studentCode, ocrArea,fileType,roomOrClass,batchNo, isFormal, clientUserId, clientUsername, clientUserLoginTime, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
+    db.serialize(() => {
+      const stmt = db.prepare(sql);
+
+      for (let i = 0; i < datas.length; i++) {
+        stmt.run(datas[i]);
+      }
+      stmt.finalize((err) => {
+        if (err) reject(err);
+        resolve();
+      });
+    });
+  });
+}
+
 function searchUploadList(params) {
 function searchUploadList(params) {
   const { where, whereData } = serializeWhere(params);
   const { where, whereData } = serializeWhere(params);
 
 
@@ -226,6 +246,7 @@ export default {
   init,
   init,
   // scan
   // scan
   saveUploadInfo,
   saveUploadInfo,
+  batchSaveUploadInfo,
   searchUploadList,
   searchUploadList,
   searchHistoryList,
   searchHistoryList,
   countScanList,
   countScanList,

+ 3 - 0
src/plugins/db.sql

@@ -27,6 +27,9 @@ CREATE TABLE "scan" (
   "versoOriginImgPath" TEXT,
   "versoOriginImgPath" TEXT,
   "studentCode" TEXT,
   "studentCode" TEXT,
   "ocrArea" TEXT,
   "ocrArea" TEXT,
+  "fileType" TEXT NOT NULL DEFAULT '0',
+  "roomOrClass" TEXT,
+  "batchNo" TEXT NOT NULL,
   "isFormal" integer NOT NULL DEFAULT 0,
   "isFormal" integer NOT NULL DEFAULT 0,
   "isUpload" integer NOT NULL DEFAULT 0,
   "isUpload" integer NOT NULL DEFAULT 0,
   "clientUserId" text NOT NULL,
   "clientUserId" text NOT NULL,