Files
CrmSystem/public/index.html
2026-01-23 21:56:02 +08:00

751 lines
20 KiB
HTML
Raw Permalink 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>
<style>
/* ========== 主题配色 ========== */
:root {
--primary: #5bbf93;
--primary-light: #8fd6b3;
--primary-dark: #2f8f67;
--primary-bg: #f0f9f5;
--primary-gradient: linear-gradient(135deg, #5bbf93 0%, #2f8f67 100%);
--text-primary: #2c3e50;
--text-secondary: #546e7a;
--text-muted: #90a4ae;
--bg-body: #f8fafc;
--bg-card: #ffffff;
--border: #e2e8f0;
--border-light: #f1f5f9;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--radius: 10px;
--radius-lg: 16px;
--radius-full: 9999px;
--transition: all 0.2s ease-in-out;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', 'Segoe UI', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-body);
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-image: url('data:image/svg+xml,<svg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h60v60H0z" fill="none"/><path d="M30 10c-11.05 0-20 8.95-20 20s8.95 20 20 20 20-8.95 20-20-8.95-20-20-20zm0 36c-8.82 0-16-7.18-16-16s7.18-16 16-16 16 7.18 16 16-7.18 16-16 16z" fill="%235bbf93" opacity="0.05"/></svg>');
}
/* ========== 登录容器 ========== */
.login-container {
width: 100%;
max-width: 440px;
background: var(--bg-card);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
overflow: hidden;
border: 1px solid var(--border);
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ========== 登录头部 ========== */
.login-header {
background: var(--primary-gradient);
color: white;
padding: 40px 30px;
text-align: center;
position: relative;
overflow: hidden;
}
.login-header::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 200px;
height: 200px;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 70%);
border-radius: 50%;
transform: translate(30%, -30%);
}
.login-header::after {
content: '';
position: absolute;
bottom: -50px;
left: -50px;
width: 150px;
height: 150px;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 70%);
border-radius: 50%;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
gap: 15px;
margin-bottom: 20px;
}
.logo-icon {
width: 60px;
height: 60px;
background: rgba(255,255,255,0.2);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
backdrop-filter: blur(5px);
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.logo-text h1 {
font-size: 1.8rem;
font-weight: 700;
text-align: left;
line-height: 1.2;
}
.logo-text .subtitle {
font-size: 0.9rem;
opacity: 0.9;
font-weight: 300;
text-align: left;
}
.login-header .welcome {
font-size: 1.1rem;
opacity: 0.95;
margin-top: 10px;
font-weight: 400;
}
/* ========== 用户类型切换 ========== */
.user-type-toggle {
display: flex;
background: rgba(255,255,255,0.1);
border-radius: var(--radius);
padding: 5px;
margin-top: 20px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255,255,255,0.2);
}
.user-type-btn {
flex: 1;
padding: 10px;
border: none;
background: transparent;
color: rgba(255,255,255,0.8);
font-weight: 600;
font-size: 0.95rem;
cursor: pointer;
transition: var(--transition);
border-radius: calc(var(--radius) - 2px);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.user-type-btn.active {
background: white;
color: var(--primary-dark);
box-shadow: var(--shadow);
}
/* ========== 登录表单 ========== */
.login-form {
padding: 40px 35px;
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: var(--text-secondary);
font-size: 0.95rem;
display: flex;
align-items: center;
gap: 8px;
}
.form-group .input-wrapper {
position: relative;
}
.form-group input, .form-group select {
width: 100%;
padding: 16px 50px 16px 20px;
border: 1px solid var(--border);
border-radius: var(--radius);
font-size: 1rem;
background: white;
color: var(--text-primary);
transition: var(--transition);
font-family: inherit;
}
.form-group input:hover, .form-group select:hover {
border-color: var(--primary-light);
}
.form-group input:focus, .form-group select:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(91, 191, 147, 0.15);
}
.form-group input::placeholder {
color: var(--text-muted);
}
.input-icon {
position: absolute;
right: 18px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
font-size: 1.1rem;
}
/* ========== 员工选择 ========== */
.staff-select {
appearance: none;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2390a4ae' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 1rem center;
background-size: 1em;
padding-right: 3rem;
}
/* ========== 记住我选项 ========== */
.remember-me {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 25px;
cursor: pointer;
}
.remember-me input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
accent-color: var(--primary);
}
.remember-me label {
margin: 0;
font-size: 0.9rem;
color: var(--text-secondary);
cursor: pointer;
font-weight: 500;
}
/* ========== 登录按钮 ========== */
.login-btn {
width: 100%;
padding: 16px;
border: none;
border-radius: var(--radius);
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: var(--transition);
background: var(--primary);
color: white;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
font-family: inherit;
box-shadow: var(--shadow);
}
.login-btn:hover {
background: var(--primary-dark);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.login-btn:active {
transform: translateY(0);
}
.login-btn:disabled {
background: var(--text-muted);
cursor: not-allowed;
transform: none;
box-shadow: none;
}
/* ========== 安全提示 ========== */
.security-tip {
margin-top: 15px;
padding: 12px 16px;
background: #fff3e0;
border-radius: var(--radius);
border: 1px solid rgba(245, 158, 11, 0.3);
font-size: 0.85rem;
color: #7c2d12;
display: flex;
align-items: center;
gap: 10px;
}
.security-tip i {
color: #f59e0b;
}
/* ========== 员工信息卡片 ========== */
.staff-info-card {
margin-top: 15px;
padding: 15px;
background: var(--primary-bg);
border-radius: var(--radius);
border: 1px solid var(--border);
display: none;
animation: fadeIn 0.3s ease;
}
.staff-info-card.show {
display: block;
}
.staff-info-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 10px;
}
.staff-avatar {
width: 40px;
height: 40px;
background: var(--primary);
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 1.2rem;
}
.staff-name {
font-weight: 600;
color: var(--text-primary);
}
.staff-details {
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.5;
}
/* ========== 消息提示 ========== */
.message {
position: fixed;
top: 20px;
right: 20px;
padding: 16px 24px;
border-radius: var(--radius);
font-weight: 600;
z-index: 10000;
color: white;
box-shadow: var(--shadow-lg);
animation: slideIn 0.3s ease;
max-width: 400px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.message.success {
background: linear-gradient(135deg, var(--success) 0%, #059669 100%);
}
.message.error {
background: linear-gradient(135deg, var(--danger) 0%, #dc2626 100%);
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
/* ========== 加载动画 ========== */
.loader {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* ========== 底部信息 ========== */
.login-footer {
text-align: center;
padding: 25px;
color: var(--text-muted);
font-size: 0.85rem;
background: var(--bg-body);
border-top: 1px solid var(--border);
line-height: 1.5;
}
/* ========== 响应式设计 ========== */
@media (max-width: 480px) {
.login-container {
max-width: 100%;
border-radius: 12px;
}
.login-header {
padding: 30px 20px;
}
.login-form {
padding: 30px 20px;
}
.logo {
flex-direction: column;
text-align: center;
}
.logo-text h1 {
text-align: center;
}
.logo-text .subtitle {
text-align: center;
}
}
/* ========== 登录说明 ========== */
.login-instructions {
margin-bottom: 20px;
padding: 12px 16px;
background: #e8f6f3;
border-radius: var(--radius);
border: 1px solid rgba(39, 174, 96, 0.3);
font-size: 0.85rem;
color: #145a32;
display: flex;
align-items: center;
gap: 10px;
}
.login-instructions i {
color: var(--success);
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<div class="logo">
<div class="logo-icon">📋</div>
<div class="logo-text">
<h1>客户管理系统</h1>
<div class="subtitle">统一登录入口</div>
</div>
</div>
<div class="welcome">请登录您的账号</div>
</div>
<div class="login-form">
<form id="loginForm" autocomplete="on">
<div class="form-group">
<label for="username"><i class="fas fa-user"></i> 账号</label>
<div class="input-wrapper">
<input id="username" name="username" type="text" placeholder="请输入账号" required>
<span class="input-icon"><i class="fas fa-user"></i></span>
</div>
</div>
<div class="form-group">
<label for="password"><i class="fas fa-lock"></i> 密码</label>
<div class="input-wrapper">
<input id="password" name="password" type="password" placeholder="请输入密码" required>
<span class="input-icon"><i class="fas fa-lock"></i></span>
</div>
</div>
<div class="remember-me">
<input type="checkbox" id="rememberMe">
<label for="rememberMe">记住账号</label>
</div>
<button type="submit" class="login-btn" id="loginBtn">
<span>登录系统</span>
<i class="fas fa-sign-in-alt"></i>
</button>
<!--<div class="login-instructions">-->
<!-- <i class="fas fa-info-circle"></i>-->
<!-- <div>-->
<!-- <strong>测试账号:</strong><br>-->
<!-- 管理员admin / niu995228...<br>-->
<!-- 员工staff1 / staff123456-->
<!-- </div>-->
<!--</div>-->
<div class="security-tip">
<i class="fas fa-shield-alt"></i>
登录信息将保存7天
</div>
</form>
</div>
<div class="login-footer">
<p>客户管理系统 © 2024 | 服务器后端连接</p>
<p style="font-size:0.8rem; margin-top:5px;">技术支持:如有问题请联系管理员</p>
</div>
</div>
<div id="message" class="message" style="display:none;"></div>
<script>
// ========== 配置 ==========
const API_BASE_URL = window.location.origin; // 根据当前页面自动获取后端地址
const API_ENDPOINTS = {
login: '/api/auth/login',
me: '/api/auth/me'
};
// 获取DOM元素
function $(id) { return document.getElementById(id); }
// 显示消息
function showMessage(text, type) {
const msg = $('message');
msg.textContent = text;
msg.className = 'message ' + type;
msg.style.display = 'block';
setTimeout(() => {
msg.style.animation = 'slideOut 0.3s ease';
setTimeout(() => {
msg.style.display = 'none';
msg.style.animation = '';
}, 300);
}, 3000);
}
// 设置按钮加载状态
function setButtonLoading(loading) {
const btn = $('loginBtn');
if (loading) {
btn.innerHTML = '<div class="loader"></div> <span>登录中...</span>';
btn.disabled = true;
} else {
btn.innerHTML = '<span>登录系统</span> <i class="fas fa-sign-in-alt"></i>';
btn.disabled = false;
}
}
// 加载记住的账号
function loadRemembered() {
const remembered = localStorage.getItem('remember_username');
if (remembered) {
$('username').value = remembered;
$('rememberMe').checked = true;
}
}
// 检查是否已登录
function checkAlreadyLoggedIn() {
const authUser = localStorage.getItem('auth_user');
const authToken = localStorage.getItem('auth_token');
if (authUser && authToken) {
// 验证token是否有效
fetch(`${API_BASE_URL}${API_ENDPOINTS.me}`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${authToken}`
}
})
.then(response => {
if (response.ok) {
response.json().then(data => {
// 自动跳转到对应页面
if (data.user.role === 'admin') {
window.location.href = 'admin.html';
} else if (data.user.role === 'leader') {
window.location.href = 'leader.html';
} else if (data.user.role === 'staff') {
window.location.href = 'staff.html';
}
});
} else {
// token无效清除本地存储
localStorage.removeItem('auth_user');
localStorage.removeItem('auth_token');
}
})
.catch(() => {
// 网络错误,清除本地存储
localStorage.removeItem('auth_user');
localStorage.removeItem('auth_token');
});
}
}
// 登录函数 - 调用后端API
async function login(username, password) {
try {
setButtonLoading(true);
const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.login}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password
})
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || '登录失败');
}
return data;
} catch (error) {
console.error('登录错误:', error);
throw error;
} finally {
setButtonLoading(false);
}
}
// 表单提交事件
$('loginForm').addEventListener('submit', async function(e) {
e.preventDefault();
const username = $('username').value.trim();
const password = $('password').value;
if (!username || !password) {
showMessage('请输入账号和密码', 'error');
return;
}
try {
const loginData = await login(username, password);
// 记住账号
if ($('rememberMe').checked) {
localStorage.setItem('remember_username', username);
} else {
localStorage.removeItem('remember_username');
}
// 保存登录信息
localStorage.setItem('auth_token', loginData.token);
localStorage.setItem('auth_user', JSON.stringify(loginData.user));
// 显示成功消息
showMessage('登录成功,正在跳转...', 'success');
// 根据角色跳转
setTimeout(() => {
if (loginData.user.role === 'admin') {
window.location.href = 'admin.html';
} else if (loginData.user.role === 'leader') {
window.location.href = 'leader.html';
} else if (loginData.user.role === 'staff') {
window.location.href = 'staff.html';
}
}, 1000);
} catch (error) {
console.error('登录失败:', error);
showMessage(error.message || '登录失败,请检查账号密码', 'error');
}
});
// 页面加载
document.addEventListener('DOMContentLoaded', function() {
loadRemembered();
// checkAlreadyLoggedIn();
});
</script>
<!-- Font Awesome图标 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</body>
</html>