Browse Source

扫描接口调试

zhangjie 1 year ago
parent
commit
edfa9d005d

+ 186 - 0
src/assets/styles/common-comp.scss

@@ -0,0 +1,186 @@
+// tips
+.cc-tips-error {
+  color: $--color-danger;
+}
+.cc-tips-success {
+  color: $--color-success;
+}
+
+// image-preview
+.cc-image-preview {
+  &-header {
+    position: absolute;
+    width: 100%;
+    padding: 15px;
+    top: 0;
+    left: 0;
+    line-height: 20px;
+    text-align: center;
+    font-size: 16px;
+    z-index: 99;
+    color: #f0f0f0;
+    h3 {
+      position: absolute;
+      left: 15px;
+      z-index: auto;
+    }
+  }
+  &-close {
+    position: absolute;
+    width: 30px;
+    height: 30px;
+    top: 5px;
+    right: 15px;
+    z-index: 100;
+    line-height: 30px;
+    text-align: center;
+    font-size: 40px;
+    color: #fff;
+    text-shadow: 0 0 2px #333;
+    cursor: pointer;
+
+    &:hover {
+      color: $--color-danger;
+    }
+  }
+  &-body {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: auto;
+    overflow: hidden;
+  }
+  &-imgs {
+    position: absolute;
+    top: 0;
+    left: 50%;
+    width: 600px;
+    margin-left: -300px;
+    // box-shadow: 0px 24px 36px 0px rgba(0, 0, 0, 0.3);
+    transition: width, height, transform 0.2s linear;
+    z-index: 8;
+    &-nosition {
+      transition: none;
+    }
+    &-move {
+      cursor: move;
+    }
+    > img {
+      display: block;
+      width: 100%;
+    }
+  }
+  &-guide {
+    position: absolute;
+    width: 80px;
+    height: 80px;
+    line-height: 80px;
+    top: 50%;
+    margin-top: -80px;
+    text-align: center;
+    color: #d0d0d0;
+    z-index: 9;
+    font-size: 60px;
+    text-shadow: 0 0 2px #333;
+    cursor: pointer;
+
+    &:hover {
+      color: #eee;
+    }
+    > i {
+      margin-top: -5px;
+    }
+    &-prev {
+      left: 0;
+    }
+    &-next {
+      right: 0;
+    }
+  }
+  &-footer {
+    position: absolute;
+    height: 60px;
+    bottom: 0;
+    right: 0;
+    padding: 10px;
+    font-size: 30px;
+    color: #d0d0d0;
+    z-index: 99;
+    li {
+      display: inline-block;
+      vertical-align: top;
+      height: 40px;
+      width: 40px;
+      line-height: 40px;
+      margin: 0 5px;
+      text-align: center;
+      cursor: pointer;
+      transition: transform 0.2s linear;
+    }
+    li:hover {
+      // color: #000;
+      transform: scale(1.1, 1.1);
+    }
+    li.li-disabled {
+      cursor: not-allowed;
+      color: #d0d0d0 !important;
+      transform: none !important;
+    }
+  }
+
+  &-loading {
+    position: absolute;
+    width: 60px;
+    height: 60px;
+    top: 0;
+    left: 50%;
+    margin: 0 0 0 -30px;
+    color: $--color-border;
+    font-size: 50px;
+    text-align: center;
+    line-height: 60px;
+    z-index: 99;
+  }
+
+  &-preload {
+    position: absolute;
+    z-index: 9;
+    width: 100px;
+    height: 100px;
+    overflow: hidden;
+    top: -1000px;
+    left: -1000px;
+  }
+
+  &-none {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    color: #e0e0e0;
+    text-align: center;
+    font-size: 20px;
+    > i {
+      font-size: 30px;
+    }
+  }
+
+  // view-ui
+  .ivu-modal-content {
+    background: transparent;
+  }
+  .ivu-modal-header {
+    display: none;
+  }
+  .ivu-modal-body {
+    top: 0;
+  }
+  .ivu-modal-close {
+    display: none;
+  }
+  .ivu-modal-mask {
+    background: rgba(55, 55, 55, 0.8);
+  }
+}

+ 11 - 1
src/assets/styles/element-ui-costom.scss

@@ -23,6 +23,15 @@
       padding-top: 90px;
       min-height: 100%;
     }
