Michael Wang hace 6 años
padre
commit
2908583bf0

+ 1 - 0
.env.development

@@ -4,3 +4,4 @@ VUE_APP_UPYUN_UPLOAD_URL=https://v0.api.upyun.com/exam-cloud-test
 VUE_APP_UPYUN_HEADER_AUTH=Basic ZXhhbWNsb3VkOmV4YW1jbG91ZDEyMzQ1Ng==
 VUE_APP_UPYUN_HEADER_AUTH=Basic ZXhhbWNsb3VkOmV4YW1jbG91ZDEyMzQ1Ng==
 VUE_APP_FACEPP_KEY=kEz_MSSjkNuHL3fHhCvv62fXkAo-vobE
 VUE_APP_FACEPP_KEY=kEz_MSSjkNuHL3fHhCvv62fXkAo-vobE
 VUE_APP_FACEPP_SECRET=aQMioMGUDShMnQmfM1_H_kPTP2pJva6J
 VUE_APP_FACEPP_SECRET=aQMioMGUDShMnQmfM1_H_kPTP2pJva6J
+VUE_APP_WK_SERVER_SOCKET=ws://192.168.10.39:8878/oewebsocket/

+ 1 - 0
.env.production

@@ -4,3 +4,4 @@ VUE_APP_UPYUN_UPLOAD_URL=https://v0.api.upyun.com/exam-cloud
 VUE_APP_UPYUN_HEADER_AUTH=Basic ZXhhbWNsb3VkOmV4YW1jbG91ZDEyMzQ1Ng==
 VUE_APP_UPYUN_HEADER_AUTH=Basic ZXhhbWNsb3VkOmV4YW1jbG91ZDEyMzQ1Ng==
 VUE_APP_FACEPP_KEY=VOlRKNlCSAYIOcSLDKOaZukkqpmi-Pwo
 VUE_APP_FACEPP_KEY=VOlRKNlCSAYIOcSLDKOaZukkqpmi-Pwo
 VUE_APP_FACEPP_SECRET=bzMjy-JfwtVUxVDMzagFh7ggbQBC71f1
 VUE_APP_FACEPP_SECRET=bzMjy-JfwtVUxVDMzagFh7ggbQBC71f1
+VUE_APP_WK_SERVER_SOCKET=wss://ecs.qmth.com.cn:8878/oewebsocket/

+ 1 - 0
src/constants/constants.js

@@ -7,3 +7,4 @@ export const UPYUN_UPLOAD_URL = process.env.VUE_APP_UPYUN_UPLOAD_URL;
 export const UPYUN_HEADER_AUTH = process.env.VUE_APP_UPYUN_HEADER_AUTH;
 export const UPYUN_HEADER_AUTH = process.env.VUE_APP_UPYUN_HEADER_AUTH;
 export const FACEPP_KEY = process.env.VUE_APP_FACEPP_KEY;
 export const FACEPP_KEY = process.env.VUE_APP_FACEPP_KEY;
 export const FACEPP_SECRET = process.env.VUE_APP_FACEPP_SECRET;
 export const FACEPP_SECRET = process.env.VUE_APP_FACEPP_SECRET;
+export const VUE_APP_WK_SERVER_SOCKET = process.env.VUE_APP_WK_SERVER_SOCKET;

+ 27 - 2
src/features/OnlineExam/Examing/ExamingHome.vue

@@ -18,6 +18,11 @@
         <!-- <FaceRecognition width="100%" height="100%" :showRecognizeButton="false" /> -->
         <!-- <FaceRecognition width="100%" height="100%" :showRecognizeButton="false" /> -->
       </div>
       </div>
     </div>
     </div>
+    <Modal v-model="showFaceId" :mask-closable="false" :closable="false">
+      <FaceId />
+      <p slot="footer">
+      </p>
+    </Modal>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -28,12 +33,16 @@ import QuestionFilters from "./QuestionFilters.vue";
 import QuestionView from "./QuestionView.vue";
 import QuestionView from "./QuestionView.vue";
 import ArrowNavView from "./ArrowNavView.vue";
 import ArrowNavView from "./ArrowNavView.vue";
 import QuestionNavView from "./QuestionNavView.vue";
 import QuestionNavView from "./QuestionNavView.vue";
