<template>
|
<div class="login-container">
|
<div class="login-header">
|
<img src="../assets/login/login-text.png" alt="" />
|
<div>
|
<img
|
v-if="!isFullscreen"
|
style="
|
width: 1.88rem;
|
height: 1.88rem;
|
margin-right: 1.81rem;
|
cursor: pointer;
|
"
|
src="@/assets/screen.png"
|
alt=""
|
@click="screenonToggle"
|
/>
|
<img
|
v-if="isFullscreen"
|
style="
|
width: 1.88rem;
|
height: 1.88rem;
|
margin-right: 1.81rem;
|
cursor: pointer;
|
"
|
src="@/assets/exitscreen.png"
|
alt=""
|
@click="screenonToggle"
|
/>
|
</div>
|
</div>
|
<div class="login-box">
|
<!-- 左侧图片 -->
|
<div class="left-img">
|
<img src="../assets/login/bg.png" alt="" />
|
</div>
|
<!-- 右侧登录 -->
|
<div class="login-formbox">
|
<el-form
|
v-if="show"
|
ref="loginRef"
|
:model="loginForm"
|
:rules="loginRules"
|
class="login-form"
|
>
|
<div class="title">欢迎登录...</div>
|
<div class="min_title">WELCOME TO LOGIN</div>
|
|
<el-form-item prop="userName">
|
<el-input
|
v-model="loginForm.userName"
|
class="login-input"
|
style="height: 3.13rem; width: 20.19rem"
|
ref="userNameRef"
|
type="text"
|
size="large"
|
autocomplete="off"
|
placeholder="请输入您的登录账号"
|
/>
|
</el-form-item>
|
<el-form-item prop="password">
|
<el-input
|
show-password
|
v-model="loginForm.password"
|
class="login-input"
|
style="height: 3.13rem; width: 20.19rem"
|
type="password"
|
size="large"
|
auto-complete="off"
|
placeholder="请输入密码"
|
>
|
</el-input>
|
</el-form-item>
|
|
<!-- <el-form-item prop="verificationCode">
|
<div style="display: flex">
|
<el-input
|
v-model="loginForm.verificationCode"
|
size="large"
|
@keyup.enter="handleLogin"
|
style="height: 3.13rem; width: 17.19rem; margin-right: 0.63rem"
|
auto-complete="off"
|
placeholder="验证码"
|
>
|
</el-input>
|
<div class="login-code" style="">
|
<img
|
:src="codeUrl"
|
@click="getCode"
|
style="width: 7.19rem; height: 3.13rem"
|
class="login-code-img"
|
/>
|
</div>
|
</div>
|
</el-form-item> -->
|
<el-form-item>
|
<el-button
|
:loading="loading"
|
color="#1F63FF"
|
size="large"
|
class="login-btn"
|
style="width: 100%; height: 3.13rem"
|
@click.prevent="handleLogin"
|
>
|
<span v-if="!loading">登 录</span>
|
<span v-else>登 录 中...</span>
|
</el-button>
|
<div
|
style="
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
width: 100%;
|
margin-top: 1.25rem;
|
"
|
>
|
<span
|
class="login-face"
|
style="
|
color: #4386ff;
|
border-bottom: 1px solid #4386ff;
|
font-weight: bold;
|
cursor: pointer;
|
font-size: 1rem;
|
"
|
@click="recognition"
|
>人脸识别登录</span
|
>
|
</div>
|
</el-form-item>
|
</el-form>
|
<div class="face-login" v-else>
|
<span
|
class="face_text"
|
style="
|
text-align: center;
|
font-size: 0.88rem;
|
font-weight: bold;
|
color: #333333;
|
"
|
>请将脸部正对蓝色显示框内,并保持光线充足</span
|
>
|
<div style="width: 100%; display: flex; justify-content: center">
|
<a href="myapp://">
|
<div
|
class="camera"
|
style="
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
border: 1px solid #4386ff;
|
border-radius: 50% 50%;
|
width: 18.75rem;
|
height: 18.75rem;
|
margin: 2.06rem 0;
|
background-color: #f1fcff;
|
"
|
@click="begin(2)"
|
>
|
<!-- v-if="!face" -->
|
<img
|
style="width: 16rem; height: 16rem"
|
src="@/assets/login/face.png"
|
alt=""
|
/>
|
<!-- <canvas v-else ref="canvasDom" /> -->
|
<!-- <div v-else> -->
|
<!-- 播放器,用来播放拍摄的视频 -->
|
<!-- <video class="camera_video" ref="videoDom" /> -->
|
<!-- </div> -->
|
</div>
|
</a>
|
</div>
|
<p style="font-size: 2rem">点击进行人脸识别登录</p>
|
<div class="button-group">
|
<button @click="download(1)" class="download-plugin">
|
<i class="fas fa-download"></i> 下载人脸识别插件
|
</button>
|
<button
|
@click="showConfigModal"
|
class="configure-plugin"
|
id="configure-plugin"
|
>
|
<i class="fas fa-cog"></i> 人脸识别插件配置
|
</button>
|
</div>
|
<!-- <el-button
|
type="primary"
|
size="small"
|
style="width: 100%; margin-top: 1rem"
|
class="reBtn"
|
@click="registerdialogVisible = true"
|
>人脸注册</el-button
|
> -->
|
<!-- <div style="width: 100%; margin-top: 1rem; display: flex">
|
<el-button
|
v-if="show"
|
type="primary"
|
size="small"
|
style="width: 100%"
|
class="reBtn"
|
@click="recognition"
|
>开始识别</el-button
|
>
|
<el-button
|
v-else
|
type="primary"
|
size="small"
|
style="width: 100%"
|
class="reBtn"
|
@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;
|
justify-content: center;
|
align-items: center;
|
width: 100%;
|
margin-top: 1.25rem;
|
"
|
>
|
<span
|
class="login-face"
|
style="
|
color: #4386ff;
|
border-bottom: 1px solid #4386ff;
|
font-weight: bold;
|
cursor: pointer;
|
font-size: 1rem;
|
"
|
@click="accountlogin"
|
>账号登录</span
|
>
|
</div>
|
</div>
|
</div>
|
</div>
|
<!-- 配置模态框 -->
|
<el-dialog
|
v-model="dialogVisible"
|
title="插件配置"
|
width="500"
|
:before-close="handleClose"
|
top="30vh"
|
>
|
<template #header="{ titleId }">
|
<div class="my-header">
|
<h2 :id="titleId" style="font-size: 2rem">插件配置</h2>
|
</div>
|
</template>
|
<el-input
|
class="downloainput"
|
v-model="pathvalue"
|
placeholder="请输入插件解压路径"
|
/>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" class="downloadreBtn" @click="download(2)"
|
>提交配置</el-button
|
>
|
</div>
|
</template>
|
</el-dialog>
|
|
<!-- 人脸注册 -->
|
<el-dialog
|
v-model="registerdialogVisible"
|
title="插件配置"
|
width="500"
|
:before-close="handleClose"
|
top="5vh"
|
>
|
<template #header="{ titleId }">
|
<div class="my-header">
|
<h2 :id="titleId" style="font-size: 2rem">人脸录入</h2>
|
</div>
|
</template>
|
<div class="content">
|
<div class="image-container">
|
<img
|
src="@/assets/login/headimg.jpg"
|
id="img"
|
style="width: 100%"
|
class="profile-image"
|
/>
|
</div>
|
<div class="action-buttons" @click="begin(1)">
|
<a href="myapp://" class="btn face-register">
|
<i class="fas fa-user-plus"></i> 人脸录入</a
|
>
|
<button class="btn submit-data" @click="faceEnter()">
|
<i class="fas fa-paper-plane"></i> 提交数据
|
</button>
|
</div>
|
</div>
|
<template #footer>
|
<!-- <div class="dialog-footer">
|
<el-button type="primary" class="downloadreBtn" @click="download(2)"
|
>提交配置</el-button
|
>
|
</div> -->
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { getCodeImg, login, CleanUnusedImages } from "@/api/login";
|
import { useRouter, useRoute } from "vue-router";
|
import { getCurrentInstance, ref, nextTick, onMounted, onUnmounted } from "vue";
|
import { ElMessage, ElLoading } from "element-plus";
|
import screenfull from "screenfull";
|
import store from "@/store";
|
import axios from "axios";
|
|
const router = useRouter();
|
const route = useRoute();
|
|
const { proxy } = getCurrentInstance();
|
|
const show = ref(true); // 是否显示登录框
|
|
const codeUrl = ref(""); // 验证码
|
const loading = ref(false); // 登录加载状态
|
const face = ref(false); // 人脸识别登录
|
const registerdialogVisible = 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: "",
|
verificationCode: "1234",
|
UUID: undefined,
|
tenantId: "0",
|
});
|
// tenantId: route.query.tenantId ? route.query.tenantId : "",
|
const loginRules = {
|
userName: [
|
{ required: true, trigger: "blur", message: "请输入您的登录账号" },
|
],
|
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
|
verificationCode: [
|
{ required: true, trigger: "blur", message: "请输入验证码" },
|
],
|
// tenantId: [{ required: true, trigger: "blur", message: "请输入公司唯一码" }],
|
};
|
const pathvalue = ref(""); // 插件解压路径
|
const dialogVisible = ref(false); // 配置模态框是否可见
|
|
function handleLogin() {
|
proxy.$refs.loginRef.validate((valid) => {
|
if (valid) {
|
loading.value = true;
|
login(loginForm.value)
|
.then((res) => {
|
if (res.status) {
|
store.commit("setUserInfo", { ...res.data });
|
router.push({ path: "/" });
|
}
|
})
|
.catch((err) => {
|
loginForm.value.verificationCode = "";
|
getCode();
|
loading.value = false;
|
return proxy.$message.error(res.message);
|
});
|
setTimeout(() => {
|
loading.value = false;
|
}, 1000);
|
}
|
});
|
}
|
//获取验证码方法
|
function getCode() {
|
getCodeImg().then((res) => {
|
if (res.Code == 500) {
|
getCode();
|
return;
|
}
|
codeUrl.value = "data:image/gif;base64," + res.img;
|
loginForm.value.UUID = res.uuid;
|
});
|
}
|
//绑定输入框焦点对象
|
const userNameRef = ref();
|
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() {
|
setTimeout(() => {
|
show.value = true;
|
face.value = false;
|
}, 500);
|
}
|
//打开摄像头
|
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 getData = (flag) => {
|
let url = "http://localhost:9298";
|
let xmlResquest = new XMLHttpRequest();
|
xmlResquest.open("post", url, true);
|
xmlResquest.onload = function (e) {
|
if (xmlResquest.status == 200) {
|
clearTimeout(interval.value);
|
imgbase64.value = xmlResquest.response;
|
if (flag == 2) {
|
// const faceContainer = document.getElementById("face-recognition");
|
// const faceIcon = faceContainer.querySelector(".face-icon");
|
// const capturedFace = document.getElementById("captured-face");
|
// capturedFace.src = "data:image/png;base64," + xmlResquest.response;
|
// faceIcon.style.display = "none";
|
// capturedFace.style.display = "block";
|
window.URL.revokeObjectURL(url);
|
faceRecognitionEvent();
|
return;
|
} else {
|
let img = document.getElementById("img");
|
img.src = "data:image/png;base64," + xmlResquest.response;
|
window.URL.revokeObjectURL(url);
|
// hideLoading();
|
onloading.value.close();
|
return;
|
}
|
}
|
// hideLoading();
|
onloading.value.close();
|
};
|
|
xmlResquest.send();
|
};
|
|
const baseUrl = "http://192.168.1.103:9093";
|
const token = ref("");
|
const imgbase64 = ref("");
|
let urlPlugin = baseUrl + "/api/UserFace/DownlodaFacePlugin";
|
let urlPReg = baseUrl + "/api/UserFace/DownloadRegFile";
|
const download = (flag, callBack) => {
|
let url = "";
|
if (flag == 1) {
|
url = urlPlugin;
|
} else {
|
url = urlPReg;
|
}
|
let xmlRequest = new XMLHttpRequest();
|
// 设置超时时间(毫秒)
|
xmlRequest.timeout = 10000;
|
xmlRequest.open("POST", url, true);
|
xmlRequest.setRequestHeader("Content-type", "application/json");
|
xmlRequest.responseType = "blob";
|
// 成功处理
|
xmlRequest.onload = function (e) {
|
if (xmlRequest.status === 200) {
|
const contentType = xmlRequest.getResponseHeader("Content-Type");
|
if (contentType && contentType.includes("application/json")) {
|
// 处理JSON响应
|
const reader = new FileReader();
|
reader.onload = function () {
|
try {
|
const jsonResponse = JSON.parse(reader.result);
|
if (!jsonResponse.status) {
|
ElMessage({
|
message: "失败:" + jsonResponse.message,
|
type: "error",
|
});
|
}
|
// 处理JSON数据...
|
} catch (e) {
|
ElMessage({
|
message: "JSON解析错误:" + e.message,
|
type: "error",
|
});
|
console.error("JSON解析错误:", e);
|
}
|
};
|
reader.readAsText(xmlRequest.response);
|
} else if (
|
contentType &&
|
(contentType.includes("application/octet-stream") ||
|
contentType.includes("application/zip") ||
|
contentType.includes("application/x-registry"))
|
) {
|
try {
|
let blob = xmlRequest.response;
|
if (!blob || blob.size === 0) {
|
throw new Error("下载内容为空");
|
}
|
let a = document.createElement("a");
|
let url = window.URL.createObjectURL(blob);
|
a.href = url;
|
if (flag == 1) {
|
a.download = "face-plugin.zip";
|
} else {
|
a.download = "reg.reg";
|
}
|
|
document.body.appendChild(a);
|
a.click();
|
|
// 清理
|
setTimeout(() => {
|
document.body.removeChild(a);
|
window.URL.revokeObjectURL(url);
|
}, 100);
|
|
// 成功回调
|
if (callBack) callBack(true, "下载成功");
|
dialogVisible.value = false;
|
// closeConfigModal();
|
} catch (error) {
|
ElMessage({
|
message: "下载处理失败" + error.message,
|
type: "error",
|
});
|
if (callBack) callBack(false, "下载处理失败");
|
}
|
}
|
} else {
|
let errorMsg = `服务器错误: ${xmlRequest.status} ${xmlRequest.statusText}`;
|
ElMessage({
|
message: errorMsg,
|
type: "error",
|
});
|
if (callBack) callBack(false, errorMsg);
|
}
|
};
|
|
// 错误处理
|
xmlRequest.onerror = function () {
|
let errorMsg = "网络错误,请检查网络连接";
|
ElMessage.error(errorMsg);
|
if (callBack) callBack(false, errorMsg);
|
};
|
|
// 超时处理
|
xmlRequest.ontimeout = function () {
|
let errorMsg = "请求超时,请重试";
|
ElMessage.error(errorMsg);
|
if (callBack) callBack(false, errorMsg);
|
};
|
|
// 发送请求
|
try {
|
if (flag == 1) {
|
xmlRequest.send();
|
} else {
|
let path = pathvalue.value;
|
if (path == "") {
|
ElMessage({
|
message: "请输入插件解压路径",
|
type: "warning",
|
});
|
return;
|
}
|
xmlRequest.send(JSON.stringify({ Path: path }));
|
}
|
} catch (error) {
|
ElMessage({
|
message: "请求发送失败:" + error.message,
|
type: "error",
|
});
|
if (callBack) callBack(false, "请求发送失败");
|
}
|
};
|
|
const faceRecognitionEvent = () => {
|
let url = baseUrl + "/api/UserFace/FaceRecognition";
|
let xmlResquest = new XMLHttpRequest();
|
xmlResquest.open("post", url, true);
|
xmlResquest.setRequestHeader("Content-Type", "application/json");
|
xmlResquest.onload = function (e) {
|
img.src = "headimg.jpg";
|
if (xmlResquest.status == 200) {
|
let response = JSON.parse(xmlResquest.response);
|
if (response.status) {
|
token.value = response.data.token;
|
} else {
|
ElMessage.error("识别失败");
|
}
|
} else {
|
ElMessage.error("数据提交失败");
|
}
|
};
|
xmlResquest.send(JSON.stringify({ Base64Image: imgbase64.value }));
|
};
|
|
function faceEnter() {
|
let url = baseUrl + "/api/UserFace/faceEnter";
|
let xmlResquest = new XMLHttpRequest();
|
xmlResquest.open("post", url, true);
|
xmlResquest.setRequestHeader("Content-Type", "application/json");
|
xmlResquest.setRequestHeader("Authorization", "Bearer " + token.value);
|
xmlResquest.onload = function (e) {
|
img.src = "headimg.jpg";
|
if (xmlResquest.status == 200) {
|
let response = JSON.parse(xmlResquest.response);
|
if (response.status) {
|
ElMessage.success("人脸录入成功,图片名称:" + response.data);
|
onloading.value.close();
|
// hideLoading();
|
} else {
|
ElMessage.error("人脸录入失败,错误信息:" + response.message);
|
onloading.value.close();
|
// hideLoading();
|
}
|
} else {
|
ElMessage.error("数据提交失败");
|
onloading.value.close();
|
// hideLoading();
|
}
|
};
|
xmlResquest.send(JSON.stringify({ Base64Image: imgbase64.value }));
|
}
|
|
const interval = ref(null);
|
const onloading = ref(null);
|
const begin = (flag) => {
|
if (interval.value) {
|
clearTimeout(interval.value);
|
}
|
onloading.value = ElLoading.service({
|
lock: true,
|
text: "正在处理中,请稍后...",
|
background: "rgba(0, 0, 0, 0.7)",
|
});
|
interval.value = setInterval(() => {
|
getData(flag);
|
}, 10000);
|
};
|
|
// 开始识别
|
const takePhoto = async () => {
|
// 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;
|
};
|
// 将 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);
|
};
|
// 显示配置模态框
|
const modal = ref(false);
|
const showConfigModal = () => {
|
dialogVisible.value = true;
|
};
|
//定时人脸识别
|
const timer = ref(null);
|
const Facerecognition = () => {
|
clearInterval(timer.value);
|
if (!show.value) {
|
timer.value = setInterval(() => {
|
takePhoto();
|
}, 3000);
|
}
|
};
|
// 是否全屏
|
const isFullscreen = ref(false);
|
// 监听变化
|
const screenchange = () => {
|
isFullscreen.value = screenfull.isFullscreen;
|
};
|
|
// 切换事件
|
const screenonToggle = () => {
|
screenfull.toggle();
|
};
|
// 设置侦听器
|
onMounted(() => {
|
screenfull.on("screenchange", screenchange);
|
});
|
|
// 删除侦听器
|
onUnmounted(() => {
|
screenfull.off("screenchange", screenchange);
|
});
|
</script>
|
|
<style lang="less" scoped>
|
.login-container {
|
width: 100%;
|
min-height: 100vh;
|
display: flex;
|
flex-direction: column;
|
.login-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
height: 4.38rem;
|
background-color: #006eff;
|
padding-left: 2.06rem;
|
box-sizing: border-box;
|
img {
|
width: 16rem;
|
height: 3.38rem;
|
}
|
}
|
.login-box {
|
width: 100%;
|
height: calc(100vh - 4.57rem);
|
display: flex;
|
background-color: #f6f7fc;
|
.left-img {
|
width: 100%;
|
height: 100%;
|
img {
|
width: 100%;
|
height: 100%;
|
}
|
}
|
.login-formbox {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
.title {
|
color: rgb(16, 16, 16);
|
font-size: 2rem;
|
font-weight: 600;
|
position: relative;
|
}
|
.title::after {
|
position: absolute;
|
bottom: 0;
|
content: "";
|
display: block;
|
width: 9rem;
|
height: 1rem;
|
background: linear-gradient(to right, #006eff, #ffffff);
|
opacity: 0.5;
|
}
|
.min_title {
|
color: #666666;
|
font-size: 0.8rem;
|
margin: 0.5rem 0;
|
}
|
}
|
.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%;
|
}
|
.button-group {
|
display: flex;
|
gap: 12px;
|
margin-top: 20px;
|
justify-content: center;
|
flex-wrap: wrap;
|
align-items: center;
|
/* 确保按钮垂直居中 */
|
}
|
/* 基础按钮样式 - 确保所有按钮使用相同的参数 */
|
.download-plugin,
|
.configure-plugin {
|
padding: 10px 20px;
|
border: none;
|
border-radius: 25px;
|
font-size: 14px;
|
font-weight: 500;
|
cursor: pointer;
|
transition: all 0.3s ease;
|
display: inline-flex;
|
align-items: center;
|
justify-content: center;
|
/* 内容居中 */
|
gap: 8px;
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
height: 40px;
|
/* 固定高度 */
|
line-height: 1;
|
/* 确保文字垂直居中 */
|
min-width: 120px;
|
/* 最小宽度 */
|
}
|
/* 下载按钮样式 */
|
.download-plugin {
|
background-color: #4285f4;
|
color: white;
|
}
|
|
/* 配置按钮样式 */
|
.configure-plugin {
|
background-color: #f1f3f4;
|
color: #5f6368;
|
}
|
/* 下载按钮样式 */
|
.download-plugin {
|
background-color: #4285f4;
|
color: white;
|
}
|
|
/* 配置按钮样式 */
|
.configure-plugin {
|
background-color: #f1f3f4;
|
color: #5f6368;
|
}
|
|
/* 确保图标大小一致 */
|
.download-plugin i,
|
.configure-plugin i {
|
font-size: 14px;
|
width: 14px;
|
/* 固定图标宽度 */
|
text-align: center;
|
/* 图标居中 */
|
}
|
|
/* 悬停效果 */
|
.download-plugin:hover {
|
background-color: #3367d6;
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(66, 133, 244, 0.3);
|
}
|
|
.configure-plugin:hover {
|
background-color: #e0e0e0;
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
}
|
|
/* 点击效果 */
|
.download-plugin:active,
|
.configure-plugin:active {
|
transform: translateY(0);
|
}
|
/* 添加字体图标库 */
|
.content {
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 30px;
|
background-color: #f8f9fa;
|
border-radius: 12px;
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
max-width: 800px;
|
margin: 0 auto;
|
}
|
|
.image-container {
|
margin-bottom: 25px;
|
border: 3px solid #e9ecef;
|
border-radius: 8px;
|
overflow: hidden;
|
}
|
|
.profile-image {
|
display: block;
|
width: 200px;
|
height: 360px;
|
object-fit: cover;
|
}
|
|
.action-buttons {
|
display: flex;
|
gap: 20px;
|
}
|
|
.btn,
|
a.btn {
|
padding: 12px 25px;
|
border: none;
|
border-radius: 50px;
|
font-size: 16px;
|
font-weight: 600;
|
cursor: pointer;
|
display: inline-flex;
|
align-items: center;
|
gap: 10px;
|
text-decoration: none;
|
color: white;
|
}
|
|
.face-register {
|
background-color: #4e73df;
|
}
|
|
.submit-data {
|
background-color: #1cc88a;
|
}
|
|
/* 确保a标签可点击区域 */
|
.btn {
|
position: relative;
|
z-index: 1;
|
}
|
|
/* 添加点击反馈 */
|
.btn:active {
|
transform: scale(0.98);
|
}
|
@media screen and (max-width: 1080px) {
|
.login-container {
|
width: 100%;
|
min-height: 100vh;
|
display: flex;
|
flex-direction: column;
|
.login-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
height: 4.38rem;
|
background-color: #006eff;
|
padding-left: 2.06rem;
|
box-sizing: border-box;
|
img {
|
width: 16rem;
|
height: 3.38rem;
|
}
|
}
|
.login-box {
|
width: 100%;
|
height: calc(100vh - 4.57rem);
|
display: flex;
|
background-color: #f6f7fc;
|
.left-img {
|
width: 100%;
|
height: 100%;
|
img {
|
width: 100%;
|
height: 100%;
|
}
|
}
|
.login-formbox {
|
width: 100%;
|
height: 100%;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
.title {
|
color: rgb(16, 16, 16);
|
font-size: 5rem;
|
font-weight: 600;
|
position: relative;
|
}
|
.title::after {
|
position: absolute;
|
bottom: 0;
|
content: "";
|
display: block;
|
width: 10rem;
|
height: 1rem;
|
background: linear-gradient(to right, #006eff, #ffffff);
|
opacity: 0.5;
|
}
|
.min_title {
|
color: #666666;
|
font-size: 2rem;
|
margin: 0.5rem 0;
|
}
|
.login-input {
|
width: 30rem !important;
|
font-size: 2rem !important;
|
height: 5rem !important;
|
}
|
.login-btn {
|
font-size: 2rem !important;
|
height: 5rem !important;
|
}
|
.login-face {
|
font-size: 2.5rem !important;
|
margin-top: 2rem !important;
|
}
|
}
|
.face-login {
|
width: 40rem;
|
display: flex;
|
flex-direction: column;
|
justify-content: center;
|
align-content: center;
|
text-align: center;
|
.face_text {
|
font-size: 2rem !important;
|
font-weight: bold;
|
color: #333333;
|
}
|
.reBtn {
|
font-size: 2rem !important;
|
height: 5rem !important;
|
}
|
}
|
}
|
}
|
.camera_video {
|
width: 40rem !important;
|
height: 40rem !important;
|
border: 1px black solid;
|
border-radius: 50% 50%;
|
}
|
.camera {
|
width: 40rem !important;
|
height: 40rem !important;
|
margin: 2.5rem 0 !important;
|
background-color: #f1fcff !important;
|
}
|
.button-group {
|
display: flex;
|
gap: 12px;
|
margin-top: 20px;
|
justify-content: center;
|
flex-wrap: wrap;
|
align-items: center;
|
/* 确保按钮垂直居中 */
|
}
|
/* 基础按钮样式 - 确保所有按钮使用相同的参数 */
|
.download-plugin,
|
.configure-plugin {
|
padding: 10px 20px;
|
border: none;
|
border-radius: 25px;
|
font-size: 14px;
|
font-weight: 500;
|
cursor: pointer;
|
transition: all 0.3s ease;
|
display: inline-flex;
|
align-items: center;
|
justify-content: center;
|
/* 内容居中 */
|
gap: 8px;
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
height: 40px;
|
/* 固定高度 */
|
line-height: 1;
|
/* 确保文字垂直居中 */
|
min-width: 120px;
|
/* 最小宽度 */
|
}
|
/* 下载按钮样式 */
|
.download-plugin {
|
background-color: #4285f4;
|
color: white;
|
}
|
|
/* 配置按钮样式 */
|
.configure-plugin {
|
background-color: #f1f3f4;
|
color: #5f6368;
|
}
|
/* 下载按钮样式 */
|
.download-plugin {
|
background-color: #4285f4;
|
color: white;
|
}
|
|
/* 配置按钮样式 */
|
.configure-plugin {
|
background-color: #f1f3f4;
|
color: #5f6368;
|
}
|
|
/* 确保图标大小一致 */
|
.download-plugin i,
|
.configure-plugin i {
|
font-size: 14px;
|
width: 14px;
|
/* 固定图标宽度 */
|
text-align: center;
|
/* 图标居中 */
|
}
|
|
/* 悬停效果 */
|
.download-plugin:hover {
|
background-color: #3367d6;
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(66, 133, 244, 0.3);
|
}
|
|
.configure-plugin:hover {
|
background-color: #e0e0e0;
|
transform: translateY(-2px);
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
}
|
|
/* 点击效果 */
|
.download-plugin:active,
|
.configure-plugin:active {
|
transform: translateY(0);
|
}
|
.downloadreBtn {
|
font-size: 2rem !important;
|
height: 6rem !important;
|
width: 100% !important;
|
}
|
.downloainput {
|
height: 6rem !important;
|
font-size: 2rem !important;
|
}
|
:deep(.el-select__wrapper) {
|
min-height: 5rem !important;
|
font-size: 2rem !important;
|
}
|
}
|
</style>
|