2025-07-25 17:24:29 +08:00

290 lines
7.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录 - 闲鱼自动回复管理系统</title>
<link rel="stylesheet" href="/static/lib/bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="/static/lib/bootstrap-icons/bootstrap-icons.css">
<style>
:root {
--primary-color: #0d6efd;
--secondary-color: #6c757d;
--success-color: #198754;
--danger-color: #dc3545;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.login-container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
width: 100%;
max-width: 400px;
}
.login-header {
background: var(--primary-color);
color: white;
padding: 30px;
text-align: center;
}
.login-header h2 {
margin: 0;
font-weight: 600;
}
.login-header p {
margin: 10px 0 0 0;
opacity: 0.9;
}
.login-body {
padding: 40px 30px;
}
.form-control {
border-radius: 10px;
border: 2px solid #e9ecef;
padding: 12px 15px;
font-size: 16px;
transition: all 0.3s ease;
}
.form-control:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
.btn-login {
background: var(--primary-color);
border: none;
border-radius: 10px;
padding: 12px;
font-size: 16px;
font-weight: 600;
width: 100%;
transition: all 0.3s ease;
}
.btn-login:hover {
background: #0b5ed7;
transform: translateY(-2px);
}
.input-group {
position: relative;
margin-bottom: 20px;
}
.input-group i {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: var(--secondary-color);
z-index: 10;
}
.input-group .form-control {
padding-left: 45px;
}
.alert {
border-radius: 10px;
border: none;
}
.loading {
display: none;
}
.loading.show {
display: inline-block;
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<i class="bi bi-chat-dots-fill fs-1 mb-3"></i>
<h2>闲鱼自动回复</h2>
<p>管理系统登录</p>
</div>
<div class="login-body">
<form id="loginForm">
<div class="input-group">
<i class="bi bi-person-fill"></i>
<input type="text" class="form-control" id="username" placeholder="请输入用户名" required>
</div>
<div class="input-group">
<i class="bi bi-lock-fill"></i>
<input type="password" class="form-control" id="password" placeholder="请输入密码" required>
</div>
<div id="errorAlert" class="alert alert-danger d-none" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
<span id="errorMessage"></span>
</div>
<button type="submit" class="btn btn-primary btn-login">
<span class="loading spinner-border spinner-border-sm me-2" role="status"></span>
<span id="loginText">登录</span>
</button>
</form>
<!-- 注册链接 -->
<div class="text-center mt-3">
<span class="text-muted">还没有账号?</span>
<a href="/register.html" class="text-decoration-none">
<i class="bi bi-person-plus me-1"></i>立即注册
</a>
</div>
<!-- 默认账号提示 -->
<div class="mt-4 p-3 bg-light rounded-3">
<div class="text-center">
<small class="text-muted">
<i class="bi bi-info-circle me-1"></i>
默认登录账号
</small>
</div>
<div class="mt-2">
<div class="d-flex justify-content-between align-items-center mb-1">
<small class="text-muted">用户名:</small>
<code class="bg-white px-2 py-1 rounded">admin</code>
</div>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">密码:</small>
<code class="bg-white px-2 py-1 rounded">admin123</code>
</div>
</div>
<div class="text-center mt-2">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="fillDefaultCredentials()">
<i class="bi bi-arrow-down-circle me-1"></i>
使用默认账号
</button>
</div>
</div>
</div>
</div>
<script src="/static/lib/bootstrap/bootstrap.bundle.min.js"></script>
<script>
const loginForm = document.getElementById('loginForm');
const errorAlert = document.getElementById('errorAlert');
const errorMessage = document.getElementById('errorMessage');
const loading = document.querySelector('.loading');
const loginText = document.getElementById('loginText');
function showError(message) {
errorMessage.textContent = message;
errorAlert.classList.remove('d-none');
}
function hideError() {
errorAlert.classList.add('d-none');
}
function setLoading(isLoading) {
if (isLoading) {
loading.classList.add('show');
loginText.textContent = '登录中...';
loginForm.querySelector('button').disabled = true;
} else {
loading.classList.remove('show');
loginText.textContent = '登录';
loginForm.querySelector('button').disabled = false;
}
}
// 填充默认登录凭据
function fillDefaultCredentials() {
document.getElementById('username').value = 'admin';
document.getElementById('password').value = 'admin123';
hideError();
// 添加一个小动画效果
const usernameInput = document.getElementById('username');
const passwordInput = document.getElementById('password');
usernameInput.style.backgroundColor = '#e3f2fd';
passwordInput.style.backgroundColor = '#e3f2fd';
setTimeout(() => {
usernameInput.style.backgroundColor = '';
passwordInput.style.backgroundColor = '';
}, 1000);
}
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
hideError();
setLoading(true);
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
try {
const response = await fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password })
});
const result = await response.json();
if (result.success) {
// 保存token到localStorage
localStorage.setItem('auth_token', result.token);
// 跳转到管理页面
window.location.href = '/admin';
} else {
showError(result.message);
}
} catch (error) {
showError('登录失败,请检查网络连接');
} finally {
setLoading(false);
}
});
// 检查是否已经登录
const token = localStorage.getItem('auth_token');
if (token) {
// 验证token是否有效
fetch('/verify', {
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(response => response.json())
.then(result => {
if (result.authenticated) {
window.location.href = '/admin';
}
})
.catch(() => {
// token无效清除
localStorage.removeItem('auth_token');
});
}
</script>
</body>
</html>