+import FaceId from "./FaceId.vue";
 import FaceRecognition from "../../../components/FaceRecognition/FaceRecognition";
 import FaceRecognition from "../../../components/FaceRecognition/FaceRecognition";
 import { createNamespacedHelpers } from "vuex";
 import { createNamespacedHelpers } from "vuex";
 const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");
 const { mapState, mapMutations } = createNamespacedHelpers("examingHomeModule");
 
 
 export default {
 export default {
   name: "ExamingHome",
   name: "ExamingHome",
+  data() {
+    return { showFaceId: false };
+  },
   created() {
   created() {
     this.initData();
     this.initData();
     if (!this.$route.params.order) {
     if (!this.$route.params.order) {
@@ -65,7 +74,22 @@ export default {
         this.$Message.error(reason);
         this.$Message.error(reason);
       });
       });
 
 
-    setInterval(() => this.answerAllQuestions(), 1 * 60 * 1000);
+    this.submitInterval = setInterval(
+      () => this.answerAllQuestions(),
+      1 * 60 * 1000
+    );
+
+    // this.$Modal.info({
+    //   // title: "活体检测",
+    //   header: "",
+    //   footerHide: true,
+    //   render: h => {
+    //     return <FaceId />;
+    //   }
+    // });
+  },
+  destroyed() {
+    clearInterval(this.submitInterval);
   },
   },
   // beforeRouteUpdate(to, from, next) {
   // beforeRouteUpdate(to, from, next) {
   //   this.updateQuestion(next);
   //   this.updateQuestion(next);
@@ -221,7 +245,8 @@ export default {
     QuestionView,
     QuestionView,
     ArrowNavView,
     ArrowNavView,
     QuestionNavView,
     QuestionNavView,
-    FaceRecognition
+    FaceRecognition,
+    FaceId
   }
   }
 };
 };
 </script>
 </script>

