feat: 实现教师资料更新、操作日志和系统设置功能

新增教师资料更新功能,包括个人信息修改和密码更新
添加操作日志记录系统,记录用户关键操作
实现系统设置模块,支持动态配置系统参数
重构数据库模型,新增教师表和系统设置表
优化成绩录入逻辑,支持平时分、期中和期末成绩计算
添加数据导出功能,支持学生、教师和成绩数据导出
完善管理员后台,增加统计图表和操作日志查看
This commit is contained in:
祀梦
2025-12-22 23:30:01 +08:00
parent 16802c85e5
commit b1da021185
43 changed files with 7860 additions and 2835 deletions

View File

@@ -253,54 +253,65 @@
</div>
<div class="col-md-8 mb-4">
<div class="card">
<div class="card-header">
<i class="fas fa-user-edit me-2 text-primary"></i> 基本信息
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white py-3">
<h5 class="mb-0 fw-bold"><i class="fas fa-user-edit me-2 text-primary"></i>基本信息</h5>
</div>
<div class="card-body p-4">
<form>
<form id="profileForm">
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">学号</label>
<input type="text" class="form-control" id="profileId" readonly disabled>
<input type="text" class="form-control bg-light" id="profileId" readonly disabled>
</div>
<div class="col-md-6">
<label class="form-label">姓名</label>
<input type="text" class="form-control" id="profileNameInput" readonly>
<input type="text" class="form-control" id="profileNameInput" placeholder="请输入姓名">
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">班级</label>
<input type="text" class="form-control" id="profileClass" readonly disabled>
<input type="text" class="form-control" id="profileClass" placeholder="请输入班级">
</div>
<div class="col-md-6">
<label class="form-label">角色</label>
<input type="text" class="form-control" value="学生" readonly disabled>
<input type="text" class="form-control bg-light" value="学生" readonly disabled>
</div>
</div>
<hr class="my-4">
<h6 class="mb-3 fw-bold text-secondary">安全设置</h6>
<div class="mb-3">
<label class="form-label">原密码</label>
<input type="password" class="form-control" id="oldPassword" placeholder="请输入原密码">
</div>
<div class="row mb-4">
<div class="col-md-6">
<label class="form-label">新密码</label>
<input type="password" class="form-control" id="newPassword" placeholder="请输入新密码">
</div>
<div class="col-md-6">
<label class="form-label">确认新密码</label>
<input type="password" class="form-control" id="confirmPassword" placeholder="再次输入新密码">
</div>
</div>
<div class="text-end">
<button type="button" class="btn btn-primary px-4" id="savePasswordBtn">
<i class="fas fa-save me-1"></i> 保存更改
<button type="button" id="saveProfileBtn" class="btn btn-outline-primary">
<i class="fas fa-save me-1"></i> 保存基本信息
</button>
</div>
</form>
</div>
</div>
<div class="card shadow-sm border-0">
<div class="card-header bg-white py-3">
<h5 class="mb-0 fw-bold"><i class="fas fa-key me-2 text-primary"></i>修改密码</h5>
</div>
<div class="card-body p-4">
<form id="passwordForm">
<div class="mb-3">
<label for="oldPassword" class="form-label">原密码</label>
<input type="password" class="form-control" id="oldPassword" required placeholder="请输入原密码">
</div>
<div class="row mb-3">
<div class="col-md-6">
<label for="newPassword" class="form-label">新密码</label>
<input type="password" class="form-control" id="newPassword" required placeholder="请输入新密码">
</div>
<div class="col-md-6">
<label for="confirmPassword" class="form-label">确认新密码</label>
<input type="password" class="form-control" id="confirmPassword" required placeholder="请再次输入新密码">
</div>
</div>
<div id="passwordError" class="text-danger mb-3" style="display: none;"></div>
<div class="text-end">
<button type="submit" class="btn btn-primary px-4">
<i class="fas fa-save me-1"></i> 修改密码
</button>
</div>
</form>
@@ -342,26 +353,58 @@
updateTime();
setInterval(updateTime, 1000);
// 保存基本信息逻辑
const saveProfileBtn = document.getElementById('saveProfileBtn');
if (saveProfileBtn) {
saveProfileBtn.addEventListener('click', async () => {
const name = document.getElementById('profileNameInput').value;
const className = document.getElementById('profileClass').value;
try {
const res = await fetch('/api/auth/update-profile', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, class: className })
});
const result = await res.json();
if (result.success) {
alert('资料更新成功');
// 更新侧边栏和顶栏
document.getElementById('userName').textContent = name;
document.getElementById('studentName').textContent = name;
document.getElementById('profileName').textContent = name;
} else {
alert(result.message || '更新失败');
}
} catch (e) {
console.error('Update profile failed', e);
alert('系统错误');
}
});
}
// 修改密码逻辑
const savePasswordBtn = document.getElementById('savePasswordBtn');
if (savePasswordBtn) {
savePasswordBtn.addEventListener('click', async () => {
const passwordForm = document.getElementById('passwordForm');
if (passwordForm) {
passwordForm.addEventListener('submit', async (e) => {
e.preventDefault();
const oldPassword = document.getElementById('oldPassword').value;
const newPassword = document.getElementById('newPassword').value;
const confirmPassword = document.getElementById('confirmPassword').value;
if (!oldPassword || !newPassword || !confirmPassword) {
alert('请填写所有密码字段');
return;
}
const errorEl = document.getElementById('passwordError');
errorEl.style.display = 'none';
if (newPassword !== confirmPassword) {
alert('两次输入的新密码不一致');
errorEl.textContent = '两次输入的新密码不一致';
errorEl.style.display = 'block';
return;
}
if (newPassword.length < 6) {
alert('新密码长度至少为 6 位');
errorEl.textContent = '新密码长度至少为 6 位';
errorEl.style.display = 'block';
return;
}
@@ -377,17 +420,16 @@
const result = await response.json();
if (result.success) {
alert('密码修改成功,请重新登录');
// 登出并跳转到登录页
fetch('/api/auth/logout', { method: 'POST' })
.then(() => {
window.location.href = '/login';
});
await fetch('/api/auth/logout', { method: 'POST' });
window.location.href = '/login';
} else {
alert(result.message || '修改失败');
errorEl.textContent = result.message || '修改失败';
errorEl.style.display = 'block';
}
} catch (error) {
console.error('Update password error:', error);
alert('网络错误,请稍后再试');
errorEl.textContent = '网络错误,请稍后再试';
errorEl.style.display = 'block';
}
});
}