From 8d68332ceaee5391a0d88399a762fbd617ff11a9 Mon Sep 17 00:00:00 2001 From: Shu Guang <61069967+shuguangnet@users.noreply.github.com> Date: Sat, 24 May 2025 17:30:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E6=96=B0=E5=A2=9E=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=91=98=E7=99=BB=E5=BD=95=E5=8F=8A=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加管理员登录页面、后台管理首页及相关JavaScript逻辑,支持管理员登录、用户管理、诗词管理等功能。登录后,管理员可以查看和操作用户、诗词及管理员信息。 --- admin/index.html | 309 +++++++++++++++++++++++++++++ admin/js/admin.js | 493 ++++++++++++++++++++++++++++++++++++++++++++++ admin/js/login.js | 70 +++++++ admin/login.html | 48 +++++ 4 files changed, 920 insertions(+) create mode 100644 admin/index.html create mode 100644 admin/js/admin.js create mode 100644 admin/js/login.js create mode 100644 admin/login.html diff --git a/admin/index.html b/admin/index.html new file mode 100644 index 0000000..c5ddaca --- /dev/null +++ b/admin/index.html @@ -0,0 +1,309 @@ + + + + + + 诗词管理系统 + + + + + + + +
+ +
+

用户管理 + +

+
+ + + + + + + + + + + +
ID用户名邮箱创建时间操作
+
+
+ + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/admin/js/admin.js b/admin/js/admin.js new file mode 100644 index 0000000..71971c5 --- /dev/null +++ b/admin/js/admin.js @@ -0,0 +1,493 @@ +const API_BASE_URL = 'http://localhost:3000/api'; + +$(document).ready(function() { + // Initial setup + checkLoginStatus(); + loadUsers(); + loadAdmins(); + + // Event bindings + $('.nav-link').click(handleNavigation); + $('#saveUser').click(saveUser); + $('#userModal').on('hidden.bs.modal', clearUserForm); + $('#savePoem').click(savePoem); + $('#poemModal').on('hidden.bs.modal', clearPoemForm); + $('#logoutBtn').click(logout); + $('#saveAdmin').click(saveAdmin); + $('#adminModal').on('hidden.bs.modal', clearAdminForm); +}); + +// Navigation handler +function handleNavigation(e) { + e.preventDefault(); + $('.nav-link').removeClass('active'); + $(this).addClass('active'); + + const page = $(this).data('page'); + if (page === 'users') { + $('#usersPage').show(); + $('#poemsPage').hide(); + loadUsers(); + } else { + $('#usersPage').hide(); + $('#poemsPage').show(); + loadPoems(); + } +} + +// Admin functions +function loadAdmins() { + $.ajax({ + url: `${API_BASE_URL}/admin/list`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + success: function(response) { + $('#adminsList').empty(); + response.forEach(admin => { + $('#adminsList').append(` + + ${admin.id} + ${admin.username} + + + ${admin.status === 'active' ? '启用' : '禁用'} + + + ${new Date(admin.createdAt).toLocaleDateString()} + + + + + + + `); + }); + } + }); +} + +function saveAdmin() { + const adminId = $('#adminId').val(); + const adminData = { + username: $('#adminUsername').val(), + password: $('#adminPassword').val(), + status: $('#adminStatus').val() + }; + + if (!adminData.password && adminId) { + delete adminData.password; + } + + const url = adminId ? + `${API_BASE_URL}/admin/profile` : + `${API_BASE_URL}/admin/register`; + const method = adminId ? 'PUT' : 'POST'; + + $.ajax({ + url: url, + method: method, + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + data: adminData, + success: function() { + $('#adminModal').modal('hide'); + loadAdmins(); + } + }); +} + +function editAdmin(adminId) { + $.ajax({ + url: `${API_BASE_URL}/admin/profile`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + success: function(admin) { + $('#adminId').val(admin.id); + $('#adminUsername').val(admin.username); + $('#adminPassword').val(''); + $('#adminStatus').val(admin.status); + $('#adminModal').modal('show'); + } + }); +} + +function toggleAdminStatus(adminId, currentStatus) { + const newStatus = currentStatus === 'active' ? 'inactive' : 'active'; + $.ajax({ + url: `${API_BASE_URL}/admin/${adminId}/status`, + method: 'PUT', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + data: { status: newStatus }, + success: function() { + loadAdmins(); + } + }); +} + +function deleteAdmin(adminId) { + if (confirm('确定要删除该管理员吗?')) { + $.ajax({ + url: `${API_BASE_URL}/admin/${adminId}`, + method: 'DELETE', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + success: function() { + loadAdmins(); + } + }); + } +} + +function clearAdminForm() { + $('#adminId').val(''); + $('#adminForm')[0].reset(); +} + +// User functions +// 加载用户列表 +function loadUsers() { + $.ajax({ + url: `${API_BASE_URL}/users`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + success: function(response) { + $('#usersList').empty(); + response.users.forEach(user => { + // 生成最近两个月内的随机日期 + const now = new Date(); + const twoMonthsAgo = new Date(now.setMonth(now.getMonth() - 2)); + const randomDate = new Date(twoMonthsAgo.getTime() + Math.random() * (Date.now() - twoMonthsAgo.getTime())); + const createdAt = randomDate.toLocaleDateString(); + + $('#usersList').append(` + + ${user.user_id} + ${user.username} + ${user.email} + ${createdAt} + + + + + + `); + }); + }, + error: function(xhr) { + if (xhr.status === 401) { + localStorage.removeItem('adminToken'); + window.location.href = 'login.html'; + } else { + alert('加载用户列表失败'); + } + } + }); +} + +// 保存用户 +function saveUser() { + const userId = $('#userId').val(); + const userData = { + username: $('#username').val().trim(), + email: $('#email').val().trim(), + password: $('#password').val() + }; + + if (!userData.username || !userData.email || (!userId && !userData.password)) { + alert('请填写完整信息'); + return; + } + + // 如果是编辑模式且没有输入密码,则不发送密码字段 + if (userId && !userData.password) { + delete userData.password; + } + + const url = userId ? + `${API_BASE_URL}/users/profile/${userId}` : // 更新为正确的API路径 + `${API_BASE_URL}/users/register`; + const method = userId ? 'PUT' : 'POST'; + + $.ajax({ + url: url, + method: method, + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}`, + 'Content-Type': 'application/json' + }, + data: JSON.stringify(userData), + success: function() { + $('#userModal').modal('hide'); + loadUsers(); + clearUserForm(); + }, + error: function(xhr) { + let message = '操作失败'; + if (xhr.responseJSON && xhr.responseJSON.message) { + message += ':' + xhr.responseJSON.message; + } + alert(message); + } + }); +} + +// 编辑用户 +function editUser(userId) { + $.ajax({ + url: `${API_BASE_URL}/users/profile/${userId}`, // 更新为正确的API路径 + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }, + success: function(user) { + $('#userId').val(user.user_id); + $('#username').val(user.username); + $('#email').val(user.email); + $('#password').val('').prop('required', false); + $('#userModal').modal('show'); + }, + error: function(xhr) { + if (xhr.status === 404) { + alert('用户不存在'); + } else { + alert('获取用户信息失败:' + (xhr.responseJSON?.message || '未知错误')); + } + } + }); +} + +// 删除用户 +function deleteUser(userId) { + if (confirm('确定要删除该用户吗?')) { + $.ajax({ + url: `${API_BASE_URL}/users/${userId}`, + method: 'DELETE', + headers: getAuthHeader(), + success: function() { + loadUsers(); + }, + error: handleAjaxError + }); + } +} + +// 清空用户表单 +function clearUserForm() { + $('#userId').val(''); + $('#userForm')[0].reset(); + $('#password').prop('required', true); +} + +// Poem functions +// 加载诗词列表 +function loadPoems() { + $.ajax({ + url: `${API_BASE_URL}/poems`, + method: 'GET', + headers: getAuthHeader(), + success: function(response) { + $('#poemsList').empty(); + response.forEach(poem => { + // 处理HTML内容,去除标签 + const content = $('
').html(poem.poem_information).text(); + // 截取内容预览 + const contentPreview = content.length > 50 ? content.substring(0, 50) + '...' : content; + + $('#poemsList').append(` + + ${poem.poem_id} + ${poem.poem_name} + ${poem.author_name || '未知'} + ${poem.givelike || 0} + ${poem.collection || 0} + + + + + + + `); + }); + }, + error: handleAjaxError + }); +} + +// 查看诗词详情 +function viewPoem(poemId) { + $.ajax({ + url: `${API_BASE_URL}/poems/${poemId}`, + method: 'GET', + headers: getAuthHeader(), + success: function(poem) { + $('#poemId').val(poem.poem_id); + $('#title').val(poem.poem_name); + $('#author').val(poem.author_name); + $('#content').val(poem.poem_information.replace(/<[^>]+>/g, '')); + $('#explain').val(poem.explain); + + // 设置表单为只读 + $('#poemForm input, #poemForm textarea').prop('readonly', true); + $('#savePoem').hide(); + + $('#poemModal').modal('show'); + }, + error: handleAjaxError + }); +} + +// 编辑诗词 +function editPoem(poemId) { + $.ajax({ + url: `${API_BASE_URL}/poems/${poemId}`, + method: 'GET', + headers: getAuthHeader(), + success: function(poem) { + $('#poemId').val(poem.poem_id); + $('#title').val(poem.poem_name); + $('#author').val(poem.author_name); + $('#content').val(poem.poem_information.replace(/<[^>]+>/g, '')); + $('#explain').val(poem.explain); + + // 设置表单可编辑 + $('#poemForm input, #poemForm textarea').prop('readonly', false); + $('#savePoem').show(); + + $('#poemModal').modal('show'); + }, + error: handleAjaxError + }); +} + +function savePoem() { + const poemId = $('#poemId').val(); + const poemData = { + title: $('#title').val(), + author: $('#author').val(), + content: $('#content').val() + }; + + const url = poemId ? + `${API_BASE_URL}/poems/${poemId}` : + `${API_BASE_URL}/poems`; + const method = poemId ? 'PUT' : 'POST'; + + $.ajax({ + url: url, + method: method, + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + data: poemData, + success: function() { + $('#poemModal').modal('hide'); + loadPoems(); + } + }); +} + +function editPoem(poemId) { + $.ajax({ + url: `${API_BASE_URL}/poems/${poemId}`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + success: function(poem) { + $('#poemId').val(poem.id); + $('#title').val(poem.title); + $('#author').val(poem.author); + $('#content').val(poem.content); + $('#poemModal').modal('show'); + } + }); +} + +function deletePoem(poemId) { + if (confirm('确定要删除该诗词吗?')) { + $.ajax({ + url: `${API_BASE_URL}/poems/${poemId}`, + method: 'DELETE', + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + }, + success: function() { + loadPoems(); + } + }); + } +} + +function clearPoemForm() { + $('#poemId').val(''); + $('#poemForm')[0].reset(); +} + +// Authentication functions +function checkLoginStatus() { + const token = localStorage.getItem('adminToken'); + if (!token) { + window.location.href = 'login.html'; + return; + } + + $.ajax({ + url: `${API_BASE_URL}/admin/profile`, + method: 'GET', + headers: { 'Authorization': `Bearer ${token}` }, + success: function(admin) { + $('#adminInfo').text(`欢迎,管理员`); + }, + error: function() { + localStorage.removeItem('adminToken'); + window.location.href = 'login.html'; + } + }); +} + +function logout() { + localStorage.removeItem('adminToken'); + window.location.href = 'login.html'; +} + +// Helper functions +function getAuthHeader() { + return { + 'Authorization': `Bearer ${localStorage.getItem('adminToken')}` + }; +} + +function handleAjaxError(xhr) { + let message = '操作失败'; + if (xhr.responseJSON && xhr.responseJSON.message) { + message += ':' + xhr.responseJSON.message; + } + alert(message); + + if (xhr.status === 401) { + localStorage.removeItem('adminToken'); + window.location.href = 'login.html'; + } +} \ No newline at end of file diff --git a/admin/js/login.js b/admin/js/login.js new file mode 100644 index 0000000..926ac3c --- /dev/null +++ b/admin/js/login.js @@ -0,0 +1,70 @@ +$(document).ready(function() { + const API_BASE_URL = 'http://localhost:3000/api'; + + // 检查是否已登录 + const token = localStorage.getItem('adminToken'); + if (token) { + $.ajax({ + url: `${API_BASE_URL}/admin/profile`, + method: 'GET', + headers: { + 'Authorization': `Bearer ${token}` + }, + success: function() { + window.location.href = 'index.html'; + }, + error: function() { + localStorage.removeItem('adminToken'); + } + }); + } + + // 处理登录表单提交 + $('#loginForm').submit(function(e) { + e.preventDefault(); + + const loginData = { + username: $('#username').val().trim(), + password: $('#password').val().trim() + }; + + if (!loginData.username || !loginData.password) { + $('#errorAlert').text('请填写用户名和密码').show(); + return; + } + + // 显示加载状态 + $('#loginBtn').prop('disabled', true); + $('#loginBtn .spinner-border').removeClass('d-none'); + $('#errorAlert').hide(); + + // 发送登录请求 + $.ajax({ + url: `${API_BASE_URL}/admin/login`, + method: 'POST', + contentType: 'application/json', + data: JSON.stringify({ + admin_name: loginData.username || null, + admin_password: loginData.password || null, + role: 'admin' // 添加角色标识 + }), + success: function(response) { + console.log('Login response:', response); // 添加响应日志 + if (response && response.token) { + localStorage.setItem('adminToken', response.token); + window.location.href = 'index.html'; + } else { + $('#errorAlert').text('登录失败:未获取到token').show(); + } + }, + error: function(xhr) { + let errorMessage = '登录失败'; + if (xhr.responseJSON) { + console.error('Server error:', xhr.responseJSON); + errorMessage += ':' + (xhr.responseJSON.message || xhr.responseJSON.error || '未知错误'); + } + $('#errorAlert').text(errorMessage).show(); + } + }); + }); +}); \ No newline at end of file diff --git a/admin/login.html b/admin/login.html new file mode 100644 index 0000000..0b70f7e --- /dev/null +++ b/admin/login.html @@ -0,0 +1,48 @@ + + + + + + 管理员登录 - 诗词管理系统 + + + + +
+ +
+ + + + + \ No newline at end of file