288 lines
8.7 KiB
JavaScript
288 lines
8.7 KiB
JavaScript
/**
|
||
* 班级操行分管理系统 - 管理端JS
|
||
*
|
||
* 开发者: Canglan
|
||
* 联系方式: admin@sea-studio.top
|
||
* 版权归属: Sea Network Technology Studio
|
||
* 许可证: MIT License
|
||
*
|
||
* 版权所有 © Sea Network Technology Studio
|
||
*/
|
||
|
||
// 全局变量(使用 var 避免与页面级 let 重复声明冲突)
|
||
var selectedStudentIds = [];
|
||
var currentPage = 1;
|
||
var totalPages = 1;
|
||
var currentHistoryPage = 1;
|
||
|
||
// 显示批量加减分模态框
|
||
function showBatchPointsModal() {
|
||
selectedStudentIds = [];
|
||
document.querySelectorAll('.student-checkbox:checked').forEach(cb => {
|
||
selectedStudentIds.push(parseInt(cb.dataset.id));
|
||
});
|
||
|
||
if (selectedStudentIds.length === 0) {
|
||
showToast('请先选择学生', 'warning');
|
||
return;
|
||
}
|
||
|
||
document.getElementById('selectedStudentsCount').innerHTML = `${selectedStudentIds.length} 人`;
|
||
document.getElementById('pointsChange').value = '';
|
||
document.getElementById('pointsReason').value = '';
|
||
document.getElementById('batchPointsModal').style.display = 'flex';
|
||
}
|
||
|
||
// 提交批量加减分
|
||
async function submitBatchPoints() {
|
||
const pointsChange = parseInt(document.getElementById('pointsChange').value);
|
||
const reason = document.getElementById('pointsReason').value;
|
||
|
||
if (isNaN(pointsChange) || pointsChange === 0) {
|
||
showToast('分值不能为0', 'error');
|
||
return;
|
||
}
|
||
|
||
if (!reason.trim()) {
|
||
showToast('请填写原因', 'error');
|
||
return;
|
||
}
|
||
|
||
const res = await apiPost('/api/admin/conduct/add', {
|
||
student_ids: selectedStudentIds,
|
||
points_change: pointsChange,
|
||
reason: reason
|
||
});
|
||
|
||
if (res && res.success) {
|
||
showToast(`操作成功: ${res.data.success_count} 人成功`);
|
||
closeModal('batchPointsModal');
|
||
loadStudents();
|
||
if (typeof loadConductStudents === 'function') loadConductStudents();
|
||
} 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>';
|
||
html += '</tr></thead><tbody>';
|
||
|
||
students.forEach(s => {
|
||
html += `<tr>
|
||
<td>${escapeHtml(s.student_no || '')}</td>
|
||
<td>${escapeHtml(s.name || '')}</td>
|
||
<td>${escapeHtml(s.parent_phone || '')}</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();
|
||
} else {
|
||
showToast(result.message, 'error');
|
||
}
|
||
}
|
||
|
||
// 显示新增学生模态框
|
||
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_phone: parentPhone
|
||
});
|
||
|
||
if (res && res.success) {
|
||
showToast('学生添加成功');
|
||
closeModal('addStudentModal');
|
||
loadStudents();
|
||
} else {
|
||
showToast(res?.message || '添加失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 显示添加管理员模态框
|
||
function showAddAdminModal() {
|
||
document.getElementById('addAdminModal').style.display = 'flex';
|
||
document.getElementById('addAdminForm').reset();
|
||
}
|
||
|
||
// 提交添加管理员
|
||
async function submitAddAdmin() {
|
||
const username = document.getElementById('adminUsername').value.trim();
|
||
const realName = document.getElementById('adminRealName').value.trim();
|
||
const password = document.getElementById('adminPassword').value;
|
||
const roleType = document.getElementById('adminRole').value;
|
||
|
||
if (!username || !realName || !roleType) {
|
||
showToast('请填写完整信息', 'warning');
|
||
return;
|
||
}
|
||
|
||
const res = await apiPost('/api/admin/add', {
|
||
username: username,
|
||
real_name: realName,
|
||
password: password || undefined,
|
||
role_type: roleType
|
||
});
|
||
|
||
if (res && res.success) {
|
||
let msg = `管理员 ${res.data.username} 添加成功`;
|
||
if (res.data.password) msg += `,密码: ${res.data.password}`;
|
||
showToast(msg);
|
||
closeModal('addAdminModal');
|
||
loadAdmins();
|
||
} else {
|
||
showToast(res?.message || '添加失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 显示添加科目模态框
|
||
function showAddSubjectModal() {
|
||
document.getElementById('addSubjectModal').style.display = 'flex';
|
||
document.getElementById('addSubjectForm').reset();
|
||
}
|
||
|
||
// 提交添加科目
|
||
async function submitAddSubject() {
|
||
const subjectName = document.getElementById('subjectName').value.trim();
|
||
const subjectCode = document.getElementById('subjectCode').value.trim();
|
||
|
||
if (!subjectName) {
|
||
showToast('请填写科目名称', 'warning');
|
||
return;
|
||
}
|
||
|
||
const res = await apiPost('/api/subject/create', {
|
||
subject_name: subjectName,
|
||
subject_code: subjectCode
|
||
});
|
||
|
||
if (res && res.success) {
|
||
showToast('科目添加成功');
|
||
closeModal('addSubjectModal');
|
||
loadSubjects();
|
||
} else {
|
||
showToast(res?.message || '添加失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 撤销扣分记录
|
||
async function revokeRecord(recordId) {
|
||
if (!confirm('确定要撤销这条扣分记录吗?')) return;
|
||
|
||
const res = await apiPost('/api/admin/conduct/revoke', { record_id: recordId });
|
||
if (res && res.success) {
|
||
showToast('撤销成功');
|
||
loadHistory(currentHistoryPage);
|
||
} else {
|
||
showToast(res?.message || '撤销失败', 'error');
|
||
}
|
||
}
|
||
|
||
// 关闭模态框
|
||
function closeModal(modalId) {
|
||
const modal = document.getElementById(modalId);
|
||
if (modal) {
|
||
modal.style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// HTML转义
|
||
function escapeHtml(str) {
|
||
if (!str) return '';
|
||
return str.replace(/[&<>]/g, function(m) {
|
||
if (m === '&') return '&';
|
||
if (m === '<') return '<';
|
||
if (m === '>') return '>';
|
||
return m;
|
||
});
|
||
}
|
||
|
||
// 全选功能
|
||
function toggleSelectAll() {
|
||
const selectAll = document.getElementById('selectAll');
|
||
if (selectAll) {
|
||
document.querySelectorAll('.student-checkbox').forEach(cb => {
|
||
cb.checked = selectAll.checked;
|
||
});
|
||
}
|
||
}
|
||
|
||
// 绑定文件选择事件
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
const fileInput = document.getElementById('importFile');
|
||
if (fileInput) {
|
||
fileInput.addEventListener('change', previewImportFile);
|
||
}
|
||
}); |