234 lines
12 KiB
HTML
234 lines
12 KiB
HTML
<script>
|
|
// 父框架刷新逻辑不变
|
|
if (window.parent && window.parent !== window) {
|
|
window.parent.location.reload();
|
|
}
|
|
</script>
|
|
<div class="relative min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-100 p-4">
|
|
<div class="hidden md:flex md:w-1/2 items-center justify-start px-4 opacity-0 translate-x-[-20px] animate-fade-in-left">
|
|
<div class="text-center w-full">
|
|
<div class="w-56 h-56 mx-auto mb-8 rounded-2xl bg-blue-500/5 flex items-center justify-center p-6 transition-all duration-300 hover:scale-105 hover:shadow-lg hover:shadow-blue-500/5"></div>
|
|
<h2 class="text-3xl font-bold text-gray-900 mb-4 opacity-0 animate-fade-in delay-100">欢迎使用 G-ERP 系统</h2>
|
|
<p class="text-gray-600 mx-auto leading-relaxed opacity-0 animate-fade-in delay-200"> 高效、安全的企业级管理平台,为您的工作提供便捷支持<br> 请尽可能使用工号和密码登录,保障账户信息安全。 </p>
|
|
<div class="relative mt-12 h-64">
|
|
<div class="absolute top-0 left-1/4 w-8 h-8 rounded bg-blue-500/30 animate-pulse"></div>
|
|
<div class="absolute top-1/4 left-1/2 w-12 h-12 rounded bg-purple-500/30 animate-pulse delay-300"></div>
|
|
<div class="absolute bottom-1/4 left-1/3 w-10 h-10 rounded bg-green-500/30 animate-pulse delay-500"></div>
|
|
<div class="absolute bottom-0 left-2/3 w-14 h-14 rounded bg-orange-500/30 animate-pulse delay-700"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="w-full md:w-1/2 max-w-md opacity-0 translate-x-[20px] animate-fade-in-right">
|
|
<div class="bg-white dark:bg-gray-50 rounded-xl shadow-xl overflow-hidden transition-all duration-300 hover:shadow-blue-500/5">
|
|
<div class="relative h-24">
|
|
<img src="https://bing.img.run/uhd.php" alt="Card image" class="w-full h-full object-cover">
|
|
<div class="absolute inset-0 bg-gradient-to-t from-white to-transparent"></div>
|
|
<h4 class="absolute bottom-4 left-6 text-xl font-bold text-gray-900">登录</h4>
|
|
</div>
|
|
<!-- Toast固定容器,永远放在表单上方 -->
|
|
<div id="toastWrap" class="px-6 pt-6"></div>
|
|
<div class="p-6 pt-0">
|
|
<form class="space-y-4" id="loginForm">
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none transition-colors duration-200">
|
|
<i class="tim-icons icon-single-02 text-gray-500 input-icon"></i>
|
|
</div>
|
|
<input type="text" name="UserName"
|
|
class="block w-full pl-10 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500 transition-all duration-200 focus:scale-[1.01] focus:bg-white" placeholder="昵称">
|
|
</div>
|
|
<div class="relative">
|
|
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none transition-colors duration-200">
|
|
<i class="tim-icons icon-lock-circle text-gray-500 input-icon"></i>
|
|
</div>
|
|
<input type="password" name="UserPassword"
|
|
class="block w-full pl-10 pr-3 py-2.5 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 placeholder-gray-500 transition-all duration-200 focus:scale-[1.01] focus:bg-white" placeholder="密码" required>
|
|
</div>
|
|
<div class="flex items-start">
|
|
<div class="flex items-center h-5">
|
|
<input id="UserConsent" name="UserConsent" type="checkbox" class="w-4 h-4 rounded border-gray-300 text-blue-500 focus:ring-blue-500 bg-gray-100 transition-all duration-200 hover:border-gray-400 checked:scale-[0.95]">
|
|
</div>
|
|
<div class="ml-3 text-sm">
|
|
<label for="UserConsent" class="text-gray-700 transition-colors duration-200 hover:text-gray-900">
|
|
我阅读并同意
|
|
<a href="https://doc.gvsds.com/d2ae1dd63e9c35d687464a160896e1ab" target="_blank"
|
|
class="text-blue-600 hover:underline transition-colors duration-200 hover:text-blue-700">GVSDS用户协议</a>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="text-sm text-gray-700">
|
|
我还没有账号,去
|
|
<a href="/register.html" class="text-blue-600 hover:underline transition-colors duration-200 hover:text-blue-700">注册</a>
|
|
</div>
|
|
<div class="pt-2">
|
|
<button type="submit" class="w-full py-3 px-4 bg-blue-500 hover:bg-blue-600 rounded-lg text-white font-medium transition-all duration-200 flex items-center justify-center hover:scale-[1.02] active:scale-[0.98] hover:shadow-lg hover:shadow-blue-500/10">
|
|
登录
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<style>
|
|
@keyframes fadeInLeft{from{opacity:0;transform:translateX(-20px)}to{opacity:1;transform:translateX(0)}}
|
|
.animate-fade-in-left{animation:fadeInLeft .5s ease-out forwards}
|
|
@keyframes fadeInRight{from{opacity:0;transform:translateX(20px)}to{opacity:1;transform:translateX(0)}}
|
|
.animate-fade-in-right{animation:fadeInRight .5s ease-out forwards}
|
|
@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
|
|
.animate-fade-in{animation:fadeIn .3s ease-out forwards}
|
|
input:focus~.input-icon{color:#a855f7}
|
|
#LoginToast{
|
|
animation:fadeIn .3s ease-out forwards;
|
|
position:relative;
|
|
z-index:999;
|
|
width:100%;
|
|
box-sizing:border-box;
|
|
}
|
|
</style>
|
|
<script>
|
|
// 统一Toast渲染函数,替换原来插入逻辑
|
|
function showToast(content, type='error'){
|
|
const wrap = document.getElementById('toastWrap');
|
|
let toast = document.getElementById('LoginToast');
|
|
// 存在先清空内容
|
|
if(toast) toast.remove();
|
|
|
|
toast = document.createElement('div');
|
|
toast.id = 'LoginToast';
|
|
toast.className = 'mb-4 p-3 rounded-lg animate-fade-in';
|
|
|
|
if(type === 'error'){
|
|
toast.style.color='#dc2626';
|
|
toast.style.background='#fef2f2';
|
|
toast.style.border='1px solid #fecaca';
|
|
}else{
|
|
toast.style.color='#16a34a';
|
|
toast.style.background='#f0fdf4';
|
|
toast.style.border='1px solid #bbf7d0';
|
|
}
|
|
toast.textContent = content;
|
|
wrap.appendChild(toast);
|
|
}
|
|
|
|
// 页面URL参数消息,DOM加载完成后执行
|
|
document.addEventListener('DOMContentLoaded', ()=>{
|
|
const msg = new URLSearchParams(window.location.search).get('msg');
|
|
const urlRedirect = new URLSearchParams(window.location.search).get('redirect');
|
|
if(msg){
|
|
showToast(msg, 'error');
|
|
}
|
|
|
|
const loginForm = document.getElementById('loginForm');
|
|
|
|
document.querySelectorAll('label[for]').forEach(label=>{
|
|
label.addEventListener('click',()=>{
|
|
const targetId=label.getAttribute('for');
|
|
const targetEl=document.getElementById(targetId);
|
|
if(targetEl)targetEl.focus()
|
|
})
|
|
});
|
|
|
|
// 表单提交逻辑
|
|
loginForm.addEventListener('submit',function(e){
|
|
e.preventDefault();
|
|
const UserConsent=document.getElementById('UserConsent').checked;
|
|
if(!UserConsent){
|
|
showToast('必须签署协议');
|
|
return
|
|
}
|
|
const submitButton=this.querySelector('button[type="submit"]');
|
|
const originalText=submitButton.innerHTML;
|
|
submitButton.disabled=true;
|
|
submitButton.innerHTML='<i class="fa fa-spinner fa-spin mr-2"></i> 登录中...';
|
|
const formData=new FormData(loginForm);
|
|
fetch('https://ugm.gvsds.com/Auth/Login',{
|
|
method:'POST',
|
|
credentials:'include',
|
|
body:formData
|
|
}).then(res=>res.json()).then(result=>{
|
|
submitButton.disabled=false;
|
|
submitButton.innerHTML=originalText;
|
|
if(result.code===0){
|
|
showToast('登录成功,即将跳转...','success');
|
|
setTimeout(()=>{
|
|
window.location.href=urlRedirect||result.redirect||'/'
|
|
},500)
|
|
}else if(result.code===2&&result.require2FA){
|
|
show2FAForm(result.pendingKey)
|
|
}else{
|
|
showToast(result.msg||'登录失败')
|
|
}
|
|
}).catch(err=>{
|
|
submitButton.disabled=false;
|
|
submitButton.innerHTML=originalText;
|
|
showToast('网络错误:'+err.message)
|
|
})
|
|
});
|
|
|
|
// 两步验证弹窗逻辑
|
|
function show2FAForm(key){
|
|
const _pendingKey=key;
|
|
const formContainer=loginForm.parentElement;
|
|
formContainer.innerHTML=`
|
|
<div class="text-center mb-6">
|
|
<div class="w-16 h-16 mx-auto mb-4 rounded-2xl bg-blue-500/10 flex items-center justify-center">
|
|
<i class="fas fa-shield-halved text-2xl text-blue-500"></i>
|
|
</div>
|
|
<h3 class="text-lg font-semibold text-gray-900">两步验证</h3>
|
|
<p class="text-sm text-gray-500 mt-1">请输入身份验证器中的6位数字</p>
|
|
</div>
|
|
<div class="space-y-4">
|
|
<div class="relative">
|
|
<input type="text" id="twoFAToken" maxlength="6" inputmode="numeric" pattern="[0-9]*"
|
|
class="block w-full py-3 px-4 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-gray-900 text-center text-2xl tracking-[8px] placeholder-gray-400 placeholder-tracking-normal placeholder-text-base"
|
|
placeholder="000000" autocomplete="one-time-code" autofocus>
|
|
</div>
|
|
<button id="verify2FABtn" class="w-full py-3 px-4 bg-blue-500 hover:bg-blue-600 rounded-lg text-white font-medium transition-all duration-200 flex items-center justify-center hover:scale-[1.02] active:scale-[0.98]">
|
|
验证
|
|
</button>
|
|
<button id="cancel2FABtn" class="w-full py-2 px-4 text-gray-500 hover:text-gray-700 text-sm transition-colors duration-200">
|
|
返回登录
|
|
</button>
|
|
</div>
|
|
`;
|
|
const tokenInput=document.getElementById('twoFAToken');
|
|
const verifyBtn=document.getElementById('verify2FABtn');
|
|
const cancelBtn=document.getElementById('cancel2FABtn');
|
|
tokenInput.focus();
|
|
tokenInput.addEventListener('input',function(){
|
|
this.value=this.value.replace(/[^0-9]/g,'')
|
|
});
|
|
verifyBtn.addEventListener('click',function(){
|
|
const token=tokenInput.value.trim();
|
|
if(!token||token.length!==6){
|
|
showToast('请输入6位验证码');
|
|
return
|
|
}
|
|
verifyBtn.disabled=true;
|
|
verifyBtn.innerHTML='<i class="fa fa-spinner fa-spin mr-2"></i> 验证中...';
|
|
fetch('https://ugm.gvsds.com/Auth/Verify2FA',{
|
|
method:'POST',
|
|
credentials:'include',
|
|
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
|
body:`pendingKey=${encodeURIComponent(_pendingKey)}&token=${encodeURIComponent(token)}`
|
|
}).then(res=>res.json()).then(result=>{
|
|
if(result.code===0){
|
|
showToast('验证成功,即将跳转...','success');
|
|
setTimeout(()=>{
|
|
window.location.href=urlRedirect||result.redirect||'/'
|
|
},500)
|
|
}else{
|
|
verifyBtn.disabled=false;
|
|
verifyBtn.textContent='验证';
|
|
showToast(result.msg||'验证码错误')
|
|
}
|
|
}).catch(err=>{
|
|
verifyBtn.disabled=false;
|
|
verifyBtn.textContent='验证';
|
|
showToast('网络错误')
|
|
})
|
|
});
|
|
cancelBtn.addEventListener('click',()=>window.location.reload())
|
|
}
|
|
})
|
|
</script> |