zhangjie %!s(int64=5) %!d(string=hai) anos
pai
achega
e4e1af1bc7

+ 19 - 0
public/index.html

@@ -6,6 +6,25 @@
     <meta name="viewport" content="width=device-width,initial-scale=1.0" />
     <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
     <title><%= htmlWebpackPlugin.options.title %></title>
+    <script>
+      (function() {
+        // 按Ctrl+Shift+U,放开U,在一秒内再按Ctrl+Shift+P,可以调出开发者工具
+        let firstStepKey = false;
+        document.addEventListener("keydown", function(e) {
+          if (e.ctrlKey && e.shiftKey && e.code === "KeyU") {
+            firstStepKey = true;
+            setTimeout(() => {
+              firstStepKey = false;
+            }, 1000);
+          }
+          if (firstStepKey && e.ctrlKey && e.shiftKey && e.code === "KeyP") {
+            require("electron")
+              .remote.getCurrentWindow()
+              .toggleDevTools();
+          }
+        });
+      })();
+    </script>
   </head>
   <body>
     <noscript>

+ 20 - 1
src/assets/styles/pages.less

@@ -330,7 +330,7 @@
     bottom: 0;
     right: 0;
     z-index: 99;
-    padding: 15px;
+    padding: 15px 15px 40px;
     overflow-y: auto;
     overflow-x: hidden;
     .history-item {
@@ -351,6 +351,14 @@
       }
     }
   }
+  &-reset-area {
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    height: 40px;
+    text-align: center;
+    padding: 5px 0;
+  }
 
   &-image {
     margin: 0 240px;
@@ -414,6 +422,17 @@
       vertical-align: middle;
     }
   }
+  // scan-info
+  &-info {
+    margin-top: 20px;
+    text-align: center;
+
+    > p {
+      display: inline-block;
+      vertical-align: middle;
+      margin: 0 10px;
+    }
+  }
 }
 
 /* scan-input */

+ 5 - 1
src/background.js

@@ -1,6 +1,6 @@
 "use strict";
 
-import { app, protocol, BrowserWindow, dialog } from "electron";
+import { app, protocol, BrowserWindow, dialog, Menu } from "electron";
 import {
   createProtocol
   /* installVueDevtools */
@@ -111,6 +111,10 @@ app.on("ready", async () => {
       console.error("Vue Devtools failed to install:", e.toString());
     }
   }
+
+  if (!isDevelopment) {
+    Menu.setApplicationMenu(null);
+  }
   createWindow();
 });
 

+ 3 - 10
src/mixins/initStoreMixin.js

@@ -1,5 +1,4 @@
 import db from "../plugins/db";
