feat: v1.4.0 - 典型方案采纳、推荐方案列表、审计字段、导航优化
- 添加典型方案采纳功能 (POST /api/plans/<id>/adopt) - 添加推荐方案列表 (GET /api/students/<id>/recommended-plans) - PracticePlan 新增 created_by/updated_by/updated_at 审计字段 - 方案编辑/详情页导航优化 (bfcache 处理、pageshow 事件) - 方案列表支持删除功能 - 学员列表'暂无方案/问题'样式统一 - 更新文档:问题文件已废弃(迁移到数据库) - 更新部署脚本和验证清单
This commit is contained in:
@@ -182,6 +182,90 @@ window.pageInit = function(data) {
|
||||
const addClassBtn = document.getElementById('addClassBtn');
|
||||
if (addClassBtn) addClassBtn.style.display = 'inline-block';
|
||||
}
|
||||
restoreClassFilterState();
|
||||
loadClasses();
|
||||
};
|
||||
|
||||
// 班级筛选状态管理
|
||||
const CLASS_FILTER_KEY = 'class_filters';
|
||||
|
||||
function saveClassFilterState() {
|
||||
const state = {
|
||||
activeFilter: document.getElementById('activeFilter').value,
|
||||
mineActive: document.getElementById('mineFilterBtn').classList.contains('active')
|
||||
};
|
||||
sessionStorage.setItem(CLASS_FILTER_KEY, JSON.stringify(state));
|
||||
}
|
||||
|
||||
function restoreClassFilterState() {
|
||||
const saved = sessionStorage.getItem(CLASS_FILTER_KEY);
|
||||
if (!saved) return;
|
||||
try {
|
||||
const state = JSON.parse(saved);
|
||||
document.getElementById('activeFilter').value = state.activeFilter || '';
|
||||
const btn = document.getElementById('mineFilterBtn');
|
||||
if (btn) {
|
||||
if (state.mineActive) {
|
||||
btn.classList.add('active', 'btn-primary');
|
||||
btn.classList.remove('btn-outline-secondary');
|
||||
} else {
|
||||
btn.classList.remove('active', 'btn-primary');
|
||||
btn.classList.add('btn-outline-secondary');
|
||||
}
|
||||
}
|
||||
saveClassFilterState();
|
||||
} catch (e) {
|
||||
console.error('恢复班级筛选状态失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
// 我的班级筛选
|
||||
function toggleMineFilter() {
|
||||
const btn = document.getElementById('mineFilterBtn');
|
||||
btn.classList.toggle('active');
|
||||
if (btn.classList.contains('active')) {
|
||||
btn.classList.remove('btn-outline-secondary');
|
||||
btn.classList.add('btn-primary');
|
||||
} else {
|
||||
btn.classList.remove('btn-primary');
|
||||
btn.classList.add('btn-outline-secondary');
|
||||
}
|
||||
saveClassFilterState();
|
||||
loadClasses();
|
||||
}
|
||||
|
||||
// 加载班级列表
|
||||
function loadClasses() {
|
||||
saveClassFilterState();
|
||||
|
||||
const activeFilter = document.getElementById('activeFilter').value;
|
||||
const mineFilter = document.getElementById('mineFilterBtn').classList.contains('active');
|
||||
let url = '/api/classes?';
|
||||
if (activeFilter) url += 'active=' + activeFilter + '&';
|
||||
if (mineFilter) url += 'mine=true&';
|
||||
url = url.endsWith('&') ? url.slice(0, -1) : url;
|
||||
url = url.endsWith('?') ? '/api/classes' : url;
|
||||
fetch(url).then(r => r.json()).then(classes => {
|
||||
const tbody = document.querySelector('#classesTable tbody');
|
||||
const isAdmin = currentUserRole === 'admin';
|
||||
tbody.innerHTML = classes.map(c => `
|
||||
<tr>
|
||||
<td>${c.id}</td>
|
||||
<td>${c.name}</td>
|
||||
<td>${c.level || '启蒙'}</td>
|
||||
<td>${c.description || '-'}</td>
|
||||
<td>${c.active ? '<span class="badge bg-success">进行中</span>' : '<span class="badge bg-secondary">已结束</span>'}</td>
|
||||
<td><a href="#" onclick="viewClassStudents(${c.id})"> ${c.student_count}</a></td>
|
||||
<td>${c.created_at}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-success me-1" onclick="openAssignGoalModal(${c.id}, '${c.name}')">分配目标</button>
|
||||
${isAdmin ? `<button type="button" class="btn btn-sm btn-primary me-1" onclick="editClass(${c.id}, '${c.name}', ${c.teacher_id || 'null'}, '${c.description || ''}', ${c.active}, '${c.level || '启蒙'}')">编辑</button>
|
||||
<button type="button" class="btn btn-sm btn-danger" onclick="deleteClass(${c.id})">删除</button>` : ''}
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
});
|
||||
}
|
||||
loadClasses();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user