v2.9update
This commit is contained in:
@@ -37,7 +37,7 @@ include __DIR__ . '/../includes/header.php';
|
||||
<div class="table-wrapper">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr><th>用户名</th><th>姓名</th><th>角色</th><th>操作</th></tr>
|
||||
<tr><th>用户名</th><th>姓名</th><th>角色</th><th>状态</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody id="adminList"></tbody>
|
||||
</table>
|
||||
|
||||
@@ -93,11 +93,12 @@ include __DIR__ . '/../includes/header.php';
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr id="historyTableHead">
|
||||
<th>时间</th>
|
||||
<th>学生</th>
|
||||
<th>分数变动</th>
|
||||
<th>类型</th>
|
||||
<th>分值</th>
|
||||
<th>原因</th>
|
||||
<th>学生</th>
|
||||
<th style="white-space: nowrap; min-width: 80px;">操作人</th>
|
||||
<th>时间</th>
|
||||
<?php if ($role === '班主任' || $role === '班长' || $role === '考勤委员'): ?>
|
||||
<th>操作</th>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 + '×' + 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>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || [];
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -34,14 +34,15 @@ include __DIR__ . '/../includes/header.php';
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>日期</th>
|
||||
<th>原因</th>
|
||||
<th>类型</th>
|
||||
<th>分值</th>
|
||||
<th>原因</th>
|
||||
<th>记录人</th>
|
||||
<th>日期</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="historyList">
|
||||
<tr><td colspan="4" style="text-align:center;">加载中...</td></tr>
|
||||
<tr><td colspan="5" style="text-align:center;">加载中...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -73,18 +74,20 @@ const pageSize = 20;
|
||||
async function loadHistory(page) {
|
||||
const res = await apiGet('/api/parent/child/history', { page: page, page_size: pageSize });
|
||||
if (res && res.success) {
|
||||
let html = '';
|
||||
if (res.data.records.length === 0) {
|
||||
html = '<tr><td colspan="4" style="text-align:center;">暂无记录</td></tr>';
|
||||
html = '<tr><td colspan="5" style="text-align:center;">暂无记录</td></tr>';
|
||||
} else {
|
||||
res.data.records.forEach(record => {
|
||||
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
|
||||
const pointsText = record.points_change > 0 ? `+${record.points_change}` : record.points_change;
|
||||
const typeLabel = { manual: '手动', homework: '作业', attendance: '考勤' }[record.related_type] || '手动';
|
||||
html += `<tr>
|
||||
<td>${formatDateTime(record.created_at)}</td>
|
||||
<td class="history-reason">${escapeHtml(record.reason || '-')}</td>
|
||||
<td>${typeLabel}</td>
|
||||
<td><span class="record-points ${pointsClass}">${pointsText}</span></td>
|
||||
<td class="history-reason">${escapeHtml(record.reason || '-')}</td>
|
||||
<td>班主任</td>
|
||||
<td>${formatDateTime(record.created_at)}</td>
|
||||
</tr>`;
|
||||
</tr>`;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,10 +140,11 @@ include __DIR__ . '/../includes/header.php';
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>时间</th>
|
||||
<th>类型</th>
|
||||
<th>分值</th>
|
||||
<th>原因</th>
|
||||
<th>操作人</th>
|
||||
<th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="homeworkList"></tbody>
|
||||
@@ -351,21 +352,23 @@ include __DIR__ . '/../includes/header.php';
|
||||
if (res && res.success) {
|
||||
document.getElementById('conductTotalPoints').textContent = res.data.total_points;
|
||||
|
||||
let html = '<div class="table-wrapper"><table><thead><tr><th>时间</th><th>分数变动</th><th>原因</th><th>操作人</th></tr></thead><tbody>';
|
||||
let html = '<div class="table-wrapper"><table><thead><tr><th>类型</th><th>分值</th><th>原因</th><th>操作人</th><th>时间</th></tr></thead><tbody>';
|
||||
res.data.records.forEach(record => {
|
||||
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
|
||||
const recorderDisplay = record.points_change < 0 ? '班主任' : escapeHtml(record.recorder_name || '班主任');
|
||||
const typeLabel = { manual: '手动', homework: '作业', attendance: '考勤' }[record.related_type] || '手动';
|
||||
html += `
|
||||
<tr>
|
||||
<td>${formatDateTime(record.created_at)}</td>
|
||||
<td>${typeLabel}</td>
|
||||
<td class="record-points ${pointsClass}">${record.points_change > 0 ? '+' : ''}${record.points_change}</td>
|
||||
<td>${escapeHtml(record.reason)}</td>
|
||||
<td>${recorderDisplay}</td>
|
||||
<td>${formatDateTime(record.created_at)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
if (res.data.records.length === 0) {
|
||||
html += '<tr><td colspan="4" style="text-align:center;">暂无记录</td></tr>';
|
||||
html += '<tr><td colspan="5" style="text-align:center;">暂无记录</td></tr>';
|
||||
}
|
||||
html += '</tbody></table></div>';
|
||||
document.getElementById('conductRecords').innerHTML = html;
|
||||
@@ -391,20 +394,22 @@ include __DIR__ . '/../includes/header.php';
|
||||
try {
|
||||
const res = await apiGet(`/api/student/homework/${STUDENT_ID}`);
|
||||
if (res && res.success) {
|
||||
let html = '';
|
||||
res.data.homework.forEach(record => {
|
||||
const pointsClass = record.points_change > 0 ? 'plus' : 'minus';
|
||||
const typeLabel = { manual: '手动', homework: '作业', attendance: '考勤' }[record.related_type] || '作业';
|
||||
html += `
|
||||
<tr>
|
||||
<td>${formatDateTime(record.created_at)}</td>
|
||||
<td>${typeLabel}</td>
|
||||
<td class="record-points ${pointsClass}">${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;">暂无作业扣分记录</td></tr>';
|
||||
html = '<tr><td colspan="5" style="text-align:center;">暂无作业扣分记录</td></tr>';
|
||||
}
|
||||
}
|
||||
document.getElementById('homeworkList').innerHTML = html;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ include __DIR__ . '/../includes/header.php';
|
||||
<div class="table-wrapper">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr><th>时间</th><th>分值</th><th>原因</th><th>操作人</th></tr>
|
||||
<tr><th>类型</th><th>分值</th><th>原因</th><th>操作人</th><th>时间</th></tr>
|
||||
</thead>
|
||||
<tbody id="homeworkList"></tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user