|
@@ -1,12 +1,33 @@
|
|
|
<template>
|
|
|
<div class="page">
|
|
|
<TopLogoVue></TopLogoVue>
|
|
|
- <!-- 主页面容器,红色背景,居中显示 -->
|
|
|
- <div class="bgcBox">
|
|
|
- <div ref="wrapper" class="camera">
|
|
|
- <!-- 视频元素容器 -->
|
|
|
- <video v-if="!takeOver" ref="videoEl" class="camera" />
|
|
|
+ <div class="scanMain">
|
|
|
+ <div class="bgcBox">
|
|
|
+ <div>
|
|
|
+ <canvas class="canvas" id="pag"></canvas>
|
|
|
+ </div>
|
|
|
+ <div ref="wrapper" class="camera wrapper">
|
|
|
+ <!-- 视频元素容器 -->
|
|
|
+ <video v-show="!takeOver && first" ref="videoEl" class="camera" />
|
|
|
+ <canvas v-if="!takeOver && !first" class="success" id="success"></canvas>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <span v-if="takeOver" class="text">扫描中...</span>
|
|
|
+ <span v-if="!takeOver && !first" class="text">人脸识别成功</span>
|
|
|
+ <div v-if="takeOver" class="loading">
|
|
|
+ <div
|
|
|
+ v-for="item in 16"
|
|
|
+ :key="item"
|
|
|
+ class="oneBox"
|
|
|
+ :class="{ check: item < loadingNum }"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="noface" class="noface err">
|
|
|
+ <img src="../../assets/img/close.png" @click="closeErr" alt="" />
|
|
|
+ </div>
|
|
|
+ <div v-if="badface" class="badface err">
|
|
|
+ <img src="../../assets/img/close.png" @click="closeErr" alt="" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
@@ -14,11 +35,16 @@
|
|
|
<script setup>
|
|
|
import TopLogoVue from "../../components/TopLogo/TopLogo.vue";
|
|
|
import { ref, onMounted } from "vue";
|
|
|
+import { PAGInit } from "libpag";
|
|
|
//使用 ref 对象来获取 DOM 元素
|
|
|
const wrapper = ref();
|
|
|
const videoEl = ref();
|
|
|
const takeOver = ref(false);
|
|
|
-
|
|
|
+const loadingNum = ref(0); //点亮的色块个数
|
|
|
+const first = ref(true); //第一次进入页面
|
|
|
+let timer = null; //定时器
|
|
|
+const noface = ref(false); //未检测到脸
|
|
|
+const badface = ref(false); //未注册的脸
|
|
|
// 存储拍摄后的图片路径
|
|
|
const imageUrl = ref(null);
|
|
|
|
|
@@ -58,6 +84,7 @@ function shoot() {
|
|
|
// 检查视频元素和页面容器是否存在
|
|
|
if (!videoEl.value || !wrapper.value) return;
|
|
|
takeOver.value = true;
|
|
|
+ first.value = false;
|
|
|
// 创建一个画布元素,设置画布尺寸为视频流的尺寸
|
|
|
const canvas = document.createElement("canvas");
|
|
|
canvas.width = videoEl.value.videoWidth;
|
|
@@ -82,11 +109,74 @@ function shoot() {
|
|
|
// 将 Base64 数据设置为图片的 src 属性
|
|
|
imageElement.src = imageDataUrl;
|
|
|
|
|
|
- console.log(imageElement, "图片路径");
|
|
|
-
|
|
|
// 将图片元素添加到页面容器中
|
|
|
wrapper.value.appendChild(imageElement);
|
|
|
+ timer = setInterval(() => {
|
|
|
+ if (loadingNum.value <= 16) {
|
|
|
+ loadingNum.value += 1;
|
|
|
+ } else {
|
|
|
+ loadingNum.value = 1;
|
|
|
+ }
|
|
|
+ // console.log(loadingNum.value, "loadingNum");
|
|
|
+ }, 500);
|
|
|
+ setTimeout(() => {
|
|
|
+ clearInterval(timer);
|
|
|
+ takeOver.value = false;
|
|
|
+ noface.value = true;
|
|
|
+ successInit()
|
|
|
+ }, 4000);
|
|
|
}
|
|
|
+// 关闭错误提示
|
|
|
+const closeErr = () => {
|
|
|
+ noface.value = false;
|
|
|
+ badface.value = false;
|
|
|
+};
|
|
|
+// 初始化 PAG
|
|
|
+const pagInit = () => {
|
|
|
+ PAGInit().then((PAG) => {
|
|
|
+ //此处特别要注意一点,你得看你的文件路径是否能够获取到你想要的pag格式文件,如果不行就用../的形式
|
|
|
+ //一层一层获取,目前在我的操作来看他目前貌似用不了 @/assets/XXX.pag的形式获取到想要的图片路径
|
|
|
+ //大家可以自行尝试看能否可以获取到对应的pag图片路径
|
|
|
+ const url = "/public/img/scaning.pag";
|
|
|
+ fetch(url)
|
|
|
+ .then((response) => response.blob())
|
|
|
+ .then(async (blob) => {
|
|
|
+ const file = new window.File(
|
|
|
+ [blob],
|
|
|
+ url.replace(/(.*\/)*([^.]+)/i, "$2")
|
|
|
+ );
|
|
|
+ const pagFile = await PAG.PAGFile.load(file);
|
|
|
+ document.getElementById("pag").width = pagFile.width();
|
|
|
+ document.getElementById("pag").height = pagFile.height();
|
|
|
+ const pagView = await PAG.PAGView.init(pagFile, "#pag");
|
|
|
+ pagView.setRepeatCount(0);
|
|
|
+ await pagView.play();
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+// 识别成功 PAG
|
|
|
+const successInit = () => {
|
|
|
+ PAGInit().then((PAG) => {
|
|
|
+ //此处特别要注意一点,你得看你的文件路径是否能够获取到你想要的pag格式文件,如果不行就用../的形式
|
|
|
+ //一层一层获取,目前在我的操作来看他目前貌似用不了 @/assets/XXX.pag的形式获取到想要的图片路径
|
|
|
+ //大家可以自行尝试看能否可以获取到对应的pag图片路径
|
|
|
+ const url = "/public/img/success.pag";
|
|
|
+ fetch(url)
|
|
|
+ .then((response) => response.blob())
|
|
|
+ .then(async (blob) => {
|
|
|
+ const file = new window.File(
|
|
|
+ [blob],
|
|
|
+ url.replace(/(.*\/)*([^.]+)/i, "$2")
|
|
|
+ );
|
|
|
+ const pagFile = await PAG.PAGFile.load(file);
|
|
|
+ document.getElementById("success").width = pagFile.width();
|
|
|
+ document.getElementById("success").height = pagFile.height();
|
|
|
+ const pagView = await PAG.PAGView.init(pagFile, "#success");
|
|
|
+ pagView.setRepeatCount(0);
|
|
|
+ await pagView.play();
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
|
|
|
// 在组件挂载后执行检查摄像头的操作
|
|
|
onMounted(() => {
|
|
@@ -94,6 +184,7 @@ onMounted(() => {
|
|
|
setTimeout(() => {
|
|
|
shoot();
|
|
|
}, 3000);
|
|
|
+ pagInit();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
@@ -105,21 +196,92 @@ onMounted(() => {
|
|
|
background-size: cover;
|
|
|
background-position: center;
|
|
|
position: relative;
|
|
|
+ .scanMain {
|
|
|
+ width: 500px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ margin: 0 auto;
|
|
|
+ .text {
|
|
|
+ color: #b7beff;
|
|
|
+ font-family: Inter-Medium-8;
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 24px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ }
|
|
|
+ .loading {
|
|
|
+ width: 421px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 5px 5px 5px 5px;
|
|
|
+ border: 1px solid #b7beff;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ align-items: center;
|
|
|
+ .oneBox {
|
|
|
+ width: 21px;
|
|
|
+ height: 30px;
|
|
|
+ border-radius: 2px 2px 2px 2px;
|
|
|
+ background: #362b5d;
|
|
|
+ }
|
|
|
+ .check {
|
|
|
+ background: #b7beff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
.camera {
|
|
|
- position: absolute;
|
|
|
- top: calc(50% - 140px);
|
|
|
- left: calc(50% - 140px);
|
|
|
width: 280px;
|
|
|
height: 280px;
|
|
|
border-radius: 50%;
|
|
|
}
|
|
|
- .bgcBox{
|
|
|
+ .bgcBox {
|
|
|
width: 450px;
|
|
|
height: 450px;
|
|
|
- position: absolute;
|
|
|
- top: calc(50% - 225px);
|
|
|
- left: calc(50% - 225px);
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
background-image: url("../../assets/img/scaning.pag");
|
|
|
+ .wrapper {
|
|
|
+ position: absolute;
|
|
|
+ // top: 10%;
|
|
|
+ // left: 10%;
|
|
|
+ }
|
|
|
+ .success{
|
|
|
+ position: absolute;
|
|
|
+ top: -100px;
|
|
|
+ left: -100px;
|
|
|
+ width: 480px;
|
|
|
+ height: 480px;
|
|
|
+ z-index: 99999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .err {
|
|
|
+ width: 800px;
|
|
|
+ height: 272px;
|
|
|
+ position: absolute;
|
|
|
+ top: calc(50% - 136px);
|
|
|
+ left: calc(50% - 400px);
|
|
|
+ z-index: 99;
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center;
|
|
|
+ img {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ top: 5%;
|
|
|
+ right: 3%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .noface {
|
|
|
+ background-image: url("../../assets/img/noface.png");
|
|
|
+ }
|
|
|
+ .badface {
|
|
|
+ background-image: url("../../assets/img/badface.png");
|
|
|
+ }
|
|
|
+ #pag {
|
|
|
+ width: 450px;
|
|
|
+ height: 450px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|