feat: 多班级版班级管理系统 v2.0
技术栈:Go (Gin + GORM) + PHP + MySQL 5.7 + Redis 主要功能: - 多班级完全隔离(class_id 贯穿全系统) - 后端从 Python FastAPI 重写为 Go Gin(端口 56789) - 超级管理员独立登录(env 配置路径,默认账密 admin/Admin123) - 科任老师/课代表新角色 - 课代表作业管理页面 - 排行榜分项排行(操行分/考勤/作业) - 角色加减分上下限由班主任配置 - 家长改密功能(可开关) - 班级角色按需开关 - 宿舍号格式:南0-000 - 周度/月度重置功能 - MySQL 5.7 兼容 - Nginx 反向代理部署 开发者: Canglan 版权归属: Sea Network Technology Studio 许可证: Apache License 2.0
This commit is contained in:
234
frontend/assets/js/modules/student-mgmt.js
Normal file
234
frontend/assets/js/modules/student-mgmt.js
Normal 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;
|
||||
})();
|
||||
Reference in New Issue
Block a user