v2.2更新

This commit is contained in:
2026-05-28 15:38:32 +08:00
parent f84c9d3efb
commit ca53fdc349
38 changed files with 688 additions and 686 deletions

View File

@@ -132,13 +132,8 @@ function formatDateTime(dateStr) {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
}
function getStatusBadge(status, type = 'homework') {
function getStatusBadge(status, type = 'attendance') {
const statusMap = {
homework: {
'submitted': '已提交',
'not_submitted': '未提交',
'late': '迟交'
},
attendance: {
'present': '出勤',
'absent': '缺勤',
@@ -146,15 +141,13 @@ function getStatusBadge(status, type = 'homework') {
'leave': '请假'
}
};
const texts = statusMap[type] || statusMap.homework;
const texts = statusMap[type] || statusMap.attendance;
const text = texts[status] || status;
let className = 'status-badge ';
switch (status) {
case 'submitted':
case 'present':
className += 'status-submitted';
break;
case 'not_submitted':
case 'absent':
className += 'status-not_submitted';
break;

View File

@@ -118,11 +118,113 @@ async function exportMoralityRecords() {
console.error('导出失败:', err);
}
}
// 宿舍集体加分相关
var dormitoryStudentIds = [];
async function showDormitoryPointsModal() {
dormitoryStudentIds = [];
document.getElementById('dormitorySelect').innerHTML = '<option value="">-- 请选择宿舍 --</option>';
document.getElementById('dormitoryStudentsGroup').style.display = 'none';
document.getElementById('dormitoryStudentsList').innerHTML = '';
document.getElementById('dormitoryPointsChange').value = '';
document.getElementById('dormitoryPointsReason').value = '';
// 加载宿舍列表
const res = await apiGet('/api/admin/students/dormitories');
if (res && res.success && res.data.dormitories) {
const select = document.getElementById('dormitorySelect');
res.data.dormitories.forEach(d => {
const option = document.createElement('option');
option.value = d;
option.textContent = d;
select.appendChild(option);
});
}
document.getElementById('dormitoryPointsModal').style.display = 'flex';
}
async function onDormitorySelected() {
const dormitory = document.getElementById('dormitorySelect').value;
const studentsGroup = document.getElementById('dormitoryStudentsGroup');
const studentsList = document.getElementById('dormitoryStudentsList');
const studentsCount = document.getElementById('dormitoryStudentsCount');
dormitoryStudentIds = [];
studentsList.innerHTML = '';
if (!dormitory) {
studentsGroup.style.display = 'none';
return;
}
// 加载该宿舍的学生
const res = await apiGet('/api/admin/students', { dormitory_number: dormitory, page_size: 1000 });
if (res && res.success && res.data.students) {
const students = res.data.students;
if (students.length === 0) {
studentsList.innerHTML = '<p style="color: var(--text-secondary);">该宿舍暂无学生</p>';
studentsCount.textContent = '';
} else {
students.forEach(s => {
dormitoryStudentIds.push(s.student_id);
const div = document.createElement('div');
div.style.cssText = 'display: flex; justify-content: space-between; padding: 4px 0; border-bottom: 1px solid var(--border-color);';
div.innerHTML = `<span>${escapeHtml(s.name)}</span><span style="color: var(--text-secondary);">${escapeHtml(s.student_no)}</span>`;
studentsList.appendChild(div);
});
studentsCount.textContent = `${students.length}`;
}
studentsGroup.style.display = 'block';
} else {
studentsList.innerHTML = '<p style="color: var(--text-secondary);">加载失败</p>';
studentsGroup.style.display = 'block';
}
}
async function submitDormitoryPoints() {
if (dormitoryStudentIds.length === 0) {
showToast('该宿舍没有学生', 'warning');
return;
}
const pointsChange = parseInt(document.getElementById('dormitoryPointsChange').value);
const reason = document.getElementById('dormitoryPointsReason').value;
if (isNaN(pointsChange) || pointsChange === 0) {
showToast('分值不能为0', 'error');
return;
}
if (!reason.trim()) {
showToast('请填写原因', 'error');
return;
}
const data = {
student_ids: dormitoryStudentIds,
points_change: pointsChange,
reason: reason
};
const res = await apiPost('/api/admin/conduct/add', data);
if (res && res.success) {
showToast(`操作成功: ${res.data.success_count} 人成功`);
closeModal('dormitoryPointsModal');
loadStudents();
} else {
showToast(res?.message || '操作失败', 'error');
}
}
loadStudents();
window.loadStudents = loadStudents;
window.showSinglePointsModal = showSinglePointsModal;
window.exportMoralityRecords = exportMoralityRecords;
window.showDormitoryPointsModal = showDormitoryPointsModal;
window.onDormitorySelected = onDormitorySelected;
window.submitDormitoryPoints = submitDormitoryPoints;
})();

View File

@@ -25,9 +25,15 @@ async function loadDashboard() {
}
let quickActions = '';
if (role === '班主任' || role === '班长' || role === '劳动委员' || role === '志愿委员') {
if (role === '班主任' || role === '班长' || role === '学习委员' || role === '劳动委员' || role === '志愿委员') {
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
}
if (role === '班主任' || role === '学习委员') {
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/homework.php\'">作业扣分</button>';
}
if (role === '班主任' || role === '考勤委员') {
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/attendance.php\'">考勤管理</button>';
}
if (role === '班主任') {
quickActions += '<button class="btn btn-outline" onclick="location.href=\'/admin/students.php\'">导入学生</button>';
quickActions += '<button class="btn btn-secondary" onclick="location.href=\'/admin/conduct.php\'">导出德育分记录</button>';

View File

@@ -40,7 +40,7 @@ async function loadHistory(page = 1) {
end_date: endDate
};
if (studentId) params.student_id = studentId;
if (relatedType && !isGrouped) params.related_type = relatedType;
if (relatedType) params.related_type = relatedType;
if (isGrouped) params.grouped = true;
const res = await apiGet('/api/admin/conduct/history', params);

View File

@@ -146,7 +146,7 @@
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 += '<th>学号</th><th>姓名</th><th>家长手机号</th><th>宿舍号</th><th>初始密码</th>';
html += '</tr></thead><tbody>';
students.forEach(s => {
@@ -154,6 +154,7 @@
<td>${escapeHtml(s.student_no || '')}</td>
<td>${escapeHtml(s.name || '')}</td>
<td>${escapeHtml(s.parent_phone || '')}</td>
<td>${escapeHtml(s.dormitory_number || '-')}</td>
<td>${escapeHtml(s.password || '123456')}</td>
</tr>`;
});

View File

@@ -16,25 +16,18 @@ async function loadHomework() {
const res = await apiGet(`/api/student/homework/${STUDENT_ID}`);
if (res && res.success) {
let html = '';
res.data.homework.forEach(hw => {
// 提交状态
let statusDisplay = '-';
if (hw.status) {
statusDisplay = getStatusBadge(hw.status, 'homework');
}
// 扣分显示
const pointsDisplay = hw.points ? `<span class="text-danger">${hw.points}分</span>` : '-';
res.data.homework.forEach(record => {
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
const pointsColor = record.points_change > 0 ? '#38a169' : '#e53e3e';
html += `<tr>
<td>${escapeHtml(hw.title)}</td>
<td>${escapeHtml(hw.subject_name)}</td>
<td>${hw.deadline || '-'}</td>
<td>${statusDisplay}</td>
<td>${pointsDisplay}</td>
<td>${formatDateTime(record.created_at)}</td>
<td style="color: ${pointsColor}; font-weight: bold;">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
<td>${escapeHtml(record.reason)}</td>
<td>${escapeHtml(record.recorder_name || '-')}</td>
</tr>`;
});
if (res.data.homework.length === 0) {
html = '<tr><td colspan="5" style="text-align:center; padding: 40px; color: #999;">📝 暂无作业记录</td></tr>';
html = '<tr><td colspan="4" style="text-align:center; padding: 40px; color: #999;">📝 暂无作业扣分记录</td></tr>';
}
document.getElementById('homeworkList').innerHTML = html;
}

View File

@@ -1,102 +0,0 @@
/**
* 班级操行分管理系统 - 科目管理页JS
*
* 开发者: Canglan
* 版权归属: Sea Network Technology Studio
*
* 版权所有 © Sea Network Technology Studio
*/
(function() {
'use strict';
async function loadSubjects() {
const res = await apiGet('/api/subject/list');
if (res && res.success) {
let html = '';
res.data.subjects.forEach(sub => {
html += `
<div class="subject-item">
<span class="subject-name">${escapeHtml(sub.subject_name)}</span>
<span class="subject-code">${escapeHtml(sub.subject_code || '')}</span>
<span class="subject-status ${sub.is_active ? 'subject-status-active' : 'subject-status-inactive'}">
${sub.is_active ? '启用' : '禁用'}
</span>
<button class="btn btn-sm btn-outline" onclick="showEditSubjectModal(${sub.subject_id}, '${escapeHtml(sub.subject_name)}', '${escapeHtml(sub.subject_code || '')}', ${sub.sort_order || 0})">编辑</button>
<button class="btn btn-sm btn-ghost" onclick="toggleSubject(${sub.subject_id}, ${!sub.is_active})">
${sub.is_active ? '禁用' : '启用'}
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteSubject(${sub.subject_id})">删除</button>
</div>
`;
});
if (res.data.subjects.length === 0) {
html = '<p style="text-align:center;padding:40px;">暂无科目,请点击"添加科目"</p>';
}
document.getElementById('subjectList').innerHTML = html;
}
}
async function toggleSubject(subjectId, enable) {
const res = await apiPut(`/api/subject/update/${subjectId}`, { is_active: enable });
if (res && res.success) {
showToast(enable ? '科目已启用' : '科目已禁用');
loadSubjects();
} else {
showToast(res?.message || '操作失败', 'error');
}
}
async function deleteSubject(subjectId) {
if (!confirm('确定要删除该科目吗?')) return;
const res = await apiDelete('/api/subject/delete/' + subjectId);
if (res && res.success) {
showToast('科目删除成功');
loadSubjects();
} else {
showToast(res?.message || '删除失败', 'error');
}
}
function showEditSubjectModal(subjectId, name, code, sortOrder) {
document.getElementById('editSubjectId').value = subjectId;
document.getElementById('editSubjectName').value = name;
document.getElementById('editSubjectCode').value = code;
document.getElementById('editSubjectSortOrder').value = sortOrder;
document.getElementById('editSubjectModal').style.display = 'flex';
}
async function submitEditSubject() {
const subjectId = document.getElementById('editSubjectId').value;
const subjectName = document.getElementById('editSubjectName').value.trim();
const subjectCode = document.getElementById('editSubjectCode').value.trim();
const sortOrder = document.getElementById('editSubjectSortOrder').value;
if (!subjectName) {
showToast('请填写科目名称', 'warning');
return;
}
const data = { subject_name: subjectName };
if (subjectCode) data.subject_code = subjectCode;
if (sortOrder !== '') data.sort_order = parseInt(sortOrder);
const res = await apiPut(`/api/subject/update/${subjectId}`, data);
if (res && res.success) {
showToast('科目更新成功');
closeModal('editSubjectModal');
loadSubjects();
} else {
showToast(res?.message || '更新失败', 'error');
}
}
loadSubjects();
window.loadSubjects = loadSubjects;
window.toggleSubject = toggleSubject;
window.deleteSubject = deleteSubject;
window.showEditSubjectModal = showEditSubjectModal;
window.submitEditSubject = submitEditSubject;
})();