v2.9update

This commit is contained in:
2026-06-08 10:40:59 +08:00
parent 8d497d73d2
commit 70e7ad8e5e
20 changed files with 162 additions and 74 deletions

View File

@@ -18,10 +18,14 @@ async function loadAdmins() {
if (res && res.success) {
let html = '';
res.data.admins.forEach(admin => {
const isActive = admin.status === 1;
const statusClass = isActive ? 'subject-status-active' : 'subject-status-inactive';
const statusText = isActive ? '启用' : '禁用';
html += `<tr>
<td>${escapeHtml(admin.username)}</td>
<td>${escapeHtml(admin.real_name)}</td>
<td>${escapeHtml(admin.role_type)}</td>
<td><span class="subject-status ${statusClass}">${statusText}</span></td>
<td>
<div class="action-dropdown">
<button class="btn btn-sm action-dropdown-toggle" onclick="toggleActionDropdown(this)">操作 ▼</button>
@@ -29,14 +33,14 @@ async function loadAdmins() {
<a onclick="showEditAdminModal(${admin.user_id}, '${escapeHtml(admin.username)}', '${escapeHtml(admin.real_name)}', '${escapeHtml(admin.role_type)}')">编辑</a>
<a onclick="resetAdminPassword(${admin.user_id}, '${escapeHtml(admin.real_name)}')">重置密码</a>
<a onclick="unlockUser('${escapeHtml(admin.username)}', '${escapeHtml(admin.real_name)}')">解锁</a>
<a class="danger" onclick="deleteAdmin(${admin.user_id}, '${escapeHtml(admin.real_name)}')">删除</a>
<a class="${isActive ? 'danger' : ''}" onclick="toggleAdminStatus(${admin.user_id}, '${escapeHtml(admin.real_name)}', ${isActive ? 1 : 0})">${isActive ? '禁用' : '启用'}</a>
</div>
</div>
</td>
</tr>`;
});
if (res.data.admins.length === 0) {
html = '<tr><td colspan="4" style="text-align:center;">暂无管理员</td></tr>';
html = '<tr><td colspan="5" style="text-align:center;">暂无管理员</td></tr>';
}
document.getElementById('adminList').innerHTML = html;
}
@@ -74,17 +78,21 @@ async function submitEditAdmin() {
}
}
async function deleteAdmin(userId, realName) {
if (!confirm(`确定要删除管理员 "${realName}" 吗?此操作不可恢复。`)) {
async function toggleAdminStatus(userId, realName, currentStatus) {
const action = currentStatus === 1 ? '禁用' : '启用';
const warnMsg = currentStatus === 1
? `禁用后该管理员将无法登录,确定要禁用 "${realName}" 吗?`
: `确定要重新启用管理员 "${realName}" 吗?`;
if (!confirm(warnMsg)) {
return;
}
const res = await apiDelete(`/api/admin/delete/${userId}`);
const res = await apiPut(`/api/admin/toggle-status/${userId}`);
if (res && res.success) {
showToast('管理员删除成功');
showToast(res.message || `管理员已${action}`);
loadAdmins();
} else {
showToast(res?.message || '删除失败', 'error');
showToast(res?.message || '操作失败', 'error');
}
}
@@ -138,7 +146,7 @@ loadAdmins();
window.loadAdmins = loadAdmins;
window.showEditAdminModal = showEditAdminModal;
window.submitEditAdmin = submitEditAdmin;
window.deleteAdmin = deleteAdmin;
window.toggleAdminStatus = toggleAdminStatus;
window.resetAdminPassword = resetAdminPassword;
window.unlockUser = unlockUser;
window.submitResetPassword = submitResetPassword;

View File

@@ -22,6 +22,11 @@ function escapeHtml(str) {
return el.innerHTML;
}
function typeMap(relatedType) {
var map = { manual: '手动', homework: '作业', attendance: '考勤' };
return map[relatedType] || '手动';
}
async function loadStudentsForSelect() {
const res = await apiGet('/api/admin/students', {page_size: 1000});
if (res && res.success) {
@@ -117,12 +122,12 @@ async function loadHistory(page) {
var nowrapStyle = ' style="white-space:nowrap;min-width:80px;"';
var headHtml = '';
if (isGrouped) {
headHtml = '<th>时间</th><th>原因</th><th>分值</th><th' + nowrapStyle + '>操作人</th><th>涉及学生</th>';
headHtml = '<th>类型</th><th>分值</th><th>原因</th><th>学生名单</th><th' + nowrapStyle + '>操作人</th><th>时间</th>';
if (role === '班主任' || role === '班长') {
headHtml += '<th>操作</th>';
}
} else {
headHtml = '<th>时间</th><th>学生</th><th>分数变动</th><th>原因</th><th' + nowrapStyle + '>操作人</th>';
headHtml = '<th>类型</th><th>分值</th><th>原因</th><th>学生</th><th' + nowrapStyle + '>操作人</th><th>时间</th>';
if (role === '班主任' || role === '班长' || role === '考勤委员') {
headHtml += '<th>操作</th>';
}
@@ -133,15 +138,17 @@ async function loadHistory(page) {
if (isGrouped) {
res.data.records.forEach(function(record) {
var pointsClass = record.points_change > 0 ? 'plus' : 'minus';
var typeLabel = typeMap(record.related_type);
var names = record.student_names || '';
var allRevoked = record.all_revoked;
var revokedStyle = allRevoked ? ' style="opacity:0.5;text-decoration:line-through;"' : '';
html += '<tr' + revokedStyle + '>' +
'<td class="history-time">' + formatDateTime(record.created_at) + '</td>' +
'<td class="history-reason">' + escapeHtml(record.reason) + '</td>' +
'<td>' + typeLabel + '</td>' +
'<td class="' + pointsClass + '">' + (record.points_change > 0 ? '+' : '') + record.points_change + '&times;' + record.student_count + '</td>' +
'<td class="history-reason">' + escapeHtml(record.reason) + '</td>' +
'<td class="history-students">' + escapeHtml(names) + '</td>' +
'<td>' + escapeHtml(record.recorder_name || '') + '</td>' +
'<td class="history-students">' + escapeHtml(names) + '</td>';
'<td class="history-time">' + formatDateTime(record.created_at) + '</td>';
if (role === '班主任' || role === '班长') {
if (allRevoked) {
html += '<td><span class="text-muted">已撤销</span></td>';
@@ -152,19 +159,21 @@ async function loadHistory(page) {
html += '</tr>';
});
if (res.data.records.length === 0) {
var colSpan = (role === '班主任' || role === '班长') ? 6 : 5;
var colSpan = (role === '班主任' || role === '班长') ? 7 : 6;
html = '<tr><td colspan="' + colSpan + '" style="text-align:center;">暂无记录</td></tr>';
}
} else {
res.data.records.forEach(function(record) {
var pointsClass = record.points_change > 0 ? 'plus' : 'minus';
var typeLabel = typeMap(record.related_type);
var revokedStyle = record.is_revoked == 1 ? ' style="opacity:0.5;text-decoration:line-through;"' : '';
html += '<tr' + revokedStyle + '>' +
'<td class="history-time">' + formatDateTime(record.created_at) + '</td>' +
'<td>' + escapeHtml(record.student_name) + '</td>' +
'<td>' + typeLabel + '</td>' +
'<td class="' + pointsClass + '">' + (record.points_change > 0 ? '+' : '') + record.points_change + '</td>' +
'<td class="history-reason">' + escapeHtml(record.reason) + '</td>' +
'<td>' + escapeHtml(record.recorder_name) + '</td>';
'<td>' + escapeHtml(record.student_name) + '</td>' +
'<td>' + escapeHtml(record.recorder_name) + '</td>' +
'<td class="history-time">' + formatDateTime(record.created_at) + '</td>';
if (role === '班主任') {
if (record.is_revoked == 1) {
var revokerInfo = record.revoker_name ? '由 ' + escapeHtml(record.revoker_name) + ' 撤销' : '已撤销';
@@ -192,7 +201,7 @@ async function loadHistory(page) {
});
if (res.data.records.length === 0) {
var colSpan = (role === '班主任' || role === '班长' || role === '考勤委员') ? 6 : 5;
var colSpan = (role === '班主任' || role === '班长' || role === '考勤委员') ? 7 : 6;
html = '<tr><td colspan="' + colSpan + '" style="text-align:center;">暂无记录</td></tr>';
}
}

View File

@@ -30,7 +30,8 @@ document.getElementById('pointsChange').setAttribute('max', hwMaxPoints);
async function loadSubjectsForHomework() {
const subjectSelect = document.getElementById('hwSubjectSelect');
if (!subjectSelect) return;
const res = await apiGet('/api/subject/list');
// 作业下拉只显示已启用的科目
const res = await apiGet('/api/subject/list', { is_active: true });
if (res && res.success && res.data && res.data.subjects) {
let html = '<option value="">不选择科目</option>';
res.data.subjects.forEach(s => {
@@ -126,7 +127,7 @@ function toggleSubjectPanel() {
}
async function loadSubjectList() {
const res = await apiGet('/api/subject/list', { is_active: true });
const res = await apiGet('/api/subject/list');
if (res && res.success && res.data) {
let html = '';
const subjects = res.data.subjects || [];

View File

@@ -38,8 +38,12 @@
});
if (res && res.success) {
let msg = `管理员 ${res.data.username} 添加成功`;
if (res.data.password) msg += `,密码: ${res.data.password}`;
let msg;
if (res.data.password) {
msg = `管理员 ${res.data.username} 添加成功,密码: ${res.data.password}`;
} else {
msg = `管理员 ${res.data.username} 已重新激活(原密码不变)`;
}
showToast(msg);
closeModal('addAdminModal');
loadAdmins();

View File

@@ -19,15 +19,17 @@ async function loadHomework() {
res.data.homework.forEach(record => {
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
const pointsColor = record.points_change > 0 ? '#38a169' : '#e53e3e';
const typeLabel = { manual: '手动', homework: '作业', attendance: '考勤' }[record.related_type] || '作业';
html += `<tr>
<td>${formatDateTime(record.created_at)}</td>
<td>${typeLabel}</td>
<td style="color: ${pointsColor}; font-weight: bold;">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
<td>${escapeHtml(record.reason)}</td>
<td>${escapeHtml(record.recorder_name || '-')}</td>
<td>${formatDateTime(record.created_at)}</td>
</tr>`;
});
if (res.data.homework.length === 0) {
html = '<tr><td colspan="4" style="text-align:center; padding: 40px; color: #999;">📝 暂无作业扣分记录</td></tr>';
html = '<tr><td colspan="5" style="text-align:center; padding: 40px; color: #999;">📝 暂无作业扣分记录</td></tr>';
}
document.getElementById('homeworkList').innerHTML = html;
}