@@ -103,4 +108,4 @@ include __DIR__ . '/../includes/header.php';
-
\ No newline at end of file
+
diff --git a/frontend/admin/semesters.php b/frontend/admin/semesters.php
index 7de76d4..9a24842 100644
--- a/frontend/admin/semesters.php
+++ b/frontend/admin/semesters.php
@@ -41,6 +41,7 @@ include __DIR__ . '/../includes/header.php';
diff --git a/frontend/assets/css/style.css b/frontend/assets/css/style.css
index 6d46902..9f336da 100644
--- a/frontend/assets/css/style.css
+++ b/frontend/assets/css/style.css
@@ -931,19 +931,20 @@ tr:hover {
/* ========== 历史记录页优化 ========== */
/* 时间列:确保分两行显示(日期+时间) */
.history-time {
- white-space: pre-line;
+ white-space: nowrap;
min-width: 80px;
line-height: 1.5;
- word-break: break-all;
+ vertical-align: top;
}
/* 原因列:每行最少7个字,自动换行 */
.history-reason {
min-width: 7em;
max-width: 200px;
- white-space: pre-wrap;
+ white-space: normal;
word-break: break-word;
line-height: 1.5;
+ vertical-align: top;
}
/* 学生名列:允许换行 */
@@ -953,6 +954,34 @@ tr:hover {
min-width: 60px;
max-width: 120px;
line-height: 1.5;
+ vertical-align: top;
+}
+
+/* 合并记录复选框样式 */
+.history-grouped-label {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ font-size: 13px;
+ padding: 6px 12px;
+ border: 1px solid var(--color-border);
+ border-radius: 6px;
+ background: var(--color-hover);
+ transition: all 0.2s;
+ white-space: nowrap;
+ user-select: none;
+}
+
+.history-grouped-label:hover {
+ border-color: var(--color-primary);
+ background: var(--color-primary-light);
+}
+
+.history-grouped-label input[type="checkbox"] {
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
}
/* 合并记录按钮样式 */
diff --git a/frontend/assets/js/common.js b/frontend/assets/js/common.js
index a3b2160..d6c3e22 100644
--- a/frontend/assets/js/common.js
+++ b/frontend/assets/js/common.js
@@ -337,25 +337,40 @@ function toggleActionDropdown(el) {
var isOpen = menu.classList.contains('show');
// 先关闭所有
- document.querySelectorAll('.action-dropdown-menu.show').forEach(function(m) {
- m.classList.remove('show');
- var toggle = m.closest('.action-dropdown').querySelector('.action-dropdown-toggle');
- if (toggle) toggle.classList.remove('open');
- });
+ closeAllDropdowns();
if (!isOpen) {
+ // 使用 fixed 定位,避免被 overflow 容器裁剪
+ var rect = el.getBoundingClientRect();
+ menu.style.position = 'fixed';
+ menu.style.bottom = 'auto';
+ menu.style.right = 'auto';
+ menu.style.left = rect.right - 120 + 'px'; // 120px = min-width
+ menu.style.top = (rect.top - 4) + 'px';
+ menu.style.transform = 'translateY(-100%)';
menu.classList.add('show');
el.classList.add('open');
}
}
+function closeAllDropdowns() {
+ document.querySelectorAll('.action-dropdown-menu.show').forEach(function(m) {
+ m.classList.remove('show');
+ m.style.position = '';
+ m.style.left = '';
+ m.style.top = '';
+ m.style.transform = '';
+ var toggle = m.closest('.action-dropdown');
+ if (toggle) {
+ var btn = toggle.querySelector('.action-dropdown-toggle');
+ if (btn) btn.classList.remove('open');
+ }
+ });
+}
+
document.addEventListener('click', function(e) {
if (!e.target.closest('.action-dropdown')) {
- document.querySelectorAll('.action-dropdown-menu.show').forEach(function(m) {
- m.classList.remove('show');
- var toggle = m.closest('.action-dropdown').querySelector('.action-dropdown-toggle');
- if (toggle) toggle.classList.remove('open');
- });
+ closeAllDropdowns();
}
});
diff --git a/frontend/assets/js/dashboard.js b/frontend/assets/js/dashboard.js
index fea9407..3a948f9 100644
--- a/frontend/assets/js/dashboard.js
+++ b/frontend/assets/js/dashboard.js
@@ -14,9 +14,15 @@ const role = window.PAGE_CONFIG.role;
let totalStudents = 0;
async function loadDashboard() {
- const studentsRes = await apiGet('/api/admin/students');
+ // 并行加载学生数据和学期信息
+ const [studentsRes, semesterRes] = await Promise.all([
+ apiGet('/api/admin/students'),
+ apiGet('/api/semester/active')
+ ]);
+
+ let statsHtml = '';
if (studentsRes && studentsRes.success) {
- document.getElementById('dashboardStats').innerHTML = `
+ statsHtml += `
学生总数
${studentsRes.data.total || 0}
@@ -24,6 +30,24 @@ async function loadDashboard() {
`;
}
+ // 显示学期信息和当前周数
+ if (semesterRes && semesterRes.success && semesterRes.data) {
+ const sem = semesterRes.data;
+ const weekNum = sem.current_week;
+ let semesterInfo = escapeHtml(sem.semester_name);
+ if (weekNum && weekNum > 0) {
+ semesterInfo += ` · 第${weekNum}周`;
+ }
+ statsHtml += `
+
+
当前学期
+
${semesterInfo}
+
+ `;
+ }
+
+ document.getElementById('dashboardStats').innerHTML = statsHtml;
+
let quickActions = '';
if (role === '班主任' || role === '班长' || role === '学习委员' || role === '劳动委员' || role === '志愿委员') {
quickActions += '
';
diff --git a/frontend/assets/js/history.js b/frontend/assets/js/history.js
index b073764..905546c 100644
--- a/frontend/assets/js/history.js
+++ b/frontend/assets/js/history.js
@@ -15,41 +15,74 @@ const currentUserId = window.PAGE_CONFIG.userId;
let currentHistoryPage = 1;
let totalHistoryPages = 1;
+function escapeHtml(str) {
+ if (!str) return '';
+ var el = document.createElement('span');
+ el.appendChild(document.createTextNode(str));
+ return el.innerHTML;
+}
+
async function loadStudentsForSelect() {
const res = await apiGet('/api/admin/students', {page_size: 1000});
if (res && res.success) {
let html = '
';
res.data.students.forEach(s => {
- html += `
`;
+ html += '
';
});
document.getElementById('historyStudentId').innerHTML = html;
}
}
-async function loadHistory(page = 1) {
+// 筛选学生时自动取消合并记录
+function onStudentFilterChange() {
+ var studentId = document.getElementById('historyStudentId').value;
+ if (studentId) {
+ var grouped = document.getElementById('historyGrouped');
+ if (grouped) grouped.checked = false;
+ }
+}
+
+// 折叠/展开筛选面板
+function toggleFilterPanel() {
+ var panel = document.getElementById('advancedFilters');
+ var btn = document.getElementById('filterToggleBtn');
+ if (panel.style.display === 'none') {
+ panel.style.display = 'block';
+ btn.textContent = '收起筛选 ▲';
+ } else {
+ panel.style.display = 'none';
+ btn.textContent = '展开筛选 ▼';
+ }
+}
+
+async function loadHistory(page) {
+ page = 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 statusFilter = document.getElementById('historyStatusFilter')?.value;
+ var startDate = document.getElementById('historyStartDate').value;
+ var endDate = document.getElementById('historyEndDate').value;
+ var studentId = document.getElementById('historyStudentId').value;
+ var reasonFilter = document.getElementById('historyReasonFilter').value;
+ var isGrouped = document.getElementById('historyGrouped').checked;
+ var statusFilter = document.getElementById('historyStatusFilter') ? document.getElementById('historyStatusFilter').value : '';
- const params = {
- page, page_size: 20,
+ // 筛选学生时强制取消合并
+ if (studentId) isGrouped = false;
+
+ var params = {
+ page: 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;
- if (statusFilter !== undefined && statusFilter !== '') params.is_revoked = parseInt(statusFilter);
+ if (statusFilter !== '') params.is_revoked = parseInt(statusFilter);
- const res = await apiGet('/api/admin/conduct/history', params);
+ var res = await apiGet('/api/admin/conduct/history', params);
if (res && res.success) {
- const nowrapStyle = ' style="white-space: nowrap; min-width: 80px;"';
- let headHtml = '';
+ var nowrapStyle = ' style="white-space:nowrap;min-width:80px;"';
+ var headHtml = '';
if (isGrouped) {
headHtml = '
时间 | 原因 | 分值 | 操作人 | 涉及学生 | ';
if (role === '班主任' || role === '班长') {
@@ -63,71 +96,71 @@ async function loadHistory(page = 1) {
}
document.getElementById('historyTableHead').innerHTML = headHtml;
- let html = '';
+ var html = '';
if (isGrouped) {
- res.data.records.forEach(record => {
- const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
- const names = record.student_names || '';
- const allRevoked = record.all_revoked;
- const revokedStyle = allRevoked ? ' style="opacity:0.5; text-decoration:line-through;"' : '';
- html += `
- | ${formatDateTime(record.created_at)} |
- ${escapeHtml(record.reason)} |
- ${record.points_change > 0 ? '+' : ''}${record.points_change}×${record.student_count} |
- ${escapeHtml(record.recorder_name || '')} |
- ${escapeHtml(names)} | `;
+ res.data.records.forEach(function(record) {
+ var pointsClass = record.points_change > 0 ? 'plus' : 'minus';
+ var names = record.student_names || '';
+ var allRevoked = record.all_revoked;
+ var revokedStyle = allRevoked ? ' style="opacity:0.5;text-decoration:line-through;"' : '';
+ html += '
' +
+ '| ' + formatDateTime(record.created_at) + ' | ' +
+ '' + escapeHtml(record.reason) + ' | ' +
+ '' + (record.points_change > 0 ? '+' : '') + record.points_change + '×' + record.student_count + ' | ' +
+ '' + escapeHtml(record.recorder_name || '') + ' | ' +
+ '' + escapeHtml(names) + ' | ';
if (role === '班主任' || role === '班长') {
if (allRevoked) {
- html += `已撤销 | `;
+ html += '已撤销 | ';
} else {
- html += ` | `;
+ html += ' | ';
}
}
- html += `
`;
+ html += '';
});
if (res.data.records.length === 0) {
- const colSpan = (role === '班主任' || role === '班长') ? 6 : 5;
+ var colSpan = (role === '班主任' || role === '班长') ? 6 : 5;
html = '
| 暂无记录 |
';
}
} 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 += `
- | ${formatDateTime(record.created_at)} |
- ${escapeHtml(record.student_name)} |
- ${record.points_change > 0 ? '+' : ''}${record.points_change} |
- ${escapeHtml(record.reason)} |
- ${escapeHtml(record.recorder_name)} | `;
+ res.data.records.forEach(function(record) {
+ var pointsClass = record.points_change > 0 ? 'plus' : 'minus';
+ var revokedStyle = record.is_revoked == 1 ? ' style="opacity:0.5;text-decoration:line-through;"' : '';
+ html += '
' +
+ '| ' + formatDateTime(record.created_at) + ' | ' +
+ '' + escapeHtml(record.student_name) + ' | ' +
+ '' + (record.points_change > 0 ? '+' : '') + record.points_change + ' | ' +
+ '' + escapeHtml(record.reason) + ' | ' +
+ '' + escapeHtml(record.recorder_name) + ' | ';
if (role === '班主任') {
if (record.is_revoked == 1) {
- const revokerInfo = record.revoker_name ? `由 ${escapeHtml(record.revoker_name)} 撤销` : '已撤销';
- html += `${revokerInfo} | `;
+ var revokerInfo = record.revoker_name ? '由 ' + escapeHtml(record.revoker_name) + ' 撤销' : '已撤销';
+ html += '' + revokerInfo + ' | ';
} else {
- html += ` | `;
+ html += ' | ';
}
} else if (role === '班长') {
if (record.is_revoked == 1) {
- const revokerInfo = record.revoker_name ? `由 ${escapeHtml(record.revoker_name)} 撤销` : '已撤销';
- html += `${revokerInfo} | `;
+ var revokerInfo = record.revoker_name ? '由 ' + escapeHtml(record.revoker_name) + ' 撤销' : '已撤销';
+ html += '' + revokerInfo + ' | ';
} else {
- html += ` | `;
+ html += ' | ';
}
} else if (role === '考勤委员') {
if (record.is_revoked == 1) {
- html += `已撤销 | `;
+ html += '已撤销 | ';
} else if (record.recorder_id == currentUserId) {
- html += ` | `;
+ html += ' | ';
} else {
- html += `- | `;
+ html += '- | ';
}
}
- html += `
`;
+ html += '';
});
if (res.data.records.length === 0) {
- const colSpan = (role === '班主任' || role === '班长' || role === '考勤委员') ? 6 : 5;
- html = `
| 暂无记录 |
`;
+ var colSpan = (role === '班主任' || role === '班长' || role === '考勤委员') ? 6 : 5;
+ html = '
| 暂无记录 |
';
}
}
@@ -145,47 +178,47 @@ function renderHistoryPagination() {
}
async function exportHistoryRecords() {
- const startDate = document.getElementById('historyStartDate').value;
- const endDate = document.getElementById('historyEndDate').value;
- const studentId = document.getElementById('historyStudentId').value;
+ var startDate = document.getElementById('historyStartDate').value;
+ var endDate = document.getElementById('historyEndDate').value;
+ var studentId = document.getElementById('historyStudentId').value;
showToast('正在导出历史记录...', 'info');
try {
- const reasonFilter = document.getElementById('historyReasonFilter').value;
- const params = { page: 1, page_size: 1000 };
+ var reasonFilter = document.getElementById('historyReasonFilter').value;
+ var 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);
+ var res = await apiGet('/api/admin/conduct/history', params);
if (res && res.success && res.data.records) {
- const records = res.data.records;
+ var records = res.data.records;
if (records.length === 0) {
showToast('没有找到记录', 'warning');
return;
}
- let csv = '\uFEFF';
+ var 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`;
+ records.forEach(function(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');
+ var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
+ var url = URL.createObjectURL(blob);
+ var link = document.createElement('a');
link.href = url;
- link.download = `历史记录_${new Date().toISOString().slice(0,10)}.csv`;
+ 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}条记录`);
+ showToast('导出成功,共' + records.length + '条记录');
} else {
- showToast('导出失败:' + (res?.message || '未知错误'), 'error');
+ showToast('导出失败:' + (res && res.message || '未知错误'), 'error');
}
} catch (err) {
showToast('导出失败:' + err.message, 'error');
@@ -194,13 +227,12 @@ async function exportHistoryRecords() {
// 批量撤销合并记录(按条件查找并撤销)
async function batchRevokeGrouped(reason, pointsChange, recorderName, createdAt) {
- if (!confirm(`确定要撤销所有"${reason}"(${pointsChange > 0 ? '+' : ''}${pointsChange}分)的记录吗?`)) return;
+ if (!confirm('确定要撤销所有"' + reason + '"(' + (pointsChange > 0 ? '+' : '') + pointsChange + '分)的记录吗?')) return;
showToast('正在批量撤销...', 'info');
try {
- // 先查询匹配的记录
- const params = {
+ var params = {
page: 1, page_size: 1000,
start_date: document.getElementById('historyStartDate').value,
end_date: document.getElementById('historyEndDate').value,
@@ -208,15 +240,14 @@ async function batchRevokeGrouped(reason, pointsChange, recorderName, createdAt)
grouped: false
};
- const res = await apiGet('/api/admin/conduct/history', params);
+ var res = await apiGet('/api/admin/conduct/history', params);
if (!res || !res.success || !res.data.records) {
showToast('查询记录失败', 'error');
return;
}
- // 精确匹配
- const matchedIds = [];
- res.data.records.forEach(r => {
+ var matchedIds = [];
+ res.data.records.forEach(function(r) {
if (r.reason === reason && r.points_change === pointsChange && r.is_revoked == 0) {
matchedIds.push(r.record_id);
}
@@ -227,32 +258,33 @@ async function batchRevokeGrouped(reason, pointsChange, recorderName, createdAt)
return;
}
- const revokeRes = await apiPost('/api/admin/conduct/batch-revoke', { record_ids: matchedIds });
+ var revokeRes = await apiPost('/api/admin/conduct/batch-revoke', { record_ids: matchedIds });
if (revokeRes && revokeRes.success) {
- showToast(`批量撤销完成: ${revokeRes.data.success_count}条成功`);
+ showToast('批量撤销完成: ' + (revokeRes.data ? revokeRes.data.success_count : 0) + '条成功');
loadHistory(currentHistoryPage);
} else {
- showToast(revokeRes?.message || '批量撤销失败', 'error');
+ showToast(revokeRes && revokeRes.message || '批量撤销失败', 'error');
}
} catch (err) {
showToast('批量撤销失败: ' + err.message, 'error');
}
}
-loadStudentsForSelect().then(() => {
- const urlParams = new URLSearchParams(window.location.search);
- const preStudentId = urlParams.get('student_id');
+loadStudentsForSelect().then(function() {
+ var urlParams = new URLSearchParams(window.location.search);
+ var preStudentId = urlParams.get('student_id');
if (preStudentId) {
document.getElementById('historyStudentId').value = preStudentId;
- loadHistory();
- } else {
- loadHistory();
+ onStudentFilterChange();
}
+ loadHistory();
});
window.loadHistory = loadHistory;
window.loadStudentsForSelect = loadStudentsForSelect;
window.exportHistoryRecords = exportHistoryRecords;
window.batchRevokeGrouped = batchRevokeGrouped;
+window.onStudentFilterChange = onStudentFilterChange;
+window.toggleFilterPanel = toggleFilterPanel;
})();
diff --git a/frontend/assets/js/homework-manage.js b/frontend/assets/js/homework-manage.js
index 723ebb5..4b27eab 100644
--- a/frontend/assets/js/homework-manage.js
+++ b/frontend/assets/js/homework-manage.js
@@ -127,25 +127,29 @@ function toggleSubjectPanel() {
async function loadSubjectList() {
const res = await apiGet('/api/subject/list');
- if (res && res.success) {
+ if (res && res.success && res.data) {
let html = '';
- res.data.subjects.forEach(sub => {
+ const subjects = res.data.subjects || [];
+ subjects.forEach(sub => {
+ const safeName = escapeHtml(sub.subject_name || '');
+ const safeCode = escapeHtml(sub.subject_code || '');
+ const sortOrder = sub.sort_order || 0;
html += `
- ${escapeHtml(sub.subject_name)}
- ${escapeHtml(sub.subject_code || '')}
+ ${safeName}
+ ${safeCode}
${sub.is_active ? '启用' : '禁用'}
-
-
`;
});
- if (res.data.subjects.length === 0) {
+ if (subjects.length === 0) {
html = '
暂无科目,请点击"添加科目"
';
}
document.getElementById('subjectList').innerHTML = html;
diff --git a/frontend/assets/js/modules/utils.js b/frontend/assets/js/modules/utils.js
index 92e807a..97aa8e2 100644
--- a/frontend/assets/js/modules/utils.js
+++ b/frontend/assets/js/modules/utils.js
@@ -15,12 +15,9 @@
// HTML转义
function escapeHtml(str) {
if (!str) return '';
- return str.replace(/[&<>]/g, function(m) {
- if (m === '&') return '&';
- if (m === '<') return '<';
- if (m === '>') return '>';
- return m;
- });
+ var el = document.createElement('span');
+ el.appendChild(document.createTextNode(str));
+ return el.innerHTML;
}
// 全选功能
diff --git a/frontend/assets/js/semesters.js b/frontend/assets/js/semesters.js
index bd58d18..960fa5a 100644
--- a/frontend/assets/js/semesters.js
+++ b/frontend/assets/js/semesters.js
@@ -81,10 +81,12 @@ async function loadSemesters() {
recordText = `${conductCount}条操行分 / ${attendanceCount}条考勤`;
}
+ const weekText = sem.current_week ? `第${sem.current_week}周` : '-';
html += `
| ${escapeHtml(sem.semester_name)} |
${formatDate(sem.start_date)} |
${formatDate(sem.end_date)} |
+ ${weekText} |
${statusText} |
${recordText} |
${formatDateTime(sem.created_at)} |
@@ -92,7 +94,7 @@ async function loadSemesters() {
`;
});
if (semesters.length === 0) {
- html = '
| 暂无学期,请点击上方按钮创建新学期 |
';
+ html = '
| 暂无学期,请点击上方按钮创建新学期 |
';
}
document.getElementById('semesterList').innerHTML = html;
}
diff --git a/frontend/parent/history.php b/frontend/parent/history.php
index 58b6823..f6061b3 100644
--- a/frontend/parent/history.php
+++ b/frontend/parent/history.php
@@ -82,7 +82,7 @@ async function loadHistory(page) {
const pointsText = record.points_change > 0 ? `+${record.points_change}` : record.points_change;
html += `
| ${formatDateTime(record.created_at)} |
- ${escapeHtml(record.reason || '-')} |
+ ${escapeHtml(record.reason || '-')} |
${pointsText} |
班主任 |
`;
diff --git a/sql/init.sql b/sql/init.sql
index fe9d3ed..2a7db7d 100644
--- a/sql/init.sql
+++ b/sql/init.sql
@@ -232,8 +232,8 @@ INSERT IGNORE INTO `subjects` (`subject_name`, `subject_code`, `sort_order`) VAL
-- 初始化系统版本号
INSERT INTO `system_settings` (`setting_key`, `setting_value`)
-VALUES ('db_version', '2.5')
-ON DUPLICATE KEY UPDATE `setting_value` = '2.5';
+VALUES ('db_version', '2.5.1')
+ON DUPLICATE KEY UPDATE `setting_value` = '2.5.1';
-- 控制台输出初始化结果(含版本号)
SELECT CONCAT('数据库初始化完成!版本: v', (SELECT setting_value FROM system_settings WHERE setting_key = 'db_version')) AS message;
diff --git a/sql/upgrades/v2.5.1.sql b/sql/upgrades/v2.5.1.sql
new file mode 100644
index 0000000..c5f0884
--- /dev/null
+++ b/sql/upgrades/v2.5.1.sql
@@ -0,0 +1,11 @@
+-- ===========================================
+-- 班级操行分管理系统 - v2.5 → v2.5.1 升级脚本
+-- 字符集: utf8mb4
+--
+-- 说明: v2.5.1 为 UI 优化版本,无数据库 schema 变更。
+-- 主要变更:
+-- 1. 筛选学生时自动取消合并记录
+-- 2. 合并记录选项样式优化(修复竖排显示)
+-- 3. 历史记录筛选功能改为折叠式
+-- 4. 科目管理调用修复
+-- ===========================================
diff --git a/sql/upgrades/v2.5.sql b/sql/upgrades/v2.5.sql
index ef4b3c0..ca5a83a 100644
--- a/sql/upgrades/v2.5.sql
+++ b/sql/upgrades/v2.5.sql
@@ -4,7 +4,7 @@
--
-- 说明: v2.5 为功能增强版本,无数据库 schema 变更。
-- 主要变更:
--- 1. 历史记录页优化(文字宽度/换行/合并按钮样式)
+-- 1. 历史记录页UI优化(文字宽度/换行/合并按钮样式)
-- 2. 新增"状态"筛选项(正常/已撤销)
-- 3. 合并记录支持批量撤销/反撤销
-- 4. 操作菜单底部遮挡修复
diff --git a/upgrade.php b/upgrade.php
index f5b0b20..7d73908 100644
--- a/upgrade.php
+++ b/upgrade.php
@@ -28,6 +28,7 @@ $UPGRADE_VERSIONS = [
'2.3' => __DIR__ . '/sql/upgrades/v2.3.sql',
'2.4' => __DIR__ . '/sql/upgrades/v2.4.sql',
'2.5' => __DIR__ . '/sql/upgrades/v2.5.sql',
+ '2.5.1' => __DIR__ . '/sql/upgrades/v2.5.1.sql',
];
/**