Files
ClassManager/frontend/assets/js/history.js
2026-05-29 11:12:13 +08:00

196 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 班级操行分管理系统 - 历史记录页JS
*
* 开发者: Canglan
* 版权归属: Sea Network Technology Studio
*
* 版权所有 © Sea Network Technology Studio
*/
(function() {
'use strict';
const role = window.PAGE_CONFIG.role;
const currentUserId = window.PAGE_CONFIG.userId;
let currentHistoryPage = 1;
let totalHistoryPages = 1;
async function loadStudentsForSelect() {
const res = await apiGet('/api/admin/students', {page_size: 1000});
if (res && res.success) {
let html = '<option value="">全部</option>';
res.data.students.forEach(s => {
html += `<option value="${s.student_id}">${escapeHtml(s.student_no)} - ${escapeHtml(s.name)}</option>`;
});
document.getElementById('historyStudentId').innerHTML = html;
}
}
async function loadHistory(page = 1) {
currentHistoryPage = page;
const startDate = document.getElementById('historyStartDate').value;
const endDate = document.getElementById('historyEndDate').value;
const studentId = document.getElementById('historyStudentId').value;
const reasonFilter = document.getElementById('historyReasonFilter').value;
const isGrouped = document.getElementById('historyGrouped').checked;
const params = {
page, page_size: 20,
start_date: startDate,
end_date: endDate
};
if (studentId) params.student_id = studentId;
if (reasonFilter) params.reason_prefix = reasonFilter;
if (isGrouped) params.grouped = true;
const res = await apiGet('/api/admin/conduct/history', params);
if (res && res.success) {
const nowrapStyle = ' style="white-space: nowrap; min-width: 80px;"';
let headHtml = '';
if (isGrouped) {
headHtml = '<th>时间</th><th>原因</th><th>分值</th><th' + nowrapStyle + '>操作人</th><th>涉及学生</th>';
} else {
headHtml = '<th>时间</th><th>学生</th><th>分数变动</th><th>原因</th><th' + nowrapStyle + '>操作人</th>';
if (role === '班主任' || role === '班长' || role === '考勤委员') {
headHtml += '<th>操作</th>';
}
}
document.getElementById('historyTableHead').innerHTML = headHtml;
let html = '';
if (isGrouped) {
res.data.records.forEach(record => {
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
const names = record.student_names || '';
html += `<tr>
<td>${formatDateTime(record.created_at)}</td>
<td class="preserve-newlines">${escapeHtml(record.reason)}</td>
<td class="${pointsClass}">${record.points_change > 0 ? '+' : ''}${record.points_change}×${record.student_count}</td>
<td>${escapeHtml(record.recorder_name || '')}</td>
<td style="white-space: nowrap;">${escapeHtml(names)}</td>
</tr>`;
});
if (res.data.records.length === 0) {
html = '<tr><td colspan="5" style="text-align:center;">暂无记录</td></tr>';
}
} else {
res.data.records.forEach(record => {
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
const revokedStyle = record.is_revoked == 1 ? ' style="opacity:0.5; text-decoration:line-through;"' : '';
html += `<tr${revokedStyle}>
<td>${formatDateTime(record.created_at)}</td>
<td>${escapeHtml(record.student_name)}</td>
<td class="${pointsClass}">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
<td class="preserve-newlines">${escapeHtml(record.reason)}</td>
<td>${escapeHtml(record.recorder_name)}</td>`;
if (role === '班主任') {
if (record.is_revoked == 1) {
const revokerInfo = record.revoker_name ? `${escapeHtml(record.revoker_name)} 撤销` : '已撤销';
html += `<td><span class="text-muted" style="margin-right:4px;">${revokerInfo}</span><button class="btn btn-sm btn-secondary" onclick="restoreRecord(${record.record_id})">反撤销</button></td>`;
} else {
html += `<td><button class="btn btn-sm btn-danger" onclick="revokeRecord(${record.record_id})">撤销</button></td>`;
}
} else if (role === '班长') {
if (record.is_revoked == 1) {
const revokerInfo = record.revoker_name ? `${escapeHtml(record.revoker_name)} 撤销` : '已撤销';
html += `<td><span class="text-muted">${revokerInfo}</span></td>`;
} else {
html += `<td><button class="btn btn-sm btn-danger" onclick="revokeRecord(${record.record_id})">撤销</button></td>`;
}
} else if (role === '考勤委员') {
if (record.is_revoked == 1) {
html += `<td><span class="text-muted">已撤销</span></td>`;
} else if (record.recorder_id == currentUserId) {
html += `<td><button class="btn btn-sm btn-danger" onclick="revokeRecord(${record.record_id})">撤销</button></td>`;
} else {
html += `<td><span class="text-muted">-</span></td>`;
}
}
html += `</tr>`;
});
if (res.data.records.length === 0) {
const colSpan = (role === '班主任' || role === '班长' || role === '考勤委员') ? 6 : 5;
html = `<tr><td colspan="${colSpan}" style="text-align:center;">暂无记录</td></tr>`;
}
}
document.getElementById('historyList').innerHTML = html;
totalHistoryPages = res.data.total_pages || 1;
renderHistoryPagination();
}
}
function renderHistoryPagination() {
renderSmartPagination('historyPagination', currentHistoryPage, totalHistoryPages, function(page) {
loadHistory(page);
});
}
async function exportHistoryRecords() {
const startDate = document.getElementById('historyStartDate').value;
const endDate = document.getElementById('historyEndDate').value;
const studentId = document.getElementById('historyStudentId').value;
showToast('正在导出历史记录...', 'info');
try {
const reasonFilter = document.getElementById('historyReasonFilter').value;
const params = { page: 1, page_size: 1000 };
if (startDate) params.start_date = startDate;
if (endDate) params.end_date = endDate;
if (studentId) params.student_id = studentId;
if (reasonFilter) params.reason_prefix = reasonFilter;
const res = await apiGet('/api/admin/conduct/history', params);
if (res && res.success && res.data.records) {
const records = res.data.records;
if (records.length === 0) {
showToast('没有找到记录', 'warning');
return;
}
let csv = '\uFEFF';
csv += '时间,学号,姓名,分数变动,原因,操作人\n';
records.forEach(r => {
csv += `${r.created_at || ''},${r.student_no || ''},${r.student_name || ''},${r.points_change > 0 ? '+' : ''}${r.points_change},${(r.reason || '').replace(/,/g, ';')},${r.recorder_name || ''}\n`;
});
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `历史记录_${new Date().toISOString().slice(0,10)}.csv`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
showToast(`导出成功,共${records.length}条记录`);
} else {
showToast('导出失败:' + (res?.message || '未知错误'), 'error');
}
} catch (err) {
showToast('导出失败:' + err.message, 'error');
}
}
loadStudentsForSelect().then(() => {
const urlParams = new URLSearchParams(window.location.search);
const preStudentId = urlParams.get('student_id');
if (preStudentId) {
document.getElementById('historyStudentId').value = preStudentId;
loadHistory();
} else {
loadHistory();
}
});
window.loadHistory = loadHistory;
window.loadStudentsForSelect = loadStudentsForSelect;
window.exportHistoryRecords = exportHistoryRecords;
})();