修复学期功能

This commit is contained in:
2026-04-22 02:37:27 +08:00
parent 4121e9624f
commit 8f77251910
8 changed files with 388 additions and 37 deletions

View File

@@ -35,9 +35,16 @@ include __DIR__ . '/../includes/header.php';
<div class="card">
<div class="card-title">操行分排行榜</div>
<div class="table-wrapper">
<div style="display: flex; align-items: center; margin-bottom: 12px; gap: 8px;">
<span style="font-size: 14px; color: #666;">显示前</span>
<input type="number" id="percentileFilter" style="width: 70px; padding: 4px 8px; border: 1px solid #ddd; border-radius: 4px;" min="1" max="100" value="100" placeholder="1-100">
<span style="font-size: 14px; color: #666;">% 的学生</span>
<button class="btn btn-sm" style="background: #667eea; color: white;" onclick="applyPercentileFilter()">筛选</button>
<button class="btn btn-sm" style="border: 1px solid #ccc; color: #666;" onclick="resetPercentileFilter()">显示全部</button>
</div>
<table class="table">
<thead>
<tr><th>排名</th><th>学号</th><th>姓名</th><th>操行分</th><th>前%</th></tr>
<tr><th>排名</th><th>学号</th><th>姓名</th><th>操行分</th></tr>
</thead>
<tbody id="rankingList"></tbody>
</table>
@@ -46,6 +53,8 @@ include __DIR__ . '/../includes/header.php';
</div>
<script>
var totalStudents = 0;
async function loadDashboard() {
const studentsRes = await apiGet('/api/admin/students');
if (studentsRes && studentsRes.success) {
@@ -69,30 +78,51 @@ async function loadDashboard() {
const rankingRes = await apiGet('/api/student/ranking', { limit: 100 });
if (rankingRes && rankingRes.success) {
const totalStudents = rankingRes.data.total_students || 0;
totalStudents = rankingRes.data.total_students || 0;
let html = '';
rankingRes.data.ranking.forEach((student, index) => {
const rank = index + 1;
let percentile = '--';
if (totalStudents > 0) {
const pct = Math.floor(rank / totalStudents * 100);
percentile = (pct === 0 ? 1 : pct) + '%';
}
html += `<tr>
<td>${rank}</td>
<td>${escapeHtml(student.student_no)}</td>
<td>${escapeHtml(student.name)}</td>
<td>${student.total_points}</td>
<td>前${percentile}</td>
</tr>`;
});
if (rankingRes.data.ranking.length === 0) {
html = '<tr><td colspan="5" style="text-align:center;">暂无数据</td></tr>';
html = '<tr><td colspan="4" style="text-align:center;">暂无数据</td></tr>';
}
document.getElementById('rankingList').innerHTML = html;
}
}
document.getElementById('percentileFilter').addEventListener('keypress', function(e) {
if (e.key === 'Enter') applyPercentileFilter();
});
function applyPercentileFilter() {
const input = document.getElementById('percentileFilter');
const percentile = parseInt(input.value);
if (isNaN(percentile) || percentile < 1 || percentile > 100) {
showToast('请输入 1-100 之间的整数', 'error');
return;
}
const rows = document.getElementById('rankingList').querySelectorAll('tr');
if (rows.length === 0) return;
const showCount = Math.ceil(totalStudents * (percentile / 100));
rows.forEach(function(row, index) {
row.style.display = index < showCount ? '' : 'none';
});
}
function resetPercentileFilter() {
document.getElementById('percentileFilter').value = 100;
const rows = document.getElementById('rankingList').querySelectorAll('tr');
rows.forEach(function(row) {
row.style.display = '';
});
}
loadDashboard();
</script>
<script src="/assets/js/admin.js"></script>

View File

@@ -64,16 +64,20 @@ include __DIR__ . '/../includes/header.php';
<label>学期名称 <span style="color:red;">*</span></label>
<input type="text" id="semesterName" required placeholder="如2025春季学期" maxlength="100">
</div>
<div style="margin-bottom: 8px;">
<button type="button" class="btn btn-sm" style="border: 1px solid #667eea; color: #667eea; margin-right: 6px;" onclick="fillSemesterDates('upper')">上学期9月-次年2月</button>
<button type="button" class="btn btn-sm" style="border: 1px solid #667eea; color: #667eea;" onclick="fillSemesterDates('lower')">下学期3月-7月</button>
</div>
<div class="form-group">
<label>开始日期</label>
<input type="date" id="semesterStartDate">
</div>
<div class="form-group">
<label>结束日期</label>
<input type="date" id="semesterEndDate">
<label>结束日期 <small style="color: #999;">(可选)</small></label>
<input type="date" id="semesterEndDate" placeholder="可选,不确定可不填">
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">创建并激活</button>
<button type="submit" class="btn btn-primary">创建学期</button>
<button type="button" class="btn" onclick="closeModal('createSemesterModal')">取消</button>
</div>
</form>
@@ -89,7 +93,7 @@ include __DIR__ . '/../includes/header.php';
</div>
<div class="form-group">
<p id="archiveConfirmText" style="margin: 10px 0;"></p>
<p style="color: #e74c3c; font-size: 14px;">注意:归档后该学期的操行分记录将不可修改或撤销,但可以查看归档数据。</p>
<p style="color: #e74c3c; font-size: 14px;">注意:归档前需确保学期已设置开始日期,否则无法归档。归档后该学期的操行分记录将不可修改或撤销,但可以查看归档数据。</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="confirmArchive()">确认归档</button>
@@ -108,11 +112,23 @@ include __DIR__ . '/../includes/header.php';
<div class="table-wrapper">
<table class="table">
<thead>
<tr>
<th colspan="2" style="text-align:center; border-bottom: none;">基本信息</th>
<th rowspan="2" style="vertical-align: middle;">姓名</th>
<th rowspan="2" style="vertical-align: middle;">操行分</th>
<th colspan="4" style="text-align:center; border-bottom: none;">考勤统计</th>
<th colspan="3" style="text-align:center; border-bottom: none;">作业统计</th>
</tr>
<tr>
<th>排名</th>
<th>学号</th>
<th>姓名</th>
<th>最终操行分</th>
<th>出勤</th>
<th>缺勤</th>
<th>迟到</th>
<th>请假</th>
<th>已交</th>
<th>未交</th>
<th>迟交</th>
</tr>
</thead>
<tbody id="archiveDataList"></tbody>
@@ -130,6 +146,28 @@ var archiveSemesterId = null;
var archivePage = 1;
var archiveTotalPages = 1;
function fillSemesterDates(type) {
var now = new Date();
var currentYear = now.getFullYear();
var currentMonth = now.getMonth() + 1;
var startDateInput = document.getElementById('semesterStartDate');
var endDateInput = document.getElementById('semesterEndDate');
if (type === 'upper') {
var year = currentMonth >= 6 ? currentYear : currentYear - 1;
var endYear = year + 1;
var febDay = 28;
if ((endYear % 4 === 0 && endYear % 100 !== 0) || endYear % 400 === 0) {
febDay = 29;
}
startDateInput.value = year + '-09-01';
endDateInput.value = endYear + '-02-' + febDay;
} else if (type === 'lower') {
startDateInput.value = currentYear + '-03-01';
endDateInput.value = currentYear + '-07-15';
}
}
async function loadSemesters() {
const res = await apiGet('/api/semester/list');
if (res && res.success) {
@@ -200,7 +238,7 @@ async function submitCreateSemester() {
});
if (res && res.success) {
showToast('学期创建成功并已激活');
showToast(res.message || '学期创建成功');
closeModal('createSemesterModal');
loadSemesters();
} else {
@@ -262,10 +300,17 @@ async function viewArchiveData(semesterId, semesterName, page) {
<td>${escapeHtml(a.student_no)}</td>
<td>${escapeHtml(a.student_name)}</td>
<td>${a.final_points}</td>
<td>${a.attendance_present || 0}</td>
<td>${a.attendance_absent || 0}</td>
<td>${a.attendance_late || 0}</td>
<td>${a.attendance_leave || 0}</td>
<td>${a.homework_submitted || 0}</td>
<td>${a.homework_not_submitted || 0}</td>
<td>${a.homework_late || 0}</td>
</tr>`;
});
if (archives.length === 0) {
html = '<tr><td colspan="4" style="text-align:center;">暂无归档数据</td></tr>';
html = '<tr><td colspan="11" style="text-align:center;">暂无归档数据</td></tr>';
}
document.getElementById('archiveDataList').innerHTML = html;

View File

@@ -166,6 +166,23 @@ async function loadSemesterRecords() {
<div class="semester-stat-label">班级总人数</div>
</div>
</div>
<div style="margin-top: 12px; padding-top: 12px; border-top: 1px solid #eee;">
<div style="font-size: 12px; color: #999; margin-bottom: 8px;">考勤统计</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<span style="background: #e8f5e9; color: #388e3c; padding: 2px 8px; border-radius: 10px; font-size: 12px;">出勤 ${record.attendance_present || 0}</span>
<span style="background: #ffebee; color: #c62828; padding: 2px 8px; border-radius: 10px; font-size: 12px;">缺勤 ${record.attendance_absent || 0}</span>
<span style="background: #fff3e0; color: #e65100; padding: 2px 8px; border-radius: 10px; font-size: 12px;">迟到 ${record.attendance_late || 0}</span>
<span style="background: #e3f2fd; color: #1565c0; padding: 2px 8px; border-radius: 10px; font-size: 12px;">请假 ${record.attendance_leave || 0}</span>
</div>
</div>
<div style="margin-top: 8px;">
<div style="font-size: 12px; color: #999; margin-bottom: 8px;">作业统计</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<span style="background: #e8f5e9; color: #388e3c; padding: 2px 8px; border-radius: 10px; font-size: 12px;">已交 ${record.homework_submitted || 0}</span>
<span style="background: #ffebee; color: #c62828; padding: 2px 8px; border-radius: 10px; font-size: 12px;">未交 ${record.homework_not_submitted || 0}</span>
<span style="background: #fff3e0; color: #e65100; padding: 2px 8px; border-radius: 10px; font-size: 12px;">迟交 ${record.homework_late || 0}</span>
</div>
</div>
</div>
`;
});