用户登录功能
This commit is contained in:
@@ -812,3 +812,98 @@ body {
|
||||
from { transform: translateX(-100%); }
|
||||
to { transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* 登录页面样式 */
|
||||
.login-page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
width: 100%;
|
||||
max-width: 450px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
animation: modalSlideIn 0.5s ease;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.login-header i {
|
||||
font-size: 3rem;
|
||||
color: #667eea;
|
||||
margin-bottom: 15px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.login-header h1 {
|
||||
color: #2d3748;
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.login-form .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-form label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
color: #4a5568;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.login-form label i {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #fed7d7;
|
||||
color: #c53030;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 14px;
|
||||
border: 1px solid #fc8181;
|
||||
}
|
||||
|
||||
/* 用户信息显示 */
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #4a5568;
|
||||
font-weight: 600;
|
||||
padding: 8px 16px;
|
||||
background: #f7fafc;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.user-info i {
|
||||
color: #667eea;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,44 @@
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- 登录页面 -->
|
||||
<div id="loginPage" class="login-page">
|
||||
<div class="login-container">
|
||||
<div class="login-header">
|
||||
<i class="fas fa-tasks"></i>
|
||||
<h1>工作任务管理系统</h1>
|
||||
</div>
|
||||
<form id="loginForm" class="login-form">
|
||||
<div class="form-group">
|
||||
<label for="loginUsername">
|
||||
<i class="fas fa-user"></i> 用户名
|
||||
</label>
|
||||
<input type="text" id="loginUsername" name="username" required autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="loginPassword">
|
||||
<i class="fas fa-lock"></i> 密码
|
||||
</label>
|
||||
<input type="password" id="loginPassword" name="password" required>
|
||||
</div>
|
||||
<div id="loginError" class="error-message" style="display: none;"></div>
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
<i class="fas fa-sign-in-alt"></i> 登录
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主应用页面 -->
|
||||
<div id="mainApp" class="container" style="display: none;">
|
||||
<!-- 头部 -->
|
||||
<header class="header">
|
||||
<h1><i class="fas fa-tasks"></i> 工作任务管理系统</h1>
|
||||
<div class="header-actions">
|
||||
<span class="user-info">
|
||||
<i class="fas fa-user-circle"></i>
|
||||
<span id="currentUsername"></span>
|
||||
</span>
|
||||
<button id="addTaskBtn" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> 添加任务
|
||||
</button>
|
||||
@@ -22,6 +55,9 @@
|
||||
<button id="timeHistoryBtn" class="btn btn-secondary">
|
||||
<i class="fas fa-history"></i> 时间历史
|
||||
</button>
|
||||
<button id="logoutBtn" class="btn btn-outline">
|
||||
<i class="fas fa-sign-out-alt"></i> 退出
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ class WorkListAPI {
|
||||
async request(endpoint, options = {}) {
|
||||
const url = `${this.baseURL}${endpoint}`;
|
||||
const config = {
|
||||
credentials: 'same-origin', // 包含cookies以支持session
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
@@ -17,7 +18,7 @@ class WorkListAPI {
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || `HTTP错误: ${response.status}`);
|
||||
@@ -30,6 +31,31 @@ class WorkListAPI {
|
||||
}
|
||||
}
|
||||
|
||||
// 认证API
|
||||
async login(username, password) {
|
||||
return this.request('/auth/login', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
}
|
||||
|
||||
async logout() {
|
||||
return this.request('/auth/logout', {
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
|
||||
async checkAuth() {
|
||||
return this.request('/auth/check');
|
||||
}
|
||||
|
||||
async register(username, password) {
|
||||
return this.request('/auth/register', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ username, password })
|
||||
});
|
||||
}
|
||||
|
||||
// 任务管理API
|
||||
async getTasks() {
|
||||
return this.request('/tasks');
|
||||
|
||||
@@ -5,18 +5,111 @@ class WorkListApp {
|
||||
this.currentEditingTask = null;
|
||||
this.currentFilter = 'all';
|
||||
this.excludedStatuses = new Set();
|
||||
this.currentUser = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
// 初始化应用
|
||||
init() {
|
||||
this.bindEvents();
|
||||
this.loadTasks();
|
||||
this.setupDatePicker();
|
||||
async init() {
|
||||
// 先检查登录状态
|
||||
await this.checkAuthStatus();
|
||||
|
||||
// 如果已登录,绑定事件并加载任务
|
||||
if (this.currentUser) {
|
||||
this.bindEvents();
|
||||
this.loadTasks();
|
||||
this.setupDatePicker();
|
||||
}
|
||||
}
|
||||
|
||||
// 检查认证状态
|
||||
async checkAuthStatus() {
|
||||
try {
|
||||
const response = await api.checkAuth();
|
||||
if (response.authenticated) {
|
||||
this.currentUser = response.user;
|
||||
this.showMainApp();
|
||||
} else {
|
||||
this.showLoginPage();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('未登录:', error);
|
||||
this.showLoginPage();
|
||||
}
|
||||
}
|
||||
|
||||
// 显示登录页面
|
||||
showLoginPage() {
|
||||
document.getElementById('loginPage').style.display = 'flex';
|
||||
document.getElementById('mainApp').style.display = 'none';
|
||||
|
||||
// 绑定登录表单事件
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
loginForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
await this.handleLogin();
|
||||
});
|
||||
}
|
||||
|
||||
// 显示主应用页面
|
||||
showMainApp() {
|
||||
document.getElementById('loginPage').style.display = 'none';
|
||||
document.getElementById('mainApp').style.display = 'block';
|
||||
|
||||
// 显示用户名
|
||||
if (this.currentUser) {
|
||||
document.getElementById('currentUsername').textContent = this.currentUser.username;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理登录
|
||||
async handleLogin() {
|
||||
const username = document.getElementById('loginUsername').value;
|
||||
const password = document.getElementById('loginPassword').value;
|
||||
const errorDiv = document.getElementById('loginError');
|
||||
|
||||
try {
|
||||
errorDiv.style.display = 'none';
|
||||
const response = await api.login(username, password);
|
||||
|
||||
if (response.user) {
|
||||
this.currentUser = response.user;
|
||||
this.showMainApp();
|
||||
|
||||
// 绑定事件并加载任务
|
||||
this.bindEvents();
|
||||
this.loadTasks();
|
||||
this.setupDatePicker();
|
||||
}
|
||||
} catch (error) {
|
||||
errorDiv.textContent = error.message || '登录失败,请检查用户名和密码';
|
||||
errorDiv.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理登出
|
||||
async handleLogout() {
|
||||
try {
|
||||
await api.logout();
|
||||
this.currentUser = null;
|
||||
this.tasks = [];
|
||||
this.showLoginPage();
|
||||
} catch (error) {
|
||||
console.error('登出失败:', error);
|
||||
alert('登出失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvents() {
|
||||
// 登出按钮
|
||||
const logoutBtn = document.getElementById('logoutBtn');
|
||||
if (logoutBtn && !logoutBtn.hasAttribute('data-bound')) {
|
||||
logoutBtn.addEventListener('click', () => {
|
||||
this.handleLogout();
|
||||
});
|
||||
logoutBtn.setAttribute('data-bound', 'true');
|
||||
}
|
||||
// 添加任务按钮
|
||||
document.getElementById('addTaskBtn').addEventListener('click', () => {
|
||||
this.showTaskModal();
|
||||
|
||||
Reference in New Issue
Block a user