feat: 问题数据迁移到数据库;学员详情页URL导航改造;侧边栏统一
- 问题从文件系统迁移到数据库 problems 表 - 移除 PROBLEMS_DIR 配置和文件读取逻辑 - student.html 完整重写:编辑/添加/删除问题,生成方案进度显示 - 学员详情页支持独立URL访问 (/student/<id>) - 统一侧边栏到 base.html - 更新文档:DEPLOYMENT_SOP, MODELS, STRUCTURE, FRONTEND_ARCH - 部署到生产环境 v1.2.0
This commit is contained in:
+97
-1
@@ -8,6 +8,8 @@
|
||||
<!-- 公共CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/tabulator-tables@5/dist/css/tabulator.min.css" rel="stylesheet">
|
||||
{% block extra_css %}{% endblock %}
|
||||
|
||||
<style>
|
||||
@@ -84,7 +86,33 @@
|
||||
<small id="currentUserDisplay" class="text-light"></small>
|
||||
</div>
|
||||
<nav class="nav flex-column">
|
||||
{% block sidebar_nav %}{% endblock %}
|
||||
<a class="nav-link {% if active_nav == 'students' %}active{% endif %}" href="/students">
|
||||
<i class="bi bi-people"></i> 学员管理
|
||||
</a>
|
||||
<a class="nav-link {% if active_nav == 'plans' %}active{% endif %}" href="/plans">
|
||||
<i class="bi bi-clipboard-check"></i> 方案管理
|
||||
</a>
|
||||
<a class="nav-link {% if active_nav == 'settings' %}active{% endif %}" href="/settings">
|
||||
<i class="bi bi-gear"></i> 问题配置
|
||||
</a>
|
||||
<a class="nav-link {% if active_nav == 'classes' %}active{% endif %}" href="/classes">
|
||||
<i class="bi bi-collection"></i> 班级管理
|
||||
</a>
|
||||
<a class="nav-link {% if active_nav == 'api-settings' %}active{% endif %}" href="/api-settings" id="apiSettingsNav" style="display:none;">
|
||||
<i class="bi bi-key"></i> API设置
|
||||
</a>
|
||||
<a class="nav-link {% if active_nav == 'templates' %}active{% endif %}" href="/templates" id="templatesNav" style="display:none;">
|
||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
||||
</a>
|
||||
{% block sidebar_extra %}
|
||||
<hr>
|
||||
<a class="nav-link" href="#" onclick="showChangePasswordModal(); return false;">
|
||||
<i class="bi bi-key"></i> 修改密码
|
||||
</a>
|
||||
<a class="nav-link" href="#" onclick="logout(); return false;">
|
||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
||||
</a>
|
||||
{% endblock %}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -97,7 +125,51 @@
|
||||
|
||||
<!-- 公共JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/tabulator-tables@5/dist/js/tabulator.min.js"></script>
|
||||
<script src="/static/js/plan_common.js"></script>
|
||||
<script>
|
||||
// 统一登录检查和权限处理
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('/api/check-login').then(r => r.json()).then(data => {
|
||||
if (!data.logged_in) {
|
||||
window.location.href = '/login';
|
||||
return;
|
||||
}
|
||||
// 显示用户名
|
||||
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
|
||||
const userDisplay = data.username + ' (' + (ROLE_LABELS[data.role] || data.role) + ')';
|
||||
const currentUserEl = document.getElementById('currentUserDisplay');
|
||||
if (currentUserEl) currentUserEl.textContent = userDisplay;
|
||||
const mobileUserEl = document.getElementById('mobileUserDisplay');
|
||||
if (mobileUserEl) mobileUserEl.textContent = userDisplay;
|
||||
|
||||
// 侧边栏权限控制
|
||||
const setDisplay = (id, val) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.style.display = val;
|
||||
};
|
||||
if (data.role === 'admin') {
|
||||
setDisplay('apiSettingsNav', '');
|
||||
setDisplay('templatesNav', '');
|
||||
setDisplay('usersNav', '');
|
||||
setDisplay('classesNav', '');
|
||||
setDisplay('settingsNav', '');
|
||||
} else {
|
||||
setDisplay('settingsNav', '');
|
||||
setDisplay('classesNav', '');
|
||||
}
|
||||
|
||||
// 调用页面初始化函数(如果定义了)
|
||||
if (typeof window.pageInit === 'function') {
|
||||
window.pageInit(data);
|
||||
}
|
||||
}).catch(() => {
|
||||
window.location.href = '/login';
|
||||
});
|
||||
});
|
||||
|
||||
// 移动端导航切换
|
||||
function toggleMobileNav() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
@@ -131,6 +203,30 @@
|
||||
</script>
|
||||
{% block extra_js %}{% endblock %}
|
||||
|
||||
<!-- 方案详情弹窗 -->
|
||||
<div class="modal fade" id="planDetailModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-fullscreen modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">练习方案</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="planDetailContent">
|
||||
<!-- 方案内容将通过JS动态生成 -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-warning" onclick="editPlanContent()">
|
||||
<i class="bi bi-edit"></i> 编辑内容
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="downloadPDF()">
|
||||
<i class="bi bi-download"></i> 下载PDF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 修改密码弹窗 -->
|
||||
<div class="modal fade" id="changePwdModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
|
||||
Reference in New Issue
Block a user