|
@@ -0,0 +1,174 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <video id="video" ref="video" :width="width" :height="height" autoplay>
|
|
|
+ </video>
|
|
|
+ <div style="position: absolute; width: 400px; text-align: center; margin-top: -50px; color: #232323;">
|
|
|
+ <span class="verify-button" @click="snap">开始识别</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { mapState } from "vuex";
|
|
|
+import {
|
|
|
+ UPYUN_URL,
|
|
|
+ FACEPP_API,
|
|
|
+ FACEPP_KEY,
|
|
|
+ FACEPP_SECRET
|
|
|
+} from "../../constants/constants.js";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "FaceRecognition",
|
|
|
+ data() {
|
|
|
+ return { hide: true };
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ width: String,
|
|
|
+ height: String,
|
|
|
+ closeCamera: Boolean // optional
|
|
|
+ },
|
|
|
+ async mounted() {
|
|
|
+ this.openCamera();
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ closeCamera: function(newValue, oldValue) {
|
|
|
+ if (newValue) {
|
|
|
+ console.log("关闭摄像头");
|
|
|
+ this.$refs.video.srcObject.getTracks().forEach(function(track) {
|
|
|
+ track.stop();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.openCamera();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ this.$refs.video.srcObject.getTracks().forEach(function(track) {
|
|
|
+ track.stop();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async openCamera() {
|
|
|
+ const video = this.$refs.video;
|
|
|
+
|
|
|
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
|
|
+ try {
|
|
|
+ console.log("启动摄像头");
|
|
|
+ const stream = await navigator.mediaDevices.getUserMedia({
|
|
|
+ video: { facingMode: "user" }
|
|
|
+ });
|
|
|
+
|
|
|
+ video.srcObject = stream;
|
|
|
+ video.play();
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ this.$Message.error("无法启用摄像头");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$Message.error("没有找到可用的摄像头");
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // TODO: 定时抓拍
|
|
|
+ snap() {
|
|
|
+ const video = this.$refs.video;
|
|
|
+ video.pause();
|
|
|
+ var canvas = document.createElement("canvas");
|
|
|
+ canvas.width = 220;
|
|
|
+ canvas.height = 165;
|
|
|
+
|
|
|
+ var context = canvas.getContext("2d");
|
|
|
+ context.drawImage(video, 0, 0, 220, 165);
|
|
|
+
|
|
|
+ canvas.toBlob(this.uploadToServer);
|
|
|
+ video.play();
|
|
|
+ },
|
|
|
+ async uploadToServer(captureBlob) {
|
|
|
+ //保存抓拍照片到又拍云
|
|
|
+ var fileName = new Date().getTime() + ".jpg";
|
|
|
+ var fileUrl =
|
|
|
+ "/capture_photo/" + this.user.identityNumber + "/" + fileName;
|
|
|
+ try {
|
|
|
+ await this.$upyunhttp.put(fileUrl, captureBlob, {
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "image/jpeg"
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ this.$Message.error(e.message);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const captureFilePath =
|
|
|
+ UPYUN_URL +
|
|
|
+ "/capture_photo/" +
|
|
|
+ this.user.identityNumber +
|
|
|
+ "/" +
|
|
|
+ fileName;
|
|
|
+ await this.faceCompare(captureFilePath);
|
|
|
+ this.$emit("on-recognize-result", "something wrong");
|
|
|
+ },
|
|
|
+ async faceCompare(captureFilePath) {
|
|
|
+ const res = await this.$http.get(
|
|
|
+ "/api/ecs_core/studentFaceInfo/identityNumber",
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ identityNumber: this.user.identityNumber,
|
|
|
+ orgId: this.user.rootOrgId
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const faceToken = res.data.faceToken;
|
|
|
+ console.log(faceToken);
|
|
|
+ console.log(captureFilePath);
|
|
|
+
|
|
|
+ // TODO: 研究是否有更合适的位置,只使用了一次. 应该由server进行检测
|
|
|
+ try {
|
|
|
+ const faceCompareRes = await fetch(
|
|
|
+ FACEPP_API +
|
|
|
+ "/compare?" +
|
|
|
+ `api_key=${FACEPP_KEY}&api_secret=${FACEPP_SECRET}&face_token1=${faceToken}&image_url2=${captureFilePath}`,
|
|
|
+ {
|
|
|
+ method: "post",
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/x-www-form-urlencoded"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const verifyResult = await faceCompareRes.json();
|
|
|
+ console.log("人脸检测结果: " + verifyResult);
|
|
|
+
|
|
|
+ // 告知服务器人脸检测结果
|
|
|
+ const params = new URLSearchParams();
|
|
|
+ params.append("pass", true);
|
|
|
+ params.append("action", "COMPARE");
|
|
|
+ await this.$http.post("/api/face_capture", params);
|
|
|
+
|
|
|
+ // TODO: 识别成功、失败的通知或跳转
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e);
|
|
|
+ this.$Message.error(e.message);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapState(["user"])
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.verify-button {
|
|
|
+ font-size: 16px;
|
|
|
+ background-color: #ffcc00;
|
|
|
+ display: inline-block;
|
|
|
+ padding: 6px 16px;
|
|
|
+ border-radius: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.verify-button:hover {
|
|
|
+ color: #444444;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+</style>
|