312 lines
9.4 KiB
Vue
312 lines
9.4 KiB
Vue
<route>
|
||
{
|
||
meta: {
|
||
ignoreRouterCheck: true,
|
||
ignoreLoginCheck: true
|
||
}
|
||
}
|
||
</route>
|
||
|
||
<style src="~/styles/login/index.scss"></style>
|
||
<template>
|
||
<div class="login-container">
|
||
<div class="login-background">
|
||
<!-- 登录页背景图替换 -->
|
||
<!-- <img src="/images/login-background.jpg" alt=""> -->
|
||
</div>
|
||
<div class="login-big-box">
|
||
<div class="login-left-box">
|
||
<!-- 登录页左图替换 -->
|
||
<img src="/images/login-left.png" alt="">
|
||
</div>
|
||
<div class="login-middle-line"></div>
|
||
<div class="login-right-box">
|
||
<form action="" autocomplete="off">
|
||
<div class="login-head-box">
|
||
<!-- 登录页Logo替换 -->
|
||
<img src="/images/logo_login.png" alt="">
|
||
<!-- <span>AERWEN</span> -->
|
||
</div>
|
||
<div class="login-right-title-box">
|
||
<!-- 登录页文字替换 -->
|
||
登录到 厚德艺术 后台管理平台
|
||
<div class="login-right-title-bottom"></div>
|
||
</div>
|
||
<div class="login-right-form-control-box">
|
||
<div class="login-right-form-control-item js-input">
|
||
<input type="text" autocomplete="off" name="account" class="login-form-input-control " @focus="formControlAnimation('inputFocus',$event)" @blur="formControlAnimation('inputBlur',$event)" placeholder="请输入账号">
|
||
<div class="account-msg msg op0"></div>
|
||
<img src="/images/login-user-icon.png" class="login-form-icon" alt="">
|
||
</div>
|
||
<div class="login-right-form-control-item js-input">
|
||
<input type="password" autocomplete="new-password" name="password" class="login-form-input-control " @focus="formControlAnimation('inputFocus',$event)" @blur="formControlAnimation('inputBlur',$event)" placeholder="请输入密码">
|
||
<div class="password-msg msg op0"></div>
|
||
<img src="/images/login-password-icon.png" class="login-form-icon" alt="">
|
||
</div>
|
||
<div class="login-right-form-control-item js-input">
|
||
<div class="login-right-captcha-box">
|
||
<div class="login-right-captcha-input-box">
|
||
<input type="text" name="captcha" class=" captcha-input " placeholder="请输入验证码">
|
||
<div class="captcha-msg msg op0"></div>
|
||
<img src="/images/login-captcha-icon.png" class="login-form-icon" alt="">
|
||
</div>
|
||
<img :src="`${getCaptcha}?v=${time}`" class="captcha-img" @click="reloadCaptcha" alt="">
|
||
</div>
|
||
</div>
|
||
<div class="login-right-form-control-item js-input">
|
||
<a class="login-right-form-control-button js-login-btn" href="#" @click="formSubmit()">
|
||
<span class="" >登录</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<div class="login-right-copyright-box">
|
||
<!-- 登录页版权文字替换 -->
|
||
©版权归xxx公司所有
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</template>
|
||
<script lang="ts" setup>
|
||
import {onMounted, reactive, ref, watch} from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { useLoginStore } from '~/store';
|
||
import { Lock, User } from '@element-plus/icons-vue';
|
||
import { getCaptcha } from '~/service/login';
|
||
|
||
const time = ref();
|
||
const login = useLoginStore();
|
||
const date = new Date();
|
||
|
||
const submitForm = formEl => {
|
||
// await login.accountLogin(ruleForm);
|
||
};
|
||
|
||
const resetForm = formEl => {
|
||
if (!formEl) return;
|
||
formEl.resetFields();
|
||
};
|
||
|
||
const reloadCaptcha = () => {
|
||
time.value = new Date().getTime();
|
||
};
|
||
|
||
reloadCaptcha();
|
||
|
||
window.onkeydown=function(e){
|
||
if(e.code === 'Enter'){
|
||
formSubmit()
|
||
}
|
||
}
|
||
|
||
/**按钮提交事件*/
|
||
async function formSubmit(){
|
||
|
||
let oBtn = document.getElementsByClassName('js-login-btn')[0]
|
||
let oBtnSpan = oBtn.getElementsByTagName('span')[0]
|
||
|
||
|
||
let verifyPass = false
|
||
for (let rKey in regPool) {
|
||
verifyPass = verify(msg?.[rKey]?.value || '',rKey,regPool,msg).pass
|
||
}
|
||
if(verifyPass){
|
||
|
||
oBtnSpan.innerText='登录中...'
|
||
oBtn.style.setProperty("pointer-events", "none")
|
||
login.accountLogin({
|
||
account:msg['account'].value,
|
||
password:msg['password'].value,
|
||
captcha:msg['captcha'].value
|
||
}).catch(res=>{
|
||
oBtnSpan.innerText='登录'
|
||
oBtn.style.setProperty("pointer-events", "auto")
|
||
|
||
})
|
||
}else{
|
||
}
|
||
}
|
||
|
||
/**消息容器*/
|
||
const msg = reactive({})
|
||
|
||
/**验证器*/
|
||
const regPool = {
|
||
account:{
|
||
r:/^(?![\s!@#])[^!@#]*(?![\s!@#]).$/,
|
||
m:'用户名不能有空和空格'
|
||
},
|
||
password:{
|
||
r:/^(?![\s!@#])[^!@#]*(?![\s!@#]).$/,
|
||
m:'密码不能有空和空格'
|
||
},
|
||
captcha:{
|
||
done: function (ctx,item){
|
||
if(!/^(?![\s!@#])[^!@#]*(?![\s!@#]).$/.test(item.value)){
|
||
return '验证码不能有空和空格'
|
||
}else{
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**输入框输入事件公用逻辑,内置函数防抖*/
|
||
function inputEvent(){
|
||
let timer
|
||
return function (name) {
|
||
if (timer!==null){
|
||
clearTimeout(timer)
|
||
}
|
||
timer = setTimeout(() => {
|
||
verify(this.value, name, regPool, msg)
|
||
}, 500)
|
||
}
|
||
}
|
||
/**监听验证器*/
|
||
watch(msg,(n,o)=>{
|
||
for (const key in n) {
|
||
dispatchMsg(n[key].msg,key+'-msg',function (tag,txt){
|
||
txt !=='' ? tag.classList.remove('op0') : tag.classList.add('op0')
|
||
})
|
||
}
|
||
},{deep:true})
|
||
|
||
|
||
/**绑定输入框输入事件*/
|
||
onMounted(()=>{
|
||
[].map.call(document.querySelectorAll('.js-input input'),function (item,idx){
|
||
item.addEventListener('input',inputEvent().bind(item,item.getAttribute('name'),false))
|
||
})
|
||
})
|
||
|
||
/**
|
||
*
|
||
* @param type
|
||
* @param e
|
||
* @author hyw
|
||
* 表单控件的动画效果
|
||
*/
|
||
const formControlAnimation = (type,e)=>{
|
||
let oInput = e.target,
|
||
oImg = document.getElementsByClassName('login-form-icon')[[...document.getElementsByClassName('login-form-input-control')].indexOf(e.target)]
|
||
new Promise((s,j)=>{
|
||
const animationType = {
|
||
'inputFocus':()=>{
|
||
oImg.classList.add('t5s')
|
||
s('inputFocus')
|
||
},
|
||
'inputBlur':()=>{
|
||
oImg.classList.remove('t5s')
|
||
s('inputBlur')
|
||
}
|
||
}
|
||
animationType[type]()
|
||
}).then(cn=>{
|
||
cn==='inputFocus' ? oInput.classList.add('inputFocus') : oInput.classList.remove('inputFocus')
|
||
})
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param txt 消息文本
|
||
* @param tag *要派发的容器,可以是样式名也可以是dom节点
|
||
* @param cb 回调 参数1为派发的容器,参数2为文本
|
||
* @author hyw
|
||
* @description 将消息派发到dom上,配合验证器一起食用,将txt派发到tag容器里,只能用于事件处理函数中
|
||
*/
|
||
function dispatchMsg(txt, tag, cb=undefined) {
|
||
txt = txt===true ? '' : txt
|
||
let dom =
|
||
typeof tag === 'string' ? document.getElementsByClassName(tag)[0] : tag;
|
||
dom !== undefined &&
|
||
(() => {
|
||
if (txt !== dom.innerText) {
|
||
dom.innerText = txt;
|
||
}
|
||
})();
|
||
cb && cb(tag !== 'string' ? document.getElementsByClassName(tag)[0] : tag,txt)
|
||
}
|
||
|
||
/**
|
||
*
|
||
* @param v 对应的输入框值
|
||
* @param t 对应的name
|
||
* @param regPool 规则集,要与输入框name对应上
|
||
* @param msg 结果容器,通过验证则对应的msg为true否则则为false
|
||
* @description 验证器v4.0
|
||
* @module if-else策略优化模式
|
||
* @author hyw
|
||
* @return verifyObj
|
||
* @regPoolDescription 规则集文档:
|
||
* r:规则,一般传入正则,当传入一个对象时,里面必须包含test方法,其内容将作为参数传入
|
||
* m:消息,当不符合规则,则消息派发
|
||
* c:是否为可选,默认false
|
||
* done:回调函数,msg上下文将作为第一个参数注册,item将作为第二个参数传入,返回值将作为msg,且r跟m将失效,done可以为async
|
||
* @regPoolExample 实例:
|
||
* {
|
||
* curriculum_activity_name: {
|
||
* r: /^\S+$/,
|
||
* m: '活动名称不能为空捏或首尾不能有空格!'
|
||
* },
|
||
* curriculum_activity_price: {
|
||
* r: /^\+?((0|([0-9]+\d*))|((0\.\d+)|([1-9]+\d*\.\d+)))$/,
|
||
* m: '价格不能为负数',
|
||
* c: true
|
||
* },
|
||
* }
|
||
*/
|
||
function verify(v, t, regPool, msg) {
|
||
regPool[t] !== undefined
|
||
? (async () => {
|
||
msg[t] = {};
|
||
msg[t].value = v;
|
||
let is = regPool[t]?.r ? regPool[t].r.test(v) : true;
|
||
if (is) {
|
||
msg[t].msg = true;
|
||
} else {
|
||
msg[t].msg = true;
|
||
msg[t].msg = regPool[t].m;
|
||
if (regPool[t]?.c) {
|
||
//nice try 包装类
|
||
msg[t].value === '' ? (msg[t].msg = true) : regPool[t].m;
|
||
msg[t].msg = new String(msg[t].msg);
|
||
msg[t].msg.type = '可选';
|
||
}
|
||
}
|
||
if (regPool[t]?.done && regPool[t]?.c) {
|
||
msg[t].msg = regPool[t]?.done instanceof Promise ? new String(await regPool[t]?.done(msg, msg[t])) : new String(regPool[t]?.done(msg, msg[t]));
|
||
msg[t].msg.type = '可选';
|
||
} else if (regPool[t]?.done && !regPool[t]?.c) {
|
||
msg[t].msg = regPool[t]?.done instanceof Promise ? regPool[t]?.done(msg, msg[t]) : regPool[t]?.done(msg, msg[t]);
|
||
}
|
||
msg[t].msg===undefined && (msg[t].msg = false)
|
||
})()
|
||
: (msg[t].msg = true)
|
||
let inputNum = 0,
|
||
inputPassNum = 0
|
||
for (let key in regPool) {
|
||
inputNum +=1
|
||
if((key in msg) && msg[key].msg === true){
|
||
inputPassNum +=1
|
||
}
|
||
}
|
||
// console.log(inputNum,inputPassNum)
|
||
return {
|
||
pass:inputNum === inputPassNum
|
||
}
|
||
}
|
||
|
||
</script>
|
||
<style>
|
||
.login-background{
|
||
background-image: linear-gradient(to top, #A30000,60%,rgba(145, 2, 2, 0.5) 160%);
|
||
}
|
||
|
||
.login-right-title-bottom{
|
||
background-color: #A30000 !important;
|
||
}
|
||
|
||
</style> |