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);
}
}