Files
ClassManager/frontend/admin/conduct.php
2026-04-16 14:20:49 +08:00

229 lines
8.6 KiB
PHP
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.
<?php
/**
* 班级操行分管理系统 - 管理端操行分管理
*
* 开发者: Canglan
* 联系方式: admin@sea-studio.top
* 版权归属: Sea Network Technology Studio
* 许可证: MIT License
*
* 版权所有 © Sea Network Technology Studio
*/
require_once __DIR__ . '/../config.php';
if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'admin') {
header('Location: /index.php');
exit();
}
$page_title = '操行分管理';
$role = $_SESSION['role'] ?? '';
if (!in_array($role, ['班主任', '班长', '劳动委员', '志愿委员'])) {
header('Location: /admin/dashboard.php');
exit();
}
include __DIR__ . '/../includes/header.php';
?>
<?php include __DIR__ . '/../includes/nav.php'; ?>
<div class="container">
<div class="card">
<div class="action-bar">
<div class="action-buttons">
<button class="btn btn-primary" onclick="showBatchPointsModal()">批量加减分</button>
<?php if ($role === '班主任'): ?>
<button class="btn btn-secondary" onclick="exportMoralityRecords()">导出德育分记录</button>
<?php endif; ?>
</div>
</div>
<div class="table-wrapper">
<table class="table">
<thead>
<tr>
<th><input type="checkbox" id="selectAll" onclick="toggleSelectAll()"></th>
<th>学号</th>
<th>姓名</th>
<th>当前操行分</th>
<th>操作</th>
</tr>
</thead>
<tbody id="studentList"></tbody>
</table>
</div>
</div>
</div>
<script>
var selectedStudentIds = [];
async function loadStudents() {
const res = await apiGet('/api/admin/students', {page_size: 1000});
if (res && res.success) {
let html = '';
res.data.students.forEach(student => {
html += `<tr>
<td><input type="checkbox" class="student-checkbox" data-id="${student.student_id}"></td>
<td>${escapeHtml(student.student_no)}</td>
<td>${escapeHtml(student.name)}</td>
<td>${student.total_points}</td>
<td><button class="btn btn-sm btn-primary" onclick="showSinglePointsModal(${student.student_id}, '${escapeHtml(student.name)}')">加减分</button></td>
</tr>`;
});
if (res.data.students.length === 0) {
html = '<tr><td colspan="5" style="text-align:center;">暂无学生数据</td></tr>';
}
document.getElementById('studentList').innerHTML = html;
}
}
function toggleSelectAll() {
const selectAll = document.getElementById('selectAll');
document.querySelectorAll('.student-checkbox').forEach(cb => {
cb.checked = selectAll.checked;
});
}
function showSinglePointsModal(studentId, studentName) {
selectedStudentIds = [studentId];
document.getElementById('selectedStudentsCount').innerHTML = `${studentName} (1人)`;
document.getElementById('pointsChange').value = '';
document.getElementById('pointsReason').value = '';
document.getElementById('batchPointsModal').style.display = 'flex';
}
// 导出德育分记录(格式:学号 姓名 分数 加分历史 减分记录)
async function exportMoralityRecords() {
showToast('正在导出德育分记录...', 'info');
try {
// 获取所有学生
const studentsRes = await apiGet('/api/admin/students', { page_size: 1000 });
if (!studentsRes || !studentsRes.success) {
showToast('获取学生列表失败', 'error');
return;
}
const students = studentsRes.data.students;
if (students.length === 0) {
showToast('没有找到学生', 'warning');
return;
}
// 获取所有历史记录获取全部API限制最大1000条
const historyRes = await apiGet('/api/admin/conduct/history', { page: 1, page_size: 1000 });
if (!historyRes || !historyRes.success) {
showToast('获取历史记录失败', 'error');
return;
}
const allRecords = historyRes.data.records || [];
// 按学生ID分组历史记录
const recordsByStudent = {};
allRecords.forEach(record => {
const sid = record.student_id;
if (!recordsByStudent[sid]) {
recordsByStudent[sid] = [];
}
recordsByStudent[sid].push(record);
});
// 构建学生记录
const studentRecords = [];
for (const student of students) {
const studentRecords_list = recordsByStudent[student.student_id] || [];
const positiveRecords = studentRecords_list.filter(r => r.points_change > 0).map(r => `${r.reason}(+${r.points_change})`);
const negativeRecords = studentRecords_list.filter(r => r.points_change < 0).map(r => `${r.reason}(${r.points_change})`);
studentRecords.push({
student_no: student.student_no,
name: student.name,
total_points: student.total_points || 0,
positive_history: positiveRecords.join('; '),
negative_history: negativeRecords.join('; ')
});
}
// CSV字段转义函数
function escapeCsvField(field) {
if (field === null || field === undefined) return '';
// 移除换行符和回车符
let str = String(field).replace(/[\r\n]+/g, ' ');
// 转义双引号
str = str.replace(/"/g, '""');
// 如果包含逗号、分号、双引号或空格,用双引号包裹
if (/[\,\;\"\s]/.test(str)) {
str = '"' + str + '"';
}
return str;
}
// 构建CSV内容
let csv = '\uFEFF'; // BOM for UTF-8
csv += '学号,姓名,分数,加分历史,减分记录\n';
studentRecords.forEach(s => {
csv += `${escapeCsvField(s.student_no)},${escapeCsvField(s.name)},${escapeCsvField(s.total_points)},${escapeCsvField(s.positive_history)},${escapeCsvField(s.negative_history)}\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(`导出成功,共${studentRecords.length}名学生`);
} catch (err) {
showToast('导出失败:' + err.message, 'error');
console.error('导出失败:', err);
}
}
loadStudents();
</script>
<script src="/assets/js/admin.js"></script>
<!-- 批量加减分模态框 -->
<div id="batchPointsModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>批量加减分</h3>
<button class="modal-close" onclick="closeModal('batchPointsModal')">&times;</button>
</div>
<form onsubmit="event.preventDefault(); submitBatchPoints()">
<div class="form-group">
<label>选中学生</label>
<div id="selectedStudentsCount">0 人</div>
</div>
<div class="form-group">
<label>分数变动</label>
<input type="number" id="pointsChange" required placeholder="正数为加分,负数为扣分">
<small><?php
if ($role === '班长') echo '班长单次±5分以内';
elseif ($role === '劳动委员') echo '劳动委员仅限±1分';
elseif ($role === '志愿委员') echo '志愿委员仅限加分';
else echo '班主任无限制';
?></small>
</div>
<div class="form-group">
<label>原因</label>
<textarea id="pointsReason" required rows="3" placeholder="请填写加减分原因"></textarea>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">确认提交</button>
<button type="button" class="btn" onclick="closeModal('batchPointsModal')">取消</button>
</div>
</form>
</div>
</div>
<?php include __DIR__ . '/../includes/footer.php'; ?>