- 修复BCryptPasswordEncoder密码验证问题 - 实现密码设置提示弹窗功能(仅对无密码用户显示一次) - 优化修改密码逻辑和验证流程 - 更新Welcome页面背景样式 - 清理临时SQL文件和测试代码 - 移动数据库备份文件到database/backups目录 - 删除不必要的MD文档和临时文件
300 lines
9.6 KiB
HTML
300 lines
9.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>用户登录 - AIGC Demo</title>
|
|
|
|
<!-- Bootstrap CSS -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<!-- Font Awesome -->
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
|
|
|
|
<style>
|
|
body {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
}
|
|
|
|
.login-container {
|
|
background: rgba(255, 255, 255, 0.95);
|
|
backdrop-filter: blur(10px);
|
|
border-radius: 20px;
|
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
padding: 3rem;
|
|
width: 100%;
|
|
max-width: 450px;
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.login-header {
|
|
text-align: center;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.login-header h2 {
|
|
color: #333;
|
|
font-weight: 600;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.login-header p {
|
|
color: #666;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.form-floating {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.form-control {
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 10px;
|
|
padding: 1rem 0.75rem;
|
|
font-size: 1rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: #667eea;
|
|
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
|
}
|
|
|
|
.btn-login {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
border: none;
|
|
border-radius: 10px;
|
|
padding: 0.75rem 2rem;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
color: white;
|
|
width: 100%;
|
|
transition: all 0.3s ease;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.btn-login:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
|
|
color: white;
|
|
}
|
|
|
|
.form-check-input:checked {
|
|
background-color: #667eea;
|
|
border-color: #667eea;
|
|
}
|
|
|
|
.alert {
|
|
border: none;
|
|
border-radius: 10px;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.alert-success {
|
|
background: linear-gradient(135deg, #d4edda, #c3e6cb);
|
|
color: #155724;
|
|
}
|
|
|
|
.alert-danger {
|
|
background: linear-gradient(135deg, #f8d7da, #f5c6cb);
|
|
color: #721c24;
|
|
}
|
|
|
|
.login-footer {
|
|
text-align: center;
|
|
margin-top: 2rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid #e9ecef;
|
|
}
|
|
|
|
.login-footer a {
|
|
color: #667eea;
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.login-footer a:hover {
|
|
color: #764ba2;
|
|
}
|
|
|
|
.language-switcher {
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.language-switcher a {
|
|
color: #666;
|
|
text-decoration: none;
|
|
margin: 0 0.5rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.language-switcher a:hover {
|
|
color: #667eea;
|
|
}
|
|
|
|
.demo-info {
|
|
background: rgba(102, 126, 234, 0.1);
|
|
border-radius: 10px;
|
|
padding: 1rem;
|
|
margin-top: 1rem;
|
|
font-size: 0.85rem;
|
|
color: #666;
|
|
}
|
|
|
|
.loading {
|
|
display: none;
|
|
}
|
|
|
|
.loading.show {
|
|
display: inline-block;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="login-container">
|
|
<div class="login-header">
|
|
<h2><i class="fas fa-rocket me-2"></i>AIGC Demo</h2>
|
|
<p>欢迎回来,请登录您的账户</p>
|
|
</div>
|
|
|
|
<!-- Success Message -->
|
|
<div id="msg" class="alert alert-success" style="display: none;"></div>
|
|
|
|
<!-- Error Message -->
|
|
<div th:if="${param.error}" class="alert alert-danger">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
<span th:text="#{msg.login.error}">用户名或密码错误</span>
|
|
</div>
|
|
|
|
<!-- Logout Message -->
|
|
<div th:if="${param.logout}" class="alert alert-success">
|
|
<i class="fas fa-check-circle me-2"></i>
|
|
<span th:text="#{msg.logout.success}">您已退出登录</span>
|
|
</div>
|
|
|
|
<form th:action="@{/login}" method="post" id="loginForm">
|
|
<div class="form-floating">
|
|
<input type="email" class="form-control" id="email" name="email"
|
|
placeholder="邮箱" required autocomplete="email">
|
|
<label for="email">
|
|
<i class="fas fa-envelope me-2"></i>邮箱
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-floating">
|
|
<input type="password" class="form-control" id="password" name="password"
|
|
placeholder="密码" required autocomplete="current-password">
|
|
<label for="password">
|
|
<i class="fas fa-lock me-2"></i>密码
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-check mb-3">
|
|
<input type="checkbox" class="form-check-input" id="remember-me" name="remember-me">
|
|
<label class="form-check-label" for="remember-me">
|
|
<i class="fas fa-clock me-2"></i>记住我
|
|
</label>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-login" id="loginBtn">
|
|
<span class="loading">
|
|
<i class="fas fa-spinner fa-spin me-2"></i>登录中...
|
|
</span>
|
|
<span class="login-text">
|
|
<i class="fas fa-sign-in-alt me-2"></i>登录
|
|
</span>
|
|
</button>
|
|
</form>
|
|
|
|
<div class="login-footer">
|
|
<p class="mb-2">
|
|
<span th:text="#{hint.noaccount}">还没有账号?</span>
|
|
<a th:href="@{/register}">立即注册</a>
|
|
</p>
|
|
|
|
<div class="language-switcher">
|
|
<a th:href="@{|?lang=zh_CN|}">中文</a> |
|
|
<a th:href="@{|?lang=en|}">English</a>
|
|
</div>
|
|
|
|
<div class="demo-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>演示账户:</strong><br>
|
|
请使用注册时的邮箱登录<br>
|
|
或使用演示邮箱(如已配置)
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bootstrap JS -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
|
|
<script>
|
|
// Show registration success message
|
|
function fromQuery(name) {
|
|
const url = new URL(window.location.href);
|
|
return url.searchParams.get(name);
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', function() {
|
|
const registered = fromQuery('registered');
|
|
if (registered) {
|
|
const msgDiv = document.getElementById('msg');
|
|
msgDiv.textContent = '注册成功,请登录';
|
|
msgDiv.style.display = 'block';
|
|
}
|
|
});
|
|
|
|
// Form submission with loading state
|
|
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
|
const loginBtn = document.getElementById('loginBtn');
|
|
const loading = loginBtn.querySelector('.loading');
|
|
const loginText = loginBtn.querySelector('.login-text');
|
|
|
|
// Show loading state
|
|
loading.classList.add('show');
|
|
loginText.style.display = 'none';
|
|
loginBtn.disabled = true;
|
|
});
|
|
|
|
// Auto-hide alerts after 5 seconds
|
|
setTimeout(function() {
|
|
const alerts = document.querySelectorAll('.alert');
|
|
alerts.forEach(function(alert) {
|
|
alert.style.transition = 'opacity 0.5s ease';
|
|
alert.style.opacity = '0';
|
|
setTimeout(function() {
|
|
alert.style.display = 'none';
|
|
}, 500);
|
|
});
|
|
}, 5000);
|
|
|
|
// Form validation
|
|
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
|
const email = document.getElementById('email').value.trim();
|
|
const password = document.getElementById('password').value.trim();
|
|
|
|
if (!email || !password) {
|
|
e.preventDefault();
|
|
alert('请填写邮箱和密码');
|
|
return false;
|
|
}
|
|
|
|
// 验证邮箱格式
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
if (!emailRegex.test(email)) {
|
|
e.preventDefault();
|
|
alert('请输入有效的邮箱地址');
|
|
return false;
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|