refactor(frontend): 重构前端目录结构并优化认证流程

将前端文件从html目录迁移到views目录,按功能模块组织
重构认证中间件和路由处理,简化页面权限控制
更新静态资源引用路径,统一使用/public前缀
添加学生仪表板页面,优化移动端显示
移除旧版html和js文件,更新样式和脚本
This commit is contained in:
祀梦
2025-12-21 22:07:23 +08:00
parent 38b200f9b3
commit bcf2c71fad
20 changed files with 2009 additions and 2009 deletions

View File

@@ -52,65 +52,72 @@ app.use(session({
}
}));
// 静态文件服务
app.use(express.static(path.join(__dirname, '../frontend')));
// 静态文件服务 - 只公开 public 目录
app.use('/public', express.static(path.join(__dirname, '../frontend/public')));
// 重定向旧路径 /frontend/html/* 到 /html/*
app.get('/frontend/html/*', (req, res) => {
const path = req.params[0];
res.redirect(`/html/${path}`);
// 页面认证中间件
const requirePageAuth = (req, res, next) => {
if (!req.session.user) {
return res.redirect('/login');
}
next();
};
const requirePageRole = (allowedRoles) => {
return (req, res, next) => {
if (!req.session.user) return res.redirect('/login');
if (!allowedRoles.includes(req.session.user.role)) {
return res.status(403).send('<h1>403 Forbidden - 权限不足</h1><a href="/dashboard">返回首页</a>');
}
next();
};
};
// 页面路由
app.get('/', (req, res) => res.redirect('/login'));
app.get('/login', (req, res) => {
if (req.session.user) return res.redirect('/dashboard');
res.sendFile(path.join(__dirname, '../frontend/views/auth/login.html'));
});
app.get('/register', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/auth/register.html')));
app.get('/dashboard', requirePageAuth, (req, res) => {
const role = req.session.user?.role;
switch (role) {
case 'student': res.redirect('/student/dashboard'); break;
case 'teacher': res.redirect('/teacher/dashboard'); break;
case 'admin': res.redirect('/admin/dashboard'); break;
default: res.redirect('/login');
}
});
// 路由
// 学生页面
app.get('/student/dashboard', requirePageAuth, requirePageRole(['student']), (req, res) => {
res.sendFile(path.join(__dirname, '../frontend/views/student/dashboard.html'));
});
// 教师页面
const teacherRouter = express.Router();
teacherRouter.use(requirePageAuth, requirePageRole(['teacher']));
teacherRouter.get('/dashboard', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/teacher/dashboard.html')));
teacherRouter.get('/grade_entry', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/teacher/grade_entry.html')));
teacherRouter.get('/grade_management', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/teacher/grade_management.html')));
app.use('/teacher', teacherRouter);
// 管理员页面
const adminRouter = express.Router();
adminRouter.use(requirePageAuth, requirePageRole(['admin']));
adminRouter.get('/dashboard', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/admin/dashboard.html')));
adminRouter.get('/student_management', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/admin/student_management.html')));
adminRouter.get('/user_management', (req, res) => res.sendFile(path.join(__dirname, '../frontend/views/admin/user_management.html')));
app.use('/admin', adminRouter);
// API 路由
app.use('/api/auth', authRoutes);
app.use('/api/student', studentRoutes);
app.use('/api/teacher', teacherRoutes);
app.use('/api/admin', adminRoutes);
// 认证中间件
const { requireAuth, requireRole } = require('./middleware/auth');
// 页面路由
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../frontend/html/login.html'));
});
app.get('/dashboard', requireAuth, (req, res) => {
// 根据用户角色重定向到不同的仪表板
const role = req.session.user?.role;
switch (role) {
case 'student':
res.redirect('/html/student_dashboard.html');
break;
case 'teacher':
res.redirect('/html/teacher_dashboard.html');
break;
case 'admin':
res.redirect('/html/admin_dashboard.html');
break;
default:
// 如果没有角色信息,重定向到登录页面
res.redirect('/');
break;
}
});
// 学生页面路由
app.get('/student/*', requireAuth, requireRole(['student', 'admin', 'teacher']), (req, res, next) => {
next();
});
// 教师页面路由
app.get('/teacher/*', requireAuth, requireRole(['teacher', 'admin']), (req, res, next) => {
next();
});
// 管理员页面路由
app.get('/admin/*', requireAuth, requireRole(['admin']), (req, res, next) => {
next();
});
// 404处理
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });

View File

@@ -1,269 +0,0 @@
class AuthManager {
constructor() {
// 动态设置API基础URL支持file:///协议和localhost:3000访问
this.apiBase = window.location.protocol === 'file:' ? 'http://localhost:3000/api' : '/api';
this.initEventListeners();
this.checkAuthStatus();
}
async checkAuthStatus() {
try {
const response = await fetch(`${this.apiBase}/auth/me`);
const data = await response.json();
if (data.success && data.user) {
// 用户已登录,根据角色重定向到正确的仪表板
const userRole = data.user.role;
let redirectUrl = '/dashboard';
if (userRole === 'student') {
redirectUrl = '/frontend/html/student_dashboard.html';
} else if (userRole === 'teacher') {
redirectUrl = '/frontend/html/teacher_dashboard.html';
} else if (userRole === 'admin') {
redirectUrl = '/frontend/html/admin_dashboard.html';
}
// 如果当前页面是登录或注册页面,则重定向到仪表板
const currentPath = window.location.pathname;
if (currentPath.includes('login.html') || currentPath.includes('register.html')) {
window.location.href = redirectUrl;
}
// 如果当前页面不是正确的仪表板页面,则重定向
else if (!currentPath.includes(redirectUrl) &&
currentPath !== '/' &&
!currentPath.includes('index.html')) {
window.location.href = redirectUrl;
}
}
} catch (error) {
console.log('用户未登录');
}
}
initEventListeners() {
// 登录表单提交
const loginForm = document.getElementById('loginForm');
if (loginForm) {
loginForm.addEventListener('submit', (e) => this.handleLogin(e));
}
// 注册表单提交
const registerForm = document.getElementById('registerForm');
if (registerForm) {
registerForm.addEventListener('submit', (e) => this.handleRegister(e));
}
// 登出按钮
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) {
logoutBtn.addEventListener('click', (e) => this.handleLogout(e));
}
}
async handleLogin(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
const submitBtn = form.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 登录中...';
submitBtn.disabled = true;
try {
const response = await fetch(`${this.apiBase}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
this.showNotification('登录成功!正在跳转...', 'success');
// 根据用户角色跳转到不同的仪表板
const userRole = result.user?.role;
let redirectUrl = '/dashboard';
if (userRole === 'student') {
redirectUrl = '/frontend/html/student_dashboard.html';
} else if (userRole === 'teacher') {
redirectUrl = '/frontend/html/teacher_dashboard.html';
} else if (userRole === 'admin') {
redirectUrl = '/frontend/html/admin_dashboard.html';
}
// 延迟跳转以显示通知
setTimeout(() => {
window.location.href = redirectUrl;
}, 1500);
} else {
this.showNotification(result.message || '登录失败', 'error');
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
} catch (error) {
console.error('登录错误:', error);
this.showNotification('网络错误,请重试', 'error');
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
}
async handleRegister(e) {
e.preventDefault();
const form = e.target;
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
// 验证密码
if (data.password !== data.confirmPassword) {
this.showNotification('两次输入的密码不一致', 'error');
return;
}
const submitBtn = form.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 注册中...';
submitBtn.disabled = true;
try {
const response = await fetch(`${this.apiBase}/auth/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
this.showNotification('注册成功!正在跳转到登录页面...', 'success');
setTimeout(() => {
window.location.href = '/html/login.html';
}, 1500);
} else {
this.showNotification(result.message || '注册失败', 'error');
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
} catch (error) {
console.error('注册错误:', error);
this.showNotification('网络错误,请重试', 'error');
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
}
}
async handleLogout(e) {
e.preventDefault();
if (!confirm('确定要退出登录吗?')) {
return;
}
try {
const response = await fetch(`${this.apiBase}/auth/logout`, {
method: 'POST'
});
const result = await response.json();
if (result.success) {
this.showNotification('已成功退出登录', 'success');
setTimeout(() => {
window.location.href = '/';
}, 1000);
} else {
this.showNotification('退出登录失败', 'error');
}
} catch (error) {
console.error('退出登录错误:', error);
this.showNotification('网络错误,请重试', 'error');
}
}
showNotification(message, type = 'info') {
// 移除现有的通知
const existingNotification = document.querySelector('.notification');
if (existingNotification) {
existingNotification.remove();
}
// 创建新的通知
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.innerHTML = `
<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-circle'}"></i>
<span>${message}</span>
`;
// 样式
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
color: white;
padding: 15px 20px;
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
gap: 10px;
z-index: 1000;
animation: slideIn 0.3s ease;
`;
document.body.appendChild(notification);
// 3秒后自动移除
setTimeout(() => {
notification.style.animation = 'slideOut 0.3s ease';
setTimeout(() => notification.remove(), 300);
}, 3000);
// 添加动画关键帧
if (!document.querySelector('#notification-styles')) {
const style = document.createElement('style');
style.id = 'notification-styles';
style.textContent = `
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
}
}
}
// 初始化认证管理器
document.addEventListener('DOMContentLoaded', () => {
window.authManager = new AuthManager();
});

View File

@@ -0,0 +1,47 @@
/* 通知消息样式 */
.notification {
position: fixed;
top: 20px;
right: 20px;
padding: 15px 25px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: flex;
align-items: center;
z-index: 1000;
transform: translateX(120%);
transition: transform 0.3s ease;
border-left: 4px solid #4e73df;
max-width: 350px;
}
.notification.show {
transform: translateX(0);
}
.notification.success {
border-left-color: #2ecc71;
}
.notification.error {
border-left-color: #e74c3c;
}
.notification i {
margin-right: 10px;
font-size: 1.2em;
}
.notification.success i {
color: #2ecc71;
}
.notification.error i {
color: #e74c3c;
}
.notification-content {
font-size: 14px;
color: #333;
}

View File

@@ -1147,4 +1147,51 @@ tr:hover {
.action-buttons {
flex-direction: column;
}
}
}/* «1laqZXð\!} */
.notification {
position: fixed;
top: 20px;
right: 20px;
padding: 15px 25px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
display: flex;
align-items: center;
z-index: 1000;
transform: translateX(120%);
transition: transform 0.3s ease;
border-left: 4px solid #4e73df;
max-width: 350px;
}
.notification.show {
transform: translateX(0);
}
.notification.success {
border-left-color: #2ecc71;
}
.notification.error {
border-left-color: #e74c3c;
}
.notification i {
margin-right: 10px;
font-size: 1.2em;
}
.notification.success i {
color: #2ecc71;
}
.notification.error i {
color: #e74c3c;
}
.notification-content {
font-size: 14px;
color: #333;
}

View File

@@ -11,9 +11,8 @@ class AdminDashboard {
}
async init() {
// 检查登录状态
if (!await this.checkAuth()) {
window.location.href = '/frontend/html/login.html';
// <EFBFBD><EFBFBD>亦蒈敶閧𠶖<EFBFBD>? if (!await this.checkAuth()) {
window.location.href = '/login';
return;
}
@@ -32,8 +31,7 @@ class AdminDashboard {
// 更新界面
this.updateUI();
// 初始化图表
this.initCharts();
// <EFBFBD><EFBFBD><EFBFBD>硋㦛銵? this.initCharts();
}
async checkAuth() {
@@ -49,7 +47,7 @@ class AdminDashboard {
const data = await response.json();
return data.success && data.user.role === 'admin';
} catch (error) {
console.error('认证检查失败:', error);
console.error('霈方<EFBFBD><EFBFBD><EFBFBD>亙仃韐?', error);
return false;
}
}
@@ -234,8 +232,7 @@ class AdminDashboard {
}
});
// 退出登录
document.getElementById('logoutBtn')?.addEventListener('click', () => {
// <EFBFBD><EFBFBD><EFBFBD>箇蒈敶? document.getElementById('logoutBtn')?.addEventListener('click', () => {
this.handleLogout();
});
@@ -247,23 +244,20 @@ class AdminDashboard {
async loadPage(page) {
// 这里可以实现页面切换逻辑
// 暂时使用简单跳转
switch (page) {
// <EFBFBD><EFBFBD>𧒄雿輻鍂蝞<EFBFBD><EFBFBD>閗歲頧? switch (page) {
case 'users':
window.location.href = '/frontend/html/user_management.html';
window.location.href = '/admin/user_management';
break;
case 'students':
window.location.href = '/frontend/html/student_management.html';
window.location.href = '/admin/student_management';
break;
case 'teachers':
// 可以跳转到教师管理页面
break;
// <EFBFBD>臭誑頝唾蓮<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? break;
case 'grades':
window.location.href = '/frontend/html/grade_management.html';
window.location.href = '/teacher/grade_management';
break;
case 'settings':
// 可以跳转到系统设置页面
break;
// <EFBFBD>臭誑頝唾蓮<EFBFBD>啁頂蝏蠘挽蝵桅△<EFBFBD>? break;
}
}
@@ -274,7 +268,7 @@ class AdminDashboard {
const className = document.getElementById('classFilter')?.value || '';
// 这里可以实现搜索逻辑
this.showNotification('搜索功能待实现', 'info');
this.showNotification('<EFBFBD>𦦵揣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?, 'info');
}
resetFilters() {
@@ -291,10 +285,10 @@ class AdminDashboard {
// 这里可以打开添加用户模态框
const userData = {
user_id: prompt('请输入用户ID:'),
full_name: prompt('请输入姓名:'),
role: prompt('请输入角色 (admin/teacher/student):'),
email: prompt('请输入邮箱:'),
class_name: prompt('请输入班级 (学生/教师可选):')
full_name: prompt('霂瑁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?'),
role: prompt('霂瑁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?(admin/teacher/student):'),
email: prompt('霂瑁<EFBFBD><EFBFBD>仿<EFBFBD>蝞?'),
class_name: prompt('霂瑁<EFBFBD><EFBFBD>亦号蝥?(摮衣<E691AE>/<2F><EFBFBD><E59D94><EFBFBD>?:')
};
if (!userData.user_id || !userData.full_name || !userData.role) {
@@ -353,7 +347,7 @@ class AdminDashboard {
return;
}
if (!confirm(`确定要删除选中的 ${checkboxes.length} 个用户吗?`)) {
if (!confirm(`蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>劐葉<EFBFBD>?${checkboxes.length} 銝芰鍂<EFBFBD><EFBFBD>嚗鬮)) {
return;
}
@@ -385,10 +379,10 @@ class AdminDashboard {
if (!user) return;
// 这里可以打开编辑模态框
const newName = prompt('请输入新的姓名:', user.full_name);
const newName = prompt('霂瑁<EFBFBD><EFBFBD>交鰵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?', user.full_name);
if (newName === null) return;
const newRole = prompt('请输入新的角色:', user.role);
const newRole = prompt('霂瑁<EFBFBD><EFBFBD>交鰵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?', user.role);
if (newRole === null) return;
try {
@@ -418,7 +412,7 @@ class AdminDashboard {
}
async deleteUser(userId) {
if (!confirm('确定要删除这个用户吗?')) {
if (!confirm('蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝芰鍂<EFBFBD><EFBFBD>?)) {
return;
}
@@ -449,17 +443,17 @@ class AdminDashboard {
});
if (response.ok) {
window.location.href = '/html/login.html';
window.location.href = '/login';
}
} catch (error) {
console.error('退出登录失败:', error);
console.error('<EFBFBD><EFBFBD><EFBFBD>箇蒈敶訫仃韐?', error);
}
}
async refreshData() {
await this.loadStats();
await this.loadUsers();
this.showNotification('数据已刷新', 'success');
this.showNotification('<EFBFBD>唳旿撌脣<EFBFBD><EFBFBD>?, 'success');
}
updateUI() {
@@ -473,11 +467,9 @@ class AdminDashboard {
}
async initCharts() {
// 加载Chart.js
await this.loadChartLibrary();
// <EFBFBD>㰘蝸Chart.js摨? await this.loadChartLibrary();
// 初始化用户分布饼图
this.initUserDistributionChart();
// <EFBFBD><EFBFBD><EFBFBD>𣇉鍂<EFBFBD><EFBFBD><EFBFBD><EFBFBD>? this.initUserDistributionChart();
// 初始化成绩分布柱状图
this.initGradeDistributionChart();
@@ -493,8 +485,7 @@ class AdminDashboard {
<button class="notification-close">&times;</button>
`;
// 添加到页面
document.body.appendChild(notification);
// 瘛餃<EFBFBD><EFBFBD>圈△<EFBFBD>? document.body.appendChild(notification);
// 添加关闭事件
notification.querySelector('.notification-close').addEventListener('click', () => {
@@ -527,7 +518,7 @@ class AdminDashboard {
// 模拟数据
const data = {
labels: ['学生', '教师', '管理员'],
labels: ['摮衣<EFBFBD>', '<EFBFBD><EFBFBD>', '<EFBFBD><EFBFBD>?],
datasets: [{
data: [this.stats.totalStudents || 100, this.stats.totalTeachers || 20, 1],
backgroundColor: [
@@ -589,3 +580,4 @@ class AdminDashboard {
});
}
}

287
frontend/public/js/auth.js Normal file
View File

@@ -0,0 +1,287 @@
/**
* 认证模块管理器
* 处理登录、注册、注销及权限检查
*/
class AuthManager {
constructor() {
this.apiBase = '/api';
this.init();
}
init() {
this.createNotificationContainer();
this.initEventListeners();
this.checkAuthStatus();
}
/**
* 创建通知容器
*/
createNotificationContainer() {
if (!document.getElementById('notification-container')) {
const container = document.createElement('div');
container.id = 'notification-container';
container.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
display: flex;
flex-direction: column;
gap: 10px;
`;
document.body.appendChild(container);
}
}
/**
* 检查用户认证状态
*/
async checkAuthStatus() {
// 如果当前是公共页面可以选择不检查或者检查后更新UI
const currentPath = window.location.pathname;
const isAuthPage = currentPath.includes('/login') || currentPath.includes('/register');
try {
const response = await fetch(`${this.apiBase}/auth/me`);
const data = await response.json();
if (data.success && data.user) {
// 用户已登录
const redirectUrl = this.getDashboardUrl(data.user.role);
// 如果在登录/注册页,跳转到仪表板
if (isAuthPage || currentPath === '/') {
window.location.href = redirectUrl;
}
} else {
// 用户未登录,如果在受保护页面,跳转到登录页
// 注意:后端通常已经处理了重定向,这里是前端的额外保障
if (!isAuthPage && currentPath !== '/') {
// 可以在这里添加逻辑,但通常交给后端控制
}
}
} catch (error) {
console.error('Auth check failed:', error);
}
}
getDashboardUrl(role) {
switch(role) {
case 'student': return '/student/dashboard';
case 'teacher': return '/teacher/dashboard';
case 'admin': return '/admin/dashboard';
default: return '/dashboard';
}
}
initEventListeners() {
// 登录表单
const loginForm = document.getElementById('loginForm');
if (loginForm) {
loginForm.addEventListener('submit', (e) => this.handleLogin(e));
}
// 注册表单
const registerForm = document.getElementById('registerForm');
if (registerForm) {
registerForm.addEventListener('submit', (e) => this.handleRegister(e));
// 角色选择联动
const roleSelect = document.getElementById('role');
if (roleSelect) {
roleSelect.addEventListener('change', (e) => this.handleRoleChange(e));
}
}
// 注销按钮 (可能有多个,例如在导航栏)
document.querySelectorAll('.btn-logout, #logoutBtn').forEach(btn => {
btn.addEventListener('click', (e) => this.handleLogout(e));
});
}
handleRoleChange(e) {
const role = e.target.value;
const classField = document.getElementById('classField');
const classInput = document.getElementById('class');
if (classField && classInput) {
if (role === 'student' || role === 'teacher') {
classField.style.display = 'block';
classInput.required = true;
} else {
classField.style.display = 'none';
classInput.required = false;
classInput.value = ''; // 清空值
}
}
}
async handleLogin(e) {
e.preventDefault();
const form = e.target;
const submitBtn = form.querySelector('button[type="submit"]');
if (this.setLoading(submitBtn, true, '登录中...')) {
try {
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
const response = await fetch(`${this.apiBase}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
this.showNotification('登录成功,正在跳转...', 'success');
setTimeout(() => {
window.location.href = this.getDashboardUrl(result.user.role);
}, 1000);
} else {
this.showNotification(result.message || '登录失败', 'error');
this.setLoading(submitBtn, false);
}
} catch (error) {
console.error('Login error:', error);
this.showNotification('网络错误,请稍后重试', 'error');
this.setLoading(submitBtn, false);
}
}
}
async handleRegister(e) {
e.preventDefault();
const form = e.target;
const submitBtn = form.querySelector('button[type="submit"]');
// 获取数据
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
// 简单验证
if (data.password !== data.confirmPassword) {
this.showNotification('两次输入的密码不一致', 'error');
return;
}
if (this.setLoading(submitBtn, true, '注册中...')) {
try {
const response = await fetch(`${this.apiBase}/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
const result = await response.json();
if (result.success) {
this.showNotification('注册成功,请登录', 'success');
setTimeout(() => {
window.location.href = '/login';
}, 1500);
} else {
this.showNotification(result.message || '注册失败', 'error');
this.setLoading(submitBtn, false);
}
} catch (error) {
console.error('Register error:', error);
this.showNotification('网络错误,请稍后重试', 'error');
this.setLoading(submitBtn, false);
}
}
}
async handleLogout(e) {
e.preventDefault();
if (confirm('确定要退出登录吗?')) {
try {
const response = await fetch(`${this.apiBase}/auth/logout`, {
method: 'POST'
});
const result = await response.json();
if (result.success) {
this.showNotification('已退出登录', 'success');
setTimeout(() => {
window.location.href = '/login';
}, 1000);
}
} catch (error) {
console.error('Logout error:', error);
// 即使出错也强制跳转到登录页
window.location.href = '/login';
}
}
}
/**
* 设置按钮加载状态
* @param {HTMLElement} btn 按钮元素
* @param {boolean} isLoading 是否正在加载
* @param {string} text 加载时的文本
* @returns {boolean} true表示状态设置成功
*/
setLoading(btn, isLoading, text = '') {
if (!btn) return false;
if (isLoading) {
if (btn.dataset.loading) return false; // 防止重复提交
btn.dataset.loading = 'true';
btn.dataset.originalText = btn.innerHTML;
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${text}`;
btn.disabled = true;
} else {
btn.innerHTML = btn.dataset.originalText || btn.innerHTML;
delete btn.dataset.loading;
btn.disabled = false;
}
return true;
}
/**
* 显示通知
* @param {string} message 消息内容
* @param {string} type 消息类型 'success' | 'error' | 'info'
*/
showNotification(message, type = 'info') {
const container = document.getElementById('notification-container');
if (!container) return;
const notification = document.createElement('div');
notification.className = `notification ${type}`;
let icon = 'info-circle';
if (type === 'success') icon = 'check-circle';
if (type === 'error') icon = 'exclamation-circle';
notification.innerHTML = `
<i class="fas fa-${icon}"></i>
<span class="notification-content">${message}</span>
`;
container.appendChild(notification);
// 动画显示
requestAnimationFrame(() => {
notification.classList.add('show');
});
// 自动消失
setTimeout(() => {
notification.classList.remove('show');
notification.addEventListener('transitionend', () => {
notification.remove();
});
}, 3000);
}
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
window.authManager = new AuthManager();
});

View File

@@ -7,8 +7,7 @@ class MainPage {
}
init() {
// 初始化所有功能
this.initNavbar();
// åˆ<EFBFBD>å§åŒæ‰€æœ‰åŠŸèƒ? this.initNavbar();
this.initScrollEffects();
this.initSmoothScroll();
this.initBackToTop();
@@ -30,8 +29,7 @@ class MainPage {
}
});
// 初始化当前页面高亮
this.highlightCurrentPage();
// åˆ<EFBFBD>å§åŒå½“å‰<EFBFBD>页é<EFBFBD>¢é«˜äº? this.highlightCurrentPage();
}
// 高亮当前页面导航链接
@@ -47,9 +45,8 @@ class MainPage {
});
}
// 初始化滚动效果
initScrollEffects() {
// 滚动时显示/隐藏元素
// åˆ<EFBFBD>å§åŒæ»šåŠ¨æ•ˆæž? initScrollEffects() {
// 滚动时显ç¤?éš<C3A9>è—<C3A8>元素
const observerOptions = {
root: null,
rootMargin: '0px',
@@ -70,8 +67,7 @@ class MainPage {
});
}
// 初始化平滑滚动
initSmoothScroll() {
// åˆ<EFBFBD>å§åŒå¹³æ»æ»šåŠ? initSmoothScroll() {
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', (e) => {
e.preventDefault();
@@ -89,15 +85,14 @@ class MainPage {
});
}
// 初始化返回顶部按钮
initBackToTop() {
// åˆ<EFBFBD>å§åŒè¿”åžé¡¶éƒ¨æŒ‰é? initBackToTop() {
const backToTopBtn = document.createElement('button');
backToTopBtn.id = 'backToTop';
backToTopBtn.innerHTML = '<i class="fas fa-chevron-up"></i>';
backToTopBtn.title = '返回顶部';
document.body.appendChild(backToTopBtn);
// 滚动时显示/隐藏按钮
// 滚动时显ç¤?éš<C3A9>è—<C3A8>按é®
window.addEventListener('scroll', () => {
if (window.scrollY > 300) {
backToTopBtn.classList.add('show');
@@ -136,8 +131,7 @@ class MainPage {
});
}
// 初始化认证按钮状态
initAuthButtons() {
// åˆ<EFBFBD>å§åŒè®¤è¯<EFBFBD>按é®çжæ€? initAuthButtons() {
// 检查用户是否已登录
this.checkLoginStatus().then(user => {
const loginBtn = document.getElementById('loginBtn');
@@ -145,23 +139,22 @@ class MainPage {
const heroLoginBtn = document.getElementById('heroLoginBtn');
if (user) {
// 用户已登录,显示仪表板按钮
// 根据用户角色设置正确的仪表板路径
// 用户已登录,显示仪表æ<EFBFBD>¿æŒ‰é? // æ ¹æ<C2B9>®ç”¨æˆ·è§è‰²è®¾ç½®æ­£ç¡®çš„仪表æ<C2A8>¿è·¯å¾„
let dashboardUrl = '/dashboard';
if (user.role === 'student') {
dashboardUrl = '/frontend/html/student_dashboard.html';
dashboardUrl = '/student/dashboard';
} else if (user.role === 'teacher') {
dashboardUrl = '/frontend/html/teacher_dashboard.html';
dashboardUrl = '/teacher/dashboard';
} else if (user.role === 'admin') {
dashboardUrl = '/frontend/html/admin_dashboard.html';
dashboardUrl = '/admin/dashboard';
}
if (loginBtn) {
loginBtn.textContent = '进入仪表板';
loginBtn.textContent = 'è¿å¥ä»ªè¡¨æ<EFBFBD>?;
loginBtn.href = dashboardUrl;
}
if (heroLoginBtn) {
heroLoginBtn.textContent = '进入仪表板';
heroLoginBtn.textContent = 'è¿å¥ä»ªè¡¨æ<EFBFBD>?;
heroLoginBtn.href = dashboardUrl;
}
if (registerBtn) {
@@ -171,15 +164,14 @@ class MainPage {
});
}
// 检查登录状态
async checkLoginStatus() {
// 检查登录状� async checkLoginStatus() {
try {
const apiBase = window.location.protocol === 'file:' ? 'http://localhost:3000/api' : '/api';
const response = await fetch(`${apiBase}/auth/me`);
const data = await response.json();
return data.success && data.user;
} catch (error) {
console.log('用户未登录');
console.log('ç¨æˆ·æœªç»å½?);
return false;
}
}
@@ -196,8 +188,7 @@ class MainPage {
</div>
`;
// 添加到页面
document.body.appendChild(notification);
// 添加到页é<EFBFBD>? document.body.appendChild(notification);
// 显示通知
setTimeout(() => {

View File

@@ -19,10 +19,10 @@ class StudentManager {
});
if (response.status === 401) {
// 未登录,重定向到登录页
// <EFBFBD>芰蒈敶𤏪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>憿?
this.showNotification('请先登录', 'error');
setTimeout(() => {
window.location.href = '/html/login.html';
window.location.href = '/login';
}, 1500);
return;
}
@@ -113,14 +113,14 @@ class StudentManager {
<i class="fas fa-star"></i>
</div>
<div class="stat-value">${statistics.totalCredits}</div>
<div class="stat-label">总学分</div>
<div class="stat-label"><EFBFBD>餃郎<EFBFBD>?/div>
</div>
<div class="stat-card">
<div class="stat-icon grade">
<i class="fas fa-chart-line"></i>
</div>
<div class="stat-value">${statistics.averageScore}</div>
<div class="stat-label">平均分</div>
<div class="stat-label">撟喳<EFBFBD><EFBFBD>?/div>
</div>
<div class="stat-card">
<div class="stat-icon teacher">
@@ -143,10 +143,10 @@ class StudentManager {
});
if (response.status === 401) {
// 未登录,重定向到登录页
// <EFBFBD>芰蒈敶𤏪<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>憿?
this.showNotification('请先登录', 'error');
setTimeout(() => {
window.location.href = '/html/login.html';
window.location.href = '/login';
}, 1500);
return;
}
@@ -156,7 +156,7 @@ class StudentManager {
if (data.success) {
const profile = data.profile;
// 更新学生仪表板顶部信息
// <EFBFBD>湔鰵摮衣<EFBFBD>隞芾”<EFBFBD>輸▲<EFBFBD>其縑<EFBFBD>?
const userNameElement = document.getElementById('userName');
const studentNameElement = document.getElementById('studentName');
const studentClassElement = document.getElementById('studentClass');
@@ -168,7 +168,7 @@ class StudentManager {
studentNameElement.textContent = profile.full_name || profile.username;
}
if (studentClassElement) {
studentClassElement.textContent = profile.class_name || '未设置';
studentClassElement.textContent = profile.class_name || '<EFBFBD>芾挽蝵?;
}
profileElement.innerHTML = `
@@ -202,14 +202,14 @@ class StudentManager {
<i class="fas fa-book"></i>
<div>
<h4>专业</h4>
<p>${profile.major || '未设置'}</p>
<p>${profile.major || '<EFBFBD>芾挽蝵?}</p>
</div>
</div>
<div class="detail-item">
<i class="fas fa-calendar-alt"></i>
<div>
<h4>入学年份</h4>
<p>${profile.enrollment_year || '未设置'}</p>
<p>${profile.enrollment_year || '<EFBFBD>芾挽蝵?}</p>
</div>
</div>
</div>
@@ -258,14 +258,14 @@ class StudentManager {
else if (grade.score >= 80) gradeDescription = '良好';
else if (grade.score >= 70) gradeDescription = '中等';
else if (grade.score >= 60) gradeDescription = '及格';
else gradeDescription = '不及格';
else gradeDescription = '銝滚<EFBFBD><EFBFBD>?;
container.innerHTML = `
<div class="grade-detail-card">
<div class="grade-header">
<h2>${grade.course_name} (${grade.course_code})</h2>
<div class="grade-score ${grade.score >= 60 ? 'score-pass' : 'score-fail'}">
${grade.score}
${grade.score} <EFBFBD>?
<span class="grade-description">${gradeDescription}</span>
</div>
</div>
@@ -274,23 +274,23 @@ class StudentManager {
<div class="detail-section">
<h3><i class="fas fa-info-circle"></i> </h3>
<div class="detail-row">
<span>学分</span>
<span>摮血<EFBFBD>?/span>
<strong>${grade.credit}</strong>
</div>
<div class="detail-row">
<span>学期</span>
<span>摮行<EFBFBD>?/span>
<strong>${grade.semester}</strong>
</div>
<div class="detail-row">
<span>考试日期</span>
<span><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?/span>
<strong>${new Date(grade.exam_date).toLocaleDateString()}</strong>
</div>
<div class="detail-row">
<span>等级</span>
<span>蝑厩漣嚗?/span>
<strong class="grade-level-${grade.grade_level}">${grade.grade_level || '-'}</strong>
</div>
<div class="detail-row">
<span>绩点</span>
<span>蝏拍<EFBFBD>?/span>
<strong>${grade.grade_point || '-'}</strong>
</div>
</div>
@@ -298,31 +298,31 @@ class StudentManager {
<div class="detail-section">
<h3><i class="fas fa-user-graduate"></i> </h3>
<div class="detail-row">
<span>姓名</span>
<span>憪枏<EFBFBD>?/span>
<strong>${grade.full_name}</strong>
</div>
<div class="detail-row">
<span>学号</span>
<span>摮血噡嚗?/span>
<strong>${grade.student_number}</strong>
</div>
<div class="detail-row">
<span>班级</span>
<span><EFBFBD>剔漣嚗?/span>
<strong>${grade.class_name}</strong>
</div>
<div class="detail-row">
<span>专业</span>
<strong>${grade.major || '未设置'}</strong>
<span>銝㮖<EFBFBD>?/span>
<strong>${grade.major || '<EFBFBD>芾挽蝵?}</strong>
</div>
</div>
<div class="detail-section">
<h3><i class="fas fa-chalkboard-teacher"></i> </h3>
<div class="detail-row">
<span>任课教师</span>
<span>隞餉紋<EFBFBD><EFBFBD>?/span>
<strong>${grade.teacher_name}</strong>
</div>
<div class="detail-row">
<span>教师邮箱</span>
<span><EFBFBD><EFBFBD><EFBFBD>桃拳嚗?/span>
<strong>${grade.teacher_email}</strong>
</div>
</div>
@@ -337,7 +337,7 @@ class StudentManager {
<div class="grade-actions">
<button onclick="window.print()" class="btn btn-secondary">
<i class="fas fa-print"></i>
<i class="fas fa-print"></i> <EFBFBD><EFBFBD><EFBFBD>?
</button>
<button onclick="window.history.back()" class="btn btn-primary">
<i class="fas fa-arrow-left"></i>
@@ -352,7 +352,7 @@ class StudentManager {
if (!ctx) return;
if (typeof Chart === 'undefined') {
// 如果没有Chart.js,延迟加载
// <EFBFBD><EFBFBD>瘝⊥<EFBFBD>Chart.js<EFBFBD>辣餈笔<EFBFBD>頧?
this.loadChartLibrary().then(() => this.updateChart(grades));
return;
}
@@ -360,7 +360,7 @@ class StudentManager {
const courseNames = grades.map(g => g.course_name);
const scores = grades.map(g => g.score);
// 销毁现有图表实例
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>匧㦛銵典<EFBFBD>靘?
if (window.gradeChart instanceof Chart) {
window.gradeChart.destroy();
}
@@ -421,7 +421,7 @@ class StudentManager {
}
showNotification(message, type = 'info') {
// 使用AuthManager的通知系统或自己实现
// 雿輻鍂AuthManager<EFBFBD><EFBFBD><EFBFBD>𡁶䰻蝟餌<EFBFBD><EFBFBD>𤥁䌊撌勗<EFBFBD><EFBFBD>?
if (window.authManager && window.authManager.showNotification) {
window.authManager.showNotification(message, type);
} else {

View File

@@ -9,9 +9,8 @@ class TeacherDashboard {
}
async init() {
// 检查登录状态
if (!await this.checkAuth()) {
window.location.href = '/frontend/html/login.html';
// <EFBFBD><EFBFBD>亦蒈敶閧𠶖<EFBFBD>? if (!await this.checkAuth()) {
window.location.href = '/login';
return;
}
@@ -44,7 +43,7 @@ class TeacherDashboard {
const data = await response.json();
return data.success && data.user.role === 'teacher';
} catch (error) {
console.error('认证检查失败:', error);
console.error('霈方<EFBFBD><EFBFBD><EFBFBD>亙仃韐?', error);
return false;
}
}
@@ -108,8 +107,7 @@ class TeacherDashboard {
}
populateCourseSelectors() {
// 填充课程选择器
const courseSelectors = document.querySelectorAll('.course-selector');
// 憛怠<EFBFBD>霂曄<EFBFBD><EFBFBD>㗇𥋘<EFBFBD>? const courseSelectors = document.querySelectorAll('.course-selector');
courseSelectors.forEach(select => {
select.innerHTML = '<option value="">请选择课程</option>';
this.courses.forEach(course => {
@@ -153,7 +151,7 @@ class TeacherDashboard {
<span class="grade-score">${grade.score}</span>
<span class="grade-level">${grade.grade_level}</span>
</td>
<td>${grade.exam_date ? new Date(grade.exam_date).toLocaleDateString() : '未设置'}</td>
<td>${grade.exam_date ? new Date(grade.exam_date).toLocaleDateString() : '<EFBFBD>芾挽蝵?}</td>
<td>
<div class="action-buttons">
<button class="btn-edit" data-id="${grade.id}">
@@ -226,8 +224,7 @@ class TeacherDashboard {
}
});
// 退出登录
document.getElementById('logoutBtn')?.addEventListener('click', () => {
// <EFBFBD><EFBFBD><EFBFBD>箇蒈敶? document.getElementById('logoutBtn')?.addEventListener('click', () => {
this.handleLogout();
});
}
@@ -275,7 +272,7 @@ class TeacherDashboard {
return;
}
if (!confirm(`确定要删除选中的 ${checkboxes.length} 条成绩记录吗?`)) {
if (!confirm(`蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>劐葉<EFBFBD>?${checkboxes.length} <EFBFBD><EFBFBD>蝏抵扇敶訫<EFBFBD>嚗鬮)) {
return;
}
@@ -308,12 +305,12 @@ class TeacherDashboard {
// 这里可以打开编辑模态框
// 暂时使用简单提示框
const newScore = prompt('请输入新的分数:', grade.score);
const newScore = prompt('霂瑁<EFBFBD><EFBFBD>交鰵<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?', grade.score);
if (newScore === null) return;
const numericScore = parseFloat(newScore);
if (isNaN(numericScore) || numericScore < 0 || numericScore > 100) {
this.showNotification('请输入0-100之间的有效分数', 'error');
this.showNotification('霂瑁<EFBFBD><EFBFBD>?-100銋钅𡢿<E99285><F0A1A2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?, 'error');
return;
}
@@ -343,7 +340,7 @@ class TeacherDashboard {
}
async deleteGrade(gradeId) {
if (!confirm('确定要删除这条成绩记录吗?')) {
if (!confirm('蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏抵扇敶訫<EFBFBD>?)) {
return;
}
@@ -374,10 +371,10 @@ class TeacherDashboard {
});
if (response.ok) {
window.location.href = '/frontend/html/login.html';
window.location.href = '/login';
}
} catch (error) {
console.error('退出登录失败:', error);
console.error('<EFBFBD><EFBFBD><EFBFBD>箇蒈敶訫仃韐?', error);
}
}

View File

@@ -4,33 +4,32 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统 - 管理员仪表板</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
</head>
<body>
<!-- 顶部导航栏 -->
<!-- 憿園<EFBFBD>撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="navbar-brand">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</div>
<div class="navbar-menu">
<a href="index.html" class="btn btn-secondary">
<a href="/" class="btn btn-secondary">
<i class="fas fa-home"></i> 主页
</a>
<div class="navbar-user">
<span class="user-name" id="userName">管理员</span>
<span class="user-name" id="userName">蝞∠<EFBFBD><EFBFBD>?/span>
<button id="logoutBtn" class="btn btn-primary">
<i class="fas fa-sign-out-alt"></i> 退出
</button>
<i class="fas fa-sign-out-alt"></i> <EFBFBD><EFBFBD><EFBFBD>? </button>
</div>
</div>
</nav>
<!-- 仪表板容器 -->
<!-- 隞芾”<EFBFBD>踹捆<EFBFBD>?-->
<div class="dashboard-container">
<!-- 左侧侧边栏 -->
<!-- 撌虫儒靘扯器<EFBFBD>?-->
<aside class="sidebar">
<div class="sidebar-header">
<div class="user-info">
@@ -38,8 +37,8 @@
<i class="fas fa-user-shield"></i>
</div>
<div class="user-details">
<h3 id="adminName">管理员</h3>
<p>系统管理员 | 权限:<span id="adminRole">超级管理员</span></p>
<h3 id="adminName">蝞∠<EFBFBD><EFBFBD>?/h3>
<p>蝟餌<EFBFBD>蝞∠<EFBFBD><EFBFBD>?| <20><><EFBFBD>嚗?span id="adminRole">頞<>漣蝞∠<E89D9E><E288A0>?/span></p>
</div>
</div>
</div>
@@ -48,17 +47,17 @@
<li>
<a href="#" class="active">
<i class="fas fa-tachometer-alt"></i>
<span>仪表板</span>
<span>隞芾”<EFBFBD>?/span>
</a>
</li>
<li>
<a href="user_management.html">
<a href="/admin/user_management">
<i class="fas fa-users"></i>
<span>用户管理</span>
</a>
</li>
<li>
<a href="student_management.html">
<a href="/admin/student_management">
<i class="fas fa-user-graduate"></i>
<span>学生管理</span>
</a>
@@ -102,7 +101,7 @@
<div>
<h1 class="page-title">管理员仪表板</h1>
<div class="breadcrumb">
<a href="index.html">主页</a>
<a href="/">銝駁△</a>
<i class="fas fa-chevron-right"></i>
<span>管理员仪表板</span>
</div>
@@ -146,8 +145,7 @@
<div class="stat-value" id="totalTeachers">128</div>
<div class="stat-label">教师总数</div>
<div class="stat-change">
<i class="fas fa-minus"></i> 无变化
</div>
<i class="fas fa-minus"></i> <EFBFBD><EFBFBD><EFBFBD>? </div>
</div>
</div>
@@ -173,8 +171,7 @@
</div>
<h3 class="function-title">用户管理</h3>
<p class="function-description">
管理所有用户账户,包括添加、编辑、删除用户,设置用户角色和权限。
</p>
蝞∠<EFBFBD><EFBFBD><EFBFBD><EFBFBD>厩鍂<EFBFBD>瑁揭<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡠺瘛餃<EFBFBD><EFBFBD><EFBFBD><EFBFBD>颲㻫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>斤鍂<EFBFBD><EFBFBD>霈曄蔭<EFBFBD><EFBFBD>閫坿𠧧<EFBFBD><EFBFBD><EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary">进入管理</button>
</div>
@@ -184,8 +181,7 @@
</div>
<h3 class="function-title">学生管理</h3>
<p class="function-description">
管理学生信息,包括学籍管理、班级分配、信息维护和批量导入导出。
</p>
蝞∠<EFBFBD>摮衣<EFBFBD>靽⊥<EFBFBD><EFBFBD><EFBFBD><EFBFBD>砍郎蝐滨恣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>号蝥批<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>舐輕<EFBFBD><EFBFBD><EFBFBD><EFBFBD>撖澆<EFBFBD>撖澆枂<EFBFBD>? </p>
<button class="btn btn-primary">进入管理</button>
</div>
@@ -195,8 +191,7 @@
</div>
<h3 class="function-title">教师管理</h3>
<p class="function-description">
管理教师信息,包括教师分配、课程安排、权限设置和绩效考核。
</p>
蝞∠<EFBFBD><EFBFBD><EFBFBD>靽⊥<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>紋蝔见<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞱挽蝵桀<EFBFBD>蝏拇<EFBFBD><EFBFBD><EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary">进入管理</button>
</div>
@@ -206,30 +201,28 @@
</div>
<h3 class="function-title">成绩统计</h3>
<p class="function-description">
查看全校成绩统计,生成分析报告,支持图表展示和数据导出。
</p>
<EFBFBD><EFBFBD><EFBFBD>冽嵗<EFBFBD>鞟貍蝏蠘恣嚗𣬚<EFBFBD><EFBFBD>𣂼<EFBFBD><EFBFBD>鞉𥁒<EFBFBD>𠺪<EFBFBD><EFBFBD><EFBFBD><EFBFBD>曇”撅閧內<EFBFBD>峕㺭<EFBFBD>桀紡<EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary">查看统计</button>
</div>
</div>
<!-- 系统状态 -->
<!-- 蝟餌<EFBFBD><EFBFBD><EFBFBD>?-->
<div class="system-status">
<h2 class="section-title">
<i class="fas fa-server"></i>
系统状态
</h2>
蝟餌<EFBFBD><EFBFBD><EFBFBD>? </h2>
<div class="status-list">
<div class="status-item">
<div class="status-indicator online"></div>
<div>
<div class="status-label">数据库服务</div>
<div class="status-label"><EFBFBD>唳旿摨𤘪<EFBFBD><EFBFBD>?/div>
<div class="status-value">运行正常 | 响应时间: 12ms</div>
</div>
</div>
<div class="status-item">
<div class="status-indicator online"></div>
<div>
<div class="status-label">Web服务器</div>
<div class="status-label">Web<EFBFBD>滚𦛚<EFBFBD>?/div>
<div class="status-value">运行正常 | 在线用户: 156</div>
</div>
</div>
@@ -237,7 +230,7 @@
<div class="status-indicator online"></div>
<div>
<div class="status-label">文件存储</div>
<div class="status-value">使用率: 65% | 剩余: 35GB</div>
<div class="status-value">雿輻鍂<EFBFBD>? 65% | <EFBFBD><EFBFBD>: 35GB</div>
</div>
</div>
<div class="status-item">
@@ -250,12 +243,11 @@
</div>
</div>
<!-- 最近活动 -->
<!-- <EFBFBD><EFBFBD>餈烐暑<EFBFBD>?-->
<div class="recent-activities">
<h2 class="section-title">
<i class="fas fa-history"></i>
最近活动
</h2>
<EFBFBD><EFBFBD>餈烐暑<EFBFBD>? </h2>
<ul class="activity-list">
<li class="activity-item">
<div class="activity-icon">
@@ -263,7 +255,7 @@
</div>
<div class="activity-content">
<div class="activity-title">新增学生用户</div>
<div class="activity-time">10分钟前 | 操作人: 管理员</div>
<div class="activity-time">10<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?| <20><EFBFBD>鈭? 蝞∠<E89D9E><E288A0>?/div>
</div>
</li>
<li class="activity-item">
@@ -272,7 +264,7 @@
</div>
<div class="activity-content">
<div class="activity-title">修改教师信息</div>
<div class="activity-time">1小时前 | 操作人: 管理员</div>
<div class="activity-time">1撠𤩺𧒄<EFBFBD>?| <20><EFBFBD>鈭? 蝞∠<E89D9E><E288A0>?/div>
</div>
</li>
<li class="activity-item">
@@ -281,7 +273,7 @@
</div>
<div class="activity-content">
<div class="activity-title">生成成绩统计报告</div>
<div class="activity-time">3小时前 | 操作人: 系统</div>
<div class="activity-time">3撠𤩺𧒄<EFBFBD>?| <20><EFBFBD>鈭? 蝟餌<E89D9F></div>
</div>
</li>
<li class="activity-item">
@@ -290,7 +282,7 @@
</div>
<div class="activity-content">
<div class="activity-title">导出用户数据</div>
<div class="activity-time">5小时前 | 操作人: 管理员</div>
<div class="activity-time">5撠𤩺𧒄<EFBFBD>?| <20><EFBFBD>鈭? 蝞∠<E89D9E><E288A0>?/div>
</div>
</li>
<li class="activity-item">
@@ -299,7 +291,7 @@
</div>
<div class="activity-content">
<div class="activity-title">系统设置更新</div>
<div class="activity-time">1天前 | 操作人: 管理员</div>
<div class="activity-time">1憭拙<EFBFBD> | <20><EFBFBD>鈭? 蝞∠<E89D9E><E288A0>?/div>
</div>
</li>
</ul>
@@ -328,16 +320,13 @@
updateCurrentTime();
setInterval(updateCurrentTime, 1000);
// 退出登录
document.getElementById('logoutBtn').addEventListener('click', function() {
if (confirm('确定要退出登录吗?')) {
// 清除登录状态
localStorage.removeItem('token');
// <EFBFBD><EFBFBD><EFBFBD>箇蒈敶? document.getElementById('logoutBtn').addEventListener('click', function() {
if (confirm('蝖桀<E89D96><EFBFBD><E996AC><EFBFBD><EFBFBD>箇蒈敶訫<E695B6>嚗?)) {
// 皜<><EFBFBD><EFBFBD><E9A483><EFBFBD>? localStorage.removeItem('token');
localStorage.removeItem('userRole');
localStorage.removeItem('userInfo');
// 跳转到登录页面
window.location.href = 'login.html';
// 頝唾蓮<EFBFBD>啁蒈敶閖△<EFBFBD>? window.location.href = 'login.html';
}
});

View File

@@ -4,55 +4,55 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生管理 - XX学校成绩管理系统</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<!-- 导航栏 -->
<!-- 撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="container">
<div class="navbar-brand">
<a href="index.html">
<a href="/">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</a>
</div>
<div class="navbar-menu">
<a href="index.html" class="navbar-item">
<a href="/" class="navbar-item">
<i class="fas fa-home"></i>
<span>主页</span>
</a>
<a href="admin_dashboard.html" class="navbar-item">
<a href="/admin/dashboard" class="navbar-item">
<i class="fas fa-tachometer-alt"></i>
<span>控制面板</span>
</a>
<a href="student_management.html" class="navbar-item active">
<a href="/admin/student_management" class="navbar-item active">
<i class="fas fa-users"></i>
<span>学生管理</span>
</a>
<a href="grade_management.html" class="navbar-item">
<a href="/teacher/grade_management" class="navbar-item">
<i class="fas fa-chart-bar"></i>
<span>成绩管理</span>
</a>
<a href="user_management.html" class="navbar-item">
<a href="/admin/user_management" class="navbar-item">
<i class="fas fa-user-cog"></i>
<span>用户管理</span>
</a>
<div class="navbar-user">
<i class="fas fa-user-circle"></i>
<span>管理员</span>
<span>蝞∠<EFBFBD><EFBFBD>?/span>
<div class="user-dropdown">
<a href="#"><i class="fas fa-user"></i> 个人资料</a>
<a href="#"><i class="fas fa-cog"></i> 设置</a>
<a href="login.html"><i class="fas fa-sign-out-alt"></i> 退出登录</a>
<a href="/login"><i class="fas fa-sign-out-alt"></i> <EFBFBD><EFBFBD><EFBFBD>箇蒈敶?/a>
</div>
</div>
</div>
</div>
</nav>
<!-- 主要内容区 -->
<!-- 銝餉<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?-->
<main class="main-content">
<div class="container">
<div class="student-management">
@@ -62,35 +62,35 @@
<p>管理学生基本信息,支持添加、编辑、删除和查询学生信息</p>
</div>
<!-- 筛选区域 -->
<!-- 蝑偦<EFBFBD>匧躹<EFBFBD>?-->
<div class="filter-section">
<div class="filter-row">
<div class="filter-group">
<label for="student-id"><i class="fas fa-id-card"></i> 学号</label>
<input type="text" id="student-id" placeholder="请输入学号">
<input type="text" id="student-id" placeholder="霂瑁<EFBFBD><EFBFBD>亙郎<EFBFBD>?>
</div>
<div class="filter-group">
<label for="student-name"><i class="fas fa-user"></i> 姓名</label>
<input type="text" id="student-name" placeholder="请输入姓名">
<input type="text" id="student-name" placeholder="霂瑁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?>
</div>
<div class="filter-group">
<label for="class-select"><i class="fas fa-school"></i> 班级</label>
<select id="class-select">
<option value="">全部班级</option>
<option value="计算机科学与技术1班">计算机科学与技术1班</option>
<option value="计算机科学与技术2班">计算机科学与技术2班</option>
<option value="软件工程1班">软件工程1班</option>
<option value="软件工程2班">软件工程2班</option>
<option value="网络工程1班">网络工程1班</option>
<option value="网络工程2班">网络工程2班</option>
<option value="霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?>霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?>霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="頧臭辣撌亦<EFBFBD>1<EFBFBD>?>頧臭辣撌亦<EFBFBD>1<EFBFBD>?/option>
<option value="頧臭辣撌亦<EFBFBD>2<EFBFBD>?>頧臭辣撌亦<EFBFBD>2<EFBFBD>?/option>
<option value="蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?>蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?/option>
<option value="蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?>蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?/option>
</select>
</div>
<div class="filter-group">
<label for="gender-select"><i class="fas fa-venus-mars"></i> 性别</label>
<select id="gender-select">
<option value="">全部性别</option>
<option value="男"></option>
<option value="女"></option>
<option value="<EFBFBD>?><EFBFBD>?/option>
<option value="憟?>憟?/option>
</select>
</div>
</div>
@@ -131,7 +131,7 @@
</tr>
</thead>
<tbody id="student-table-body">
<!-- 数据将通过JavaScript动态加载 -->
<!-- <EFBFBD>唳旿撠<EFBFBD><EFBFBD><EFBFBD>JavaScript<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧?-->
<tr>
<td colspan="8" class="loading">
<i class="fas fa-spinner fa-spin"></i>
@@ -146,14 +146,12 @@
<div class="pagination" id="pagination">
<button id="prev-btn" disabled>
<i class="fas fa-chevron-left"></i>
上一页
</button>
銝𠹺<EFBFBD>憿? </button>
<button class="active">1</button>
<button>2</button>
<button>3</button>
<button id="next-btn">
下一页
<i class="fas fa-chevron-right"></i>
銝衤<EFBFBD>憿? <i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
@@ -163,8 +161,8 @@
<!-- 页脚 -->
<footer class="footer">
<div class="container">
<p>© 2023 XX学校成绩管理系统. 版权所有.</p>
<p>技术支持: 计算机科学与技术学院</p>
<p> 2023 XX摮行嵗<EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?</p>
<p><EFBFBD><EFBFBD><EFBFBD>舀𣈲<EFBFBD>? 霈∠<E99C88><E288A0><EFBFBD>摮虫<E691AE><E899AB><EFBFBD><EFBFBD>臬郎<E887AC>?/p>
</div>
</footer>
@@ -174,8 +172,8 @@
{
id: '20230001',
name: '张三',
gender: '男',
class: '计算机科学与技术1班',
gender: '<EFBFBD>?,
class: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138001',
email: 'zhangsan@example.com',
enrollmentDate: '2023-09-01'
@@ -183,8 +181,8 @@
{
id: '20230002',
name: '李四',
gender: '女',
class: '计算机科学与技术1班',
gender: '憟?,
class: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138002',
email: 'lisi@example.com',
enrollmentDate: '2023-09-01'
@@ -192,8 +190,8 @@
{
id: '20230003',
name: '王五',
gender: '男',
class: '计算机科学与技术2班',
gender: '<EFBFBD>?,
class: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138003',
email: 'wangwu@example.com',
enrollmentDate: '2023-09-01'
@@ -201,8 +199,8 @@
{
id: '20230004',
name: '赵六',
gender: '女',
class: '软件工程1班',
gender: '憟?,
class: '頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138004',
email: 'zhaoliu@example.com',
enrollmentDate: '2023-09-01'
@@ -210,8 +208,8 @@
{
id: '20230005',
name: '钱七',
gender: '男',
class: '软件工程2班',
gender: '<EFBFBD>?,
class: '頧臭辣撌亦<EFBFBD>2<EFBFBD>?,
phone: '13800138005',
email: 'qianqi@example.com',
enrollmentDate: '2023-09-01'
@@ -219,8 +217,8 @@
{
id: '20230006',
name: '孙八',
gender: '男',
class: '网络工程1班',
gender: '<EFBFBD>?,
class: '蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138006',
email: 'sunba@example.com',
enrollmentDate: '2023-09-01'
@@ -228,8 +226,8 @@
{
id: '20230007',
name: '周九',
gender: '女',
class: '网络工程2班',
gender: '憟?,
class: '蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?,
phone: '13800138007',
email: 'zhoujiu@example.com',
enrollmentDate: '2023-09-01'
@@ -237,16 +235,15 @@
{
id: '20230008',
name: '吴十',
gender: '男',
class: '计算机科学与技术1班',
gender: '<EFBFBD>?,
class: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138008',
email: 'wushi@example.com',
enrollmentDate: '2023-09-01'
}
];
// 当前页数据
let currentPage = 1;
// 敶枏<EFBFBD>憿菜㺭<EFBFBD>? let currentPage = 1;
const pageSize = 5;
let filteredStudents = [...mockStudents];
@@ -272,7 +269,7 @@
<td colspan="8" class="no-results">
<i class="fas fa-user-slash"></i>
<h3>没有找到学生信息</h3>
<p>请尝试调整筛选条件或添加新学生</p>
<p>霂瑕<EFBFBD>霂閗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇辺隞嗆<EFBFBD>瘛餃<EFBFBD><EFBFBD>啣郎<EFBFBD>?/p>
</td>
</tr>
`;
@@ -325,13 +322,11 @@
}
});
// 更新上一页/下一页按钮状态
prevBtn.disabled = currentPage === 1;
// <EFBFBD>湔鰵銝𠹺<EFBFBD>憿?銝衤<E98A9D>憿菜<E686BF><E88F9C>桃𠶖<E6A183>? prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
}
// 筛选学生
function filterStudents() {
// 蝑偦<EFBFBD>匧郎<EFBFBD>? function filterStudents() {
const studentId = document.getElementById('student-id').value.trim();
const studentName = document.getElementById('student-name').value.trim();
const selectedClass = document.getElementById('class-select').value;
@@ -351,8 +346,7 @@
updatePagination();
}
// 重置筛选条件
function resetFilters() {
// <EFBFBD>滨蔭蝑偦<EFBFBD>㗇辺隞? function resetFilters() {
document.getElementById('student-id').value = '';
document.getElementById('student-name').value = '';
document.getElementById('class-select').value = '';
@@ -366,15 +360,13 @@
// 添加学生
function addStudent() {
alert('添加学生功能将在后端API完成后实现');
// 这里可以打开一个模态框来添加学生信息
}
alert('瘛餃<EFBFBD>摮衣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡒊垢API摰峕<EFBFBD><EFBFBD>𤾸<EFBFBD><EFBFBD>?);
// 餈䠷<EFBFBD><EFBFBD>臭誑<EFBFBD><EFBFBD><EFBFBD>銝芣芋<EFBFBD><EFBFBD><EFBFBD><EFBFBD>交溶<EFBFBD>惩郎<EFBFBD>煺縑<EFBFBD>? }
// 编辑学生
function editStudent(studentId) {
alert(`编辑学生 ${studentId} 功能将在后端API完成后实现`);
// 这里可以打开一个模态框来编辑学生信息
}
// 餈䠷<EFBFBD><EFBFBD>臭誑<EFBFBD><EFBFBD><EFBFBD>銝芣芋<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>颲穃郎<EFBFBD>煺縑<EFBFBD>? }
// 删除学生
function deleteStudent(studentId) {
@@ -386,7 +378,7 @@
// 导出数据
function exportData() {
alert('导出数据功能将在后端API完成后实现');
alert('撖澆枂<EFBFBD>唳旿<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡒊垢API摰峕<EFBFBD><EFBFBD>𤾸<EFBFBD><EFBFBD>?);
// 这里可以调用API导出Excel或CSV文件
}
@@ -397,8 +389,7 @@
updatePagination();
}
// 初始化事件监听
function initEventListeners() {
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>隞嗥<EFBFBD><EFBFBD>? function initEventListeners() {
searchBtn.addEventListener('click', filterStudents);
resetBtn.addEventListener('click', resetFilters);
addBtn.addEventListener('click', addStudent);
@@ -427,8 +418,7 @@
}
});
// 输入框回车搜索
document.getElementById('student-id').addEventListener('keypress', (e) => {
// 颲枏<EFBFBD><EFBFBD><EFBFBD>頧行<EFBFBD>蝝? document.getElementById('student-id').addEventListener('keypress', (e) => {
if (e.key === 'Enter') filterStudents();
});

View File

@@ -4,35 +4,35 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户管理 - XX学校成绩管理系统</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<!-- 导航栏 -->
<!-- 撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="container">
<div class="navbar-brand">
<a href="index.html">
<a href="/">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</a>
</div>
<div class="navbar-menu">
<div class="navbar-start">
<a href="admin_dashboard.html" class="navbar-item">
<a href="/admin/dashboard" class="navbar-item">
<i class="fas fa-tachometer-alt"></i>
<span>仪表板</span>
<span>隞芾”<EFBFBD>?/span>
</a>
<a href="user_management.html" class="navbar-item active">
<a href="/admin/user_management" class="navbar-item active">
<i class="fas fa-users"></i>
<span>用户管理</span>
</a>
<a href="student_management.html" class="navbar-item">
<a href="/admin/student_management" class="navbar-item">
<i class="fas fa-user-graduate"></i>
<span>学生管理</span>
</a>
<a href="grade_management.html" class="navbar-item">
<a href="/teacher/grade_management" class="navbar-item">
<i class="fas fa-chart-bar"></i>
<span>成绩统计</span>
</a>
@@ -40,25 +40,23 @@
<div class="navbar-end">
<div class="navbar-item user-info">
<i class="fas fa-user-circle"></i>
<span>管理员</span>
<span>蝞∠<EFBFBD><EFBFBD>?/span>
<div class="dropdown">
<a href="#" class="dropdown-toggle">
<i class="fas fa-caret-down"></i>
</a>
<div class="dropdown-menu">
<a href="admin_dashboard.html" class="dropdown-item">
<a href="/admin/dashboard" class="dropdown-item">
<i class="fas fa-tachometer-alt"></i>
仪表板
</a>
隞芾”<EFBFBD>? </a>
<a href="#" class="dropdown-item">
<i class="fas fa-cog"></i>
系统设置
</a>
<div class="dropdown-divider"></div>
<a href="index.html" class="dropdown-item">
<a href="/" class="dropdown-item">
<i class="fas fa-sign-out-alt"></i>
退出登录
</a>
<EFBFBD><EFBFBD><EFBFBD>箇蒈敶? </a>
</div>
</div>
</div>
@@ -75,13 +73,13 @@
<div class="page-header">
<h1>用户管理</h1>
<div class="breadcrumb">
<a href="index.html">主页</a> &gt;
<a href="admin_dashboard.html">管理员仪表板</a> &gt;
<a href="/">銝駁△</a> &gt;
<a href="/admin/dashboard">蝞∠<EFBFBD><EFBFBD>䀝貌銵冽踎</a> &gt;
<span>用户管理</span>
</div>
</div>
<!-- 筛选区域 -->
<!-- 蝑偦<EFBFBD>匧躹<EFBFBD>?-->
<div class="filter-section">
<form class="filter-form" id="filter-form">
<div class="filter-group">
@@ -90,13 +88,13 @@
</div>
<div class="filter-group">
<label for="user-name">姓名</label>
<input type="text" id="user-name" placeholder="请输入姓名">
<input type="text" id="user-name" placeholder="霂瑁<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?>
</div>
<div class="filter-group">
<label for="role-select">角色</label>
<select id="role-select">
<option value="">全部角色</option>
<option value="admin">管理员</option>
<option value="admin">蝞∠<EFBFBD><EFBFBD>?/option>
<option value="teacher">教师</option>
<option value="student">学生</option>
</select>
@@ -105,12 +103,12 @@
<label for="class-select">班级</label>
<select id="class-select">
<option value="">全部班级</option>
<option value="计算机科学与技术1班">计算机科学与技术1班</option>
<option value="计算机科学与技术2班">计算机科学与技术2班</option>
<option value="软件工程1班">软件工程1班</option>
<option value="软件工程2班">软件工程2班</option>
<option value="网络工程1班">网络工程1班</option>
<option value="网络工程2班">网络工程2班</option>
<option value="霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?>霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?>霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="頧臭辣撌亦<EFBFBD>1<EFBFBD>?>頧臭辣撌亦<EFBFBD>1<EFBFBD>?/option>
<option value="頧臭辣撌亦<EFBFBD>2<EFBFBD>?>頧臭辣撌亦<EFBFBD>2<EFBFBD>?/option>
<option value="蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?>蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?/option>
<option value="蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?>蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?/option>
</select>
</div>
<div class="filter-actions">
@@ -150,7 +148,7 @@
</tr>
</thead>
<tbody id="user-table-body">
<!-- 数据将通过JavaScript动态加载 -->
<!-- <EFBFBD>唳旿撠<EFBFBD><EFBFBD><EFBFBD>JavaScript<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧?-->
<tr>
<td colspan="8" class="loading">
<i class="fas fa-spinner fa-spin"></i>
@@ -165,16 +163,14 @@
<div class="pagination" id="pagination">
<button id="prev-btn" disabled>
<i class="fas fa-chevron-left"></i>
上一页
</button>
銝𠹺<EFBFBD>憿? </button>
<div id="page-numbers">
<button class="active">1</button>
<button>2</button>
<button>3</button>
</div>
<button id="next-btn">
下一页
<i class="fas fa-chevron-right"></i>
銝衤<EFBFBD>憿? <i class="fas fa-chevron-right"></i>
</button>
</div>
</div>
@@ -184,8 +180,8 @@
<!-- 页脚 -->
<footer class="footer">
<div class="container">
<p>&copy; 2023 XX学校成绩管理系统. 版权所有.</p>
<p>技术支持: 信息技术中心 | 联系电话: 010-12345678</p>
<p>&copy; 2023 XX摮行嵗<EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?</p>
<p><EFBFBD><EFBFBD><EFBFBD>舀𣈲<EFBFBD>? 靽⊥<E99DBD><E28AA5><EFBFBD><EFBFBD>臭葉敹?| <20>𠉛頂<F0A0899B><EFBFBD>: 010-12345678</p>
</div>
</footer>
@@ -206,7 +202,7 @@
id: 'teacher001',
name: '李老师',
role: 'teacher',
className: '计算机科学与技术1班',
className: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138002',
email: 'li.teacher@xxschool.edu.cn',
registerTime: '2023-02-10'
@@ -215,7 +211,7 @@
id: 'teacher002',
name: '王老师',
role: 'teacher',
className: '软件工程1班',
className: '頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138003',
email: 'wang.teacher@xxschool.edu.cn',
registerTime: '2023-02-12'
@@ -224,7 +220,7 @@
id: 'student001',
name: '张三',
role: 'student',
className: '计算机科学与技术1班',
className: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138004',
email: 'zhangsan@xxschool.edu.cn',
registerTime: '2023-03-01'
@@ -233,7 +229,7 @@
id: 'student002',
name: '李四',
role: 'student',
className: '计算机科学与技术1班',
className: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138005',
email: 'lisi@xxschool.edu.cn',
registerTime: '2023-03-01'
@@ -242,7 +238,7 @@
id: 'student003',
name: '王五',
role: 'student',
className: '软件工程1班',
className: '頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138006',
email: 'wangwu@xxschool.edu.cn',
registerTime: '2023-03-02'
@@ -251,7 +247,7 @@
id: 'student004',
name: '赵六',
role: 'student',
className: '软件工程1班',
className: '頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138007',
email: 'zhaoliu@xxschool.edu.cn',
registerTime: '2023-03-02'
@@ -260,7 +256,7 @@
id: 'student005',
name: '钱七',
role: 'student',
className: '网络工程1班',
className: '蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?,
phone: '13800138008',
email: 'qianqi@xxschool.edu.cn',
registerTime: '2023-03-03'
@@ -269,7 +265,7 @@
id: 'student006',
name: '孙八',
role: 'student',
className: '网络工程2班',
className: '蝵𤑳<EFBFBD>撌亦<EFBFBD>2<EFBFBD>?,
phone: '13800138009',
email: 'sunba@xxschool.edu.cn',
registerTime: '2023-03-03'
@@ -278,15 +274,14 @@
id: 'student007',
name: '周九',
role: 'student',
className: '计算机科学与技术2班',
className: '霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
phone: '13800138010',
email: 'zhoujiu@xxschool.edu.cn',
registerTime: '2023-03-04'
}
];
// 当前显示的用户数据
let currentUsers = [...mockUsers];
// 敶枏<EFBFBD><EFBFBD>曄內<EFBFBD><EFBFBD><EFBFBD>瑟㺭<EFBFBD>? let currentUsers = [...mockUsers];
let currentPage = 1;
const usersPerPage = 5;
@@ -305,15 +300,13 @@
const roleSelect = document.getElementById('role-select');
const classSelect = document.getElementById('class-select');
// 初始化
document.addEventListener('DOMContentLoaded', function() {
// <EFBFBD><EFBFBD><EFBFBD>? document.addEventListener('DOMContentLoaded', function() {
renderUserTable();
setupEventListeners();
updatePagination();
});
// 设置事件监听器
function setupEventListeners() {
// 霈曄蔭鈭衤辣<EFBFBD>穃𨯬<EFBFBD>? function setupEventListeners() {
searchBtn.addEventListener('click', handleSearch);
resetBtn.addEventListener('click', handleReset);
addBtn.addEventListener('click', handleAddUser);
@@ -330,7 +323,7 @@
<td colspan="8" class="no-results">
<i class="fas fa-user-slash"></i>
<h3>没有找到用户</h3>
<p>请尝试其他筛选条件或添加新用户</p>
<p>霂瑕<EFBFBD>霂訫<EFBFBD>隞𣇉<EFBFBD><EFBFBD>㗇辺隞嗆<EFBFBD>瘛餃<EFBFBD><EFBFBD>啁鍂<EFBFBD>?/p>
</td>
</tr>
`;
@@ -347,7 +340,7 @@
// 角色徽章
let roleBadge = '';
if (user.role === 'admin') {
roleBadge = '<span class="role-badge role-admin">管理员</span>';
roleBadge = '<span class="role-badge role-admin">蝞∠<EFBFBD><EFBFBD>?/span>';
} else if (user.role === 'teacher') {
roleBadge = '<span class="role-badge role-teacher">教师</span>';
} else {
@@ -359,7 +352,7 @@
<td>${user.id}</td>
<td>${user.name}</td>
<td>${roleBadge}</td>
<td>${user.className || '—'}</td>
<td>${user.className || '<EFBFBD>?}</td>
<td>${user.phone}</td>
<td>${user.email}</td>
<td>${user.registerTime}</td>
@@ -386,15 +379,13 @@
function updatePagination() {
const totalPages = Math.ceil(currentUsers.length / usersPerPage);
// 更新按钮状态
prevBtn.disabled = currentPage === 1;
// <EFBFBD>湔鰵<EFBFBD>厰僼<EFBFBD><EFBFBD>? prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
// 更新页码按钮
let pageButtonsHTML = '';
for (let i = 1; i <= totalPages; i++) {
if (i <= 5) { // 最多显示5个页码
pageButtonsHTML += `<button class="${i === currentPage ? 'active' : ''}" onclick="goToPage(${i})">${i}</button>`;
if (i <= 5) { // <EFBFBD><EFBFBD>憭𡁏遬蝷?銝芷△<E88AB7>? pageButtonsHTML += `<button class="${i === currentPage ? 'active' : ''}" onclick="goToPage(${i})">${i}</button>`;
}
}
pageNumbers.innerHTML = pageButtonsHTML;
@@ -408,23 +399,19 @@
const className = classSelect.value;
currentUsers = mockUsers.filter(user => {
// 用户ID筛选
if (userId && !user.id.toLowerCase().includes(userId.toLowerCase())) {
// <EFBFBD><EFBFBD>ID蝑偦<EFBFBD>? if (userId && !user.id.toLowerCase().includes(userId.toLowerCase())) {
return false;
}
// 姓名筛选
if (userName && !user.name.toLowerCase().includes(userName.toLowerCase())) {
// 憪枏<EFBFBD>蝑偦<EFBFBD>? if (userName && !user.name.toLowerCase().includes(userName.toLowerCase())) {
return false;
}
// 角色筛选
if (role && user.role !== role) {
// 閫坿𠧧蝑偦<EFBFBD>? if (role && user.role !== role) {
return false;
}
// 班级筛选
if (className && user.className !== className) {
// <EFBFBD>剔漣蝑偦<EFBFBD>? if (className && user.className !== className) {
return false;
}
@@ -451,31 +438,29 @@
// 处理添加用户
function handleAddUser() {
alert('添加用户功能将在后端API完成后实现');
alert('瘛餃<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡒊垢API摰峕<EFBFBD><EFBFBD>𤾸<EFBFBD><EFBFBD>?);
// 这里可以打开一个模态框来添加新用户
}
// 处理导出
function handleExport() {
alert('导出功能将在后端API完成后实现');
alert('撖澆枂<EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡒊垢API摰峕<EFBFBD><EFBFBD>𤾸<EFBFBD><EFBFBD>?);
// 这里可以导出为Excel或CSV格式
}
// 编辑用户
function editUser(userId) {
alert(`编辑用户 ${userId} - 功能将在后端API完成后实现`);
// 这里可以打开一个模态框来编辑用户信息
}
// 餈䠷<EFBFBD><EFBFBD>臭誑<EFBFBD><EFBFBD><EFBFBD>銝芣芋<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>颲𤑳鍂<EFBFBD>瑚縑<EFBFBD>? }
// 删除用户
function deleteUser(userId) {
if (confirm(`确定要删除用户 ${userId} 吗?此操作不可撤销。`)) {
if (confirm(`蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD>斤鍂<EFBFBD>?${userId} <20><EFBFBD>甇斗<E79487>雿靝<E99BBF><E99D9D>舀伃<E88880><E4BC83><EFBFBD><EFBFBD>)) {
// 从模拟数据中删除
const index = mockUsers.findIndex(user => user.id === userId);
if (index !== -1) {
mockUsers.splice(index, 1);
// 更新当前显示的数据
handleSearch();
// <EFBFBD>湔鰵敶枏<EFBFBD><EFBFBD>曄內<EFBFBD><EFBFBD><EFBFBD>? handleSearch();
alert('用户删除成功');
}
}

View File

@@ -4,43 +4,41 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="../css/main.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="/public/css/main.css">
</head>
<body>
<!-- 导航栏 -->
<!-- 撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="navbar-brand">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</div>
<div class="navbar-menu">
<a href="index.html" class="btn btn-secondary">
<a href="/" class="btn btn-secondary">
<i class="fas fa-home"></i> 主页
</a>
<div class="navbar-user">
<a href="login.html" class="btn btn-primary" id="loginBtn">
<a href="/login" class="btn btn-primary" id="loginBtn">
<i class="fas fa-sign-in-alt"></i> 登录
</a>
<a href="register.html" class="btn btn-secondary" id="registerBtn">
<a href="/register" class="btn btn-secondary" id="registerBtn">
<i class="fas fa-user-plus"></i> 注册
</a>
</div>
</div>
</nav>
<!-- 主体内容区 -->
<!-- 銝颱<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?-->
<main>
<!-- 英雄区域 -->
<section class="hero-section">
<div class="hero-content">
<h1 class="hero-title">XX学校学生成绩管理系统</h1>
<p class="hero-subtitle">
高效、安全、智能的成绩管理平台,为学校师生提供全方位的成绩管理服务,
实现成绩录入、查询、统计和分析的一体化解决方案。
</p>
擃䀹<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD>撟喳蝱嚗䔶蛹摮行嵗撣<EFBFBD><EFBFBD><EFBFBD>𣂷<EFBFBD><EFBFBD>冽䲮雿滨<EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD><EFBFBD>滚𦛚嚗? 摰䂿緵<E482BF>鞟貍敶訫<E695B6><E8A8AB><EFBFBD>䰻霂<E99C82><EFBCB5><EFBFBD><E99C88><E288AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>雿枏<E99BBF><EFBFBD><E996AB><EFBFBD><EFBFBD><E5AF9E>? </p>
<div class="cta-buttons">
<a href="login.html" class="btn btn-primary" id="heroLoginBtn">
<a href="/login" class="btn btn-primary" id="heroLoginBtn">
<i class="fas fa-sign-in-alt"></i> 立即登录
</a>
<a href="#features" class="btn btn-secondary">
@@ -60,9 +58,7 @@
</div>
<h3 class="feature-title">学生成绩查询</h3>
<p class="feature-description">
学生可随时查看个人成绩,包括各科成绩、平均分、排名等信息,
支持成绩趋势分析和历史记录查看。
</p>
摮衣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>嗆䰻<EFBFBD>衤葵鈭箸<EFBFBD>蝏抬<EFBFBD><EFBFBD><EFBFBD>𡠺<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>靽⊥<EFBFBD>嚗? <20><EFBFBD><E88880>鞟貍頞见飵<E8A781><E9A3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>脰扇敶閙䰻<E99699><EFBFBD>? </p>
</div>
<div class="feature-card">
@@ -72,19 +68,16 @@
<h3 class="feature-title">教师成绩管理</h3>
<p class="feature-description">
教师可便捷录入、修改、查询学生成绩,支持批量操作和成绩统计分析,
提供多种数据导出格式。
</p>
<EFBFBD>𣂷<EFBFBD>憭𡁶<EFBFBD><EFBFBD>唳旿撖澆枂<EFBFBD><EFBFBD><EFBFBD>? </p>
</div>
<div class="feature-card">
<div class="feature-icon">
<i class="fas fa-user-shield"></i>
</div>
<h3 class="feature-title">管理员权限控制</h3>
<h3 class="feature-title">蝞∠<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞉綉<EFBFBD>?/h3>
<p class="feature-description">
管理员可管理用户账户、学生信息,查看系统统计报表,
设置权限和系统参数,确保数据安全。
</p>
蝞∠<EFBFBD><EFBFBD>睃虾蝞∠<EFBFBD><EFBFBD><EFBFBD>韐行<EFBFBD><EFBFBD><EFBFBD><EFBFBD>煺縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝟餌<EFBFBD>蝏蠘恣<EFBFBD>亥”嚗? 霈曄蔭<E69B84><E894AD><EFBFBD><EFBFBD>𣬚頂蝏笔<E89D8F><E7AC94><EFBFBD>蝖桐<E89D96><E6A190>唳旿摰匧<E691B0><E58CA7>? </p>
</div>
<div class="feature-card">
@@ -93,9 +86,7 @@
</div>
<h3 class="feature-title">智能统计分析</h3>
<p class="feature-description">
提供丰富的图表统计功能,包括成绩分布、趋势分析、对比图表等,
帮助学校进行教学评估和决策支持。
</p>
<EFBFBD>𣂷<EFBFBD>銝啣<EFBFBD><EFBFBD><EFBFBD>㦛銵函<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡠺<EFBFBD>鞟貍<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>笆瘥𥪜㦛銵函<EFBFBD>嚗? 撣桀𨭌摮行嵗餈𥡝<E9A488><F0A5A19D>坔郎霂<E9838E><EFBFBD><E691AF><EFBFBD>蝑𡝗𣈲<F0A19D97><F0A388B2><EFBFBD>? </p>
</div>
</div>
</section>
@@ -104,12 +95,10 @@
<section class="cta-section">
<h2 class="cta-title">立即体验智能成绩管理</h2>
<p style="font-size: 1.2rem; color: #666; margin-bottom: 40px; max-width: 600px; margin-left: auto; margin-right: auto;">
加入XX学校成绩管理系统体验高效、便捷的成绩管理服务。
</p>
<EFBFBD><EFBFBD>XX摮行嵗<EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD>嚗䔶<EFBFBD>撉屸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD><EFBFBD>滚𦛚<EFBFBD>? </p>
<div class="cta-buttons">
<a href="login.html" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> 开始使用
</a>
<a href="/login" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <EFBFBD>憪衤蝙<EFBFBD>? </a>
<a href="#" class="btn btn-secondary">
<i class="fas fa-book"></i> 查看文档
</a>
@@ -122,8 +111,7 @@
<div class="footer-content">
<h3 style="margin-bottom: 20px;">XX学校学生成绩管理系统</h3>
<p style="color: #ccc; margin-bottom: 20px; max-width: 600px; margin-left: auto; margin-right: auto;">
致力于为学校提供专业、安全、高效的数字化成绩管理解决方案。
</p>
<EFBFBD><EFBFBD>鈭𦒘蛹摮行嵗<EFBFBD>𣂷<EFBFBD>銝㮖<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𡝗<EFBFBD>蝏拍恣<EFBFBD><EFBFBD><EFBFBD>單䲮獢<EFBFBD><EFBFBD>? </p>
<div class="footer-links">
<a href="#"><i class="fas fa-info-circle"></i> 关于我们</a>
<a href="#"><i class="fas fa-envelope"></i> 联系我们</a>
@@ -131,12 +119,12 @@
<a href="#"><i class="fas fa-file-contract"></i> 服务条款</a>
</div>
<div class="copyright">
<p>© 2023 XX学校学生成绩管理系统 版权所有</p>
<p>联系电话010-12345678 | 邮箱contact@school.edu.cn</p>
<p> 2023 XX摮行嵗摮衣<EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?/p>
<p><EFBFBD>𠉛頂<EFBFBD><EFBFBD>嚗?10-12345678 | <EFBFBD>桃拳嚗䬙ontact@school.edu.cn</p>
</div>
</div>
</footer>
<script src="../js/main.js"></script>
<script src="/public/js/main.js"></script>
</body>
</html>

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统 - 登录</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
@@ -21,7 +21,7 @@
<i class="fas fa-user"></i> 学号/工号
</label>
<input type="text" id="id" name="id" required
placeholder="请输入学号/工号">
placeholder="请输入学号/工号" autocomplete="username">
</div>
<div class="form-group">
@@ -29,7 +29,7 @@
<i class="fas fa-lock"></i> 密码
</label>
<input type="password" id="password" name="password" required
placeholder="请输入密码">
placeholder="请输入密码" autocomplete="current-password">
</div>
<div class="form-group">
@@ -45,17 +45,18 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">
<button type="submit" class="btn btn-primary btn-block">
<i class="fas fa-sign-in-alt"></i> 登录
</button>
</div>
<div class="auth-footer">
<p>没有账户? <a href="register.html">立即注册</a></p>
<p>没有账户? <a href="/register">立即注册</a></p>
</div>
</form>
</div>
</div>
<script src="../js/auth.js"></script>
<script src="/public/js/auth.js"></script>
</body>
</html>

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统 - 注册</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
@@ -21,7 +21,7 @@
<i class="fas fa-id-card"></i> 学号/工号
</label>
<input type="text" id="id" name="id" required
placeholder="请输入学号或工号">
placeholder="请输入学号或工号" autocomplete="username">
</div>
<div class="form-group">
@@ -37,7 +37,7 @@
<i class="fas fa-lock"></i> 密码
</label>
<input type="password" id="password" name="password" required
placeholder="请输入密码">
placeholder="请输入密码" autocomplete="new-password">
</div>
<div class="form-group">
@@ -45,7 +45,7 @@
<i class="fas fa-lock"></i> 确认密码
</label>
<input type="password" id="confirmPassword" name="confirmPassword" required
placeholder="请再次输入密码">
placeholder="请再次输入密码" autocomplete="new-password">
</div>
<div class="form-group">
@@ -69,38 +69,18 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">
<button type="submit" class="btn btn-primary btn-block">
<i class="fas fa-user-plus"></i> 注册
</button>
</div>
<div class="auth-footer">
<p>已有账户? <a href="login.html">立即登录</a></p>
<p>已有账户? <a href="/login">立即登录</a></p>
</div>
</form>
</div>
</div>
<script src="../js/auth.js"></script>
<script>
// 显示/隐藏班级字段
document.getElementById('role').addEventListener('change', function() {
const role = this.value;
const classField = document.getElementById('classField');
const classInput = document.getElementById('class');
if (role === 'student' || role === 'teacher') {
classField.style.display = 'block';
classInput.required = true;
} else {
classField.style.display = 'none';
classInput.required = false;
}
});
// 初始化AuthManager
document.addEventListener('DOMContentLoaded', () => {
new AuthManager();
});
</script>
<script src="/public/js/auth.js"></script>
</body>
</html>

View File

@@ -3,34 +3,33 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统 - 学生仪表板</title>
<link rel="stylesheet" href="../css/style.css">
<title>摮衣<EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD> - 摮衣<E691AE>隞芾”<E88ABE>?/title>
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
</head>
<body>
<!-- 顶部导航栏 -->
<!-- 憿園<EFBFBD>撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="navbar-brand">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</div>
<div class="navbar-menu">
<a href="index.html" class="btn btn-secondary">
<a href="/" class="btn btn-secondary">
<i class="fas fa-home"></i> 主页
</a>
<div class="navbar-user">
<span class="user-name" id="userName">加载中...</span>
<span class="user-name" id="userName"><EFBFBD>㰘蝸銝?..</span>
<button id="logoutBtn" class="btn btn-primary">
<i class="fas fa-sign-out-alt"></i> 退出
</button>
<i class="fas fa-sign-out-alt"></i> <EFBFBD><EFBFBD><EFBFBD>? </button>
</div>
</div>
</nav>
<!-- 仪表板容器 -->
<!-- 隞芾”<EFBFBD>踹捆<EFBFBD>?-->
<div class="dashboard-container">
<!-- 左侧侧边栏 -->
<!-- 撌虫儒靘扯器<EFBFBD>?-->
<aside class="sidebar">
<div class="sidebar-header">
<div class="user-info">
@@ -38,8 +37,8 @@
<i class="fas fa-user-graduate"></i>
</div>
<div class="user-details">
<h3 id="studentName">加载中...</h3>
<p>学生 | 班级:<span id="studentClass">加载中...</span></p>
<h3 id="studentName"><EFBFBD>㰘蝸銝?..</h3>
<p>摮衣<EFBFBD> | <20>剔漣嚗?span id="studentClass"><3E>㰘蝸銝?..</span></p>
</div>
</div>
</div>
@@ -48,7 +47,7 @@
<li>
<a href="#" class="active">
<i class="fas fa-tachometer-alt"></i>
<span>仪表板</span>
<span>隞芾”<EFBFBD>?/span>
</a>
</li>
<li>
@@ -88,11 +87,11 @@
<main class="main-content">
<div class="content-header">
<div>
<h1 class="page-title">学生仪表板</h1>
<h1 class="page-title">摮衣<EFBFBD>隞芾”<EFBFBD>?/h1>
<div class="breadcrumb">
<a href="index.html">主页</a>
<a href="/">銝駁△</a>
<i class="fas fa-chevron-right"></i>
<span>学生仪表板</span>
<span>摮衣<EFBFBD>隞芾”<EFBFBD>?/span>
</div>
</div>
<div class="current-time" id="currentTime"></div>
@@ -121,7 +120,7 @@
<i class="fas fa-certificate"></i>
</div>
<div class="stat-value" id="creditTotal">24</div>
<div class="stat-label">总学分</div>
<div class="stat-label"><EFBFBD>餃郎<EFBFBD>?/div>
</div>
<div class="stat-card">
@@ -136,16 +135,15 @@
<!-- 成绩表格 -->
<div class="grades-table">
<div class="table-header">
<h2 class="table-title">本学期成绩</h2>
<h2 class="table-title"><EFBFBD>砍郎<EFBFBD><EFBFBD><EFBFBD>蝏?/h2>
<div class="table-actions">
<select class="form-select" style="width: 150px;">
<option value="all">所有学期</option>
<option value="all"><EFBFBD><EFBFBD><EFBFBD>匧郎<EFBFBD>?/option>
<option value="2023-2" selected>2023-2024学年第二学期</option>
<option value="2023-1">2023-2024学年第一学期</option>
</select>
<button class="btn btn-primary">
<i class="fas fa-download"></i> 导出成绩单
</button>
<i class="fas fa-download"></i> 撖澆枂<EFBFBD>鞟貍<EFBFBD>? </button>
</div>
</div>
@@ -158,13 +156,13 @@
<th>学分</th>
<th>平时成绩</th>
<th>期末成绩</th>
<th>总成绩</th>
<th><EFBFBD><EFBFBD>蝏?/th>
<th>绩点</th>
<th>操作</th>
</tr>
</thead>
<tbody id="gradesTableBody">
<!-- 成绩数据将通过JavaScript动态加载 -->
<!-- <EFBFBD>鞟貍<EFBFBD>唳旿撠<EFBFBD><EFBFBD><EFBFBD>JavaScript<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧?-->
</tbody>
</table>
</div>
@@ -172,8 +170,8 @@
</main>
</div>
<script src="../js/student.js"></script>
<script src="../js/auth.js"></script>
<script src="/public/js/student.js"></script>
<script src="/public/js/auth.js"></script>
<script>
// 更新当前时间
function updateCurrentTime() {

View File

@@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>学生成绩管理系统 - 教师仪表板</title>
<link rel="stylesheet" href="../css/style.css">
<title>摮衣<EFBFBD><EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD> - <20><EFBFBD>隞芾”<E88ABE>?/title>
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
/* 仪表板布局 */
@@ -13,7 +13,7 @@
min-height: calc(100vh - 80px);
}
/* 侧边栏 */
/* 靘扯器<EFBFBD>?*/
.sidebar {
width: 250px;
background: linear-gradient(180deg, #43e97b 0%, #38f9d7 100%);
@@ -183,7 +183,7 @@
margin-bottom: 20px;
}
/* 快速操作 */
/* 敹恍<EFBFBD><EFBFBD><EFBFBD>雿?*/
.quick-actions {
background: white;
border-radius: 15px;
@@ -230,7 +230,7 @@
border-color: #43e97b;
}
/* 最近活动 */
/* <EFBFBD><EFBFBD>餈烐暑<EFBFBD>?*/
.recent-activities {
background: white;
border-radius: 15px;
@@ -282,7 +282,7 @@
color: #999;
}
/* 响应式设计 */
/* <EFBFBD><EFBFBD>撘讛挽霈?*/
@media (max-width: 992px) {
.dashboard-container {
flex-direction: column;
@@ -344,28 +344,27 @@
</style>
</head>
<body>
<!-- 顶部导航栏 -->
<!-- 憿園<EFBFBD>撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="navbar-brand">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</div>
<div class="navbar-menu">
<a href="index.html" class="btn btn-secondary">
<a href="/" class="btn btn-secondary">
<i class="fas fa-home"></i> 主页
</a>
<div class="navbar-user">
<span class="user-name" id="userName">李老师</span>
<button id="logoutBtn" class="btn btn-primary">
<i class="fas fa-sign-out-alt"></i> 退出
</button>
<i class="fas fa-sign-out-alt"></i> <EFBFBD><EFBFBD><EFBFBD>? </button>
</div>
</div>
</nav>
<!-- 仪表板容器 -->
<!-- 隞芾”<EFBFBD>踹捆<EFBFBD>?-->
<div class="dashboard-container">
<!-- 左侧侧边栏 -->
<!-- 撌虫儒靘扯器<EFBFBD>?-->
<aside class="sidebar">
<div class="sidebar-header">
<div class="user-info">
@@ -374,7 +373,7 @@
</div>
<div class="user-details">
<h3 id="teacherName">李老师</h3>
<p>教师 | 部门:<span id="teacherDept">计算机学院</span></p>
<p><EFBFBD><EFBFBD> | <20>券秄嚗?span id="teacherDept">霈∠<E99C88><E288A0>箏郎<E7AE8F>?/span></p>
</div>
</div>
</div>
@@ -383,11 +382,11 @@
<li>
<a href="#" class="active">
<i class="fas fa-tachometer-alt"></i>
<span>仪表板</span>
<span>隞芾”<EFBFBD>?/span>
</a>
</li>
<li>
<a href="grade_entry.html">
<a href="/teacher/grade_entry">
<i class="fas fa-edit"></i>
<span>成绩录入</span>
</a>
@@ -429,11 +428,11 @@
<main class="main-content">
<div class="content-header">
<div>
<h1 class="page-title">教师仪表板</h1>
<h1 class="page-title"><EFBFBD><EFBFBD>隞芾”<EFBFBD>?/h1>
<div class="breadcrumb">
<a href="index.html">主页</a>
<a href="/">銝駁△</a>
<i class="fas fa-chevron-right"></i>
<span>教师仪表板</span>
<span><EFBFBD><EFBFBD>隞芾”<EFBFBD>?/span>
</div>
</div>
<div class="current-time" id="currentTime"></div>
@@ -447,9 +446,8 @@
</div>
<h3 class="function-title">成绩录入</h3>
<p class="function-description">
为学生录入新的课程成绩,支持批量导入和单个录入。
</p>
<button class="btn btn-primary">开始录入</button>
銝箏郎<EFBFBD><EFBFBD><EFBFBD>交鰵<EFBFBD><EFBFBD>紋蝔𧢲<EFBFBD>蝏抬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>撖澆<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝芸<EFBFBD><EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary"><EFBFBD>憪见<EFBFBD><EFBFBD>?/button>
</div>
<div class="function-card" onclick="window.location.href='grade_query.html'">
@@ -458,9 +456,8 @@
</div>
<h3 class="function-title">成绩查询</h3>
<p class="function-description">
查询学生成绩,支持按班级、课程、学期等多维度筛选。
</p>
<button class="btn btn-primary">开始查询</button>
<EFBFBD>亥砭摮衣<EFBFBD><EFBFBD>鞟貍嚗峕𣈲<EFBFBD><EFBFBD><EFBFBD><EFBFBD>剔漣<EFBFBD><EFBFBD>紋蝔卝<EFBFBD><EFBFBD><EFBFBD><EFBFBD>憭𡁶輕摨衣<EFBFBD><EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary"><EFBFBD>憪𧢲䰻霂?/button>
</div>
<div class="function-card" onclick="window.location.href='grade_manage.html'">
@@ -469,9 +466,8 @@
</div>
<h3 class="function-title">成绩管理</h3>
<p class="function-description">
修改或删除已录入的成绩,管理成绩记录和状态。
</p>
<button class="btn btn-primary">开始管理</button>
靽格㺿<EFBFBD><EFBFBD><EFBFBD>文歇敶訫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏抬<EFBFBD>蝞∠<EFBFBD><EFBFBD>鞟貍霈啣<EFBFBD><EFBFBD>𣬚𠶖<EFBFBD><EFBFBD><EFBFBD>? </p>
<button class="btn btn-primary"><EFBFBD>憪讠恣<EFBFBD>?/button>
</div>
<div class="function-card" onclick="window.location.href='#'">
@@ -480,31 +476,27 @@
</div>
<h3 class="function-title">统计分析</h3>
<p class="function-description">
查看成绩统计图表,分析教学效果和学生表现。
</p>
<EFBFBD><EFBFBD><EFBFBD>鞟貍蝏蠘恣<EFBFBD>曇”嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>摮行<EFBFBD><EFBFBD>𨅯<EFBFBD>摮衣<EFBFBD>銵函緵<EFBFBD>? </p>
<button class="btn btn-primary">查看统计</button>
</div>
</div>
<!-- 快速操作 -->
<!-- 敹恍<EFBFBD><EFBFBD><EFBFBD>雿?-->
<div class="quick-actions">
<h2 class="section-title">
<i class="fas fa-bolt"></i>
快速操作
</h2>
敹恍<EFBFBD><EFBFBD><EFBFBD>雿? </h2>
<div class="action-buttons">
<a href="grade_entry.html" class="action-btn">
<a href="/teacher/grade_entry" class="action-btn">
<i class="fas fa-plus"></i>
录入新成绩
</a>
敶訫<EFBFBD><EFBFBD><EFBFBD>蝏? </a>
<a href="grade_query.html" class="action-btn">
<i class="fas fa-search"></i>
查询成绩
</a>
<a href="#" class="action-btn">
<i class="fas fa-download"></i>
导出成绩单
</a>
撖澆枂<EFBFBD>鞟貍<EFBFBD>? </a>
<a href="#" class="action-btn">
<i class="fas fa-chart-pie"></i>
生成统计报告
@@ -512,4 +504,4 @@
</div>
</div>
<!-- 最近活动
<!-- <EFBFBD><EFBFBD>餈烐暑<EFBFBD>

View File

@@ -4,34 +4,34 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>成绩录入 - XX学校成绩管理系统</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<!-- 导航栏 -->
<!-- 撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="navbar-brand">
<a href="index.html"><i class="fas fa-graduation-cap"></i> XX学校成绩管理系统</a>
<a href="/"><i class="fas fa-graduation-cap"></i> XX摮行嵗<EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD></a>
</div>
<div class="navbar-menu">
<a href="teacher_dashboard.html" class="navbar-item"><i class="fas fa-tachometer-alt"></i> 教师仪表板</a>
<a href="grade_entry.html" class="navbar-item active"><i class="fas fa-edit"></i> 成绩录入</a>
<a href="grade_management.html" class="navbar-item"><i class="fas fa-list"></i> 成绩管理</a>
<a href="/teacher/dashboard" class="navbar-item"><i class="fas fa-tachometer-alt"></i> <EFBFBD><EFBFBD>隞芾”<EFBFBD>?/a>
<a href="/teacher/grade_entry" class="navbar-item active"><i class="fas fa-edit"></i> <EFBFBD>鞟貍敶訫<EFBFBD></a>
<a href="/teacher/grade_management" class="navbar-item"><i class="fas fa-list"></i> <EFBFBD>鞟貍蝞∠<EFBFBD></a>
<div class="user-info">
<span class="user-name">李老师</span>
<span class="user-role">教师</span>
<a href="login.html" class="btn btn-outline btn-small"><i class="fas fa-sign-out-alt"></i> 退出</a>
<a href="/login" class="btn btn-outline btn-small"><i class="fas fa-sign-out-alt"></i> <EFBFBD><EFBFBD><EFBFBD>?/a>
</div>
</div>
</nav>
<!-- 面包屑导航 -->
<!-- <EFBFBD><EFBFBD>撅穃紡<EFBFBD>?-->
<div class="container">
<div class="breadcrumb">
<a href="index.html">主页</a>
<a href="/">銝駁△</a>
<i class="fas fa-chevron-right"></i>
<a href="teacher_dashboard.html">教师仪表板</a>
<a href="/teacher/dashboard"><EFBFBD><EFBFBD>隞芾”<EFBFBD>?/a>
<i class="fas fa-chevron-right"></i>
<span>成绩录入</span>
</div>
@@ -41,7 +41,7 @@
<div class="grade-entry-container">
<div class="entry-header">
<h1><i class="fas fa-edit"></i> 成绩录入</h1>
<p>请选择班级和课程,然后为每个学生录入成绩</p>
<p>霂琿<EFBFBD>㗇𥋘<EFBFBD>剔漣<EFBFBD>諹紋蝔页<EFBFBD><EFBFBD><EFBFBD>銝箸<EFBFBD>銝芸郎<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏?/p>
</div>
<div class="entry-form">
@@ -50,11 +50,11 @@
<label for="class-select"><i class="fas fa-users"></i> 选择班级</label>
<select id="class-select" class="form-control">
<option value="">请选择班级</option>
<option value="class1">计算机科学与技术2021级1班</option>
<option value="class2">计算机科学与技术2021级2班</option>
<option value="class3">软件工程2021级1班</option>
<option value="class4">软件工程2021级2班</option>
<option value="class5">网络工程2021级1班</option>
<option value="class1">霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?021蝥?<3F>?/option>
<option value="class2">霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?021蝥?<3F>?/option>
<option value="class3">頧臭辣撌亦<EFBFBD>2021蝥?<3F>?/option>
<option value="class4">頧臭辣撌亦<EFBFBD>2021蝥?<3F>?/option>
<option value="class5">蝵𤑳<EFBFBD>撌亦<EFBFBD>2021蝥?<3F>?/option>
</select>
</div>
@@ -71,12 +71,12 @@
<div class="form-group">
<label><i class="fas fa-info-circle"></i> 备注说明(可选)</label>
<textarea id="remarks" rows="3" placeholder="可输入本次考试的说明信息,如:期中考试、期末考试等"></textarea>
<textarea id="remarks" rows="3" placeholder="<EFBFBD><EFBFBD><EFBFBD>交𧋦甈∟<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𦒘縑<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>煺葉<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝑?></textarea>
</div>
<div class="students-table-container">
<h3><i class="fas fa-user-graduate"></i> 学生成绩录入</h3>
<p class="text-muted">选择班级后,系统将自动加载该班级的学生列表</p>
<p class="text-muted"><EFBFBD>㗇𥋘<EFBFBD>剔漣<EFBFBD>𠬍<EFBFBD>蝟餌<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧質砲<EFBFBD>剔漣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銵?/p>
<div id="students-loading" class="loading" style="display: none;">
<i class="fas fa-spinner"></i>
@@ -100,7 +100,7 @@
</tr>
</thead>
<tbody id="students-tbody">
<!-- 学生数据将通过JavaScript动态加载 -->
<!-- 摮衣<EFBFBD><EFBFBD>唳旿撠<EFBFBD><EFBFBD><EFBFBD>JavaScript<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧?-->
</tbody>
</table>
</div>
@@ -118,11 +118,11 @@
<div class="card">
<h3><i class="fas fa-lightbulb"></i> 使用说明</h3>
<ul class="text-muted">
<li>首先选择要录入成绩的班级和课程</li>
<li>系统会自动加载该班级的学生列表</li>
<li>擐硋<EFBFBD><EFBFBD>㗇𥋘閬<EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏拍<EFBFBD><EFBFBD>剔漣<EFBFBD>諹紋蝔?/li>
<li>蝟餌<EFBFBD>隡朞䌊<EFBFBD><EFBFBD>頧質砲<EFBFBD>剔漣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銵?/li>
<li>为每个学生输入平时成绩、期中成绩和期末成绩</li>
<li>总评成绩将根据权重自动计算默认权重平时20%期中30%期末50%</li>
<li>确认无误后点击“提交成绩”按钮保存数据</li>
<li><EFBFBD><EFBFBD><EFBFBD>鞟貍撠<EFBFBD><EFBFBD><EFBFBD><EFBFBD>滩䌊<EFBFBD>刻恣蝞梹<EFBFBD>暺䁅恕<EFBFBD><EFBFBD><EFBFBD>嚗𡁜像<EFBFBD>?0%嚗峕<E59A97>銝?0%嚗峕<E59A97><E5B395>?0%嚗?/li>
<li>蝖株恕<EFBFBD>㰘秤<EFBFBD>𡒊<EFBFBD><EFBFBD><EFBFBD>𨀣<EFBFBD>鈭斗<EFBFBD>蝏抽<EFBFBD><EFBFBD><EFBFBD><EFBFBD>摮䀹㺭<EFBFBD>?/li>
<li>提交后可以在“成绩管理”页面查看和修改已录入的成绩</li>
</ul>
</div>
@@ -154,8 +154,7 @@
const cancelBtn = document.getElementById('cancel-btn');
const submitBtn = document.getElementById('submit-btn');
// 设置默认考试日期为今天
const today = new Date().toISOString().split('T')[0];
// 霈曄蔭暺䁅恕<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝箔<EFBFBD>憭? const today = new Date().toISOString().split('T')[0];
examDateInput.value = today;
// 班级选择变化事件
@@ -168,8 +167,7 @@
return;
}
// 显示加载状态
showLoading();
// <EFBFBD>曄內<EFBFBD>㰘蝸<EFBFBD><EFBFBD>? showLoading();
// 模拟API调用延迟
setTimeout(() => {
@@ -194,8 +192,7 @@
// 清空表格
studentsTbody.innerHTML = '';
// 添加学生行
students.forEach((student, index) => {
// 瘛餃<EFBFBD>摮衣<EFBFBD>銵? students.forEach((student, index) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${student.id}</td>
@@ -234,20 +231,17 @@
addGradeInputListeners();
}
// 显示加载状态
function showLoading() {
// <EFBFBD>曄內<EFBFBD>㰘蝸<EFBFBD><EFBFBD>? function showLoading() {
studentsLoading.style.display = 'block';
studentsTable.style.display = 'none';
noStudents.style.display = 'none';
}
// 隐藏加载状态
function hideLoading() {
// <EFBFBD><EFBFBD><EFBFBD>㰘蝸<EFBFBD><EFBFBD>? function hideLoading() {
studentsLoading.style.display = 'none';
}
// 显示无学生数据
function showNoStudents() {
// <EFBFBD>曄內<EFBFBD>惩郎<EFBFBD><EFBFBD><EFBFBD>? function showNoStudents() {
hideLoading();
studentsTable.style.display = 'none';
noStudents.style.display = 'block';
@@ -293,11 +287,9 @@
const midterm = parseFloat(midtermInput.value) || 0;
const final = parseFloat(finalInput.value) || 0;
// 计算总评成绩权重平时20%期中30%期末50%
const total = (usual * 0.2) + (midterm * 0.3) + (final * 0.5);
// 霈∠<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>撟單𧒄20%嚗峕<E59A97>銝?0%嚗峕<E59A97><E5B395>?0%嚗? const total = (usual * 0.2) + (midterm * 0.3) + (final * 0.5);
// 显示总评成绩(四舍五入到整数)
totalSpan.textContent = Math.round(total);
// <EFBFBD>曄內<EFBFBD><EFBFBD><EFBFBD>鞟貍嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>湔㺭嚗? totalSpan.textContent = Math.round(total);
// 根据成绩范围设置颜色
if (total >= 90) {
@@ -323,13 +315,12 @@
}
if (!courseName) {
alert('请输入课程名称');
alert('霂瑁<EFBFBD><EFBFBD>亥紋蝔见<EFBFBD>蝘?);
courseNameInput.focus();
return false;
}
// 检查是否有学生成绩未填写
const usualGrades = document.querySelectorAll('.usual-grade');
// <EFBFBD><EFBFBD>交糓<EFBFBD><EFBFBD>摮衣<EFBFBD><EFBFBD>鞟貍<EFBFBD><EFBFBD>? const usualGrades = document.querySelectorAll('.usual-grade');
const midtermGrades = document.querySelectorAll('.midterm-grade');
const finalGrades = document.querySelectorAll('.final-grade');
@@ -350,7 +341,7 @@
if (usualNum < 0 || usualNum > 100 ||
midtermNum < 0 || midtermNum > 100 ||
finalNum < 0 || finalNum > 100) {
alert(`第${i + 1}行学生的成绩必须在0-100之间`);
alert(`蝚?{i + 1}<EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍敹<EFBFBD><EFBFBD>?-100銋钅𡢿`);
return false;
}
}
@@ -403,17 +394,15 @@
const formData = collectFormData();
// 显示提交中状态
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 提交中...';
// <EFBFBD>曄內<EFBFBD>𣂷漱銝剔𠶖<EFBFBD>? submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> <20>𣂷漱銝?..';
submitBtn.disabled = true;
// 模拟API调用
setTimeout(() => {
// 模拟成功响应
alert(`成绩提交成功!\n班级${formData.className}\n课程:${formData.courseName}\n共录入${formData.grades.length}名学生成绩`);
alert(`<EFBFBD>鞟貍<EFBFBD>𣂷漱<EFBFBD>𣂼<EFBFBD><EFBFBD>n<EFBFBD>剔漣嚗?{formData.className}\n霂曄<EFBFBD>嚗?{formData.courseName}\n<EFBFBD><EFBFBD><EFBFBD>?{formData.grades.length}<EFBFBD>滚郎<EFBFBD><EFBFBD><EFBFBD>蝏奈);
// 重置按钮状态
submitBtn.innerHTML = '<i class="fas fa-check"></i> 提交成绩';
// <EFBFBD>滨蔭<EFBFBD>厰僼<EFBFBD><EFBFBD>? submitBtn.innerHTML = '<i class="fas fa-check"></i> <20>𣂷漱<F0A382B7>鞟貍';
submitBtn.disabled = false;
// 重置表单
@@ -439,7 +428,7 @@
// 取消按钮事件
cancelBtn.addEventListener('click', function() {
if (confirm('确定要取消吗?所有未保存的更改将会丢失。')) {
if (confirm('蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㗇𧊋靽嘥<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>隡帋腺憭晞<EFBFBD>?)) {
resetForm();
}
});
@@ -449,8 +438,7 @@
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
// 检查是否有必要的数据
if (!classSelect.value) {
// <EFBFBD><EFBFBD>交糓<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? if (!classSelect.value) {
submitBtn.disabled = true;
}
});

View File

@@ -4,30 +4,30 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>成绩查询/管理 - 学生成绩管理系统</title>
<link rel="stylesheet" href="../css/style.css">
<link rel="stylesheet" href="/public/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body>
<!-- 导航栏 -->
<!-- 撖潸⏛<EFBFBD>?-->
<nav class="navbar">
<div class="nav-container">
<div class="nav-brand">
<a href="index.html">
<a href="/">
<i class="fas fa-graduation-cap"></i>
<span>XX学校成绩管理系统</span>
</a>
</div>
<div class="nav-menu">
<a href="teacher_dashboard.html" class="nav-link">
<a href="/teacher/dashboard" class="nav-link">
<i class="fas fa-tachometer-alt"></i>
<span>教师仪表板</span>
<span><EFBFBD><EFBFBD>隞芾”<EFBFBD>?/span>
</a>
<a href="grade_entry.html" class="nav-link">
<a href="/teacher/grade_entry" class="nav-link">
<i class="fas fa-edit"></i>
<span>成绩录入</span>
</a>
<a href="grade_management.html" class="nav-link active">
<a href="/teacher/grade_management" class="nav-link active">
<i class="fas fa-search"></i>
<span>成绩管理</span>
</a>
@@ -37,9 +37,9 @@
<i class="fas fa-user-circle"></i>
<span>张老师</span>
</div>
<a href="login.html" class="btn-logout">
<a href="/login" class="btn-logout">
<i class="fas fa-sign-out-alt"></i>
<span>退出</span>
<span><EFBFBD><EFBFBD><EFBFBD>?/span>
</a>
</div>
</div>
@@ -48,11 +48,11 @@
<!-- 主内容区 -->
<main class="main-content">
<div class="container">
<!-- 面包屑导航 -->
<!-- <EFBFBD><EFBFBD>撅穃紡<EFBFBD>?-->
<div class="breadcrumb">
<a href="index.html">主页</a>
<a href="/">銝駁△</a>
<i class="fas fa-chevron-right"></i>
<a href="teacher_dashboard.html">教师仪表板</a>
<a href="/teacher/dashboard"><EFBFBD><EFBFBD>隞芾”<EFBFBD>?/a>
<i class="fas fa-chevron-right"></i>
<span>成绩查询/管理</span>
</div>
@@ -63,22 +63,21 @@
<p class="page-description">查询、修改和删除学生成绩记录</p>
</div>
<!-- 筛选区域 -->
<!-- 蝑偦<EFBFBD>匧躹<EFBFBD>?-->
<div class="filter-section">
<h2 class="filter-title">
<i class="fas fa-filter"></i>
筛选条件
</h2>
蝑偦<EFBFBD>㗇辺隞? </h2>
<div class="filter-form">
<div class="form-group">
<label for="class-select">班级</label>
<select id="class-select" class="form-control">
<option value="">全部班级</option>
<option value="class1">计算机科学与技术1班</option>
<option value="class2">计算机科学与技术2班</option>
<option value="class3">软件工程1班</option>
<option value="class4">软件工程2班</option>
<option value="class5">网络工程1班</option>
<option value="class1">霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="class2">霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?/option>
<option value="class3">頧臭辣撌亦<EFBFBD>1<EFBFBD>?/option>
<option value="class4">頧臭辣撌亦<EFBFBD>2<EFBFBD>?/option>
<option value="class5">蝵𤑳<EFBFBD>撌亦<EFBFBD>1<EFBFBD>?/option>
</select>
</div>
<div class="form-group">
@@ -87,8 +86,8 @@
<option value="">全部课程</option>
<option value="course1">数据结构</option>
<option value="course2">操作系统</option>
<option value="course3">计算机网络</option>
<option value="course4">数据库系统</option>
<option value="course3">霈∠<EFBFBD><EFBFBD><EFBFBD>蝏?/option>
<option value="course4"><EFBFBD>唳旿摨梶頂蝏?/option>
<option value="course5">软件工程</option>
</select>
</div>
@@ -147,7 +146,7 @@
</tr>
</thead>
<tbody id="grade-table-body">
<!-- 数据将通过JavaScript动态加载 -->
<!-- <EFBFBD>唳旿撠<EFBFBD><EFBFBD><EFBFBD>JavaScript<EFBFBD><EFBFBD><EFBFBD><EFBFBD>頧?-->
<tr>
<td colspan="11" class="loading">
<i class="fas fa-spinner fa-spin"></i>
@@ -160,11 +159,11 @@
<!-- 分页 -->
<div class="pagination">
<button id="prev-page" disabled>上一页</button>
<button id="prev-page" disabled>銝𠹺<EFBFBD>憿?/button>
<button class="active">1</button>
<button>2</button>
<button>3</button>
<button id="next-page">下一页</button>
<button id="next-page">銝衤<EFBFBD>憿?/button>
</div>
</div>
</div>
@@ -173,8 +172,8 @@
<!-- 页脚 -->
<footer class="footer">
<div class="container">
<p>&copy; 2023 XX学校成绩管理系统. 版权所有.</p>
<p>技术支持: 计算机科学与技术学院</p>
<p>&copy; 2023 XX摮行嵗<EFBFBD>鞟貍蝞∠<EFBFBD>蝟餌<EFBFBD>. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>?</p>
<p><EFBFBD><EFBFBD><EFBFBD>舀𣈲<EFBFBD>? 霈∠<E99C88><E288A0><EFBFBD>摮虫<E691AE><E899AB><EFBFBD><EFBFBD>臬郎<E887AC>?/p>
</div>
</footer>
@@ -185,7 +184,7 @@
id: 1,
studentId: "20230001",
studentName: "张三",
className: "计算机科学与技术1班",
className: "霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
courseName: "数据结构",
regularScore: 85,
midtermScore: 88,
@@ -197,7 +196,7 @@
id: 2,
studentId: "20230002",
studentName: "李四",
className: "计算机科学与技术1班",
className: "霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
courseName: "数据结构",
regularScore: 78,
midtermScore: 82,
@@ -209,7 +208,7 @@
id: 3,
studentId: "20230003",
studentName: "王五",
className: "计算机科学与技术2班",
className: "霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
courseName: "操作系统",
regularScore: 92,
midtermScore: 88,
@@ -221,7 +220,7 @@
id: 4,
studentId: "20230004",
studentName: "赵六",
className: "计算机科学与技术2班",
className: "霈∠<EFBFBD><EFBFBD><EFBFBD>摮虫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>?<3F>?,
courseName: "操作系统",
regularScore: 65,
midtermScore: 70,
@@ -233,8 +232,8 @@
id: 5,
studentId: "20230005",
studentName: "钱七",
className: "软件工程1班",
courseName: "数据库系统",
className: "頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
courseName: "<EFBFBD>唳旿摨梶頂蝏?,
regularScore: 88,
midtermScore: 85,
finalScore: 90,
@@ -245,8 +244,8 @@
id: 6,
studentId: "20230006",
studentName: "孙八",
className: "软件工程1班",
courseName: "数据库系统",
className: "頧臭辣撌亦<EFBFBD>1<EFBFBD>?,
courseName: "<EFBFBD>唳旿摨梶頂蝏?,
regularScore: 75,
midtermScore: 78,
finalScore: 80,
@@ -257,7 +256,7 @@
id: 7,
studentId: "20230007",
studentName: "周九",
className: "软件工程2班",
className: "頧臭辣撌亦<EFBFBD>2<EFBFBD>?,
courseName: "软件工程",
regularScore: 90,
midtermScore: 92,
@@ -269,7 +268,7 @@
id: 8,
studentId: "20230008",
studentName: "吴十",
className: "软件工程2班",
className: "頧臭辣撌亦<EFBFBD>2<EFBFBD>?,
courseName: "软件工程",
regularScore: 82,
midtermScore: 85,
@@ -294,8 +293,7 @@
// 当前选中的成绩ID
let selectedGradeIds = new Set();
// 初始化页面
function initPage() {
// <EFBFBD><EFBFBD><EFBFBD>㚚△<EFBFBD>? function initPage() {
renderGradeTable(mockGrades);
setupEventListeners();
updateSelectedCount();
@@ -308,7 +306,7 @@
<tr>
<td colspan="11" class="no-results">
<i class="fas fa-search"></i>
<h3>未找到相关成绩记录</h3>
<h3><EFBFBD>芣𪄳<EFBFBD>啁㮾<EFBFBD><EFBFBD>蝏抵扇敶?/h3>
<p>请尝试调整筛选条件或添加新的成绩记录</p>
</td>
</tr>
@@ -319,8 +317,7 @@
let tableHTML = '';
grades.forEach(grade => {
// 根据成绩确定CSS类
let gradeClass = 'grade-cell';
// <EFBFBD>寞旿<EFBFBD>鞟貍蝖桀<EFBFBD>CSS蝐? let gradeClass = 'grade-cell';
if (grade.totalScore >= 90) {
gradeClass += ' grade-excellent';
} else if (grade.totalScore >= 80) {
@@ -377,8 +374,7 @@
});
}
// 设置事件监听器
function setupEventListeners() {
// 霈曄蔭鈭衤辣<EFBFBD>穃𨯬<EFBFBD>? function setupEventListeners() {
// 查询按钮
searchBtn.addEventListener('click', function() {
performSearch();
@@ -404,11 +400,11 @@
// 批量删除按钮
batchDeleteBtn.addEventListener('click', function() {
if (selectedGradeIds.size === 0) {
alert('请先选择要删除的成绩记录!');
alert('霂瑕<EFBFBD><EFBFBD>㗇𥋘閬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>鞟貍霈啣<EFBFBD>嚗?);
return;
}
if (confirm(`确定要删除选中的 ${selectedGradeIds.size} 条成绩记录吗?此操作不可撤销。`)) {
if (confirm(`蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>劐葉<EFBFBD>?${selectedGradeIds.size} <EFBFBD><EFBFBD>蝏抵扇敶訫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝滚虾<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)) {
batchDeleteGrades();
}
});
@@ -445,8 +441,7 @@
const studentId = studentIdInput.value.trim();
const studentName = studentNameInput.value.trim();
// 显示加载状态
gradeTableBody.innerHTML = `
// <EFBFBD>曄內<EFBFBD>㰘蝸<EFBFBD><EFBFBD>? gradeTableBody.innerHTML = `
<tr>
<td colspan="11" class="loading">
<i class="fas fa-spinner fa-spin"></i>
@@ -458,23 +453,19 @@
// 模拟API延迟
setTimeout(() => {
let filteredGrades = mockGrades.filter(grade => {
// 班级筛选
if (selectedClass && grade.className !== selectedClass) {
// <EFBFBD>剔漣蝑偦<EFBFBD>? if (selectedClass && grade.className !== selectedClass) {
return false;
}
// 课程筛选
if (selectedCourse && grade.courseName !== selectedCourse) {
// 霂曄<EFBFBD>蝑偦<EFBFBD>? if (selectedCourse && grade.courseName !== selectedCourse) {
return false;
}
// 学号筛选
if (studentId && !grade.studentId.includes(studentId)) {
// 摮血噡蝑偦<EFBFBD>? if (studentId && !grade.studentId.includes(studentId)) {
return false;
}
// 姓名筛选
if (studentName && !grade.studentName.includes(studentName)) {
// 憪枏<EFBFBD>蝑偦<EFBFBD>? if (studentName && !grade.studentName.includes(studentName)) {
return false;
}
@@ -492,10 +483,10 @@
function exportGrades() {
// 这里应该调用后端API导出成绩
// 暂时使用模拟导出
alert('成绩导出功能正在开发中将支持Excel和CSV格式导出。');
alert('<EFBFBD>鞟貍撖澆枂<EFBFBD><EFBFBD><EFBFBD>銁撘<EFBFBD><EFBFBD>睲葉嚗<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Excel<EFBFBD>龦SV<EFBFBD><EFBFBD>撖澆枂<EFBFBD>?);
// 模拟导出过程
exportBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 导出中...';
exportBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 撖澆枂銝?..';
exportBtn.disabled = true;
setTimeout(() => {
@@ -504,7 +495,7 @@
// 在实际应用中,这里会触发文件下载
// 暂时显示成功消息
showNotification('成绩导出成功!文件已开始下载。', 'success');
showNotification('<EFBFBD>鞟貍撖澆枂<EFBFBD>𣂼<EFBFBD><EFBFBD><EFBFBD>隞嗅歇撘<EFBFBD>憪衤<EFBFBD>頧賬<EFBFBD>?, 'success');
}, 1500);
}
@@ -512,12 +503,11 @@
function batchDeleteGrades() {
// 这里应该调用后端API删除成绩
// 暂时使用模拟删除
batchDeleteBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 删除中...';
batchDeleteBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> <EFBFBD>𣳇膄銝?..';
batchDeleteBtn.disabled = true;
setTimeout(() => {
// 从模拟数据中删除选中的成绩
selectedGradeIds.forEach(id => {
// 隞擧芋<EFBFBD><EFBFBD><EFBFBD>桐葉<EFBFBD>𣳇膄<EFBFBD>劐葉<EFBFBD><EFBFBD><EFBFBD>蝏? selectedGradeIds.forEach(id => {
const index = mockGrades.findIndex(grade => grade.id === id);
if (index !== -1) {
mockGrades.splice(index, 1);
@@ -546,7 +536,7 @@
// 删除单个成绩
function deleteGrade(gradeId) {
if (confirm('确定要删除这条成绩记录吗?此操作不可撤销。')) {
if (confirm('蝖桀<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>蝏抵扇敶訫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>銝滚虾<EFBFBD><EFBFBD><EFBFBD>?)) {
// 这里应该调用后端API删除成绩
// 暂时使用模拟删除
const index = mockGrades.findIndex(grade => grade.id === gradeId);