瀏覽代碼

rotate and scan upload md

zhangjie 4 年之前
父節點
當前提交
5f800ce74e

+ 2 - 1
config.sample.json

@@ -1,4 +1,5 @@
 {
 {
   "domain": "http://localhost:9000",
   "domain": "http://localhost:9000",
-  "input": ""
+  "input": "",
+  "compressRate": 1
 }
 }

+ 14 - 1
src/assets/styles/manage.less

@@ -3,10 +3,23 @@
     border-radius: 10px;
     border-radius: 10px;
     background-color: @background-light;
     background-color: @background-light;
     margin: 0 20px 20px;
     margin: 0 20px 20px;
-    padding: 20px;
+    padding: 20px 140px 20px 20px;
+    position: relative;
     .ivu-form-item {
     .ivu-form-item {
       margin-bottom: 0;
       margin-bottom: 0;
     }
     }
+
+    .paper-unfinish {
+      position: absolute;
+      height: 36px;
+      width: 110px;
+      top: 20px;
+      right: 20px;
+      z-index: auto;
+      padding: 8px 0;
+      line-height: 20px;
+      text-align: right;
+    }
   }
   }
   .paper-list {
   .paper-list {
     padding: 20px;
     padding: 20px;

+ 2 - 1
src/config.js

@@ -1,4 +1,5 @@
 export default {
 export default {
   domain: process.env.VUE_APP_DOMAIN,
   domain: process.env.VUE_APP_DOMAIN,
-  input: ""
+  input: "",
+  compressRate: 100
 };
 };

+ 5 - 6
src/main.js

@@ -77,12 +77,11 @@ axios.interceptors.request.use(
       config.url = GLOBAL.domain + config.url;
       config.url = GLOBAL.domain + config.url;
     }
     }
 
 
-    // 为请求头添加token信息
-    // let token = Vue.ls.get("token");
-    // if (token) {
-    //   config.headers["Authorization"] = token;
-    // }
-
+    // 为请求头添加信息
+    let organizationId = Vue.ls.get("organizationId");
+    if (organizationId) {
+      config.headers["organizationId"] = organizationId;
+    }
     // 设置延迟时效
     // 设置延迟时效
     config.timeout = 10 * 60 * 1000;
     config.timeout = 10 * 60 * 1000;
     return config;
     return config;

+ 6 - 0
src/modules/client/views/GroupScan.vue

@@ -350,11 +350,13 @@ export default {
       return validInfo;
       return validInfo;
     },
     },
     async toSaveStudent(examNumber, type) {
     async toSaveStudent(examNumber, type) {
+      const compressRate = this.GLOBAL.compressRate;
       const result = await saveOutputImage(
       const result = await saveOutputImage(
         this.curImage.url,
         this.curImage.url,
         {
         {
           examId: this.user.examId,
           examId: this.user.examId,
           subjectId: this.curSubject.id,
           subjectId: this.curSubject.id,
+          compressRate,
           examNumber
           examNumber
         },
         },
         this.getCurCollectConfig()
         this.getCurCollectConfig()
@@ -367,8 +369,10 @@ export default {
         this.curStudent = Object.assign(this.curStudent, {
         this.curStudent = Object.assign(this.curStudent, {
           isCurrent: false,
           isCurrent: false,
           isClient: true,
           isClient: true,
+          originImgPath: result.outputOriginPath,
           formalImgPath: result.outputFormalPath,
           formalImgPath: result.outputFormalPath,
           sliceImgPath: result.outputSlicelPath,
           sliceImgPath: result.outputSlicelPath,
+          compressRate,
           isManual: type === "MANUAL"
           isManual: type === "MANUAL"
         });
         });
         this.updateHistory(this.curStudent);
         this.updateHistory(this.curStudent);
@@ -405,8 +409,10 @@ export default {
           studentName: curStudent.name,
           studentName: curStudent.name,
           siteCode: curStudent.siteCode,
           siteCode: curStudent.siteCode,
           roomCode: curStudent.roomCode,
           roomCode: curStudent.roomCode,
+          originImgPath: curStudent.originImgPath,
           formalImgPath: curStudent.formalImgPath,
           formalImgPath: curStudent.formalImgPath,
           sliceImgPath: curStudent.sliceImgPath,
           sliceImgPath: curStudent.sliceImgPath,
+          compressRate: curStudent.compressRate,
           isManual: curStudent.isManual,
           isManual: curStudent.isManual,
           imageEncrypt: this.clientConfig.imageEncrypt,
           imageEncrypt: this.clientConfig.imageEncrypt,
           level: this.curLevel,
           level: this.curLevel,

+ 6 - 0
src/modules/client/views/LineScan.vue

@@ -286,11 +286,13 @@ export default {
       return validInfo;
       return validInfo;
     },
     },
     async toSaveStudent(examNumber, type) {
     async toSaveStudent(examNumber, type) {
+      const compressRate = this.GLOBAL.compressRate;
       const result = await saveOutputImage(
       const result = await saveOutputImage(
         this.curImage.url,
         this.curImage.url,
         {
         {
           examId: this.user.examId,
           examId: this.user.examId,
           subjectId: this.curSubject.id,
           subjectId: this.curSubject.id,
+          compressRate,
           examNumber
           examNumber
         },
         },
         this.getCurCollectConfig()
         this.getCurCollectConfig()
@@ -302,8 +304,10 @@ export default {
       if (result) {
       if (result) {
         this.curStudent = Object.assign(this.curStudent, {
         this.curStudent = Object.assign(this.curStudent, {
           isClient: true,
           isClient: true,
+          originImgPath: result.outputOriginPath,
           formalImgPath: result.outputFormalPath,
           formalImgPath: result.outputFormalPath,
           sliceImgPath: result.outputSlicelPath,
           sliceImgPath: result.outputSlicelPath,
+          compressRate,
           isManual: type === "MANUAL"
           isManual: type === "MANUAL"
         });
         });
         await this.appendUploadTask();
         await this.appendUploadTask();
@@ -325,8 +329,10 @@ export default {
         studentName: this.curStudent.name,
         studentName: this.curStudent.name,
         siteCode: this.curStudent.siteCode,
         siteCode: this.curStudent.siteCode,
         roomCode: this.curStudent.roomCode,
         roomCode: this.curStudent.roomCode,
+        originImgPath: this.curStudent.originImgPath,
         formalImgPath: this.curStudent.formalImgPath,
         formalImgPath: this.curStudent.formalImgPath,
         sliceImgPath: this.curStudent.sliceImgPath,
         sliceImgPath: this.curStudent.sliceImgPath,
+        compressRate: this.curStudent.compressRate,
         isManual: this.curStudent.isManual,
         isManual: this.curStudent.isManual,
         imageEncrypt: this.clientConfig.imageEncrypt,
         imageEncrypt: this.clientConfig.imageEncrypt,
         level: this.curLevel,
         level: this.curLevel,

+ 118 - 0
src/modules/manage/components/ImageView.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="image-view">
+    <div class="image-view-container">
+      <h5 class="image-view-title">{{ image.title }}</h5>
+      <div class="image-view-contain" :style="styles">
+        <img :src="image.thumbSrc" :alt="image.title" @click="toReview" />
+      </div>
+      <div class="image-view-actions" v-if="actions.length">
+        <Button
+          class="view-action-save"
+          size="small"
+          type="primary"
+          @click="toSaveRotate"
+          :disabled="saving"
+          v-if="canRotate && stepDeg"
+          >保存</Button
+        >
+        <Button
+          class="view-action-rotate"
+          size="small"
+          icon="md-refresh"
+          :disabled="saving"
+          @click="toRotate"
+          v-if="canRotate"
+        ></Button>
+        <Button
+          class="view-action-absent"
+          :type="image.missing ? 'error' : 'default'"
+          size="small"
+          @click="toSignAbsent"
+          v-if="canAbsent"
+          >缺考</Button
+        >
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { absentPaper, absentLocalPaper } from "../api";
+import { rotateImage } from "@/plugins/imageOcr";
+
+export default {
+  name: "image-view",
+  props: {
+    image: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    actions: {
+      type: Array,
+      default() {
+        return [];
+      }
+    }
+  },
+  data() {
+    return {
+      styles: {},
+      deg: 0,
+      stepDeg: 0,
+      saving: false
+    };
+  },
+  computed: {
+    canRotate() {
+      return this.actions.includes("rotate");
+    },
+    canAbsent() {
+      return this.actions.includes("absent");
+    }
+  },
+  methods: {
+    toRotate() {
+      this.deg += 90;
+      if (this.deg === 360) this.deg = 0;
+      this.stepDeg += 90;
+      if (this.stepDeg === 360) this.stepDeg = 0;
+      this.styles = {
+        transform: `rotate(${this.deg}deg)`
+      };
+    },
+    async toSaveRotate() {
+      if (this.saving) return;
+      if (!this.stepDeg) return;
+      this.saving = true;
+
+      const imagePath = await rotateImage(
+        this.image.sliceImgPath,
+        this.stepDeg
+      ).catch(() => {
+        this.$Message.error("图片旋转失败,请重新尝试!");
+      });
+
+      this.saving = false;
+      if (!imagePath) return;
+
+      this.stepDeg = 0;
+      this.$Message.success("图片旋转成功,等待上传。");
+      this.$emit("on-rotate-success", this.image);
+    },
+    async toSignAbsent() {
+      if (!this.image.paperId) {
+        this.$Message.error("图片数据有误或没有上传,无法标记缺考!");
+        return;
+      }
+      await absentPaper(this.image.paperId);
+      await absentLocalPaper(this.image.id, this.image.missing ? 0 : 1);
+      this.image.missing = !this.image.missing;
+    },
+    toReview() {
+      this.$emit("on-review");
+    }
+  }
+};
+</script>

+ 26 - 8
src/modules/manage/views/PaperManage.vue

@@ -72,15 +72,22 @@
           >
           >
         </FormItem>
         </FormItem>
       </Form>
       </Form>
+      <div class="paper-unfinish">
+        <span>未上传:{{ unfinishCount }}</span>
+      </div>
     </div>
     </div>
 
 
     <div class="paper-list">
     <div class="paper-list">
-      <image-action-list
-        :data="papers"
-        :actions="['rotate', 'absent']"
-        @on-review="toReview"
-        ref="ImageActionList"
-      ></image-action-list>
+      <div class="image-action-list image-view-list image-view-list-5">
+        <image-view
+          v-for="(paper, index) in papers"
+          :key="paper.id"
+          :image="paper"
+          :actions="['rotate', 'absent']"
+          @on-review="toReview(index)"
+          @on-rotate-success="appendHistory"
+        ></image-view>
+      </div>
     </div>
     </div>
 
 
     <div class="part-page" v-if="total > size">
     <div class="part-page" v-if="total > size">
@@ -107,12 +114,14 @@
 <script>
 <script>
 import { paperPageList, areaList } from "../api";
 import { paperPageList, areaList } from "../api";
 import { SORT_RULE_TYPE, CAFA_EXCEPTION_TYPE } from "@/constants/enumerate";
 import { SORT_RULE_TYPE, CAFA_EXCEPTION_TYPE } from "@/constants/enumerate";
-import ImageActionList from "../components/ImageActionList";
+import ImageView from "../components/ImageView";
 import SimpleImagePreview from "../components/SimpleImagePreview";
 import SimpleImagePreview from "../components/SimpleImagePreview";
+import rotateHistoryMixin from "./rotateHistoryMixin";
 
 
 export default {
 export default {
   name: "paper-manage",
   name: "paper-manage",
-  components: { ImageActionList, SimpleImagePreview },
+  mixins: [rotateHistoryMixin],
+  components: { ImageView, SimpleImagePreview },
   data() {
   data() {
     return {
     return {
       filter: {
       filter: {
@@ -140,6 +149,8 @@ export default {
   mounted() {
   mounted() {
     this.CAFA_EXCEPTION_TYPE = { ...CAFA_EXCEPTION_TYPE, 2: "全部" };
     this.CAFA_EXCEPTION_TYPE = { ...CAFA_EXCEPTION_TYPE, 2: "全部" };
     this.initData();
     this.initData();
+    // 开启上传
+    this.initUploadTask();
   },
   },
   methods: {
   methods: {
     initData() {
     initData() {
@@ -147,6 +158,8 @@ export default {
       if (user) {
       if (user) {
         this.filter.examId = user.examId;
         this.filter.examId = user.examId;
         this.subjects = user.subjects;
         this.subjects = user.subjects;
+        this.filter.subjectId = this.subjects[0].id;
+        this.toPage(1);
       }
       }
     },
     },
     async getList() {
     async getList() {
@@ -200,6 +213,11 @@ export default {
         this.filter.missing = null;
         this.filter.missing = null;
       }
       }
     },
     },
+    appendHistory(image) {
+      console.log(image);
+      image.filePath = image.sliceImgPath;
+      this.addRotateHistory(image);
+    },
     // paper view
     // paper view
     toReview(index) {
     toReview(index) {
       this.selectPaper(index);
       this.selectPaper(index);

+ 64 - 0
src/modules/manage/views/rotateHistoryMixin.js

@@ -0,0 +1,64 @@
+import db from "@/plugins/db";
+import { toUploadImg } from "@/plugins/imageUpload";
+
+export default {
+  data() {
+    return {
+      uploadList: [],
+      setT: null,
+      unfinishCount: 0,
+      uploadRunning: false
+    };
+  },
+  methods: {
+    async addRotateHistory(data) {
+      await db.saveRotateHistory(data).catch(err => {
+        console.log(err);
+      });
+    },
+    async initUploadTask() {
+      if (this.setT) clearTimeout(this.setT);
+      this.uploadList = await db.getUnfinishRotateHistoryList();
+      this.uploadRunning = true;
+      this.startUploadTask();
+    },
+    async startUploadTask() {
+      if (this.setT) clearTimeout(this.setT);
+
+      if (!this.uploadList.length || !this.uploadRunning) {
+        this.overUploadTask();
+        return;
+      }
+      let curTask = this.uploadList.shift();
+      curTask.sliceImgPath = curTask.filePath;
+      let uploadRes = true;
+      await toUploadImg(curTask, "slice").catch(() => {
+        uploadRes = false;
+      });
+
+      if (uploadRes) {
+        await db.finishRotateHistory(curTask.id).catch(() => {});
+      }
+
+      const unfinishCount = await db
+        .getUnfinishRotateHistoryCount()
+        .catch(() => {});
+      this.unfinishCount =
+        unfinishCount !== undefined ? unfinishCount : this.unfinishCount;
+
+      this.setT = setTimeout(() => {
+        this.startUploadTask();
+      }, 10);
+    },
+    overUploadTask() {
+      if (!this.uploadRunning) return;
+      this.setT = setTimeout(() => {
+        this.initUploadTask();
+      }, 5 * 1000);
+    }
+  },
+  beforeDestroy() {
+    this.uploadRunning = false;
+    if (this.setT) clearTimeout(this.setT);
+  }
+};

+ 114 - 38
src/plugins/db.js

@@ -20,8 +20,30 @@ function init() {
   db = new sqlite.Database(clientDb, sqlite.OPEN_READWRITE);
   db = new sqlite.Database(clientDb, sqlite.OPEN_READWRITE);
 }
 }
 
 
+function serializeWhere(params) {
+  const where = Object.keys(params)
+    .map(key => {
+      if (key.indexOf("Time") !== -1) {
+        return `${key} LIKE $${key}`;
+      } else {
+        return `${key} = $${key}`;
+      }
+    })
+    .join(" AND ");
+  const whereData = {};
+  Object.entries(params).map(([key, val]) => {
+    whereData[`$${key}`] = key.indexOf("Time") !== -1 ? `${val}%` : val;
+  });
+
+  return {
+    where,
+    whereData
+  };
+}
+
+// scan
 function saveUploadInfo(params) {
 function saveUploadInfo(params) {
-  const sql = `INSERT INTO scan (examId, examName, subjectId, subjectName, examNumber, studentName, siteCode, roomCode, formalImgPath, sliceImgPath,isManual,imageEncrypt,level,clientUserId, clientUsername, clientUserLoginTime, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
+  const sql = `INSERT INTO scan (examId, examName, subjectId, subjectName, examNumber, studentName, siteCode, roomCode, originImgPath,formalImgPath, sliceImgPath,compressRate,isManual,imageEncrypt,level,clientUserId, clientUsername, clientUserLoginTime, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`;
   const datas = [
   const datas = [
     params.examId,
     params.examId,
     params.examName,
     params.examName,
@@ -31,8 +53,10 @@ function saveUploadInfo(params) {
     params.studentName,
     params.studentName,
     params.siteCode,
     params.siteCode,
     params.roomCode,
     params.roomCode,
+    params.originImgPath || "",
     params.formalImgPath,
     params.formalImgPath,
     params.sliceImgPath,
     params.sliceImgPath,
+    params.compressRate || 100,
     params.isManual ? 1 : 0,
     params.isManual ? 1 : 0,
     params.imageEncrypt,
     params.imageEncrypt,
     params.level,
     params.level,
@@ -131,6 +155,36 @@ function updateUploadState(id) {
   });
   });
 }
 }
 
 
+function updateLocalPaperId(id, paperId) {
+  const sql = `UPDATE scan SET paperId=$paperId WHERE id=$id`;
+  const datas = {
+    $paperId: paperId,
+    $id: id
+  };
+  return new Promise((resolve, reject) => {
+    db.run(sql, datas, err => {
+      if (err) reject("update paperId info fail!");
+
+      resolve();
+    });
+  });
+}
+
+function deleteScanById(id) {
+  const sql = `DELETE FROM scan WHERE id=$id`;
+  const datas = {
+    $id: id
+  };
+  return new Promise((resolve, reject) => {
+    db.run(sql, datas, err => {
+      if (err) reject("delete scan fail!");
+
+      resolve(true);
+    });
+  });
+}
+
+// dict
 function getAllDict() {
 function getAllDict() {
   const sql = `SELECT * FROM dict`;
   const sql = `SELECT * FROM dict`;
 
 
@@ -181,27 +235,7 @@ function setDict(key, val) {
   });
   });
 }
 }
 
 
-function serializeWhere(params) {
-  const where = Object.keys(params)
-    .map(key => {
-      if (key.indexOf("Time") !== -1) {
-        return `${key} LIKE $${key}`;
-      } else {
-        return `${key} = $${key}`;
-      }
-    })
-    .join(" AND ");
-  const whereData = {};
-  Object.entries(params).map(([key, val]) => {
-    whereData[`$${key}`] = key.indexOf("Time") !== -1 ? `${val}%` : val;
-  });
-
-  return {
-    where,
-    whereData
-  };
-}
-
+// paper-manage
 function getAreas(subjectId) {
 function getAreas(subjectId) {
   const sql = `SELECT DISTINCT siteCode from scan WHERE subjectId = '${subjectId}'`;
   const sql = `SELECT DISTINCT siteCode from scan WHERE subjectId = '${subjectId}'`;
 
 
@@ -288,29 +322,63 @@ function absentLocalPaper(id, missing) {
   });
   });
 }
 }
 
 
-function updateLocalPaperId(id, paperId) {
-  const sql = `UPDATE scan SET paperId=$paperId WHERE id=$id`;
-  const datas = {
-    $paperId: paperId,
-    $id: id
-  };
+function saveRotateHistory(params) {
+  const sql = `INSERT INTO rotate_history (examId,subjectId,paperId, studentName, examNumber, filePath, isUpload,createdTime, finishTime) VALUES (?,?,?,?,?,?,?,?,?)`;
+  const datas = [
+    params.examId,
+    params.subjectId,
+    params.paperId,
+    params.studentName,
+    params.examNumber,
+    params.filePath,
+    0, // isUpload
+    formatDate(), // createdTime
+    null
+  ];
   return new Promise((resolve, reject) => {
   return new Promise((resolve, reject) => {
-    db.run(sql, datas, err => {
-      if (err) reject("update paperId info fail!");
+    db.serialize(() => {
+      db.run(sql, datas, function(err) {
+        if (err) reject(err);
+        resolve(this.lastID);
+      });
+    });
+  });
+}
 
 
-      resolve();
+function getUnfinishRotateHistoryList() {
+  const sql = `SELECT * FROM rotate_history WHERE isUpload = 0`;
+
+  return new Promise((resolve, reject) => {
+    db.all(sql, (err, rows) => {
+      if (err) reject("get history list fail!");
+
+      resolve(rows);
     });
     });
   });
   });
 }
 }
 
 
-function deleteScanById(id) {
-  const sql = `DELETE FROM scan WHERE id=$id`;
+function getUnfinishRotateHistoryCount() {
+  const sql = `SELECT COUNT(1) AS count FROM rotate_history WHERE isUpload = 0`;
+
+  return new Promise((resolve, reject) => {
+    db.all(sql, (err, rows) => {
+      if (err) reject("count history list fail!");
+
+      resolve(rows[0].count);
+    });
+  });
+}
+
+function finishRotateHistory(id) {
+  const sql = `UPDATE rotate_history SET isUpload=$isUpload,finishTime=$finishTime WHERE id=$id`;
   const datas = {
   const datas = {
-    $id: id
+    $id: id,
+    $isUpload: 1,
+    $finishTime: formatDate()
   };
   };
   return new Promise((resolve, reject) => {
   return new Promise((resolve, reject) => {
     db.run(sql, datas, err => {
     db.run(sql, datas, err => {
-      if (err) reject("delete scan fail!");
+      if (err) reject("update download task info fail!");
 
 
       resolve(true);
       resolve(true);
     });
     });
@@ -460,6 +528,7 @@ function updateTaskFinish(id) {
 
 
 export default {
 export default {
   init,
   init,
+  // scan
   saveUploadInfo,
   saveUploadInfo,
   searchUploadList,
   searchUploadList,
   countScanList,
   countScanList,
@@ -467,18 +536,25 @@ export default {
   getScanCount,
   getScanCount,
   getHistory,
   getHistory,
   updateUploadState,
   updateUploadState,
+  updateLocalPaperId,
+  deleteScanById,
+  // dict
   getDict,
   getDict,
   setDict,
   setDict,
   getAllDict,
   getAllDict,
   initDict,
   initDict,
+  // paper-manage
   getAreas,
   getAreas,
   getPaperList,
   getPaperList,
   absentLocalPaper,
   absentLocalPaper,
-  updateLocalPaperId,
-  deleteScanById,
+  saveRotateHistory,
+  getUnfinishRotateHistoryList,
+  finishRotateHistory,
+  getUnfinishRotateHistoryCount,
+  // export data
   addExportTask,
   addExportTask,
-  getUnfinishTask,
   addExportTaskDetail,
   addExportTaskDetail,
+  getUnfinishTask,
   getDownloadTaskList,
   getDownloadTaskList,
   getDownloadTaskCount,
   getDownloadTaskCount,
   updateDownloadTaskDownload,
   updateDownloadTaskDownload,

+ 20 - 4
src/plugins/encryptProcess.js

@@ -1,6 +1,7 @@
 import { getEncryptPath } from "./env";
 import { getEncryptPath } from "./env";
 import { formatDate } from "./utils";
 import { formatDate } from "./utils";
-var request = require("request");
+const request = require("request");
+const isDevelopment = process.env.NODE_ENV !== "production";
 
 
 const childProcess = require("child_process");
 const childProcess = require("child_process");
 const encryptTool = getEncryptPath();
 const encryptTool = getEncryptPath();
@@ -123,7 +124,20 @@ const encryptCheck = async resultCallback => {
   }, interval);
   }, interval);
 };
 };
 
 
+const encryptCheckDev = resultCallback => {
+  resultCallback({
+    success: true,
+    type: "success",
+    msg: ""
+  });
+};
+
 const startEncryptCheck = async resultCallback => {
 const startEncryptCheck = async resultCallback => {
+  if (isDevelopment) {
+    encryptCheckDev(resultCallback);
+    return;
+  }
+
   checkResults = [];
   checkResults = [];
   lastConfirmResult = "";
   lastConfirmResult = "";
   if (setT) clearTimeout(setT);
   if (setT) clearTimeout(setT);
@@ -138,7 +152,9 @@ const closeEncryptCheck = async () => {
   await requestGet("close").catch(() => {});
   await requestGet("close").catch(() => {});
 };
 };
 
 
-startEncryptTool();
+if (!isDevelopment) {
+  startEncryptTool();
+}
 
 
 export { closeEncryptCheck, startEncryptCheck };
 export { closeEncryptCheck, startEncryptCheck };
 
 
@@ -148,11 +164,11 @@ export { closeEncryptCheck, startEncryptCheck };
  * 采集端与collect通讯设计要求:
  * 采集端与collect通讯设计要求:
  * 如果连续 2次 是ALIVE,则正常;
  * 如果连续 2次 是ALIVE,则正常;
  * 如果连续 2次 是INVALID,则过期;
  * 如果连续 2次 是INVALID,则过期;
- * 如果连续 5次 是NO_DRIVER或者LOGIN_ERROR则提示异常;
+ * 如果连续 2次 是NO_DRIVER或者LOGIN_ERROR则提示异常;
  *
  *
  * 采集端的线程循环原则:
  * 采集端的线程循环原则:
  * 如果异常,则线程的循环为 1秒;
  * 如果异常,则线程的循环为 1秒;
- * 如果正常,则线程的循环为 5分钟;
+ * 如果正常,则线程的循环为 10秒;
  * 如果失效,则线程退出;
  * 如果失效,则线程退出;
  *
  *
  */
  */

+ 5 - 0
src/plugins/env.js

@@ -81,6 +81,10 @@ function makeDirSync(pathContent) {
   });
   });
 }
 }
 
 
+function formatNum(num, [min, max]) {
+  return !num || num > max || num < min ? max : num;
+}
+
 function initConfigData(data) {
 function initConfigData(data) {
   let configData = { ...data };
   let configData = { ...data };
   if (!configData.input) configData.input = getInputDir();
   if (!configData.input) configData.input = getInputDir();
@@ -90,6 +94,7 @@ function initConfigData(data) {
   const configPath = path.join(homePath, "config.json");
   const configPath = path.join(homePath, "config.json");
   if (fs.existsSync(configPath)) {
   if (fs.existsSync(configPath)) {
     configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
     configData = JSON.parse(fs.readFileSync(configPath, "utf8"));
+    configData.compressRate = formatNum(configData.compressRate, [0, 100]);
     if (!configData.input) configData.input = getInputDir();
     if (!configData.input) configData.input = getInputDir();
   } else {
   } else {
     fs.writeFileSync(configPath, JSON.stringify(configData), "utf8");
     fs.writeFileSync(configPath, JSON.stringify(configData), "utf8");

+ 44 - 5
src/plugins/imageOcr.js

@@ -75,22 +75,46 @@ function decodeImageCode(imgPath, codeArea) {
  * @param {Object} collectConfig 裁剪区域
  * @param {Object} collectConfig 裁剪区域
  */
  */
 async function saveOutputImage(imgPath, paperInfo, collectConfig) {
 async function saveOutputImage(imgPath, paperInfo, collectConfig) {
-  const outputFormalPath = saveFormalImage(imgPath, paperInfo);
+  const outputOriginPath = saveOriginImage(imgPath, paperInfo);
+  const outputFormalPath = await saveFormalImage(imgPath, paperInfo);
   const outputSlicelPath = await saveSliceImage(
   const outputSlicelPath = await saveSliceImage(
-    imgPath,
+    outputFormalPath,
     paperInfo,
     paperInfo,
     collectConfig
     collectConfig
   ).catch(() => {});
   ).catch(() => {});
 
 
   if (outputSlicelPath && outputFormalPath)
   if (outputSlicelPath && outputFormalPath)
-    return { outputSlicelPath, outputFormalPath };
+    return { outputSlicelPath, outputFormalPath, outputOriginPath };
   return Promise.reject("试卷保存失败");
   return Promise.reject("试卷保存失败");
 }
 }
 
 
+function saveOriginImage(imgPath, paperInfo) {
+  if (paperInfo.compressRate === 100) return "";
+
+  const outputOriginPath = getOutputImagePath(paperInfo, "origin");
+  fs.copyFileSync(imgPath, outputOriginPath);
+  return outputOriginPath;
+}
+
 function saveFormalImage(imgPath, paperInfo) {
 function saveFormalImage(imgPath, paperInfo) {
   const outputFormalPath = getOutputImagePath(paperInfo, "formal");
   const outputFormalPath = getOutputImagePath(paperInfo, "formal");
-  fs.copyFileSync(imgPath, outputFormalPath);
-  return outputFormalPath;
+
+  if (paperInfo.compressRate === 100) {
+    fs.copyFileSync(imgPath, outputFormalPath);
+    return Promise.resolve(outputFormalPath);
+  }
+
+  let imgObj = gm(imgPath);
+  imgObj.setFormat("jpeg").quality(paperInfo.compressRate);
+
+  return new Promise((resolve, reject) => {
+    imgObj.write(outputFormalPath, function(err) {
+      if (err) {
+        reject(err);
+      }
+      resolve(outputFormalPath);
+    });
+  });
 }
 }
 
 
 function saveSliceImage(imgPath, paperInfo, collectConfig) {
 function saveSliceImage(imgPath, paperInfo, collectConfig) {
@@ -134,6 +158,20 @@ function saveSliceImage(imgPath, paperInfo, collectConfig) {
   });
   });
 }
 }
 
 
+function compressImage(imgPath, compressRate, outputPath) {
+  let imgObj = gm(imgPath);
+  imgObj.setFormat("jpeg").quality(compressRate);
+
+  return new Promise((resolve, reject) => {
+    imgObj.write(outputPath, function(err) {
+      if (err) {
+        reject(err);
+      }
+      resolve(outputPath);
+    });
+  });
+}
+
 function rotateImage(imgPath, imageRotate) {
 function rotateImage(imgPath, imageRotate) {
   let imgObj = gm(imgPath);
   let imgObj = gm(imgPath);
 
 
@@ -251,6 +289,7 @@ export {
   saveOutputImage,
   saveOutputImage,
   getEarliestFile,
   getEarliestFile,
   rotateImage,
   rotateImage,
+  compressImage,
   downloadFile,
   downloadFile,
   downloadServerFile
   downloadServerFile
 };
 };

+ 11 - 12
src/plugins/imageUpload.js

@@ -100,7 +100,7 @@ class UploadTask {
     this.taskRunning = true;
     this.taskRunning = true;
     setTimeout(() => {
     setTimeout(() => {
       this.runUploadTask();
       this.runUploadTask();
-    }, 100);
+    }, 10);
   }
   }
 
 
   async runUploadTask() {
   async runUploadTask() {
@@ -110,18 +110,17 @@ class UploadTask {
     }
     }
     const curTask = this.getCurTask();
     const curTask = this.getCurTask();
 
 
-    let uploadFormalRes = true;
-    await toUploadImg(curTask, "formal").catch(() => {
-      uploadFormalRes = false;
-    });
-    let uploadSliceRes = true;
-    await toUploadImg(curTask, "slice").catch(() => {
-      uploadSliceRes = false;
+    const uploadAll = [
+      toUploadImg(curTask, "formal"),
+      toUploadImg(curTask, "slice")
+    ];
+    let uploadResult = true;
+    await Promise.all(uploadAll).catch(() => {
+      uploadResult = false;
     });
     });
 
 
     let updateStdRes, saveLogRes;
     let updateStdRes, saveLogRes;
-
-    if (uploadFormalRes && uploadSliceRes) {
+    if (uploadResult) {
       updateStdRes = await toUploadStudent(curTask).catch(() => {});
       updateStdRes = await toUploadStudent(curTask).catch(() => {});
       saveLogRes = await toSaveCollectLog(curTask).catch(() => {});
       saveLogRes = await toSaveCollectLog(curTask).catch(() => {});
 
 
@@ -132,13 +131,13 @@ class UploadTask {
       }
       }
     }
     }
     // 待定:只要有一个接口出错,则提示上传失败!
     // 待定:只要有一个接口出错,则提示上传失败!
-    if (!uploadFormalRes || !uploadSliceRes || !updateStdRes || !saveLogRes) {
+    if (!uploadResult || !updateStdRes || !saveLogRes) {
       this.uploadErrorCallBack(curTask);
       this.uploadErrorCallBack(curTask);
     }
     }
 
 
     this.setT = setTimeout(() => {
     this.setT = setTimeout(() => {
       this.runUploadTask();
       this.runUploadTask();
-    }, 200);
+    }, 10);
   }
   }
 
 
   overUploadTask() {
   overUploadTask() {

+ 1 - 0
src/views/Login.vue

@@ -141,6 +141,7 @@ export default {
       await this.initStartCountTime(data.subjects);
       await this.initStartCountTime(data.subjects);
 
 
       this.$ls.set("user", data);
       this.$ls.set("user", data);
+      this.$ls.set("organizationId", data.organizationId);
       this.$store.commit("setUser", data);
       this.$store.commit("setUser", data);
       this.$store.commit("client/setClientConfig", {
       this.$store.commit("client/setClientConfig", {
         imageEncrypt: data.paramSetting.imageEncrypt,
         imageEncrypt: data.paramSetting.imageEncrypt,