<template> <!-- 登录 --> <div class="loginPage"> <!-- 登录表单 --> <div class="formCenter"> <p class="logo">孝感市海绵城市综合管理信息平台</p> <el-form ref="loginRef" :model="loginForm" :rules="loginRules" class="loginForm"> <el-form-item prop="username"> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="请输入账号" :prefix-icon="User"> </el-input> </el-form-item> <el-form-item prop="password"> <el-input v-model="loginForm.password" type="password" :prefix-icon="Lock" auto-complete="off" placeholder="8-20位大小写字母+数字+特殊符号" show-password @keyup.enter="handleLogin" > </el-input> </el-form-item> <el-form-item prop="code" v-if="captchaEnabled" style="display: flex"> <el-input v-model="loginForm.code" auto-complete="off" placeholder="请输入" style="flex: 1" @keyup.enter="handleLogin" maxlength="8" > </el-input> <div class="login-code"> <img :src="codeUrl" @click="getCode" /> </div> </el-form-item> <el-form-item prop="otp"> <el-input v-model="loginForm.otp" type="text" :prefix-icon="Lock" auto-complete="off" placeholder="请输入手机令牌中的令牌" @keyup.enter="handleLogin" > </el-input> <p class="appNoneReg" @click="dialogShow = true">手机令牌已注册未扫码?</p> </el-form-item> <el-checkbox v-model="loginForm.rememberMe" size="large"> 记住密码 </el-checkbox> <el-form-item> <el-button size="large" @click.prevent="handleLogin" class="loginBtn" :loading="loginLoading"> <span>登 录</span> </el-button> </el-form-item> </el-form> </div> <!-- 国密注册弹窗 --> <el-dialog v-model="dialogShow" title="国密扫码注册" width="500px" append-to-body> <div class="guomiRegisterDia"> <div class="title"> 1,应国密要求,请手机应用商店搜索"手机令牌"并下载之后扫码进行令牌的输入;<br /> 2,请扫描下方二维码完成注册,否则将无法获取手机令牌; </div> <img :src="qrCodeUrl" alt="" /> </div> </el-dialog> </div> </template> <script setup> import { getCodeImg, guomiRegister } from '@/api/login'; import { setToken } from '@/utils/auth'; import Cookies from 'js-cookie'; import { encrypt, decrypt } from '@/utils/jsencrypt'; import { EncryptAES } from '@/utils/AES.js'; import useUserStore from '@/store/modules/user'; import { User, Lock } from '@element-plus/icons-vue'; import usePermissionStore from '@/store/modules/permission'; import axios from 'axios'; import qrcode from 'qrcode'; //生成二维码 const userStore = useUserStore(); const router = useRouter(); const { proxy } = getCurrentInstance(); const permissionStore = usePermissionStore(); const dialogShow = ref(false); const qrCodeUrl = ref(''); const loginLoading = ref(false); const loginForm = ref({ username: '', password: '', rememberMe: false, code: '', uuid: '', otp: '', }); 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 captchaEnabled = ref(true); // 登录 function handleLogin() { proxy.$refs.loginRef.validate(valid => { if (valid) { loginLoading.value = true; // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 if (loginForm.value.rememberMe) { Cookies.set('usernameXG', loginForm.value.username, { expires: 30 }); Cookies.set('passwordXG', encrypt(loginForm.value.password), { expires: 30, }); Cookies.set('rememberMeXG', loginForm.value.rememberMe, { expires: 30, }); } else { // 否则移除 Cookies.remove('usernameXG'); Cookies.remove('passwordXG'); Cookies.remove('rememberMeXG'); } // 调用action的登录方法 let params = { ...loginForm.value }; params.password = EncryptAES(params.password); if (params.username == 'admin') { // 非国密登录 userStore .login(params) .then(res => { console.log(res); // 登录成功之后都加载对应路由 permissionStore.generateRoutes(); router.push({ path: '/index' }); loginLoading.value = false; }) .catch(err => { console.log(err); getCode(); loginLoading.value = false; }); } else { // 国密登录 axios.post('/auth/loginByGuomi', params).then(res => { let datas = res.data; if (datas.code == 200) { setToken(datas.data.access_token); setTimeout(() => { // 登录成功之后都加载对应路由 permissionStore.generateRoutes(); router.push({ path: '/index' }); loginLoading.value = false; }); } else if (datas.code == 14140) { //未注册国密验证 proxy.$modal.msgError(datas.msg); loginLoading.value = false; getCode(); //刷新二维码 guomiCode(); // 国密注册获取二维码 setTimeout(() => { dialogShow.value = true; }, 2000); } else if (datas.code == 14141) { //请输入手机令牌 proxy.$modal.msgError(datas.msg); loginLoading.value = false; getCode(); //刷新二维码 toCreateCode(datas.data); // 生成二维码 } else if (datas.code == 14142) { //手机令牌不正确 proxy.$modal.msgError(datas.msg); loginLoading.value = false; getCode(); //刷新二维码 toCreateCode(datas.data); // 生成二维码 } else { loginLoading.value = false; getCode(); //刷新二维码 } }); } } }); } // 国密注册获取二维码 async function guomiCode(data) { let res = await guomiRegister({ username: loginForm.value.username }); if (res.code == 200) { toCreateCode(res.data); // 生成二维码 } } // 生成二维码 function toCreateCode(data) { qrcode.toDataURL(data, (err, url) => { if (err) { console.error(err); } else { qrCodeUrl.value = url; } }); } // 获取验证码 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('usernameXG'); const password = Cookies.get('passwordXG'); const rememberMe = Cookies.get('rememberMeXG'); loginForm.value = { username: username === undefined ? loginForm.value.username : username, password: password === undefined ? loginForm.value.password : decrypt(password), rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), }; } onMounted(() => { Cookies.remove('xiaogan-Token'); //清除token localStorage.removeItem('routerPartXG'); localStorage.removeItem('fromDoorXG'); localStorage.removeItem('routerPartXG'); getCode(); getCookie(); }); </script> <style lang="scss"> .guomiRegisterDia { display: flex; flex-direction: column; align-items: center; .title { background: linear-gradient(180deg, #015b9c 0%, #01466f 100%); font-size: 16px; padding: 15px; border-radius: 8px; margin-bottom: 20px; color: #fff; line-height: 30px; text-align: left; } img { width: 300px; height: 300px; margin-bottom: 30px; border: 1px solid #015b9c; } } .loginPage { .formCenter { width: 460px; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.3); .logo { text-align: center; color: #0584ba; font-size: 24px; font-weight: 400; margin: 30px auto; } .loginForm { width: 80%; margin-left: 10%; .appNoneReg { color: red; cursor: pointer; } .el-form-item { margin-bottom: 30px; position: relative; .el-input { width: 100%; height: 40px; border-color: #8d8d8d !important; .el-input__wrapper { background: #fff !important; box-shadow: none; .el-input__inner { font-size: 18px; color: #8d8d8d !important; } svg path { fill: #0584ba !important; } } .el-input__icon { width: 30px; height: 30px; font-size: 22px; } input::placeholder { font-size: 16px; } } .el-form-item__error { left: 5px; top: 45px; font-size: 15px; } .loginBtn { width: 100%; height: 48px; font-size: 24px; font-family: PangMenZhengDao; font-weight: 400; border: none; background: #0584ba; } } .el-checkbox { margin: 0px 0px 15px 5px; .el-checkbox__label { color: #8d8d8d; } } .login-code { height: 40px; img { width: 120px; height: 40px; cursor: pointer; } } } } } </style>