336 lines
12 KiB
HTML
336 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>登录 - 韬智生产管理系统</title>
|
||
<link rel="icon" type="image/svg+xml" href="./assets/favicon.svg" />
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="./assets/login.css" />
|
||
</head>
|
||
<body>
|
||
<div class="login-container">
|
||
<div class="login-background"></div>
|
||
<div class="login-card">
|
||
<div class="login-header">
|
||
<div class="logo-container">
|
||
<div class="logo-icon">
|
||
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<!-- 工厂主体 -->
|
||
<path d="M8 52h48v8H8z" fill="url(#grad1)"/>
|
||
<!-- 左侧建筑 -->
|
||
<path d="M8 28h16v24H8z" fill="url(#grad2)"/>
|
||
<!-- 中间建筑 -->
|
||
<path d="M24 20h16v32H24z" fill="url(#grad3)"/>
|
||
<!-- 右侧建筑 -->
|
||
<path d="M40 24h16v28H40z" fill="url(#grad4)"/>
|
||
<!-- 烟囱 -->
|
||
<rect x="14" y="16" width="4" height="12" rx="1" fill="#60a5fa"/>
|
||
<rect x="30" y="10" width="4" height="10" rx="1" fill="#60a5fa"/>
|
||
<rect x="46" y="14" width="4" height="10" rx="1" fill="#60a5fa"/>
|
||
<!-- 烟雾 -->
|
||
<circle cx="16" cy="14" r="2" fill="#93c5fd" opacity="0.6"/>
|
||
<circle cx="18" cy="12" r="2.5" fill="#93c5fd" opacity="0.5"/>
|
||
<circle cx="32" cy="8" r="2" fill="#93c5fd" opacity="0.6"/>
|
||
<circle cx="34" cy="6" r="2.5" fill="#93c5fd" opacity="0.5"/>
|
||
<circle cx="48" cy="12" r="2" fill="#93c5fd" opacity="0.6"/>
|
||
<circle cx="50" cy="10" r="2.5" fill="#93c5fd" opacity="0.5"/>
|
||
<!-- 窗户 -->
|
||
<rect x="12" y="34" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="18" y="34" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="12" y="42" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="18" y="42" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="28" y="26" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="34" y="26" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="28" y="34" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="34" y="34" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="28" y="42" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="34" y="42" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="44" y="30" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="50" y="30" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="44" y="38" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<rect x="50" y="38" width="4" height="4" rx="0.5" fill="#dbeafe"/>
|
||
<!-- 大门 -->
|
||
<rect x="28" y="48" width="8" height="4" rx="0.5" fill="#1e40af"/>
|
||
<!-- 渐变定义 -->
|
||
<defs>
|
||
<linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#1e3a8a;stop-opacity:1" />
|
||
<stop offset="100%" style="stop-color:#1e40af;stop-opacity:1" />
|
||
</linearGradient>
|
||
<linearGradient id="grad2" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#2563eb;stop-opacity:1" />
|
||
<stop offset="100%" style="stop-color:#1e40af;stop-opacity:1" />
|
||
</linearGradient>
|
||
<linearGradient id="grad3" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#3b82f6;stop-opacity:1" />
|
||
<stop offset="100%" style="stop-color:#2563eb;stop-opacity:1" />
|
||
</linearGradient>
|
||
<linearGradient id="grad4" x1="0%" y1="0%" x2="0%" y2="100%">
|
||
<stop offset="0%" style="stop-color:#60a5fa;stop-opacity:1" />
|
||
<stop offset="100%" style="stop-color:#3b82f6;stop-opacity:1" />
|
||
</linearGradient>
|
||
</defs>
|
||
</svg>
|
||
</div>
|
||
<h1 class="system-title">韬智生产管理系统</h1>
|
||
</div>
|
||
<p class="system-subtitle">Production Management System</p>
|
||
</div>
|
||
|
||
<div class="login-form">
|
||
<div class="form-group">
|
||
<label for="username">用户名</label>
|
||
<div class="input-wrapper">
|
||
<span class="input-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<circle cx="12" cy="8" r="4" stroke="currentColor" stroke-width="2"/>
|
||
<path d="M6 21c0-3.314 2.686-6 6-6s6 2.686 6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||
</svg>
|
||
</span>
|
||
<input
|
||
type="text"
|
||
id="username"
|
||
class="form-input"
|
||
placeholder="请输入用户名"
|
||
autocomplete="username"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="password">密码</label>
|
||
<div class="input-wrapper">
|
||
<span class="input-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="5" y="11" width="14" height="10" rx="2" stroke="currentColor" stroke-width="2"/>
|
||
<path d="M8 11V7a4 4 0 0 1 8 0v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||
<circle cx="12" cy="16" r="1.5" fill="currentColor"/>
|
||
</svg>
|
||
</span>
|
||
<input
|
||
type="password"
|
||
id="password"
|
||
class="form-input"
|
||
placeholder="请输入密码"
|
||
autocomplete="current-password"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="captcha">验证码</label>
|
||
<div class="captcha-wrapper">
|
||
<div class="input-wrapper" style="flex: 1;">
|
||
<span class="input-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||
<rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" stroke-width="2"/>
|
||
<path d="M7 9h2m3 0h2m3 0h2M7 13h3m4 0h3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||
</svg>
|
||
</span>
|
||
<input
|
||
type="text"
|
||
id="captcha"
|
||
class="form-input"
|
||
placeholder="请输入验证码"
|
||
maxlength="4"
|
||
autocomplete="off"
|
||
/>
|
||
</div>
|
||
<div class="captcha-image-wrapper" id="captcha-image-wrapper" title="点击刷新验证码">
|
||
<img id="captcha-image" class="captcha-image" alt="验证码" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="error-message" class="error-message" style="display:none;"></div>
|
||
|
||
<button id="login-btn" class="login-btn">
|
||
<span id="login-text">登录</span>
|
||
<span id="login-loader" class="btn-loader" style="display:none;">
|
||
<span class="dot"></span>
|
||
<span class="dot"></span>
|
||
<span class="dot"></span>
|
||
</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="login-footer">
|
||
<p>© 2025 韬智科技 · 智能制造</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 检查是否已登录
|
||
async function checkAuth() {
|
||
try {
|
||
const response = await fetch('/api/auth/me', {
|
||
credentials: 'include'
|
||
});
|
||
if (response.ok) {
|
||
const user = await response.json();
|
||
if (user && user.username) {
|
||
window.location.replace('/index.html#/dashboard');
|
||
}
|
||
}
|
||
} catch(e) {
|
||
// 未登录,继续显示登录页面
|
||
console.log('未登录,显示登录页面');
|
||
}
|
||
}
|
||
|
||
checkAuth();
|
||
|
||
// 登录处理
|
||
const usernameInput = document.getElementById('username');
|
||
const passwordInput = document.getElementById('password');
|
||
const captchaInput = document.getElementById('captcha');
|
||
const captchaImage = document.getElementById('captcha-image');
|
||
const captchaImageWrapper = document.getElementById('captcha-image-wrapper');
|
||
const loginBtn = document.getElementById('login-btn');
|
||
const loginText = document.getElementById('login-text');
|
||
const loginLoader = document.getElementById('login-loader');
|
||
const errorMessage = document.getElementById('error-message');
|
||
|
||
function showError(message) {
|
||
errorMessage.textContent = message;
|
||
errorMessage.style.display = 'block';
|
||
setTimeout(() => {
|
||
errorMessage.style.display = 'none';
|
||
}, 3000);
|
||
}
|
||
|
||
function setLoading(loading) {
|
||
if (loading) {
|
||
loginBtn.disabled = true;
|
||
loginText.style.display = 'none';
|
||
loginLoader.style.display = 'flex';
|
||
} else {
|
||
loginBtn.disabled = false;
|
||
loginText.style.display = 'inline';
|
||
loginLoader.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 加载验证码
|
||
async function loadCaptcha() {
|
||
try {
|
||
const response = await fetch('/api/auth/captcha', {
|
||
credentials: 'include'
|
||
});
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
if (data.image) {
|
||
captchaImage.src = data.image;
|
||
}
|
||
}
|
||
} catch(e) {
|
||
console.error('加载验证码失败:', e);
|
||
}
|
||
}
|
||
|
||
// 点击图片刷新验证码
|
||
captchaImageWrapper.addEventListener('click', () => {
|
||
captchaInput.value = '';
|
||
captchaImageWrapper.classList.add('refreshing');
|
||
loadCaptcha();
|
||
setTimeout(() => {
|
||
captchaImageWrapper.classList.remove('refreshing');
|
||
}, 300);
|
||
});
|
||
|
||
// 页面加载时获取验证码
|
||
loadCaptcha();
|
||
|
||
async function handleLogin() {
|
||
const username = usernameInput.value.trim();
|
||
const password = passwordInput.value.trim();
|
||
const captcha = captchaInput.value.trim();
|
||
|
||
if (!username) {
|
||
showError('请输入用户名');
|
||
usernameInput.focus();
|
||
return;
|
||
}
|
||
|
||
if (!password) {
|
||
showError('请输入密码');
|
||
passwordInput.focus();
|
||
return;
|
||
}
|
||
|
||
if (!captcha) {
|
||
showError('请输入验证码');
|
||
captchaInput.focus();
|
||
return;
|
||
}
|
||
|
||
if (captcha.length !== 4) {
|
||
showError('验证码为4位数字');
|
||
captchaInput.focus();
|
||
return;
|
||
}
|
||
|
||
setLoading(true);
|
||
|
||
try {
|
||
// 直接使用 fetch,避免 API.login 的 overlay 问题
|
||
const response = await fetch('/api/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
credentials: 'include',
|
||
body: JSON.stringify({ username, password, captcha })
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (!response.ok) {
|
||
throw new Error(result.error || '登录失败');
|
||
}
|
||
|
||
if (result.ok) {
|
||
// 登录成功,跳转到主页面
|
||
// 使用 replace 避免 Safari 缓存问题
|
||
window.location.replace('/index.html#/dashboard');
|
||
} else {
|
||
throw new Error('登录失败');
|
||
}
|
||
} catch(e) {
|
||
showError(e.message || '登录失败');
|
||
setLoading(false);
|
||
// 刷新验证码
|
||
captchaInput.value = '';
|
||
loadCaptcha();
|
||
}
|
||
}
|
||
|
||
loginBtn.addEventListener('click', handleLogin);
|
||
|
||
// 回车键登录
|
||
usernameInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
passwordInput.focus();
|
||
}
|
||
});
|
||
|
||
passwordInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
captchaInput.focus();
|
||
}
|
||
});
|
||
|
||
captchaInput.addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
handleLogin();
|
||
}
|
||
});
|
||
|
||
// 自动聚焦用户名输入框
|
||
usernameInput.focus();
|
||
</script>
|
||
</body>
|
||
</html>
|