+ 227 - 0
src/features/OnlineExam/Examing/FaceId.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="row" style="margin: 0;">
+    <div class="col-md-12 text-center" style="padding:8px;">
+      <div style="font-size: 30px;">
+        <span>人脸检测</span>
+        <span v-if="showIframe">({{timeCount}})</span>
+      </div>
+      <div v-if="showIframe" class="text-center" style="color: red; font-size: 16px;">
+        (注意:请点击下方“开始比对”按钮并在60秒内完成人脸检测,超时将退出考试)
+      </div>
+    </div>
+    <div id="faceIdDiv" style="position: relative;
+								   height:620px;
+								   background-color: #6e6f72!important;
+  								background-image: radial-gradient(circle at 50% 0,#a9a9a9,#34363c);">
+      <div v-if="!showIframe" width="100%" height="200px" style="text-align: center;line-height:100px;margin-top:5px;">
+        <div style="color:white;font-weight: bold;font-size:20px;">
+          {{redoBtnMsg}}
+        </div>
+        <button ng-show="redoBtnShow" type="button" class="btn" ng-disabled="redoBtnDisabled" ng-click="startFaceVerify()">重试</button>
+      </div>
+      <iframe ng-show="showIframe" allow="camera *" allowusermedia id="myFrame" scrolling="no" width="100%" height="620px" frameborder="0"></iframe>
+    </div>
+  </div>
+</template>
+
+<script>
+import {
+  FACEID_LINENESS_URL,
+  VUE_APP_WK_SERVER_SOCKET
+} from "@/constants/constants.js";
+
+export default {
+  name: "FaceId",
+  data() {
+    return {
+      showIframe: false,
+      redoBtnShow: false,
+      timeCount: 60,
+      redoBtnMsg: ""
+    };
+  },
+  mounted() {
+    this.startFaceVerify();
+  },
+  methods: {
+    showRedo(redoMsg) {
+      this.showIframe = false;
+      this.redoBtnDisabled = false;
+      this.redoBtnShow = true;
+      if (redoMsg) {
+        this.redoBtnMsg = redoMsg;
+      } else {
+        this.redoBtnMsg = "系统繁忙,请手动点击重试";
+      }
+    },
+    updateFaceVerify(errorMsg, redoMsg) {
+      this.showRedo(redoMsg);
+      this.$http.get(
+        "/api/face_verify/updateFaceVerify/" +
+          this.$route.params.examRecordDataId,
+        { params: { errorMsg: errorMsg } }
+      );
+    },
+    checkIframeOnload() {
+      var iframe = document.getElementById("myFrame");
+      if (!iframe) {
+        return null;
+      }
+      var app = iframe.contentWindow.document.getElementById("app");
+      if (app) {
+        return "success";
+      } else {
+        var preLabel = iframe.contentWindow.document.getElementsByTagName(
+          "pre"
+        )[0];
+        if (
+          preLabel &&
+          preLabel.innerText &&
+          preLabel.innerText.indexOf("error_message") > -1
+        ) {
+          return preLabel.innerText;
+        }
+      }
+      return null;
+    },
+    iframeLoadSuccess() {
+      try {
+        var iframe = document.getElementById("myFrame");
+        var app = iframe.contentWindow.document.getElementById("app");
+        app.querySelector(".footer").remove();
+      } catch (err) {
+        console.error(err);
+      }
+
+      const examRecordId = this.$route.params.examRecordDataId;
+
+      this.timeCount = 60; //人脸检测倒计时60秒
+      setInterval(() => {
+        --this.timeCount;
+      }, 1000);
+
+      //定时事件,如果1分钟内未完成人脸检测,执行内部程序
+      var faceIdTime = setTimeout(() => {
+        this.$Modal.remove();
+        ws.close();
+        var that = this;
+        this.$http
+          .get(
+            "/api/ecs_oe_student/examFaceLivenessVerify/faceLivenessVerifyTimeOut/" +
+              examRecordId
+          )
+          .then(function success(response) {
+            if (response.status == 200) {
+              var receivedMsg = response.data;
+              that.faceTestEnd(receivedMsg);
+            }
+          });
+      }, 60000); //60000
+      /**
+       * 人脸检测结果返回后台处理
+       */
+      this.faceTestEndHandle = result => {
+        this.$http
+          .get(
+            "/api/ecs_oe_student/examFaceLivenessVerify/faceLivenessVerifyEnd/" +
+              examRecordId +
+              "?result=" +
+              result
+          )
+          .then(() => {
+            if (result != "SUCCESS") {
+              this.$router.push("/login");
+            }
+          });
+      };
+      /**
+       * 人脸检测结束
+       */
+      this.faceTestEnd = receivedMsg => {
+        if (receivedMsg.verifyCount == 1) {
+          if (
+            receivedMsg.verifyResult == "VERIFY_FAILED" ||
+            receivedMsg.verifyResult == "TIME_OUT"
+          ) {
+            this.$Message.info("第一次人脸检测失败,系统退出,请重新登录", {
+              time: 5000
+            });
+            this.$router.push("/login");
+          } else if (receivedMsg.verifyResult == "NOT_ONESELF") {
+            this.$Message.info("人脸检测不合格,结束考试", { time: 5000 });
+            this.faceTestEndHandle("FAILED");
+          } else if (receivedMsg.verifyResult == "VERIFY_SUCCESS") {
+            this.$Message.info("人脸检测成功,请继续完成考试", { time: 5000 });
+            this.faceTestEndHandle("SUCCESS");
+          }
+        } else if (receivedMsg.verifyCount >= 2) {
+          if (receivedMsg.verifyResult == "VERIFY_SUCCESS") {
+            this.$Message.info("人脸检测成功,请继续完成考试", { time: 5000 });
+            this.faceTestEndHandle("SUCCESS");
+          } else {
+            this.$Message.info("人脸检测不合格,结束考试", { time: 5000 });
+            this.faceTestEndHandle("FAILED");
+          }
+        }
+      };
+
+      // open websocket
+      var ws = new WebSocket(VUE_APP_WK_SERVER_SOCKET + examRecordId);
+      ws.onopen = function() {
+        console.log("websocket已连接");
+      };
+      ws.onmessage = response => {
+        if (response.data.indexOf("verifyResult") > -1) {
+          var receivedMsg = JSON.parse(response.data);
+          clearTimeout(faceIdTime);
+          this.$router.push("/login");
+          ws.close();
+          this.faceTestEnd(receivedMsg);
+        }
+      };
+      ws.onclose = function() {
+        console.log("websocket连接已关闭...");
+      };
+    },
+    async startFaceVerify() {
+      this.redoBtnDisabled = true;
+      this.redoBtnMsg = "正在进入人脸检测...";
+      const examRecordId = this.$route.params.examRecordDataId;
+      const response = await this.$http.get(
+        "/api/ecs_oe_student/examFaceLivenessVerify/getFaceLivenessVerifyToken/" +
+          examRecordId
+      );
+      if (!response.data || !response.data.token) {
+        this.updateFaceVerify("TOKEN_EXPIRED", null);
+        return;
+      }
+
+      this.showIframe = true;
+      var iframe = document.getElementById("myFrame");
+      try {
+        iframe.src = FACEID_LINENESS_URL + response.data.token;
+      } catch (err) {
+        console.error(err);
+      }
+      var index = 0;
+      var iframeLoadTime = setInterval(() => {
+        var iframeLoadMsg = this.checkIframeOnload();
+        if (!iframeLoadMsg) {
+          index++;
+          if (index == 20) {
+            //检测达到20次
+            clearInterval(iframeLoadTime);
+            this.showRedo("网络异常,请手动点击重试");
+          }
+        } else if (iframeLoadMsg.indexOf("error_message") > -1) {
+          clearInterval(iframeLoadTime);
+          this.updateFaceVerify(iframeLoadMsg, null);
+        } else if (iframeLoadMsg == "success") {
+          clearInterval(iframeLoadTime);
+          this.iframeLoadSuccess();
+        }
+      }, 500);
+    }
+  }
+};
+</script>