feat: 多班级版班级管理系统 v2.0

技术栈:Go (Gin + GORM) + PHP + MySQL 5.7 + Redis

主要功能:
- 多班级完全隔离(class_id 贯穿全系统)
- 后端 Go Gin(端口 56789),Nginx 反代
- 超级管理员独立登录(env 配置,默认账密 admin/Admin123)
- bcrypt 密码加密(无 PASSWORD_SALT)
- 科任老师/课代表新角色
- 课代表作业管理页面
- 排行榜分项排行(操行分/考勤/作业)
- 角色加减分上下限由班主任配置
- 家长改密功能(可开关)
- 班级角色按需开关
- 宿舍号格式:南0-000
- 周度/月度重置功能
- MySQL 5.7 兼容
- 43 轮代码审查 + 全部修复

开发者: Canglan
版权归属: Sea Network Technology Studio
许可证: Apache License 2.0
This commit is contained in:
2026-06-22 10:21:52 +08:00
commit c6db68a9f4
135 changed files with 19933 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
/**
* 多班级版班级管理系统 - 学生管理函数
*
* 开发者: Canglan
* 联系方式: admin@sea-studio.top
* 版权归属: Sea Network Technology Studio
* 许可证: Apache License 2.0
*
* 版权所有 © Sea Network Technology Studio
*/
(function() {
'use strict';
// 显示新增学生模态框
function showAddStudentModal() {
document.getElementById('addStudentModal').style.display = 'flex';
document.getElementById('addStudentForm').reset();
}
// 提交新增学生
async function submitAddStudent() {
const studentNo = document.getElementById('studentNo').value.trim();
const name = document.getElementById('studentName').value.trim();
const parentPhone = document.getElementById('parentPhone').value.trim();
if (!studentNo || !name) {
showToast('请填写学号和姓名', 'warning');
return;
}
const res = await apiPost('/api/admin/students', {
student_no: studentNo,
name: name,
parent_account: parentPhone,
dormitory_number: document.getElementById('addDormitoryNumber').value.trim()
});
if (res && res.success) {
showToast('学生添加成功');
closeModal('addStudentModal');
loadStudents();
} else {
showToast(res?.message || '添加失败', 'error');
}
}
// 显示编辑学生模态框
function showEditStudentModal(studentId, studentNo, name, phone, dormitoryNumber) {
document.getElementById('editStudentId').value = studentId;
document.getElementById('editStudentNo').value = studentNo;
document.getElementById('editStudentName').value = name;
document.getElementById('editStudentPhone').value = phone || '';
document.getElementById('editDormitoryNumber').value = dormitoryNumber || '';
document.getElementById('editStudentModal').style.display = 'flex';
}
// 提交编辑学生
async function submitEditStudent() {
const studentId = document.getElementById('editStudentId').value;
const name = document.getElementById('editStudentName').value.trim();
const phone = document.getElementById('editStudentPhone').value.trim();
if (!name) {
showToast('请输入姓名', 'warning');
return;
}
const res = await apiPut(`/api/admin/students/${studentId}`, {
name: name,
parent_account: phone || null,
dormitory_number: document.getElementById('editDormitoryNumber').value.trim()
});
if (res && res.success) {
showToast('学生信息更新成功');
closeModal('editStudentModal');
location.reload();
} else {
showToast(res?.message || '更新失败', 'error');
}
}
// 显示重置学生密码模态框
function showResetStudentPasswordModal(studentId, name) {
document.getElementById('resetStudentId').value = studentId;
document.getElementById('resetStudentInfo').textContent = `正在重置学生 "${name}" 的密码`;
document.getElementById('newStudentPassword').value = '';
document.getElementById('resetStudentPasswordModal').style.display = 'flex';
}
// 提交重置学生密码
async function submitResetStudentPassword() {
const studentId = document.getElementById('resetStudentId').value;
const newPassword = document.getElementById('newStudentPassword').value;
if (!newPassword || newPassword.length < 6) {
showToast('密码至少6位', 'warning');
return;
}
const res = await apiPost(`/api/admin/students/reset-password/${studentId}`, {
new_password: newPassword
});
if (res && res.success) {
showToast('密码重置成功');
closeModal('resetStudentPasswordModal');
} else {
showToast(res?.message || '重置失败', 'error');
}
}
// 删除学生
async function deleteStudent(studentId, name) {
if (!confirm(`确定要删除学生 "${name}" 吗?删除后学生账号将被禁用。`)) return;
const res = await apiDelete(`/api/admin/students/${studentId}`);
if (res && res.success) {
showToast('学生删除成功');
location.reload();
} else {
showToast(res?.message || '删除失败', 'error');
}
}
// 显示导入模态框
function showImportModal() {
document.getElementById('importModal').style.display = 'flex';
document.getElementById('importPreview').style.display = 'none';
document.getElementById('importPreview').innerHTML = '';
document.getElementById('importBtn').style.display = 'none';
document.getElementById('importFile').value = '';
}
// 预览导入文件
function previewImportFile() {
const file = document.getElementById('importFile').files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
const students = data.students || [];
let html = '<h4>预览数据</h4><div class="table-wrapper"><table><thead><tr>';
html += '<th>学号</th><th>姓名</th><th>家长账号(推荐手机号)</th><th>宿舍号</th><th>初始密码</th>';
html += '</tr></thead><tbody>';
students.forEach(s => {
html += `<tr>
<td>${escapeHtml(s.student_no || '')}</td>
<td>${escapeHtml(s.name || '')}</td>
<td>${escapeHtml(s.parent_account || '')}</td>
<td>${escapeHtml(s.dormitory_number || '-')}</td>
<td>${escapeHtml(s.password || '123456')}</td>
</tr>`;
});
html += `</tbody></table></div><p>共 ${students.length} 条记录初始操行分默认为60分</p>`;
document.getElementById('importPreview').innerHTML = html;
document.getElementById('importPreview').style.display = 'block';
document.getElementById('importBtn').style.display = 'inline-block';
} catch (error) {
showToast('JSON格式错误', 'error');
}
};
reader.readAsText(file);
}
// 执行导入
async function doImport() {
const file = document.getElementById('importFile').files[0];
if (!file) {
showToast('请选择文件', 'warning');
return;
}
const formData = new FormData();
formData.append('file', file);
const token = getToken();
const response = await fetch(`${API_BASE_URL}/api/admin/students/import`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`
},
body: formData
});
const result = await response.json();
if (result.success) {
showToast(result.message);
closeModal('importModal');
loadStudents();
// 显示详细导入结果
if (result.data && result.data.results) {
const failedList = result.data.results.filter(r => !r.success);
if (failedList.length > 0) {
let detail = '失败详情:\n';
failedList.forEach(r => {
detail += `${r.student_no || '未知'}: ${r.error}\n`;
});
alert(detail);
}
}
} else {
showToast(result.message, 'error');
}
}
// 绑定文件选择事件
document.addEventListener('DOMContentLoaded', () => {
const fileInput = document.getElementById('importFile');
if (fileInput) {
fileInput.addEventListener('change', previewImportFile);
}
});
window.showAddStudentModal = showAddStudentModal;
window.submitAddStudent = submitAddStudent;
window.showEditStudentModal = showEditStudentModal;
window.submitEditStudent = submitEditStudent;
window.showResetStudentPasswordModal = showResetStudentPasswordModal;
window.submitResetStudentPassword = submitResetStudentPassword;
window.deleteStudent = deleteStudent;
window.showImportModal = showImportModal;
window.previewImportFile = previewImportFile;
window.doImport = doImport;
})();