-import { getLocalDate } from "../plugins/utils";
 
 export default {
   methods: {
@@ -19,15 +18,9 @@ export default {
       this.$store.commit("client/setScanArea", newScanArea);
     },
     async initStore() {
-      // 今日事今日毕的前提下,采集数和上传数只取当天的记录数。
-      const curDate = getLocalDate();
-      const scanNo = await db.countUploadList({
-        createdTime: curDate
-      });
-      const uploadNo = await db.countUploadList({
-        fininshTime: curDate,
-        isUpload: 1
-      });
+      const curDate = this.$store.state.client.startCountTime;
+      const scanNo = await db.countScanList(curDate);
+      const uploadNo = await db.getUploadCount(curDate);
 
       this.$store.commit("client/setScanNo", scanNo);
       this.$store.commit("client/setUploadNo", uploadNo);

+ 2 - 1
src/mixins/uploadTaskMixin.js

@@ -33,7 +33,8 @@ export default {
     },
     async uploadSuccessCallback(curUploadTask) {
       await db.updateUploadState(curUploadTask.id);
-      this.$store.commit("setUploadNo", this.uploadNo + 1);
+      const unuploadNo = await db.countScanList({ isUpload: 0 });
+      this.$store.commit("client/setUnuploadNo", unuploadNo);
     },
     async initUploadTask() {
       if (this.setT) clearTimeout(this.setT);

+ 6 - 0
src/modules/client/router.js

@@ -2,6 +2,7 @@ import Camera from "./views/Camera.vue";
 import ScanArea from "./views/ScanArea.vue";
 import CheckInfo from "./views/CheckInfo.vue";
 import GroupScan from "./views/GroupScan.vue";
+import LineScan from "./views/LineScan.vue";
 
 export default [
   {
@@ -23,5 +24,10 @@ export default [
     path: "/group-scan",
     name: "GroupScan",
     component: GroupScan
+  },
+  {
+    path: "/line-scan",
+    name: "LineScan",
+    component: LineScan
   }
 ];

+ 10 - 2
src/modules/client/store.js

@@ -6,8 +6,10 @@ const state = {
   camera: "", // 相机编号
   curSubject: {},
   scanArea: {},
-  scanNo: 0, // 已采集数量(当天登录)
-  uploadNo: 0, // 已上传数量(当天登录),
+  scanNo: 0, // 已采集数量(从当前设置的计数时间算起)
+  uploadNo: 0, // 已上传数量(从当前设置的计数时间算起),
+  unuploadNo: 0, // 未上传数量(从当前设置的计数时间算起),
+  startCountTime: null, // 计数时间,默认:当前登录时间
   showToLoginModel: false
 };
 
@@ -21,6 +23,9 @@ const mutations = {
   setCamera(state, camera) {
     state.camera = camera;
   },
+  setStartCountTime(state, startCountTime) {
+    state.startCountTime = startCountTime;
+  },
   setShowToLoginModel(state, showToLoginModel) {
     state.showToLoginModel = showToLoginModel;
   },
@@ -35,6 +40,9 @@ const mutations = {
   },
   setUploadNo(state, uploadNo) {
     state.uploadNo = uploadNo;
+  },
+  setUnuploadNo(state, unuploadNo) {
+    state.unuploadNo = unuploadNo;
   }
 };
 

+ 44 - 12
src/modules/client/views/GroupScan.vue

@@ -34,8 +34,23 @@
       <div class="scan-main scan-picture" v-else>
         <img class="img-contain" :src="curImage.url" :alt="curImage.name" />
       </div>
+      <div class="scan-info">
+        <p>
+          <span>已采集:</span>
+          <span>{{ scanNo }}</span>
+          <span>,</span>
+          <span>未上传:</span>
+          <span>{{ unuploadNo }}</span>
+        </p>
+        <p>
+          <Button type="error" @click="resetStartCountTime">清零</Button>
+        </p>
+      </div>
     </div>
     <div class="scan-history">
+      <div class="scan-reset-area">
+        <Button type="primary" @click="toResetArea">重新设置采集信息</Button>
+      </div>
       <div
         class="history-item"
         v-for="(task, tindex) in historyList"
@@ -72,6 +87,7 @@
 
 <script>
 const fs = require("fs");
+import db from "../plugins/db";
 import { getStudentGroupByExamNumber } from "../api";
 import {
   decodeImageCode,
@@ -81,7 +97,7 @@ import {
 import { deepCopy } from "../../../plugins/utils";
 import ScanAreaDialog from "../components/ScanAreaDialog";
 import ScanExceptionDialog from "../components/ScanExceptionDialog";
-import { mapState } from "vuex";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "group-scan",
@@ -126,7 +142,14 @@ export default {
     };
   },
   computed: {
-    ...mapState("client", ["curSubject", "clientConfig", "curLevel"]),
+    ...mapState("client", [
+      "scanNo",
+      "unuploadNo",
+      "curSubject",
+      "clientConfig",
+      "curLevel",
+      "startCountTime"
+    ]),
     user() {
       return this.$store.state.user;
     },
@@ -139,14 +162,14 @@ export default {
         return 0;
       });
     },
-    scanNo() {
+    curTaskScanCount() {
       return this.students.filter(item => item.isClient).length;
     },
-    taskNo() {
+    taskCount() {
       return this.students.length;
     },
     isFinished() {
-      return this.taskNo && this.scanNo === this.taskNo;
+      return this.taskCount && this.curTaskScanCount === this.taskCount;
     }
   },
   mounted() {
@@ -158,6 +181,7 @@ export default {
     // this.test();
   },
   methods: {
+    ...mapMutations("client", ["setScanNo", "setStartCountTime"]),
     async test() {
       this.curImage = getEarliestFile();
       const codeAreas = {
@@ -373,6 +397,9 @@ export default {
         });
       }
 
+      // 更新采集数
+      this.updateScanNo();
+
       this.allReScan();
     },
     allReScan() {
@@ -383,6 +410,15 @@ export default {
     getCurCollectConfig() {
       return this.curStudent.collectConfig || this.curSubject.collectConfig;
     },
+    // count
+    async updateScanNo() {
+      const scanNo = await db.getScanCount(this.startCountTime);
+      this.setScanNo(scanNo);
+    },
+    resetStartCountTime() {
+      this.setStartCountTime(Math.floor(Date.now() / 1000));
+      this.updateScanNo();
+    },
     // history
     updateHistory(curStudent) {
       const student = deepCopy(curStudent);
@@ -400,13 +436,9 @@ export default {
       this.curStudent.collectConfig = setting;
       this.startDecodeTask(setting.codeArea);
     },
-    goBack() {
-      this.$confirm({
-        content: "当前正处于采集状态,确定要退出吗?",
-        onOk: () => {
-          this.$router.go(-1);
-        }
-      });
+    // toreset
+    toResetArea() {
+      this.$router.push({ name: "ScanArea" });
     }
   },
   beforeDestroy() {

+ 39 - 9
src/modules/client/views/LineScan.vue

@@ -22,8 +22,23 @@
       <div class="scan-main scan-picture" v-else>
         <img class="img-contain" :src="curImage.url" :alt="curImage.name" />
       </div>
+      <div class="scan-info">
+        <p>
+          <span>已采集:</span>
+          <span>{{ scanNo }}</span>
+          <span>,</span>
+          <span>未上传:</span>
+          <span>{{ unuploadNo }}</span>
+        </p>
+        <p>
+          <Button type="error" @click="resetStartCountTime">清零</Button>
+        </p>
+      </div>
     </div>
     <div class="scan-history">
+      <div class="scan-reset-area">
+        <Button type="primary" @click="toResetArea">重新设置采集信息</Button>
+      </div>
       <div
         class="history-item"
         v-for="(task, tindex) in historyList"
@@ -60,6 +75,7 @@
 
 <script>
 const fs = require("fs");
+import db from "../plugins/db";
 import { getStudentByExamNumber } from "../api";
 import {
   decodeImageCode,
@@ -69,7 +85,7 @@ import {
 import { deepCopy } from "../../../plugins/utils";
 import ScanAreaDialog from "../components/ScanAreaDialog";
 import ScanExceptionDialog from "../components/ScanExceptionDialog";
-import { mapState } from "vuex";
+import { mapState, mapMutations } from "vuex";
 
 export default {
   name: "line-scan",
@@ -114,7 +130,14 @@ export default {
     };
   },
   computed: {
-    ...mapState("client", ["curSubject", "clientConfig", "curLevel"]),
+    ...mapState("client", [
+      "scanNo",
+      "unuploadNo",
+      "curSubject",
+      "clientConfig",
+      "curLevel",
+      "startCountTime"
+    ]),
     user() {
       return this.$store.state.user;
     }
@@ -128,6 +151,7 @@ export default {
     // this.test();
   },
   methods: {
+    ...mapMutations("client", ["setScanNo", "setStartCountTime"]),
     async test() {
       this.curImage = getEarliestFile();
       const codeAreas = {
@@ -276,6 +300,7 @@ export default {
           isManual: type === "MANUAL"
         });
         await this.appendUploadTask();
+        await this.updateScanNo();
         this.updateHistory(this.curStudent);
       }
       // 删除扫描文件,继续开始下一个任务
@@ -306,6 +331,15 @@ export default {
     getCurCollectConfig() {
       return this.curStudent.collectConfig || this.curSubject.collectConfig;
     },
+    // count
+    async updateScanNo() {
+      const scanNo = await db.getScanCount(this.startCountTime);
+      this.setScanNo(scanNo);
+    },
+    resetStartCountTime() {
+      this.setStartCountTime(Math.floor(Date.now() / 1000));
+      this.updateScanNo();
+    },
     // history
     updateHistory(curStudent) {
       const student = deepCopy(curStudent);
@@ -323,13 +357,9 @@ export default {
       this.curStudent.collectConfig = setting;
       this.startDecodeTask(setting.codeArea);
     },
-    goBack() {
-      this.$confirm({
-        content: "当前正处于采集状态,确定要退出吗?",
-        onOk: () => {
-          this.$router.go(-1);
-        }
-      });
+    // toreset
+    toResetArea() {
+      this.$router.push({ name: "ScanArea" });
     }
   },
   beforeDestroy() {

+ 29 - 4
src/plugins/db.js

@@ -66,9 +66,9 @@ function searchUploadList(params) {
   });
 }
 
-function countUploadList(params) {
+function countScanList(params) {
   const { where, whereData } = serializeWhere(params);
-  const sql = `SELECT COUNT(1) as count FROM scan WHERE ${where}`;
+  const sql = `SELECT COUNT(1) AS count FROM scan WHERE ${where}`;
 
   return new Promise((resolve, reject) => {
     db.all(sql, whereData, (err, rows) => {
@@ -79,6 +79,29 @@ function countUploadList(params) {
   });
 }
 
+function getUploadCount(limitTime) {
+  const sql = `SELECT COUNT(1) AS count FROM scan WHERE strftime('%s',fininshTime) >= '${limitTime}' AND isUpload = 1`;
+
+  return new Promise((resolve, reject) => {
+    db.all(sql, (err, rows) => {
+      if (err) reject("count list fail!");
+
+      resolve(rows[0].count);
+    });
+  });
+}
+function getScanCount(limitTime) {
+  const sql = `SELECT COUNT(DISTINCT ticketNumber) AS count FROM scan WHERE strftime('%s',createdTime) >= '${limitTime}'`;
+
+  return new Promise((resolve, reject) => {
+    db.all(sql, (err, rows) => {
+      if (err) reject("count list fail!");
+
+      resolve(rows[0].count);
+    });
+  });
+}
+
 function updateUploadState(id) {
   const sql = `UPDATE scan SET isUpload=$isUpload,fininshTime=$fininshTime WHERE id=$id`;
   const datas = {
@@ -135,7 +158,7 @@ function getDict(key, defaultVal = "") {
 }
 
 function setDict(key, val) {
-  const sql = `UPDATE dict SET val=? where key=?`;
+  const sql = `UPDATE dict SET val=? WHERE key=?`;
   return new Promise((resolve, reject) => {
     db.run(sql, [val, key], err => {
       if (err) reject(`update dict ${key} fail!`);
@@ -170,7 +193,9 @@ export default {
   init,
   saveUploadInfo,
   searchUploadList,
-  countUploadList,
+  countScanList,
+  getUploadCount,
+  getScanCount,
   updateUploadState,
   getDict,
   setDict,

+ 30 - 25
src/views/Home.vue

@@ -2,7 +2,7 @@
   <div class="home">
     <div class="home-header">
       <div class="head-back">
-        <i-button type="default" @click="goback"
+        <i-button type="default" @click="toBack"
           ><i class="icon icon-left"></i>返回</i-button
         >
       </div>
@@ -22,25 +22,6 @@
     <div class="home-body">
       <router-view />
     </div>
-
-    <div class="home-progress" v-if="showProgress">
-      <div class="progress-item progress-name">
-        <span>今日上传进度:</span>
-      </div>
-      <div class="progress-item progress-info">
-        <span>已采集:{{ scanNo }}</span>
-        <span>/</span>
-        <span>已上传:{{ uploadNo }}</span>
-      </div>
-      <div class="progress-item progress-main">
-        <i-progress
-          :percent="curProgress"
-          :stroke-width="10"
-          status="active"
-          text-inside
-        ></i-progress>
-      </div>
-    </div>
   </div>
 </template>
 
@@ -54,25 +35,49 @@ export default {
   data() {
     return {
       showProgress: false,
-      examName: ""
+      examName: "",
+      // 路由历史只前进,不后退
+      backRouters: {
+        Camera: "Subject",
+        ScanArea: "Camera",
+        CheckInfo: "ScanArea",
+        GroupScan: "",
+        LineScan: ""
+      }
     };
   },
   computed: {
-    ...mapState("client", ["curSubject", "scanNo", "uploadNo"]),
-    curProgress() {
-      return !this.scanNo ? 0 : Math.ceil((this.uploadNo * 100) / this.scanNo);
-    },
+    ...mapState("client", ["curSubject", "clientConfig"]),
     username() {
       return this.$store.state.user.name;
     }
   },
   created() {
     this.examName = this.$ls.get("user", { examName: "" }).examName;
+    const scanBackRouter = this.clientConfig.isLevelKnown
+      ? "CheckInfo"
+      : "ScanArea";
+    this.backRouters.GroupScan = scanBackRouter;
+    this.backRouters.LineScan = scanBackRouter;
   },
   methods: {
     logout() {
       this.$ls.clear();
       this.$router.push({ name: "Login" });
+    },
+    toBack() {
+      const curRouteName = this.$route.name;
+      const backRouter = this.backRouters[curRouteName];
+      if (curRouteName === "GroupScan" || curRouteName === "LineScan") {
+        this.$confirm({
+          content: "当前正处于采集状态,确定要退出吗?",
+          onOk: () => {
+            this.$router.push({ name: backRouter });
+          }
+        });
+      } else {
+        this.$router.push({ name: backRouter });
+      }
     }
   },
   beforeDestroy() {

+ 6 - 2
src/views/Login.vue

@@ -81,11 +81,15 @@ export default {
       this.isSubmit = false;
       if (!data) return;
 
+      data.loginTime = formatDate();
+      this.$store.commit(
+        "client/setStartCountTime",
+        Math.floor(Date.now() / 1000)
+      );
+
       await this.initScanArea(data.subjects);
       await this.initStore();
 
-      data.loginTime = formatDate();
-
       this.$ls.set("user", data);
       this.$store.commit("setUser", data);
       this.$store.commit("client/setClientConfig", {