refactor: 简化各页面模板,移除重复代码;添加plan_common.js

This commit is contained in:
hmo
2026-04-23 06:40:23 +08:00
parent baaa6ca2f8
commit 285979ff70
6 changed files with 163 additions and 259 deletions
+7 -56
View File
@@ -2,34 +2,6 @@
{% 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 %}
<div class="card">
<div class="card-header">
@@ -141,34 +113,13 @@
{% block extra_js %}
<script>
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
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') {
window.location.href = '/';
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();
}).catch(() => {
window.location.href = '/login';
});
});
window.pageInit = function(data) {
if (data.role !== 'admin') {
window.location.href = '/';
return;
}
loadApiConfig();
};
const providerDefaults = {
'minimax': {
+4 -51
View File
@@ -2,34 +2,6 @@
{% 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 %}
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="d-flex align-items-center gap-3">
@@ -168,33 +140,14 @@ function showToast(message, isError = true) {
setTimeout(() => toast.remove(), 3000);
}
// 检查登录状态
fetch('/api/check-login').then(r => r.json()).then(data => {
if (!data.logged_in) {
window.location.href = '/login';
return;
}
window.pageInit = function(data) {
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') {
document.getElementById('usersNav').style.display = '';
document.getElementById('settingsNav').style.display = '';
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';
const addClassBtn = document.getElementById('addClassBtn');
if (addClassBtn) addClassBtn.style.display = 'inline-block';
}
loadClasses();
});
};
// 加载班级列表
function loadClasses() {
+54 -60
View File
@@ -17,34 +17,6 @@
</style>
{% 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 %}
<!-- Tab导航 -->
<ul class="nav nav-tabs mb-4" id="settingsTabs" role="tablist">
@@ -135,7 +107,7 @@
</div>
</div>
<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>
</div>
</div>
@@ -164,39 +136,14 @@
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
<script>
<script>
let allProblems = [];
let currentEditId = null;
let currentDeleteId = null;
document.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) + ')';
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';
});
window.pageInit = function() {
loadProblems();
});
};
// ========== 问题配置相关 ==========
@@ -281,6 +228,8 @@ async function createProblem() {
}
// 编辑
let editProblemOriginalState = { name: '', content: '' }; // 记录原始状态
async function editProblem(problemId) {
currentEditId = problemId;
const response = await fetch(`/api/problems/${problemId}`);
@@ -291,9 +240,13 @@ async function editProblem(problemId) {
return;
}
const name = data.filename.replace(`${problemId}_`, '').replace('.md', '');
const name = data.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) {
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._element.addEventListener('shown.bs.modal', function() {
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() {
const name = document.getElementById('editProblemName').value.trim();
const content = window.problemEditor ? window.problemEditor.value() : document.getElementById('editProblemContent').value;
+3 -49
View File
@@ -12,31 +12,6 @@
</style>
{% 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 %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h4><i class="bi bi-file-earmark-text"></i> 模板管理</h4>
@@ -147,36 +122,15 @@
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
<script>
<script>
let templates = [];
let currentTemplate = null;
let editor = null;
let createModal;
document.addEventListener('DOMContentLoaded', () => {
window.pageInit = function() {
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();
}).catch(() => {
window.location.href = '/login';
});
loadTemplates();
}
async function loadTemplates() {
+2 -43
View File
@@ -2,34 +2,6 @@
{% 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 %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h4><i class="bi bi-person-badge"></i> 用户管理</h4>
@@ -121,22 +93,9 @@
{% block extra_js %}
<script>
const ROLE_LABELS = { 'admin': '管理员', 'user': '普通用户' };
// 检查登录状态
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 = '';
window.pageInit = function() {
loadUsers();
});
};
// Toast 通知函数
function showToast(message, isError = true) {