refactor: 简化各页面模板,移除重复代码;添加plan_common.js
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
// 方案相关公共函数(currentPlanId 在各页面自行声明)
|
||||||
|
|
||||||
|
// 查看方案详情
|
||||||
|
async function viewPlan(planId) {
|
||||||
|
currentPlanId = planId;
|
||||||
|
const response = await fetch(`/api/plans/${planId}`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
let html = `
|
||||||
|
<div class="mb-3">
|
||||||
|
<strong>学员:</strong>${data.student_name}
|
||||||
|
<strong>练习时间:</strong>${data.content.practice_time}
|
||||||
|
<strong>生成时间:</strong>${data.created_at}
|
||||||
|
</div>
|
||||||
|
<h6>问题诊断</h6>
|
||||||
|
<div class="mb-3">
|
||||||
|
`;
|
||||||
|
|
||||||
|
data.content.problems.forEach(p => {
|
||||||
|
html += `<span class="problem-tag severity-${p.severity}">${p.name}(${p.severity})</span> `;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += `</div>`;
|
||||||
|
|
||||||
|
if (data.content.ai_report) {
|
||||||
|
const aiReportHtml = marked.parse(data.content.ai_report);
|
||||||
|
html += `
|
||||||
|
<h6>AI个性化练习报告</h6>
|
||||||
|
<div class="mb-3 p-3 bg-light rounded" style="max-height: 500px; overflow-y: auto;">${aiReportHtml}</div>
|
||||||
|
`;
|
||||||
|
} else if (data.content.ai_report_error) {
|
||||||
|
html += `
|
||||||
|
<h6>AI报告</h6>
|
||||||
|
<div class="mb-3 p-3 bg-warning rounded">AI生成失败: ${data.content.ai_report_error}</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
html += `
|
||||||
|
<h6>每日练习计划(共${data.content.total_daily_minutes}分钟)</h6>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<thead><tr><th>环节</th><th>时长</th><th>内容</th><th>目的</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
`;
|
||||||
|
|
||||||
|
data.content.daily_schedule.forEach(item => {
|
||||||
|
html += `<tr><td>${item.phase}</td><td>${item.duration}</td><td>${item.content}</td><td>${item.purpose}</td></tr>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
html += '</tbody></table>';
|
||||||
|
|
||||||
|
document.getElementById('planDetailContent').innerHTML = html;
|
||||||
|
new bootstrap.Modal(document.getElementById('planDetailModal')).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载PDF
|
||||||
|
function downloadPDF() {
|
||||||
|
const templateId = document.getElementById('reportTemplateSelect')?.value;
|
||||||
|
const url = templateId ? `/api/plans/${currentPlanId}/pdf?template_id=${templateId}` : `/api/plans/${currentPlanId}/pdf`;
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载MD
|
||||||
|
function downloadMD() {
|
||||||
|
const templateId = document.getElementById('reportTemplateSelect')?.value;
|
||||||
|
const url = templateId ? `/api/plans/${currentPlanId}/md?template_id=${templateId}` : `/api/plans/${currentPlanId}/md`;
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 别名(兼容旧代码)
|
||||||
|
const downloadPlanPDF = downloadPDF;
|
||||||
|
const downloadPlanMD = downloadMD;
|
||||||
|
|
||||||
|
// 预览报告模板
|
||||||
|
async function previewReportTemplate() {
|
||||||
|
if (!currentPlanId) {
|
||||||
|
alert('请先选择一个方案');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const templateId = document.getElementById('reportTemplateSelect')?.value;
|
||||||
|
const url = templateId ? `/api/plans/${currentPlanId}/md?template_id=${templateId}` : `/api/plans/${currentPlanId}/md`;
|
||||||
|
try {
|
||||||
|
const resp = await fetch(url);
|
||||||
|
if (resp.ok) {
|
||||||
|
const md = await resp.text();
|
||||||
|
document.getElementById('reportPreviewContent').innerHTML = marked.parse(md);
|
||||||
|
new bootstrap.Modal(document.getElementById('reportPreviewModal')).show();
|
||||||
|
} else {
|
||||||
|
alert('预览失败');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert('预览失败: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,34 +2,6 @@
|
|||||||
|
|
||||||
{% block title %}API设置 - 钢琴练习方案系统{% endblock %}
|
{% block title %}API设置 - 钢琴练习方案系统{% endblock %}
|
||||||
|
|
||||||
{% block sidebar_nav %}
|
|
||||||
<a class="nav-link" href="/">
|
|
||||||
<i class="bi bi-people"></i> 学员管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/settings">
|
|
||||||
<i class="bi bi-gear"></i> 问题配置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link active" href="/api-settings">
|
|
||||||
<i class="bi bi-key"></i> API设置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/templates" id="templatesNav" style="display:none;">
|
|
||||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/classes">
|
|
||||||
<i class="bi bi-collection"></i> 班级管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/users" id="usersNav" style="display:none;">
|
|
||||||
<i class="bi bi-person-badge"></i> 用户管理
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<a class="nav-link" href="#" onclick="showChangePasswordModal()">
|
|
||||||
<i class="bi bi-key"></i> 修改密码
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="#" onclick="logout()">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@@ -141,34 +113,13 @@
|
|||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script>
|
<script>
|
||||||
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
|
window.pageInit = function(data) {
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
fetch('/api/check-login').then(r => r.json()).then(data => {
|
|
||||||
if (!data.logged_in) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (data.role !== 'admin') {
|
if (data.role !== 'admin') {
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userDisplay = data.username + ' (' + ROLE_LABELS[data.role] + ')';
|
|
||||||
document.getElementById('currentUserDisplay').textContent = userDisplay;
|
|
||||||
const mobileDisplay = document.getElementById('mobileUserDisplay');
|
|
||||||
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
|
|
||||||
|
|
||||||
if (data.role === 'admin') {
|
|
||||||
document.getElementById('usersNav').style.display = '';
|
|
||||||
document.getElementById('templatesNav').style.display = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
loadApiConfig();
|
loadApiConfig();
|
||||||
}).catch(() => {
|
};
|
||||||
window.location.href = '/login';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const providerDefaults = {
|
const providerDefaults = {
|
||||||
'minimax': {
|
'minimax': {
|
||||||
|
|||||||
@@ -2,34 +2,6 @@
|
|||||||
|
|
||||||
{% block title %}班级管理 - 钢琴练习方案系统{% endblock %}
|
{% block title %}班级管理 - 钢琴练习方案系统{% endblock %}
|
||||||
|
|
||||||
{% block sidebar_nav %}
|
|
||||||
<a class="nav-link" href="/">
|
|
||||||
<i class="bi bi-people"></i> 学员管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/settings" id="settingsNav" style="display:none;">
|
|
||||||
<i class="bi bi-gear"></i> 问题配置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/api-settings" id="apiSettingsNav" style="display:none;">
|
|
||||||
<i class="bi bi-key"></i> API设置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/templates" id="templatesNav" style="display:none;">
|
|
||||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link active" href="/classes">
|
|
||||||
<i class="bi bi-collection"></i> 班级管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/users" id="usersNav" style="display:none;">
|
|
||||||
<i class="bi bi-person-badge"></i> 用户管理
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<a class="nav-link" href="#" onclick="showChangePasswordModal()">
|
|
||||||
<i class="bi bi-key"></i> 修改密码
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="#" onclick="logout()">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<div class="d-flex align-items-center gap-3">
|
<div class="d-flex align-items-center gap-3">
|
||||||
@@ -168,33 +140,14 @@ function showToast(message, isError = true) {
|
|||||||
setTimeout(() => toast.remove(), 3000);
|
setTimeout(() => toast.remove(), 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查登录状态
|
window.pageInit = function(data) {
|
||||||
fetch('/api/check-login').then(r => r.json()).then(data => {
|
|
||||||
if (!data.logged_in) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
currentUserRole = data.role;
|
currentUserRole = data.role;
|
||||||
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
|
|
||||||
|
|
||||||
const userDisplay = data.username + ' (' + (ROLE_LABELS[data.role] || data.role) + ')';
|
|
||||||
document.getElementById('currentUserDisplay').textContent = userDisplay;
|
|
||||||
const mobileDisplay = document.getElementById('mobileUserDisplay');
|
|
||||||
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
|
|
||||||
|
|
||||||
if (data.role === 'admin') {
|
if (data.role === 'admin') {
|
||||||
document.getElementById('usersNav').style.display = '';
|
const addClassBtn = document.getElementById('addClassBtn');
|
||||||
document.getElementById('settingsNav').style.display = '';
|
if (addClassBtn) addClassBtn.style.display = 'inline-block';
|
||||||
document.getElementById('apiSettingsNav').style.display = '';
|
|
||||||
document.getElementById('templatesNav').style.display = '';
|
|
||||||
document.getElementById('addClassBtn').style.display = 'inline-block';
|
|
||||||
} else {
|
|
||||||
document.getElementById('settingsNav').style.display = '';
|
|
||||||
document.getElementById('apiSettingsNav').style.display = 'none';
|
|
||||||
document.getElementById('templatesNav').style.display = 'none';
|
|
||||||
}
|
}
|
||||||
loadClasses();
|
loadClasses();
|
||||||
});
|
};
|
||||||
|
|
||||||
// 加载班级列表
|
// 加载班级列表
|
||||||
function loadClasses() {
|
function loadClasses() {
|
||||||
|
|||||||
+53
-59
@@ -17,34 +17,6 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block sidebar_nav %}
|
|
||||||
<a class="nav-link" href="/">
|
|
||||||
<i class="bi bi-people"></i> 学员管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link active" href="/settings">
|
|
||||||
<i class="bi bi-gear"></i> 问题配置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/api-settings" id="apiSettingsNav" style="display:none;">
|
|
||||||
<i class="bi bi-key"></i> API设置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/templates" id="templatesNav" style="display:none;">
|
|
||||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/classes">
|
|
||||||
<i class="bi bi-collection"></i> 班级管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/users" id="usersNav" style="display:none;">
|
|
||||||
<i class="bi bi-person-badge"></i> 用户管理
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<a class="nav-link" href="#" onclick="showChangePasswordModal()">
|
|
||||||
<i class="bi bi-key"></i> 修改密码
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="#" onclick="logout()">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Tab导航 -->
|
<!-- Tab导航 -->
|
||||||
<ul class="nav nav-tabs mb-4" id="settingsTabs" role="tablist">
|
<ul class="nav nav-tabs mb-4" id="settingsTabs" role="tablist">
|
||||||
@@ -135,7 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
<button type="button" class="btn btn-secondary" id="cancelEditProblemBtn">取消</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="saveProblem()">保存</button>
|
<button type="button" class="btn btn-primary" onclick="saveProblem()">保存</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,39 +136,14 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
let allProblems = [];
|
let allProblems = [];
|
||||||
let currentEditId = null;
|
let currentEditId = null;
|
||||||
let currentDeleteId = null;
|
let currentDeleteId = null;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
window.pageInit = 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) + ')';
|
|
||||||
document.getElementById('currentUserDisplay').textContent = userDisplay;
|
|
||||||
const mobileDisplay = document.getElementById('mobileUserDisplay');
|
|
||||||
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
|
|
||||||
|
|
||||||
if (data.role === 'admin') {
|
|
||||||
document.getElementById('usersNav').style.display = '';
|
|
||||||
document.getElementById('templatesNav').style.display = '';
|
|
||||||
document.getElementById('apiSettingsNav').style.display = '';
|
|
||||||
} else {
|
|
||||||
document.getElementById('templatesNav').style.display = 'none';
|
|
||||||
document.getElementById('apiSettingsNav').style.display = 'none';
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
window.location.href = '/login';
|
|
||||||
});
|
|
||||||
|
|
||||||
loadProblems();
|
loadProblems();
|
||||||
});
|
};
|
||||||
|
|
||||||
// ========== 问题配置相关 ==========
|
// ========== 问题配置相关 ==========
|
||||||
|
|
||||||
@@ -281,6 +228,8 @@ async function createProblem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 编辑
|
// 编辑
|
||||||
|
let editProblemOriginalState = { name: '', content: '' }; // 记录原始状态
|
||||||
|
|
||||||
async function editProblem(problemId) {
|
async function editProblem(problemId) {
|
||||||
currentEditId = problemId;
|
currentEditId = problemId;
|
||||||
const response = await fetch(`/api/problems/${problemId}`);
|
const response = await fetch(`/api/problems/${problemId}`);
|
||||||
@@ -291,9 +240,13 @@ async function editProblem(problemId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = data.filename.replace(`${problemId}_`, '').replace('.md', '');
|
const name = data.name;
|
||||||
document.getElementById('editProblemName').value = name;
|
document.getElementById('editProblemName').value = name;
|
||||||
document.getElementById('editProblemContent').value = data.content;
|
document.getElementById('editProblemContent').value = data.content || '';
|
||||||
|
|
||||||
|
// 记录原始状态
|
||||||
|
editProblemOriginalState.name = name;
|
||||||
|
editProblemOriginalState.content = data.content;
|
||||||
|
|
||||||
if (window.problemEditor) {
|
if (window.problemEditor) {
|
||||||
window.problemEditor.toTextArea();
|
window.problemEditor.toTextArea();
|
||||||
@@ -309,7 +262,40 @@ async function editProblem(problemId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var editModal = new bootstrap.Modal(document.getElementById('editModal'));
|
const editModal = new bootstrap.Modal(document.getElementById('editModal'), {
|
||||||
|
keyboard: false // 禁用 ESC 关闭,由我们手动处理
|
||||||
|
});
|
||||||
|
const modalEl = document.getElementById('editModal');
|
||||||
|
|
||||||
|
// 取消按钮点击处理
|
||||||
|
document.getElementById('cancelEditProblemBtn').onclick = () => {
|
||||||
|
if (isEditProblemDirty()) {
|
||||||
|
if (confirm('内容已修改,确定要关闭吗?')) {
|
||||||
|
editModal.hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
editModal.hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ESC 键处理
|
||||||
|
const handleEscape = (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (isEditProblemDirty()) {
|
||||||
|
if (confirm('内容已修改,确定要关闭吗?')) {
|
||||||
|
modalEl.removeEventListener('keydown', handleEscape);
|
||||||
|
editModal.hide();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modalEl.removeEventListener('keydown', handleEscape);
|
||||||
|
editModal.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
modalEl.addEventListener('keydown', handleEscape);
|
||||||
|
|
||||||
editModal.show();
|
editModal.show();
|
||||||
editModal._element.addEventListener('shown.bs.modal', function() {
|
editModal._element.addEventListener('shown.bs.modal', function() {
|
||||||
if (window.problemEditor && window.problemEditor.codemirror) {
|
if (window.problemEditor && window.problemEditor.codemirror) {
|
||||||
@@ -318,6 +304,14 @@ async function editProblem(problemId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检测编辑问题是否有修改
|
||||||
|
function isEditProblemDirty() {
|
||||||
|
const currentName = document.getElementById('editProblemName').value;
|
||||||
|
const currentContent = window.problemEditor ? window.problemEditor.value() : document.getElementById('editProblemContent').value;
|
||||||
|
|
||||||
|
return currentName !== editProblemOriginalState.name || currentContent !== editProblemOriginalState.content;
|
||||||
|
}
|
||||||
|
|
||||||
async function saveProblem() {
|
async function saveProblem() {
|
||||||
const name = document.getElementById('editProblemName').value.trim();
|
const name = document.getElementById('editProblemName').value.trim();
|
||||||
const content = window.problemEditor ? window.problemEditor.value() : document.getElementById('editProblemContent').value;
|
const content = window.problemEditor ? window.problemEditor.value() : document.getElementById('editProblemContent').value;
|
||||||
|
|||||||
@@ -12,31 +12,6 @@
|
|||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block sidebar_nav %}
|
|
||||||
<a class="nav-link" href="/">
|
|
||||||
<i class="bi bi-people"></i> 学员管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/settings">
|
|
||||||
<i class="bi bi-gear"></i> 问题配置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/api-settings">
|
|
||||||
<i class="bi bi-key"></i> API设置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link active" href="/templates">
|
|
||||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/classes">
|
|
||||||
<i class="bi bi-collection"></i> 班级管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/users" id="usersNav" style="display:none;">
|
|
||||||
<i class="bi bi-person-badge"></i> 用户管理
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<a class="nav-link" href="#" onclick="logout()">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h4><i class="bi bi-file-earmark-text"></i> 模板管理</h4>
|
<h4><i class="bi bi-file-earmark-text"></i> 模板管理</h4>
|
||||||
@@ -147,36 +122,15 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
|
|
||||||
<script>
|
<script>
|
||||||
let templates = [];
|
let templates = [];
|
||||||
let currentTemplate = null;
|
let currentTemplate = null;
|
||||||
let editor = null;
|
let editor = null;
|
||||||
let createModal;
|
let createModal;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
window.pageInit = function() {
|
||||||
createModal = new bootstrap.Modal(document.getElementById('createModal'));
|
createModal = new bootstrap.Modal(document.getElementById('createModal'));
|
||||||
checkLogin();
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkLogin() {
|
|
||||||
fetch('/api/check-login').then(r => r.json()).then(data => {
|
|
||||||
if (!data.logged_in) {
|
|
||||||
window.location.href = '/login';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const userDisplay = data.username + ' (' + (data.role === 'admin' ? '管理员' : '用户') + ')';
|
|
||||||
document.getElementById('currentUserDisplay').textContent = userDisplay;
|
|
||||||
const mobileDisplay = document.getElementById('mobileUserDisplay');
|
|
||||||
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
|
|
||||||
|
|
||||||
if (data.role === 'admin') {
|
|
||||||
document.getElementById('usersNav').style.display = '';
|
|
||||||
}
|
|
||||||
loadTemplates();
|
loadTemplates();
|
||||||
}).catch(() => {
|
|
||||||
window.location.href = '/login';
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTemplates() {
|
async function loadTemplates() {
|
||||||
|
|||||||
@@ -2,34 +2,6 @@
|
|||||||
|
|
||||||
{% block title %}用户管理 - 钢琴练习方案系统{% endblock %}
|
{% block title %}用户管理 - 钢琴练习方案系统{% endblock %}
|
||||||
|
|
||||||
{% block sidebar_nav %}
|
|
||||||
<a class="nav-link" href="/">
|
|
||||||
<i class="bi bi-people"></i> 学员管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/settings">
|
|
||||||
<i class="bi bi-gear"></i> 问题配置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/api-settings">
|
|
||||||
<i class="bi bi-key"></i> API设置
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/classes">
|
|
||||||
<i class="bi bi-collection"></i> 班级管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link active" href="/users">
|
|
||||||
<i class="bi bi-person-badge"></i> 用户管理
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="/templates" id="templatesNav" style="display:none;">
|
|
||||||
<i class="bi bi-file-earmark-text"></i> 模板管理
|
|
||||||
</a>
|
|
||||||
<hr>
|
|
||||||
<a class="nav-link" href="#" onclick="showChangePasswordModal()">
|
|
||||||
<i class="bi bi-key"></i> 修改密码
|
|
||||||
</a>
|
|
||||||
<a class="nav-link" href="#" onclick="logout()">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> 退出登录
|
|
||||||
</a>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<h4><i class="bi bi-person-badge"></i> 用户管理</h4>
|
<h4><i class="bi bi-person-badge"></i> 用户管理</h4>
|
||||||
@@ -121,22 +93,9 @@
|
|||||||
|
|
||||||
{% block extra_js %}
|
{% block extra_js %}
|
||||||
<script>
|
<script>
|
||||||
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
|
window.pageInit = function() {
|
||||||
|
|
||||||
// 检查登录状态
|
|
||||||
fetch('/api/check-login').then(r => r.json()).then(data => {
|
|
||||||
if (!data.logged_in || data.role !== 'admin') {
|
|
||||||
window.location.href = '/login';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const userDisplay = data.username + ' (' + ROLE_LABELS[data.role] + ')';
|
|
||||||
document.getElementById('currentUserDisplay').textContent = userDisplay;
|
|
||||||
const mobileDisplay = document.getElementById('mobileUserDisplay');
|
|
||||||
if (mobileDisplay) mobileDisplay.textContent = userDisplay;
|
|
||||||
|
|
||||||
document.getElementById('templatesNav').style.display = '';
|
|
||||||
loadUsers();
|
loadUsers();
|
||||||
});
|
};
|
||||||
|
|
||||||
// Toast 通知函数
|
// Toast 通知函数
|
||||||
function showToast(message, isError = true) {
|
function showToast(message, isError = true) {
|
||||||
|
|||||||
Reference in New Issue
Block a user