Files
ClassManager/frontend/admin/attendance.php
2026-04-07 17:07:13 +08:00

184 lines
6.8 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';
?>
<div class="nav">
<a href="/admin/dashboard.php" class="nav-item">首页</a>
<a href="/admin/students.php" class="nav-item">学生管理</a>
<?php if ($role === '班主任' || $role === '班长'): ?>
<a href="/admin/conduct.php" class="nav-item">操行分管理</a>
<?php endif; ?>
<?php if ($role === '班主任' || $role === '科代表'): ?>
<a href="/admin/homework.php" class="nav-item">作业管理</a>
<?php endif; ?>
<a href="/admin/attendance.php" class="nav-item active">考勤管理</a>
<?php if ($role === '班主任'): ?>
<a href="/admin/subjects.php" class="nav-item">科目管理</a>
<a href="/admin/admins.php" class="nav-item">管理员管理</a>
<?php endif; ?>
<a href="/admin/history.php" class="nav-item">历史记录</a>
<a href="/admin/password.php" class="nav-item">修改密码</a>
</div>
<div class="container">
<div class="card">
<div class="action-bar">
<button class="btn btn-primary" onclick="showAddAttendanceModal()">添加考勤</button>
<div class="search-bar">
<input type="date" id="attendanceDate" value="<?php echo date('Y-m-d'); ?>">
<button class="btn btn-primary" onclick="loadAttendanceRecords()">查询</button>
</div>
</div>
<div class="table-wrapper">
<table class="table">
<thead>
<tr><th>学号</th><th>姓名</th><th>状态</th><th>原因</th><th>记录人</th><th>扣分</th></tr>
</thead>
<tbody id="attendanceList"></tbody>
</table>
</div>
</div>
</div>
<!-- 添加考勤模态框 -->
<div id="addAttendanceModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>添加考勤记录</h3>
<button class="modal-close" onclick="closeModal('addAttendanceModal')">&times;</button>
</div>
<form onsubmit="event.preventDefault(); submitAddAttendance()">
<div class="form-group">
<label>学生</label>
<select id="attendanceStudentId" required></select>
</div>
<div class="form-group">
<label>日期</label>
<input type="date" id="attAttendanceDate" required>
</div>
<div class="form-group">
<label>状态</label>
<select id="attendanceStatus" required>
<option value="present">出勤</option>
<option value="absent">缺勤</option>
<option value="late">迟到</option>
<option value="leave">请假</option>
</select>
</div>
<div class="form-group">
<label>原因</label>
<input type="text" id="attendanceReason" placeholder="缺勤/迟到/请假原因">
</div>
<div class="form-group">
<label><input type="checkbox" id="attendanceDeduct"> 同时扣分</label>
<small>扣分规则:缺勤-5分迟到-2分请假-1分</small>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">提交</button>
<button type="button" class="btn" onclick="closeModal('addAttendanceModal')">取消</button>
</div>
</form>
</div>
</div>
<script>
async function loadAttendanceRecords() {
const date = document.getElementById('attendanceDate').value;
const res = await apiGet('/api/admin/attendance/records', { date });
if (res && res.success) {
let html = '';
res.data.records.forEach(record => {
html += `<tr>
<td>${escapeHtml(record.student_no)}</td>
<td>${escapeHtml(record.student_name)}</td>
<td>${getStatusBadge(record.status, 'attendance')}</td>
<td>${escapeHtml(record.reason || '-')}</td>
<td>${escapeHtml(record.recorder_name || '-')}</td>
<td>${record.deduction_applied ? '已扣分' : '-'}</td>
</tr>`;
});
if (res.data.records.length === 0) {
html = '<tr><td colspan="6" style="text-align:center;">暂无考勤记录</td></tr>';
}
document.getElementById('attendanceList').innerHTML = html;
}
}
async function loadStudentsForSelect() {
const res = await apiGet('/api/admin/students');
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('attendanceStudentId').innerHTML = html;
}
}
async function showAddAttendanceModal() {
await loadStudentsForSelect();
document.getElementById('addAttendanceModal').style.display = 'flex';
document.getElementById('attAttendanceDate').value = new Date().toISOString().split('T')[0];
}
async function submitAddAttendance() {
const studentId = document.getElementById('attendanceStudentId').value;
const date = document.getElementById('attAttendanceDate').value;
const status = document.getElementById('attendanceStatus').value;
const reason = document.getElementById('attendanceReason').value;
const applyDeduction = document.getElementById('attendanceDeduct').checked;
if (!studentId || !date || !status) {
showToast('请填写完整信息', 'warning');
return;
}
const res = await apiPost('/api/admin/attendance', {
student_id: parseInt(studentId),
date: date,
status: status,
reason: reason,
apply_deduction: applyDeduction
});
if (res && res.success) {
showToast('考勤记录添加成功');
closeModal('addAttendanceModal');
loadAttendanceRecords();
} else {
showToast(res?.message || '添加失败', 'error');
}
}
loadAttendanceRecords();
</script>
<script src="/assets/js/admin.js"></script>
<?php include __DIR__ . '/../includes/footer.php'; ?>