203 lines
11 KiB
HTML
203 lines
11 KiB
HTML
<!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/css/style.css?v=317">
|
||
</head>
|
||
<body class="login-page">
|
||
<div class="login-container">
|
||
<div class="login-card">
|
||
<div class="login-header">
|
||
<div class="login-logo">
|
||
<img src="/static/logo-small.png" alt="Logo" style="width:64px;height:64px;border-radius:12px;">
|
||
</div>
|
||
<h1>蝶雅采购管理系统</h1>
|
||
<p class="login-subtitle">采购智能管理平台</p>
|
||
</div>
|
||
<form id="loginForm" class="login-form" onsubmit="return false;">
|
||
<div class="form-group">
|
||
<label>用户名</label>
|
||
<input type="text" id="username" class="form-input" placeholder="请输入用户名" autocomplete="off" autofocus>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>密码</label>
|
||
<div class="password-input-wrap">
|
||
<input type="password" id="password" class="form-input" placeholder="请输入密码" autocomplete="off">
|
||
<button type="button" class="password-toggle" onclick="togglePassword('password', this)" aria-label="显示密码" title="显示密码">
|
||
<svg class="eye-open" viewBox="0 0 24 24" aria-hidden="true"><path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg>
|
||
<svg class="eye-closed" viewBox="0 0 24 24" aria-hidden="true"><path d="m3 3 18 18M10.6 10.7a2 2 0 0 0 2.7 2.7M9.9 5.2A11.7 11.7 0 0 1 12 5c6.5 0 10 7 10 7a18.8 18.8 0 0 1-2.1 3M6.6 6.7C3.7 8.5 2 12 2 12s3.5 7 10 7a10.5 10.5 0 0 0 4.1-.8"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-error" id="loginError"></div>
|
||
<button type="submit" class="btn btn-primary login-btn" onclick="handleLogin()">
|
||
<span class="btn-text">登 录</span>
|
||
<span class="btn-loading" style="display:none">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<circle cx="12" cy="12" r="10" stroke-dasharray="31.4 31.4" stroke-linecap="round"/>
|
||
</svg>
|
||
</span>
|
||
</button>
|
||
</form>
|
||
<form id="changePasswordForm" class="login-form" onsubmit="return false;" style="display:none">
|
||
<p class="password-notice">首次登录或密码重置后,必须先设置新密码。</p>
|
||
<div class="form-group">
|
||
<label>新密码</label>
|
||
<div class="password-input-wrap">
|
||
<input type="password" id="newPassword" class="form-input" placeholder="至少10位,包含字母、数字和特殊字符" autocomplete="off">
|
||
<button type="button" class="password-toggle" onclick="togglePassword('newPassword', this)" aria-label="显示密码" title="显示密码">
|
||
<svg class="eye-open" viewBox="0 0 24 24" aria-hidden="true"><path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg>
|
||
<svg class="eye-closed" viewBox="0 0 24 24" aria-hidden="true"><path d="m3 3 18 18M10.6 10.7a2 2 0 0 0 2.7 2.7M9.9 5.2A11.7 11.7 0 0 1 12 5c6.5 0 10 7 10 7a18.8 18.8 0 0 1-2.1 3M6.6 6.7C3.7 8.5 2 12 2 12s3.5 7 10 7a10.5 10.5 0 0 0 4.1-.8"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>确认新密码</label>
|
||
<div class="password-input-wrap">
|
||
<input type="password" id="confirmPassword" class="form-input" placeholder="请再次输入新密码" autocomplete="off">
|
||
<button type="button" class="password-toggle" onclick="togglePassword('confirmPassword', this)" aria-label="显示密码" title="显示密码">
|
||
<svg class="eye-open" viewBox="0 0 24 24" aria-hidden="true"><path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg>
|
||
<svg class="eye-closed" viewBox="0 0 24 24" aria-hidden="true"><path d="m3 3 18 18M10.6 10.7a2 2 0 0 0 2.7 2.7M9.9 5.2A11.7 11.7 0 0 1 12 5c6.5 0 10 7 10 7a18.8 18.8 0 0 1-2.1 3M6.6 6.7C3.7 8.5 2 12 2 12s3.5 7 10 7a10.5 10.5 0 0 0 4.1-.8"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-error" id="changePasswordError"></div>
|
||
<button type="submit" class="btn btn-primary login-btn" onclick="handleChangePassword()">
|
||
<span class="btn-text">确认修改</span>
|
||
<span class="btn-loading" style="display:none">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<circle cx="12" cy="12" r="10" stroke-dasharray="31.4 31.4" stroke-linecap="round"/>
|
||
</svg>
|
||
</span>
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<div id="passwordPrompt" class="password-prompt-overlay" style="display:none" role="dialog" aria-modal="true" aria-labelledby="passwordPromptTitle">
|
||
<div class="password-prompt-card">
|
||
<div class="password-prompt-icon">!</div>
|
||
<h2 id="passwordPromptTitle">需要修改密码</h2>
|
||
<p>为了账号安全,本次登录需要先设置新密码。修改完成后才能正常访问系统。</p>
|
||
<button type="button" class="btn btn-primary password-prompt-btn" onclick="enterChangePassword()">我知道了,去修改</button>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
function handleLogin() {
|
||
var btn = document.querySelector('.login-btn');
|
||
var text = btn.querySelector('.btn-text');
|
||
var loading = btn.querySelector('.btn-loading');
|
||
var error = document.getElementById('loginError');
|
||
|
||
btn.disabled = true;
|
||
text.style.display = 'none';
|
||
loading.style.display = 'inline';
|
||
error.textContent = '';
|
||
|
||
fetch('/api/login', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({
|
||
username: document.getElementById('username').value,
|
||
password: document.getElementById('password').value
|
||
})
|
||
})
|
||
.then(function(r) { return r.json(); })
|
||
.then(function(data) {
|
||
if (data.code === 0) {
|
||
if (data.data && data.data.must_change_password) {
|
||
document.getElementById('password').value = '';
|
||
document.getElementById('passwordPrompt').style.display = 'flex';
|
||
document.querySelector('.password-prompt-btn').focus();
|
||
} else {
|
||
window.location.href = '/dashboard';
|
||
}
|
||
} else {
|
||
error.textContent = data.msg;
|
||
btn.disabled = false;
|
||
text.style.display = 'inline';
|
||
loading.style.display = 'none';
|
||
}
|
||
})
|
||
.catch(function() {
|
||
error.textContent = '网络错误,请重试';
|
||
btn.disabled = false;
|
||
text.style.display = 'inline';
|
||
loading.style.display = 'none';
|
||
});
|
||
}
|
||
|
||
function enterChangePassword() {
|
||
document.getElementById('passwordPrompt').style.display = 'none';
|
||
document.getElementById('loginForm').style.display = 'none';
|
||
document.getElementById('changePasswordForm').style.display = 'block';
|
||
document.querySelector('.login-subtitle').textContent = '请设置新的登录密码';
|
||
document.getElementById('newPassword').focus();
|
||
}
|
||
|
||
function togglePassword(inputId, button) {
|
||
var input = document.getElementById(inputId);
|
||
var show = input.type === 'password';
|
||
input.type = show ? 'text' : 'password';
|
||
button.classList.toggle('is-visible', show);
|
||
button.setAttribute('aria-label', show ? '隐藏密码' : '显示密码');
|
||
button.setAttribute('title', show ? '隐藏密码' : '显示密码');
|
||
input.focus();
|
||
}
|
||
|
||
function handleChangePassword() {
|
||
var form = document.getElementById('changePasswordForm');
|
||
var btn = form.querySelector('.login-btn');
|
||
var text = btn.querySelector('.btn-text');
|
||
var loading = btn.querySelector('.btn-loading');
|
||
var error = document.getElementById('changePasswordError');
|
||
var newPassword = document.getElementById('newPassword').value;
|
||
var confirmPassword = document.getElementById('confirmPassword').value;
|
||
|
||
error.textContent = '';
|
||
if (newPassword !== confirmPassword) {
|
||
error.textContent = '两次输入的密码不一致';
|
||
return;
|
||
}
|
||
btn.disabled = true;
|
||
text.style.display = 'none';
|
||
loading.style.display = 'inline';
|
||
|
||
fetch('/api/change-password', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({
|
||
new_password: newPassword,
|
||
confirm_password: confirmPassword
|
||
})
|
||
})
|
||
.then(function(r) { return r.json(); })
|
||
.then(function(data) {
|
||
if (data.code === 0) {
|
||
window.location.href = '/dashboard';
|
||
return;
|
||
}
|
||
error.textContent = data.msg;
|
||
btn.disabled = false;
|
||
text.style.display = 'inline';
|
||
loading.style.display = 'none';
|
||
})
|
||
.catch(function() {
|
||
error.textContent = '网络错误,请重试';
|
||
btn.disabled = false;
|
||
text.style.display = 'inline';
|
||
loading.style.display = 'none';
|
||
});
|
||
}
|
||
|
||
document.getElementById('loginForm').addEventListener('keydown', function(e) {
|
||
if (e.key === 'Enter') handleLogin();
|
||
});
|
||
document.getElementById('changePasswordForm').addEventListener('keydown', function(e) {
|
||
if (e.key === 'Enter') handleChangePassword();
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|