From 3a4e0357a3017cd63c20a7a08fd8db0f226a6208 Mon Sep 17 00:00:00 2001 From: canglan Date: Thu, 16 Apr 2026 10:55:34 +0800 Subject: [PATCH] =?UTF-8?q?v0.8.6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/routes/admin.py | 40 +++++++++++++++++++++++++++++++- frontend/admin/admins.php | 14 ++++++++++++ frontend/admin/conduct.php | 47 ++++++++++++++++++++++++++------------ 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/backend/routes/admin.py b/backend/routes/admin.py index 2320634..56e863d 100644 --- a/backend/routes/admin.py +++ b/backend/routes/admin.py @@ -435,4 +435,42 @@ async def delete_admin(request: Request, user_id: int): ) return success_response(message="管理员删除成功") else: - return error_response(message="删除失败或管理员不存在") \ No newline at end of file + return error_response(message="删除失败或管理员不存在") + + +@router.post("/reset-password/{user_id}") +async def reset_admin_password(request: Request, user_id: int): + """重置管理员密码(班主任)""" + user = await get_current_user(request) + is_teacher = await PermissionChecker.check_is_teacher(user["user_id"]) + if not is_teacher: + return error_response(message="仅班主任可重置密码", code=403) + + from models.user import UserModel + from utils.security import SecurityUtils + + # 获取管理员信息 + target_user = await UserModel.get_by_user_id(user_id) + if not target_user: + return error_response(message="管理员不存在", code=404) + + if target_user["user_type"] != "admin": + return error_response(message="只能重置管理员密码", code=400) + + # 生成新密码 + new_password = SecurityUtils.generate_random_password(8) + password_hash = SecurityUtils.sha1_md5_password(new_password) + + # 更新密码 + updated = await UserModel.update_password(user_id, password_hash) + if updated: + await LogService.write_operation_log( + operator_id=user["user_id"], operator_name=user["username"], + operator_role="班主任", operation_type="reset_password", + target_type="admin", target_id=user_id, + details=f"重置管理员密码: {target_user['real_name']}({target_user['username']})", + ip=request.client.host + ) + return success_response(data={"password": new_password}, message="密码重置成功") + else: + return error_response(message="密码重置失败") \ No newline at end of file diff --git a/frontend/admin/admins.php b/frontend/admin/admins.php index 9a9b90d..dd16968 100644 --- a/frontend/admin/admins.php +++ b/frontend/admin/admins.php @@ -135,6 +135,7 @@ async function loadAdmins() { ${escapeHtml(admin.role_type)} + `; @@ -227,6 +228,19 @@ async function deleteAdmin(userId, realName) { } } +async function resetAdminPassword(userId, realName) { + if (!confirm(`确定要重置管理员 "${realName}" 的密码吗?`)) { + return; + } + + const res = await apiPost(`/api/admin/reset-password/${userId}`, {}); + if (res && res.success) { + alert(`密码重置成功!\n管理员:${realName}\n新密码:${res.data.password}\n请妥善保管并及时通知该管理员。`); + } else { + showToast(res?.message || '密码重置失败', 'error'); + } +} + function closeModal(modalId) { const modal = document.getElementById(modalId); if (modal) modal.style.display = 'none'; diff --git a/frontend/admin/conduct.php b/frontend/admin/conduct.php index 667a63a..d158b73 100644 --- a/frontend/admin/conduct.php +++ b/frontend/admin/conduct.php @@ -114,23 +114,39 @@ async function exportMoralityRecords() { return; } - // 获取每个学生的历史记录 + // 获取所有历史记录(不分页,获取全部) + const historyRes = await apiGet('/api/admin/conduct/history', { page: 1, page_size: 10000 }); + if (!historyRes || !historyRes.success) { + showToast('获取历史记录失败', 'error'); + return; + } + + const allRecords = historyRes.data.records || []; + + // 按学生ID分组历史记录 + const recordsByStudent = {}; + allRecords.forEach(record => { + const sid = record.student_id; + if (!recordsByStudent[sid]) { + recordsByStudent[sid] = []; + } + recordsByStudent[sid].push(record); + }); + + // 构建学生记录 const studentRecords = []; for (const student of students) { - const historyRes = await apiGet(`/api/student/conduct/${student.student_id}`, { limit: 1000 }); - if (historyRes && historyRes.success) { - const records = historyRes.data.records || []; - const positiveRecords = records.filter(r => r.points_change > 0).map(r => `${r.reason}(${r.points_change > 0 ? '+' : ''}${r.points_change})`); - const negativeRecords = records.filter(r => r.points_change < 0).map(r => `${r.reason}(${r.points_change})`); - - studentRecords.push({ - student_no: student.student_no, - name: student.name, - total_points: historyRes.data.total_points || 0, - positive_history: positiveRecords.join(', '), - negative_history: negativeRecords.join(', ') - }); - } + const studentRecords_list = recordsByStudent[student.student_id] || []; + const positiveRecords = studentRecords_list.filter(r => r.points_change > 0).map(r => `${r.reason}(+${r.points_change})`); + const negativeRecords = studentRecords_list.filter(r => r.points_change < 0).map(r => `${r.reason}(${r.points_change})`); + + studentRecords.push({ + student_no: student.student_no, + name: student.name, + total_points: student.total_points || 0, + positive_history: positiveRecords.join(','), + negative_history: negativeRecords.join(',') + }); } // 构建CSV内容 @@ -154,6 +170,7 @@ async function exportMoralityRecords() { showToast(`导出成功,共${studentRecords.length}名学生`); } catch (err) { showToast('导出失败:' + err.message, 'error'); + console.error('导出失败:', err); } }