<template> <div class="login"> <!-- 顶部Logo --> <!-- <div class="TopLogo"></div> --> <div class="TopStyle"></div> <div class="TopName">延安城市生命线</div> <!-- 登录表单 --> <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="login-form"> <h3 class="title">登录</h3> <el-form-item prop="username"> <el-input v-model="loginForm.username" style="background: #eaf1fb" type="text" size="large" auto-complete="off" placeholder="请输入账号" > <template #prefix> <span class="input-Title">账号</span> </template> </el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="8-20位大小写字母+数字+特殊符号" show-password @keyup.enter="handleLogin" > <template #prefix> <span class="input-Title">密码</span> </template> </el-input> </el-form-item> <el-form-item prop="code" v-if="captchaEnabled"> <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="请输入" style="width: 63%" @keyup.enter="handleLogin" > <template #prefix> <span class="input-Title">验证码</span> </template> </el-input> <div class="login-code"> <img :src="codeUrl" @click="getCode" class="login-code-img" /> </div> </el-form-item> <el-checkbox v-model="loginForm.rememberMe" style="margin: 0px 0px 25px 0px"> 记住密码 </el-checkbox> <el-form-item style="width: 100%"> <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin" class="LoginBurtton" > <span v-if="!loading">登 录</span> <span v-else>登 录 中...</span> </el-button> <div style="float: right" v-if="register"> <router-link class="link-type" :to="'/register'"> 立即注册 </router-link> </div> </el-form-item> </el-form> <!-- 底部 --> <div class="el-login-footer"> <!-- <span>Copyright</span> --> </div> </div> </template> <script setup> import { getCodeImg } from "@/api/login"; import Cookies from "js-cookie"; import { encrypt, decrypt } from "@/utils/jsencrypt"; import { EncryptAES } from "@/utils/AES.js"; import useUserStore from "@/store/modules/user"; const userStore = useUserStore(); const router = useRouter(); const { proxy } = getCurrentInstance(); const loginForm = ref({ username: "", password: "", rememberMe: false, code: "", uuid: "", }); const loginRules = { username: [{ required: true, trigger: "blur", message: "请输入您的账号" }], code: [{ required: true, trigger: "blur", message: "请输入验证码" }], password: [ { min: 8, max: 20, message: "8-20位大小写字母+数字+特殊符号", required: true, trigger: "blur", validator: validPassword, }, ], }; function validPassword(rule, value, callback) { // 密码校验 至少8位大小写英文字母+数字+特殊符号 let reg = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,20}$/; if (!reg.test(value)) { callback(new Error("密码8-20位大小写英文字母+数字+特殊符号")); } else { callback(); } } const codeUrl = ref(""); const loading = ref(false); // 验证码开关 const captchaEnabled = ref(true); // 注册开关 const register = ref(false); const redirect = ref("/oneMap"); function handleLogin() { proxy.$refs.loginRef.validate((valid) => { if (valid) { loading.value = true; // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 if (loginForm.value.rememberMe) { Cookies.set("usernameNF", loginForm.value.username, { expires: 30 }); Cookies.set("passwordNF", encrypt(loginForm.value.password), { expires: 30, }); Cookies.set("rememberMeNF", loginForm.value.rememberMe, { expires: 30, }); } else { // 否则移除 Cookies.remove("usernameNF"); Cookies.remove("passwordNF"); Cookies.remove("rememberMeNF"); } // 调用action的登录方法 let params = { ...loginForm.value }; params.password = EncryptAES(params.password); userStore .login(params) .then(() => { router.push({ path: "/oneMap", name: "oneMap", meta: { title: "一张图", icon: "dashboard", affix: true, noCache: true }, query: { type: "FullScreen" }, }); }) .catch((err) => { getCode(); loading.value = false; }); } }); } // 获取验证码 function getCode() { getCodeImg().then((res) => { captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled; if (captchaEnabled.value) { codeUrl.value = "data:image/gif;base64," + res.img; loginForm.value.uuid = res.uuid; } }); } function getCookie() { const username = Cookies.get("usernameNF"); const password = Cookies.get("passwordNF"); const rememberMe = Cookies.get("rememberMeNF"); loginForm.value = { username: username === undefined ? loginForm.value.username : username, password: password === undefined ? loginForm.value.password : decrypt(password), rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), }; } getCode(); getCookie(); </script> <style lang="scss" scoped> .login { height: 100%; background-image: url("@/assets/images/login-background.jpg"); background-size: cover; position: relative; } .TopLogo { background-image: url("@/assets/images/logo.png"); background-size: cover; width: 114px; height: 36px; position: absolute; top: 33px; left: 40px; } .TopStyle { width: 1px; height: 20px; background: #cfd0e5; position: absolute; top: 49px; left: 191px; } .TopName { height: 26px; font-size: 26px; font-family: Source Han Sans CN; font-weight: bold; color: #000046; position: absolute; top: 39px; left: 30px; } .login-form { position: absolute; top: 314px; right: 223px; border-radius: 6px; background: #ffffff; width: 450px; height: 462px; padding: 80px 37px 5px 49px; background-image: url("@/assets/images/LoginForm.jpg"); background-size: cover; box-sizing: border-box; .title { text-align: left; margin: 0 0 30px 0px; color: #707070; font-size: 24px; font-family: Source Han Sans CN; font-weight: 600; color: #030a1e; letter-spacing: 3px; } .el-input { height: 40px; input { height: 40px; } } .input-icon { height: 39px; width: 14px; margin-left: 0px; } } .login-tip { font-size: 13px; text-align: center; color: #bfbfbf; } .login-code { width: 33%; height: 40px; float: right; img { cursor: pointer; vertical-align: middle; } } .el-login-footer { position: fixed; bottom: 40px; width: 100%; text-align: center; color: #fff; font-family: Arial; letter-spacing: 1px; height: 18px; font-size: 16px; font-family: Source Han Sans CN; font-weight: bold; color: #5266ab; } .login-code-img { height: 40px; padding-left: 12px; } .LoginBurtton { width: 300px; height: 40px; background: linear-gradient(90deg, #2270ff 0%, #5f98ff 100%); border-radius: 20px; } .input-Title { width: 65px; height: 100%; text-align: left; font-size: 16px; font-family: Source Han Sans CN; font-weight: 500; color: #030a1e; position: relative; &::after { content: ""; width: 1px; height: 14px; background: #d1dff2; position: absolute; right: 0; top: 12px; } } :deep(.el-input__wrapper) { background: #eaf1fb; border: none; } </style>