+    .el-dialog__footer {
+      width: 100%;
+      position: fixed;
+      z-index: 9;
+      background-color: #fff;
+      bottom: 0;
+      left: 0;
+      border-top: 1px solid $--color-border;
+    }
   }
 }
 .el-dialog__header {
@@ -65,6 +74,7 @@
 }
 .el-dialog__footer {
   overflow: hidden;
+  padding: 15px 20px;
   .el-button {
     width: 100px;
     border-radius: 8px;
@@ -77,7 +87,7 @@
   .el-dialog.is-fullscreen {
     background: $--color-background;
     .el-dialog__body {
-      padding: 70px 20px 20px;
+      padding: 50px 20px 60px;
     }
   }
   .el-dialog {

+ 1 - 0
src/assets/styles/index.scss

@@ -7,3 +7,4 @@
 @import "./pages.scss";
 
 @import "./element-ui-costom.scss";
+@import "./common-comp.scss";

+ 37 - 0
src/assets/styles/pages.scss

@@ -124,6 +124,43 @@
     font-size: 20px;
     z-index: 9;
   }
+  .el-dialog__footer {
+    .el-button {
+      float: none;
+    }
+  }
+
+  .scan-image {
+    &-list {
+      font-size: 0;
+    }
+    &-item {
+      display: inline-block;
+      vertical-align: top;
+      margin: 5px 10px;
+      font-size: 14px;
+
+      > p {
+        line-height: 20px;
+        text-align: center;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+      .el-image {
+        height: 100px;
+        width: 100px;
+        overflow: hidden;
+        cursor: pointer;
+      }
+      img {
+        transition: 0.3s transform;
+      }
+      img:hover {
+        transform: scale(1.1, 1.2);
+      }
+    }
+  }
 }
 
 // ocr-area-dialog

+ 16 - 1
src/components/SecSelect.vue

@@ -7,6 +7,7 @@
         default-select
         :clearable="!defaultSelectExam"
         @default-selected="semesterDefaultSelect"
+        @change="semesterChange"
       ></semester-select>
     </el-form-item>
     <el-form-item v-if="filterProps.includes('examId')" label="考试:">
@@ -16,6 +17,7 @@
         :clearable="!defaultSelectExam"
         :default-select="defaultSelectExam"
         @default-selected="examDefaultSelect"
+        @change="examChange"
       ></exam-select>
     </el-form-item>
     <el-form-item
@@ -28,6 +30,7 @@
         :filter-data="{ semesterId: filter.semesterId, examId: filter.examId }"
         placeholder="课程(代码)"
         clearable
+        @change="courseChange"
       ></course-select>
     </el-form-item>
   </div>
@@ -60,6 +63,7 @@ export default {
     return {
       filter: {},
       filterProps: [],
+      selectData: {},
     };
   },
   watch: {
@@ -91,7 +95,6 @@ export default {
     emitChange() {
       const data = this.getFilterData();
       this.$emit("input", data);
-      this.$emit("change", data);
     },
     semesterDefaultSelect() {
       if (this.defaultSelectExam) return;
@@ -102,6 +105,18 @@ export default {
       this.emitChange();
       this.$emit("exam-default", this.getFilterData());
     },
+    semesterChange(val) {
+      this.selectData.semester = val || {};
+      this.$emit("change", this.selectData);
+    },
+    examChange(val) {
+      this.selectData.exam = val || {};
+      this.$emit("change", this.selectData);
+    },
+    courseChange(val) {
+      this.selectData.course = val || {};
+      this.$emit("change", this.selectData);
+    },
   },
 };
 </script>

+ 1 - 1
src/components/base/ExamSelect.vue

@@ -78,7 +78,7 @@ export default {
       const defaultData = this.optionList[0];
       if (defaultData) {
         this.selected = defaultData.id;
-        this.$emit("input", this.selected);
+        this.select();
         this.$emit("default-selected", defaultData);
       }
     },

+ 1 - 1
src/components/base/SemesterSelect.vue

@@ -70,7 +70,7 @@ export default {
       const defaultCollege = this.optionList[0];
       if (defaultCollege) {
         this.selected = defaultCollege.id;
-        this.$emit("input", this.selected);
+        this.select();
         this.$emit("default-selected", defaultCollege);
       }
     },

+ 8 - 0
src/mixins/uploadTaskMixin.js

@@ -31,6 +31,14 @@ export default {
         isUpload: 0,
         clientUserId: this.$ls.get("user", { id: "" }).id,
       });
+      if (!unuploadList.length) {
+        this.taskSetTs.push(
+          setTimeout(() => {
+            this.initUploadTask();
+          }, 5 * 1000)
+        );
+        return;
+      }
       // 创建上传任务
       this.uploadTask = new UploadTask({
         taskList: unuploadList,

+ 3 - 0
src/modules/client/components/OcrAreaSetDialog.vue

@@ -127,6 +127,9 @@ export default {
         ...this.cropper.getData(),
         rotate: this.rotate,
       };
+      Object.keys(ocrArea).forEach((k) => {
+        ocrArea[k] = Math.floor(ocrArea[k]);
+      });
       db.setDict("ocrArea", JSON.stringify(ocrArea));
       this.$store.commit("client/setOcrArea", ocrArea);
       this.$emit("modified", ocrArea);

+ 34 - 17
src/modules/client/components/ScanTaskProcessDialog.vue

@@ -29,15 +29,20 @@
       <div class="scan-image-list">
         <div
           v-for="item in scanHistoryList"
-          :key="item"
+          :key="item.url"
           class="scan-image-item"
-          @click="toViewPaper(item)"
         >
-          <img :src="item" />
+          <el-image
+            :src="item.url"
+            fit="contain"
+            lazy
+            @click="toViewPaper(item)"
+          ></el-image>
+          <p v-if="item.name" :title="item.name">{{ item.name }}</p>
         </div>
       </div>
 
-      <div slot="footer">
+      <div class="text-center" slot="footer">
         <el-button
           type="primary"
           :loading="scanStatus !== 'INIT'"
@@ -97,6 +102,7 @@ export default {
         SCAN: "扫描中",
         SAVING: "保存数据中",
       },
+      user: this.$ls.get("user", {}),
     };
   },
   computed: {
@@ -138,17 +144,22 @@ export default {
         logger.error(`03扫描仪停止,故障:${res.errorMsg}`);
         this.$message.error(res.errorMsg);
         this.scanStatus = "INIT";
+        clearDir(this.GLOBAL.input);
         return;
       }
       logger.info(`03扫描仪停止,扫描数:${res.data.length}`);
       this.scanStatus = "SAVING";
-      await this.saveScanImage(res.data).catch(() => {
+      await this.saveScanImage(res.data).catch((e) => {
+        console.dir(e);
         this.$message.error("保存数据失败,请重新扫描!");
         logger.error(`保存数据失败,请重新扫描!`);
       });
       clearDir(this.GLOBAL.input);
       this.scanStatus = "INIT";
       await this.getScanHistory();
+
+      this.curPaper = {};
+      this.$refs.SimpleImagePreview.close();
     },
     // scan relate
     async getScanHistory() {
@@ -157,17 +168,22 @@ export default {
           isFormal: this.task.isFormal ? 1 : 0,
           taskId: this.task.id,
         })
-        .catch(() => {});
+        .catch((e) => {
+          console.log(e);
+        });
       if (!res) return;
 
       this.scanHistoryList = [];
       res.forEach((item) => {
-        this.scanHistoryList.push(item.frontOriginImgPath);
-        this.scanHistoryList.push(item.versoOriginImgPath);
+        this.scanHistoryList.push({
+          url: "file:///" + item.frontOriginImgPath,
+          name: `${item.studentCode}-1`,
+        });
+        this.scanHistoryList.push({
+          url: "file:///" + item.versoOriginImgPath,
+          name: `${item.studentCode}-2`,
+        });
       });
-
-      this.curPaper = {};
-      this.$refs.SimpleImagePreview.close();
     },
     async saveScanImage(imageList) {
       logger.info(`04-1开始保存数据`);
@@ -176,12 +192,13 @@ export default {
         const ouputImageList = saveOutputImage(
           [files.frontFile, files.versoFile],
           {
-            taskId: this.task.id,
+            courseCode: this.task.courseCode,
           }
         );
         const fileInfo = {
           taskId: this.task.id,
           schoolId: this.task.schoolId,
+          semesterId: this.task.semesterId,
           examId: this.task.examId,
           courseCode: this.task.courseCode,
           courseName: this.task.courseName,
@@ -189,6 +206,7 @@ export default {
           versoOriginImgPath: ouputImageList[1],
           isFormal: this.task.isFormal ? 1 : 0,
           studentCode: "",
+          ocrArea: "",
           clientUserId: this.user.id,
           clientUsername: this.user.loginName,
           clientUserLoginTime: this.user.loginTime,
@@ -202,7 +220,6 @@ export default {
             console.error(err);
             logger.error(`04-2条码解析失败,${err}`);
           });
-          console.log(num);
           fileInfo.studentCode = num || "";
           fileInfo.ocrArea = JSON.stringify(this.ocrArea);
         }
@@ -218,20 +235,20 @@ export default {
       logger.info(`04-2保存数据结束`);
     },
     // image-preview
-    toViewPaper(imgUrl) {
-      this.curPaper = { url: imgUrl };
+    toViewPaper(imgItem) {
+      this.curPaper = { ...imgItem };
       this.$refs.SimpleImagePreview.open();
     },
     toPrevPaper() {
       const curPaperIndex = this.scanHistoryList.findIndex(
-        (item) => item === this.curPaper.url
+        (item) => item.url === this.curPaper.url
       );
       if (curPaperIndex <= 0) return;
       this.curPaper = this.scanHistoryList[curPaperIndex - 1];
     },
     toNextPaper() {
       const curPaperIndex = this.scanHistoryList.findIndex(
-        (item) => item === this.curPaper.url
+        (item) => item.url === this.curPaper.url
       );
       if (curPaperIndex >= this.scanHistoryList.length - 1) return;
       this.curPaper = this.scanHistoryList[curPaperIndex + 1];

+ 14 - 4
src/modules/client/views/Scan.vue

@@ -107,6 +107,7 @@ export default {
         examId: "",
         courseCode: "",
       },
+      searchFilter: {},
       task: {},
       scanInfo: {},
       ocrArea: null,
@@ -124,13 +125,13 @@ export default {
   },
   mounted() {
     this.$store.commit("setBreadcrumbs", [{ url: "Scan", name: "扫描" }]);
-    // this.getOcrArea();
-    // this.search();
+    this.getOcrArea();
   },
   methods: {
     async search() {
       const res = await taskInfos(this.filter);
-      this.task = res || {};
+      this.task = { ...res, semesterId: this.filter.semesterId };
+      this.searchFilter = { ...this.filter };
     },
     async getOcrArea() {
       const ocrArea = await db.getDict("ocrArea", "").catch(() => {});
@@ -145,11 +146,20 @@ export default {
         this.$message.error("请选择课程!");
         return;
       }
+
+      if (!this.task.id) {
+        this.$message.error("请先查询任务!");
+        return;
+      }
+
       if (isFormal && !this.ocrArea) {
         this.$message.error("请先设置条形码识别区!");
         return;
       }
-      this.scanInfo = { ...this.task, isFormal };
+      this.scanInfo = {
+        ...this.task,
+        isFormal,
+      };
       this.$refs.ScanTaskProcessDialog.open();
     },
     toSetOrcArea() {

+ 1 - 1
src/plugins/db.js

@@ -106,7 +106,7 @@ function searchUploadList(params) {
 function searchHistoryList(params) {
   const { where, whereData } = serializeWhere(params);
 
-  const sql = `SELECT * FROM scan WHERE ${where} LIMIT 100 OFFSET 0 ORDER BY id DESC`;
+  const sql = `SELECT * FROM scan WHERE ${where} ORDER BY id DESC LIMIT 100 OFFSET 0`;
 
   return new Promise((resolve, reject) => {
     db.all(sql, whereData, (err, rows) => {

+ 10 - 2
src/plugins/imageOcr.js

@@ -10,6 +10,7 @@ import gm from "./gm";
 const fs = window.nodeRequire("fs");
 const path = window.nodeRequire("path");
 const childProcess = window.nodeRequire("child_process");
+const isWindowsPlatform = process.platform === "win32";
 
 /**
  * 旋转图片,并保存为正式文件
@@ -30,8 +31,8 @@ export function saveOutputImage(scaningImageList, paperInfo) {
 }
 
 function saveOriginImage(imagePath, paperInfo) {
-  console.log(imagePath);
-  const outputDir = path.join(getOutputDir("origin"), paperInfo.taskId + "");
+  const outputDir = path.join(getOutputDir("origin"), paperInfo.courseCode);
+  console.log(outputDir);
 
   if (!fs.existsSync(outputDir)) makeDirSync(outputDir);
   const outputOriginPath = path.join(outputDir, path.basename(imagePath));
@@ -177,12 +178,19 @@ export function renamePreUploadJsonFile(dir) {
 }
  */
 
+export function decodeImageCodeMac(imgPath) {
+  // 以400001-1.jpg名称为例
+  return path.basename(imgPath).split("-")[0];
+}
+
 /**
  *  解析图片code信息
  * @param {String} imgPath 图片路径
  * @param {Object} codeArea code所在文件区域信息
  */
 export function decodeImageCode(imgPath, codeArea) {
+  if (!isWindowsPlatform) return Promise.resolve(decodeImageCodeMac(imgPath));
+
   const tmpFile = path.join(
     getTmpDir(),
     `${formatDate("YYYYMMDDHHmmss")}_${randomCode(8)}.jpg`

+ 0 - 1
src/views/Home.vue

@@ -48,7 +48,6 @@ export default {
     };
   },
   created() {
-    console.log(this.curSchool);
     this.initUploadTask();
     // this.updateUnuploadCount();
   },

+ 3 - 7
src/views/Layout.vue

@@ -66,13 +66,9 @@ export default {
       ipcRenderer.send("maximize-window");
     },
     close() {
-      this.$confirm(
-        "请确保当前窗口没有任务正在进行,确认要关闭当前窗口吗?",
-        "提示",
-        {
-          type: "warning",
-        }
-      )
+      this.$confirm("确认要退出系统吗?", "提示", {
+        type: "warning",
+      })
         .then(() => {
           ipcRenderer.send("close-window");
         })