| | |
| | | cursor: pointer; |
| | | font-size: 1rem; |
| | | " |
| | | @click="show = false" |
| | | @click="recognition" |
| | | >人è¸è¯å«ç»å½</span |
| | | > |
| | | </div> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="face-login" v-else> |
| | | <span style="font-size: 0.88rem; font-weight: bold; color: #333333" |
| | | <span |
| | | style=" |
| | | text-align: center; |
| | | font-size: 0.88rem; |
| | | font-weight: bold; |
| | | color: #333333; |
| | | " |
| | | >请å°è¸é¨æ£å¯¹èè²æ¾ç¤ºæ¡å
ï¼å¹¶ä¿æå
线å
è¶³</span |
| | | > |
| | | <div |
| | | style=" |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | border: 1px solid #4386ff; |
| | | border-radius: 50%; |
| | | width: 18.75rem; |
| | | height: 18.75rem; |
| | | margin: 2.06rem 0; |
| | | background-color: #f1fcff; |
| | | " |
| | | > |
| | | <img src="@/assets/login/face.png" alt="" /> |
| | | <div style="width: 100%; display: flex; justify-content: center"> |
| | | <div |
| | | style=" |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | border: 1px solid #4386ff; |
| | | border-radius: 50%; |
| | | width: 18.75rem; |
| | | height: 18.75rem; |
| | | margin: 2.06rem 0; |
| | | background-color: #f1fcff; |
| | | " |
| | | > |
| | | <img v-if="!face" src="@/assets/login/face.png" alt="" /> |
| | | <!-- <canvas v-else ref="canvasDom" /> --> |
| | | <div v-else> |
| | | <!-- ææ¾å¨ï¼ç¨æ¥ææ¾ææçè§é¢ --> |
| | | <video class="camera_video" ref="videoDom" /> |
| | | <!-- æ¾ç¤ºç
§ç --> |
| | | <!-- <img |
| | | style="border-radius: 50%; width: 18.75rem; height: 18.75rem" |
| | | v-else |
| | | :src="imgurl" |
| | | /> --> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-button type="primary" size="small" style="width: 100%" |
| | | <!-- <el-button |
| | | v-if="!reBtn" |
| | | type="primary" |
| | | size="small" |
| | | style="width: 100%" |
| | | @click="takePhoto" |
| | | >å¼å§è¯å«</el-button |
| | | > |
| | | <el-button |
| | | v-else |
| | | type="primary" |
| | | size="small" |
| | | style="width: 100%" |
| | | @click="REtakePhoto" |
| | | >éæ°è¯å«</el-button |
| | | > --> |
| | | <div style="width: 100%; margin-top: 1rem; display: flex"> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | style="width: 100%" |
| | | @click="recognition" |
| | | >éæ°è·åæå头</el-button |
| | | > |
| | | <el-select |
| | | v-if="videoArr.length > 1" |
| | | v-model="constraints" |
| | | placeholder="è¯·éæ©æå头" |
| | | size="samll" |
| | | @change="changeconstraints" |
| | | style="height: 2rem" |
| | | :disabled="!videoArr.length > 1" |
| | | > |
| | | <el-option |
| | | v-for="item in videoArr" |
| | | :key="item.id" |
| | | :label="item.label" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | <div |
| | | style=" |
| | | display: flex; |
| | |
| | | cursor: pointer; |
| | | font-size: 1rem; |
| | | " |
| | | @click="show = true" |
| | | @click="accountlogin" |
| | | >è´¦å·ç»å½</span |
| | | > |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { getCodeImg, login } from "@/api/login"; |
| | | import { getCodeImg, login, CleanUnusedImages } from "@/api/login"; |
| | | |
| | | import { useRouter, useRoute } from "vue-router"; |
| | | import { getCurrentInstance, ref, nextTick, onMounted } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import store from "@/store"; |
| | | import axios from "axios"; |
| | | |
| | | const router = useRouter(); |
| | | const route = useRoute(); |
| | |
| | | |
| | | const codeUrl = ref(""); // éªè¯ç |
| | | const loading = ref(false); // ç»å½å è½½ç¶æ |
| | | |
| | | const face = ref(false); // 人è¸è¯å«ç»å½ |
| | | // ç
§çè·¯å¾ |
| | | const imgurl = ref(null); |
| | | // canvasæ§ä»¶å¯¹è±¡ |
| | | const canvasDom = ref(null); |
| | | // video æ§ä»¶å¯¹è±¡ |
| | | const videoDom = ref(null); |
| | | const reBtn = ref(false); |
| | | const loginForm = ref({ |
| | | userName: "", |
| | | password: "", |
| | |
| | | nextTick(() => { |
| | | userNameRef.value.focus(); |
| | | }); |
| | | const videoArr = ref([]); |
| | | //éæ©çæå头çid |
| | | const constraints = ref(""); |
| | | const videoConstraints = ref({}); |
| | | //人è¸è¯å«ç»å½ |
| | | const recognition = () => { |
| | | show.value = false; |
| | | videoArr.value = []; |
| | | setTimeout(async () => { |
| | | face.value = true; |
| | | navigator.mediaDevices |
| | | .enumerateDevices() |
| | | .then((devices) => { |
| | | devices.forEach(function (device) { |
| | | if (device.kind == "videoinput") { |
| | | videoArr.value.push({ |
| | | label: device.label, |
| | | id: device.deviceId, |
| | | }); |
| | | constraints.value = videoArr.value[0].id; |
| | | } |
| | | }); |
| | | openCamera(); |
| | | }) |
| | | .catch(function (err) { |
| | | layer.msg(err.name + ": " + err.message); |
| | | }); |
| | | }, 1000); |
| | | ElMessage({ |
| | | message: "æ£å¨è°ç¨æå头ï¼è¯·ç¨ç...", |
| | | type: "warning", |
| | | plain: true, |
| | | duration: 1000, |
| | | }); |
| | | // 人è¸è¯å«ç»å½é»è¾ |
| | | }; |
| | | |
| | | //è´¦å·ç»å½ |
| | | function accountlogin() { |
| | | stop(); |
| | | ElMessage({ |
| | | message: "æ£å¨å
³éæå头ï¼è¯·ç¨ç...", |
| | | type: "warning", |
| | | plain: true, |
| | | duration: 2000, |
| | | }); |
| | | setTimeout(() => { |
| | | ElMessage({ |
| | | message: "å
³éæå头æå", |
| | | type: "success", |
| | | plain: true, |
| | | }); |
| | | }, 3000); |
| | | setTimeout(() => { |
| | | show.value = true; |
| | | face.value = false; |
| | | }, 2000); |
| | | } |
| | | //æå¼æå头 |
| | | const openCamera = async () => { |
| | | videoConstraints.value.deviceId = { exact: constraints.value }; |
| | | |
| | | // æ£æµæµè§å¨æ¯å¦æ¯æmediaDevices |
| | | if (navigator.mediaDevices) { |
| | | navigator.mediaDevices |
| | | // å¼å¯è§é¢ï¼å
³éé³é¢ |
| | | .getUserMedia({ |
| | | audio: false, |
| | | video: { |
| | | width: 300, // 设置è§é¢å®½åº¦ |
| | | height: 300, // 设置è§é¢é«åº¦ |
| | | facingMode: "user", // 使ç¨åç½®æå头 |
| | | deviceId: videoConstraints.value.deviceId, |
| | | }, |
| | | }) |
| | | .then((stream) => { |
| | | // å°è§é¢æµä¼ å
¥viedoæ§ä»¶ |
| | | videoDom.value.srcObject = stream; |
| | | // ææ¾ |
| | | videoDom.value.play(); |
| | | Facerecognition(); |
| | | ElMessage({ |
| | | message: "æå头è°ç¨æå", |
| | | type: "success", |
| | | plain: true, |
| | | }); |
| | | }) |
| | | .catch((err) => { |
| | | console.log(err); |
| | | }); |
| | | } else { |
| | | window.alert("该æµè§å¨ä¸æ¯æå¼å¯æå头ï¼è¯·æ´æ¢ææ°çæµè§å¨"); |
| | | } |
| | | }; |
| | | const changeconstraints = (res) => { |
| | | openCamera(); |
| | | }; |
| | | |
| | | // å¼å§è¯å« |
| | | const takePhoto = async () => { |
| | | // å¦æå·²ç»æç
§äºå°±éæ°å¯å¨æå头 |
| | | // if (imgurl.value) { |
| | | // imgurl.value = null; |
| | | // openCamera(); |
| | | // return; |
| | | // } |
| | | |
| | | console.log(videoDom.value.videoWidth, videoDom.value.videoHeight); |
| | | // å建ä¸ä¸ªç»å¸å
ç´ ï¼è®¾ç½®ç»å¸å°ºå¯¸ä¸ºè§é¢æµç尺寸 |
| | | const canvas = document.createElement("canvas"); |
| | | // 设置ç»å¸å¤§å°ä¸æå大å°ä¸è´ |
| | | canvas.width = videoDom.value.videoWidth; |
| | | canvas.height = videoDom.value.videoHeight; |
| | | // è·åç»å¸ä¸ä¸æå¯¹è±¡ |
| | | const ctx = canvas.getContext("2d"); |
| | | // ç»å¶å½åè§é¢å¸§å°ç»å¸ä¸ |
| | | ctx.drawImage(videoDom.value, 0, 0, canvas.width, canvas.height); |
| | | // å°ç»å¸å
容转为 Base64 æ°æ® |
| | | const imageDataUrl = canvas.toDataURL("image/png"); |
| | | // åå¨å¾çè·¯å¾ |
| | | imgurl.value = imageDataUrl; |
| | | |
| | | // // å建ä¸ä¸ªå¾çå
ç´ |
| | | // const imageElement = new Image(); |
| | | // // å° Base64 æ°æ®è®¾ç½®ä¸ºå¾çç src 屿§ |
| | | // imageElement.src = imageDataUrl; |
| | | // console.log(imageElement, imageDataUrl, "å¾çè·¯å¾"); |
| | | // return; |
| | | // canvasDom.value.width = videoDom.value.videoWidth; |
| | | // canvasDom.value.height = videoDom.value.videoHeight; |
| | | // // æ§è¡ç»çæä½ |
| | | // canvasDom.value.getContext("2d").drawImage(videoDom.value, 0, 0); |
| | | // // å°ç»æè½¬æ¢ä¸ºå¯å±ç¤ºçæ ¼å¼ |
| | | // imgurl.value = canvasDom.value.toDataURL("image/webp"); |
| | | // å
³éæå头 |
| | | let files = dataURLtoFile(imgurl.value, new Date().getTime() + ".png"); |
| | | const formdata = new FormData(); |
| | | formdata.append("files", files); |
| | | let response = await axios.post("/api/User/SaveFiles", formdata, { |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | }); |
| | | ElMessage({ |
| | | message: "å¼å§è¯å«ä¸ï¼è¯·ç¨ç...", |
| | | type: "warning", |
| | | plain: true, |
| | | duration: 2000, |
| | | }); |
| | | setTimeout(() => { |
| | | login({ |
| | | userName: "", |
| | | password: "", |
| | | path: response.data.data, |
| | | }) |
| | | .then((res) => { |
| | | if (res.status) { |
| | | store.commit("setUserInfo", { ...res.data }); |
| | | ElMessage({ |
| | | message: "è¯å«æåï¼å¼å§ç»å½", |
| | | type: "success", |
| | | plain: true, |
| | | duration: 2000, |
| | | }); |
| | | CleanUnusedImages(); |
| | | stop(); |
| | | setTimeout(() => { |
| | | router.push({ path: "/" }); |
| | | }, 1000); |
| | | } |
| | | }) |
| | | .catch((err) => { |
| | | loading.value = false; |
| | | return proxy.$message.error(err.message); |
| | | }); |
| | | setTimeout(() => { |
| | | loading.value = false; |
| | | }, 1000); |
| | | }, 1000); |
| | | reBtn.value = true; |
| | | }; |
| | | //éæ°è¯å« |
| | | // const REtakePhoto = () => { |
| | | // reBtn.value = false; |
| | | // takePhoto(); |
| | | // }; |
| | | // å° base64 转æ¢ä¸º Blob |
| | | const dataURLtoFile = (dataurl, filename) => { |
| | | let arr = dataurl.split(","), |
| | | mime = arr[0].match(/:(.*?);/)[1], |
| | | bstr = atob(arr[1]), |
| | | n = bstr.length, |
| | | u8arr = new Uint8Array(n); |
| | | while (n--) { |
| | | u8arr[n] = bstr.charCodeAt(n); |
| | | } |
| | | return new File([u8arr], filename, { |
| | | type: mime, |
| | | }); |
| | | }; |
| | | // å
³éæå头 |
| | | const stop = () => { |
| | | let stream = videoDom.value.srcObject; |
| | | if (!stream) return; |
| | | let tracks = stream.getTracks(); |
| | | tracks.forEach((x) => { |
| | | x.stop(); |
| | | }); |
| | | clearInterval(timer.value); |
| | | }; |
| | | |
| | | //è·åéªè¯ç |
| | | getCode(); |
| | | //宿¶äººè¸è¯å« |
| | | const timer = ref(null); |
| | | const Facerecognition = () => { |
| | | clearInterval(timer.value); |
| | | if (!show.value) { |
| | | timer.value = setInterval(() => { |
| | | takePhoto(); |
| | | }, 3000); |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | // * { |
| | | // box-sizing: border-box; |
| | | // padding: 0; |
| | | // margin: 0; |
| | | // } |
| | | .login-container { |
| | | width: 100%; |
| | | min-height: 100vh; |
| | |
| | | } |
| | | .login-box { |
| | | width: 100%; |
| | | height: ceil(100vh - 8rem); |
| | | height: calc(100vh - 4.57rem); |
| | | display: flex; |
| | | background-color: #f6f7fc; |
| | | .left-img { |
| | |
| | | } |
| | | } |
| | | .face-login { |
| | | width: 30rem; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-content: center; |
| | | text-align: center; |
| | | } |
| | | } |
| | | } |
| | | .camera_video { |
| | | width: 18.75rem; |
| | | height: 18.75rem; |
| | | border: 1px black solid; |
| | | border-radius: 50% 50%; |
| | | } |
| | | </style> |