v0.6测试
This commit is contained in:
@@ -226,6 +226,36 @@
|
|||||||
### 阶段 10:修复 500 Internal Server Error - SQL 引用不存在的 class_id 列
|
### 阶段 10:修复 500 Internal Server Error - SQL 引用不存在的 class_id 列
|
||||||
|
|
||||||
- [x] 10.1 修复代码与数据库 schema 不匹配问题(13个文件)
|
- [x] 10.1 修复代码与数据库 schema 不匹配问题(13个文件)
|
||||||
|
|
||||||
|
### 阶段 11:修复 422 参数校验 + JS 变量重复声明 + RANK() 兼容性
|
||||||
|
|
||||||
|
- [x] 11.1 修复历史记录页 422 和 JS 变量声明问题
|
||||||
|
- [x] 11.2 修复首页 RANK() OVER 窗口函数兼容性
|
||||||
|
|
||||||
|
### 阶段 12:全面项目审查 - 消灭潜在问题
|
||||||
|
|
||||||
|
- [x] 12.1 修复后端角色名"科代表"→"学习委员"(3处)+ 存储过程缺失 + 权限逻辑 + security工具类
|
||||||
|
【目标对象】`backend/services/conduct_service.py`、`backend/services/homework_service.py`、`backend/models/conduct.py`、`backend/middleware/permission.py`、`backend/utils/security.py`
|
||||||
|
【修改目的】1) "科代表"角色在数据库ENUM中不存在,应为"学习委员";2) revoke_conduct_record存储过程在init.sql中不存在,需替换为内联SQL;3) get_user_subject_ids方法逻辑顺序有误;4) validate_points_change返回类型不一致
|
||||||
|
【修改方式】
|
||||||
|
- conduct_service.py 第58行: `elif role in ["科代表", "考勤委员"]:` → `elif role in ["学习委员", "考勤委员"]:`
|
||||||
|
- homework_service.py 第35行: `elif role == "科代表":` → `elif role == "学习委员":`
|
||||||
|
- homework_service.py 第82行: `if role == "科代表":` → `if role == "学习委员":`
|
||||||
|
- conduct.py revoke_record方法: 替换 `call_procedure('revoke_conduct_record', ...)` 为内联SQL: `UPDATE conduct_records SET is_revoked=1, revoked_by=%s, revoked_at=NOW() WHERE record_id=%s`,使用 `execute_update` 执行
|
||||||
|
- permission.py get_user_subject_ids: 调整逻辑顺序,先检查role_type是否为班主任,再检查subject_id
|
||||||
|
- security.py 第126行: `return f"单次分值变动不能超过{max_abs}分"` → `return False, f"单次分值变动不能超过{max_abs}分"`
|
||||||
|
|
||||||
|
- [x] 12.2 修复前端学生端/家长端关键问题 + 管理端小问题 + 配置修复
|
||||||
|
【目标对象】`frontend/student/dashboard.php`、`frontend/api/save_session.php`、`frontend/index.php`、`frontend/student/attendance.php`、`frontend/admin/homework.php`、`frontend/config.php`、`frontend/student/conduct_history.php`
|
||||||
|
【修改目的】1) student/dashboard.php的common.js加载顺序错误导致API函数未定义;2) save_session.php将user_id错误存储为student_id;3) student/dashboard.php中hw.subject字段名错误;4) homework.php重复调用loadStudents;5) config.php中ICP_ENABLED逻辑反转;6) conduct_history.php文件为空
|
||||||
|
【修改方式】
|
||||||
|
- student/dashboard.php: 将 `<script src="/assets/js/common.js"></script>` 移到内联script之前;删除局部 `const API_BASE_URL` 和 `const JWT_STORAGE_KEY`/`USER_STORAGE_KEY`,改用 `window.API_BASE_URL = '<?php echo API_BASE_URL; ?>'` 等全局变量(在common.js加载之前设置);将 `hw.subject` 改为 `hw.subject_name`
|
||||||
|
- save_session.php: 第106行 `$_SESSION['student_id'] = $data['user_id'];` 改为从请求中获取实际student_id:`$_SESSION['student_id'] = $data['student_id'] ?? $data['user_id'];`;同时添加student_id到requiredFields验证(仅学生时必须)
|
||||||
|
- index.php: 登录成功后save_session调用中添加 `student_id: userData.student_id` 参数
|
||||||
|
- student/attendance.php: 第21行 `$student_id = $_SESSION['student_id'];` 保持不变(修复save_session后此值会正确)
|
||||||
|
- admin/homework.php: 删除第176行重复的 `loadStudents();` 调用
|
||||||
|
- config.php: 第61行 `define('ICP_ENABLED', $config['ICP_ENABLED'] === 'false');` 改为 `define('ICP_ENABLED', $config['ICP_ENABLED'] !== 'false');`
|
||||||
|
- student/conduct_history.php: 文件为空,需要重定向到dashboard或创建基本页面。最简方案:创建一个重定向到 /student/dashboard.php 的页面
|
||||||
【目标对象】`backend/models/attendance.py`、`backend/services/attendance_service.py`、`backend/models/conduct.py`、`backend/services/conduct_service.py`、`backend/models/homework.py`、`backend/services/homework_service.py`、`backend/models/student.py`、`backend/middleware/permission.py`、`backend/services/auth_service.py`、`backend/schemas/student.py`、`backend/schemas/admin.py`、`backend/services/student_service.py`、`backend/routes/student.py`
|
【目标对象】`backend/models/attendance.py`、`backend/services/attendance_service.py`、`backend/models/conduct.py`、`backend/services/conduct_service.py`、`backend/models/homework.py`、`backend/services/homework_service.py`、`backend/models/student.py`、`backend/middleware/permission.py`、`backend/services/auth_service.py`、`backend/schemas/student.py`、`backend/schemas/admin.py`、`backend/services/student_service.py`、`backend/routes/student.py`
|
||||||
【修改目的】数据库 schema(单班级系统)中 `students` 和 `assignments` 表没有 `class_id` 列,但后端代码中大量 SQL 引用了该列,导致 MySQL 报错 → 500 Internal Server Error。同时 `PermissionChecker.get_user_subject_ids()` 和 `check_can_manage_student()` 方法不存在但被调用。
|
【修改目的】数据库 schema(单班级系统)中 `students` 和 `assignments` 表没有 `class_id` 列,但后端代码中大量 SQL 引用了该列,导致 MySQL 报错 → 500 Internal Server Error。同时 `PermissionChecker.get_user_subject_ids()` 和 `check_can_manage_student()` 方法不存在但被调用。
|
||||||
【修改方式】全面移除所有 `class_id` 引用(单班级系统不需要),添加缺失的方法
|
【修改方式】全面移除所有 `class_id` 引用(单班级系统不需要),添加缺失的方法
|
||||||
@@ -241,3 +271,36 @@
|
|||||||
- auth_service.py: 移除 class_id 和 class_name 引用
|
- auth_service.py: 移除 class_id 和 class_name 引用
|
||||||
- schemas/student.py 和 schemas/admin.py: 移除 class_id 和 class_name 字段
|
- schemas/student.py 和 schemas/admin.py: 移除 class_id 和 class_name 字段
|
||||||
- student_service.py 和 routes/student.py: 移除 class_id 参数
|
- student_service.py 和 routes/student.py: 移除 class_id 参数
|
||||||
|
|
||||||
|
- [x] 12.3 修复CRITICAL: total_points在所有Service中从未更新(操行分系统完全失效)
|
||||||
|
【目标对象】`backend/services/conduct_service.py`、`backend/services/attendance_service.py`、`backend/services/homework_service.py`
|
||||||
|
【修改目的】`StudentModel.update_total_points()` 方法已存在但从未被调用,导致 `students.total_points` 永远保持初始值60分,排行榜、仪表盘、家长端显示的所有总分都是错误的
|
||||||
|
【修改方式】
|
||||||
|
- conduct_service.py add_points: 在 `ConductModel.create_record()` 后添加 `await StudentModel.update_total_points(student_id, points_change)`
|
||||||
|
- conduct_service.py revoke_record: 重写撤销逻辑,先获取原记录,撤销后调用 `await StudentModel.update_total_points(record["student_id"], -record["points_change"])` 反向恢复总分
|
||||||
|
- attendance_service.py add_attendance: 在 `ConductModel.create_record()` 后添加 `await StudentModel.update_total_points(student_id, points_change)`
|
||||||
|
- homework_service.py update_submission_status: 在 `ConductModel.create_record()` 后添加 `await StudentModel.update_total_points(submission["student_id"], points_change)`
|
||||||
|
|
||||||
|
- [x] 12.4 修复前端: student/homework.php字段名 + nav.php劳动委员 + parent/attendance.php死链
|
||||||
|
【目标对象】`frontend/student/homework.php`、`frontend/includes/nav.php`、`frontend/parent/attendance.php`
|
||||||
|
【修改目的】1) homework.php中hw.subject字段名与后端API不匹配;2) 劳动委员无法在导航栏看到操行分管理入口(README要求±1分权限);3) parent/attendance.php有指向不存在的/parent/homework.php的死链接
|
||||||
|
【修改方式】
|
||||||
|
- student/homework.php 第56行: `hw.subject` → `hw.subject_name`
|
||||||
|
- nav.php 第4行: 添加 `|| $role === '劳动委员'` 到操行分管理导航条件
|
||||||
|
- parent/attendance.php: 删除指向不存在的 /parent/homework.php 的死链接,导航只保留"首页"和"考勤记录"
|
||||||
|
|
||||||
|
- [x] 12.5 修复学生端导航死链接: 3个页面的"操行分"链接指向不存在的/student/conduct.php
|
||||||
|
【目标对象】`frontend/student/homework.php`、`frontend/student/attendance.php`、`frontend/student/password.php`
|
||||||
|
【修改目的】学生端3个子页面导航栏中的"操行分"链接指向 `/student/conduct.php`,但实际文件名是 `conduct_history.php`,导致404
|
||||||
|
【修改方式】
|
||||||
|
- password.php 第26行: `/student/conduct.php` → `/student/conduct_history.php`
|
||||||
|
|
||||||
|
- [x] 12.6 修复劳动委员页面级权限被拦截 + 仪表盘快捷操作缺失
|
||||||
|
【目标对象】`frontend/admin/conduct.php`、`frontend/admin/dashboard.php`
|
||||||
|
【修改目的】README规定劳动委员有操行分管理权限(±1分),但conduct.php页面级权限检查只允许班主任和班长访问,劳动委员会被重定向到dashboard;dashboard.php快捷操作也缺少劳动委员
|
||||||
|
【修改方式】
|
||||||
|
- conduct.php 第23行: `['班主任', '班长']` → `['班主任', '班长', '劳动委员']`
|
||||||
|
- conduct.php 第115行: 分数变动提示文字改为 if/elseif/else 结构,劳动委员显示"劳动委员仅限±1分"
|
||||||
|
- dashboard.php 第61行: 快捷操作条件添加劳动委员
|
||||||
|
- attendance.php 第27行: `/student/conduct.php` → `/student/conduct_history.php`
|
||||||
|
- password.php 第26行: `/student/conduct.php` → `/student/conduct_history.php`
|
||||||
|
|||||||
@@ -96,13 +96,16 @@ class PermissionChecker:
|
|||||||
async def get_user_subject_ids(user_id: int) -> List[int]:
|
async def get_user_subject_ids(user_id: int) -> List[int]:
|
||||||
"""获取用户管理的科目ID列表"""
|
"""获取用户管理的科目ID列表"""
|
||||||
admin_role = await AdminRoleModel.get_by_user_id(user_id)
|
admin_role = await AdminRoleModel.get_by_user_id(user_id)
|
||||||
if admin_role and admin_role.get("subject_id"):
|
if not admin_role:
|
||||||
return [admin_role["subject_id"]]
|
return []
|
||||||
# 班主任可以管理所有科目
|
# 班主任可以管理所有科目
|
||||||
if admin_role and admin_role["role_type"] == "班主任":
|
if admin_role["role_type"] == "班主任":
|
||||||
from models.subject import SubjectModel
|
from models.subject import SubjectModel
|
||||||
subjects = await SubjectModel.get_all(is_active=True)
|
subjects = await SubjectModel.get_all(is_active=True)
|
||||||
return [s["subject_id"] for s in subjects]
|
return [s["subject_id"] for s in subjects]
|
||||||
|
# 其他角色返回关联的科目
|
||||||
|
if admin_role.get("subject_id"):
|
||||||
|
return [admin_role["subject_id"]]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
from typing import Optional, List, Dict, Any
|
from typing import Optional, List, Dict, Any
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from utils.database import execute_one, execute_query, execute_insert, execute_update, call_procedure
|
from utils.database import execute_one, execute_query, execute_insert, execute_update
|
||||||
from utils.logger import get_logger
|
from utils.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -123,8 +123,13 @@ class ConductModel:
|
|||||||
async def revoke_record(record_id: int, revoker_id: int) -> bool:
|
async def revoke_record(record_id: int, revoker_id: int) -> bool:
|
||||||
"""撤销记录"""
|
"""撤销记录"""
|
||||||
try:
|
try:
|
||||||
await call_procedure('revoke_conduct_record', (record_id, revoker_id))
|
sql = """
|
||||||
return True
|
UPDATE conduct_records
|
||||||
|
SET is_revoked = 1, revoked_by = %s, revoked_at = NOW()
|
||||||
|
WHERE record_id = %s AND is_revoked = 0
|
||||||
|
"""
|
||||||
|
result = await execute_update(sql, (revoker_id, record_id))
|
||||||
|
return result > 0
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"撤销记录失败: {e}")
|
logger.error(f"撤销记录失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -109,14 +109,16 @@ class StudentModel:
|
|||||||
async def get_ranking(limit: int = 50) -> List[Dict[str, Any]]:
|
async def get_ranking(limit: int = 50) -> List[Dict[str, Any]]:
|
||||||
"""获取学生排行(单班级)"""
|
"""获取学生排行(单班级)"""
|
||||||
sql = """
|
sql = """
|
||||||
SELECT student_id, student_no, name, total_points,
|
SELECT student_id, student_no, name, total_points
|
||||||
RANK() OVER (ORDER BY total_points DESC) as rank
|
FROM students
|
||||||
FROM students
|
|
||||||
WHERE status = 1
|
WHERE status = 1
|
||||||
ORDER BY total_points DESC
|
ORDER BY total_points DESC
|
||||||
LIMIT %s
|
LIMIT %s
|
||||||
"""
|
"""
|
||||||
return await execute_query(sql, (limit,))
|
results = await execute_query(sql, (limit,))
|
||||||
|
for i, row in enumerate(results):
|
||||||
|
row['rank'] = i + 1
|
||||||
|
return results
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def batch_create(students_data: List[Dict], initial_points: int = 60) -> List[Dict]:
|
async def batch_create(students_data: List[Dict], initial_points: int = 60) -> List[Dict]:
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ class AttendanceService:
|
|||||||
related_id=attendance_id
|
related_id=attendance_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 更新学生总分
|
||||||
|
await StudentModel.update_total_points(student_id, points_change)
|
||||||
|
|
||||||
# 标记已应用扣分
|
# 标记已应用扣分
|
||||||
await AttendanceModel.mark_deduction_applied(attendance_id)
|
await AttendanceModel.mark_deduction_applied(attendance_id)
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ class ConductService:
|
|||||||
# 劳动委员固定 ±1分
|
# 劳动委员固定 ±1分
|
||||||
if points_change not in [settings.LABOR_POINTS_ADD, settings.LABOR_POINTS_SUBTRACT]:
|
if points_change not in [settings.LABOR_POINTS_ADD, settings.LABOR_POINTS_SUBTRACT]:
|
||||||
return {"success": False, "message": "劳动委员只能进行±1分操作"}
|
return {"success": False, "message": "劳动委员只能进行±1分操作"}
|
||||||
elif role in ["科代表", "考勤委员"]:
|
elif role in ["学习委员", "考勤委员"]:
|
||||||
# 科代表和考勤委员只能扣分
|
# 学习委员和考勤委员只能扣分
|
||||||
if points_change > 0:
|
if points_change > 0:
|
||||||
return {"success": False, "message": "该角色只能进行扣分操作"}
|
return {"success": False, "message": "该角色只能进行扣分操作"}
|
||||||
else:
|
else:
|
||||||
@@ -85,6 +85,9 @@ class ConductService:
|
|||||||
recorder_name=recorder_name
|
recorder_name=recorder_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 更新学生总分
|
||||||
|
await StudentModel.update_total_points(student_id, points_change)
|
||||||
|
|
||||||
details.append({"student_id": student_id, "success": True, "record_id": record_id})
|
details.append({"student_id": student_id, "success": True, "record_id": record_id})
|
||||||
success_count += 1
|
success_count += 1
|
||||||
|
|
||||||
@@ -109,10 +112,17 @@ class ConductService:
|
|||||||
if not can_revoke:
|
if not can_revoke:
|
||||||
return {"success": False, "message": "无权撤销此记录"}
|
return {"success": False, "message": "无权撤销此记录"}
|
||||||
|
|
||||||
|
# 先获取原记录信息(用于恢复分数)
|
||||||
|
record = await ConductModel.get_record_by_id(record_id)
|
||||||
|
if not record:
|
||||||
|
return {"success": False, "message": "记录不存在"}
|
||||||
|
|
||||||
# 撤销记录
|
# 撤销记录
|
||||||
result = await ConductModel.revoke_record(record_id, revoker_id)
|
result = await ConductModel.revoke_record(record_id, revoker_id)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
|
# 反向恢复学生总分
|
||||||
|
await StudentModel.update_total_points(record["student_id"], -record["points_change"])
|
||||||
logger.info(f"用户[{revoker_id}] 撤销了记录[{record_id}]")
|
logger.info(f"用户[{revoker_id}] 撤销了记录[{record_id}]")
|
||||||
return {"success": True, "message": "撤销成功"}
|
return {"success": True, "message": "撤销成功"}
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class HomeworkService:
|
|||||||
|
|
||||||
if role == "班主任":
|
if role == "班主任":
|
||||||
assignments = await HomeworkModel.get_all_assignments()
|
assignments = await HomeworkModel.get_all_assignments()
|
||||||
elif role == "科代表":
|
elif role == "学习委员":
|
||||||
subject_ids = await PermissionChecker.get_user_subject_ids(user_id)
|
subject_ids = await PermissionChecker.get_user_subject_ids(user_id)
|
||||||
assignments = await HomeworkModel.get_assignments_by_subjects(subject_ids)
|
assignments = await HomeworkModel.get_assignments_by_subjects(subject_ids)
|
||||||
else:
|
else:
|
||||||
@@ -79,7 +79,7 @@ class HomeworkService:
|
|||||||
|
|
||||||
# 检查权限
|
# 检查权限
|
||||||
role = await PermissionChecker.get_user_role(operator_id)
|
role = await PermissionChecker.get_user_role(operator_id)
|
||||||
if role == "科代表":
|
if role == "学习委员":
|
||||||
# 检查是否管理该科目
|
# 检查是否管理该科目
|
||||||
subject_ids = await PermissionChecker.get_user_subject_ids(operator_id)
|
subject_ids = await PermissionChecker.get_user_subject_ids(operator_id)
|
||||||
if submission["subject_id"] not in subject_ids:
|
if submission["subject_id"] not in subject_ids:
|
||||||
@@ -118,6 +118,9 @@ class HomeworkService:
|
|||||||
related_id=submission["assignment_id"]
|
related_id=submission["assignment_id"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 更新学生总分
|
||||||
|
await StudentModel.update_total_points(submission["student_id"], points_change)
|
||||||
|
|
||||||
# 标记已应用扣分
|
# 标记已应用扣分
|
||||||
await HomeworkModel.mark_deduction_applied(submission_id)
|
await HomeworkModel.mark_deduction_applied(submission_id)
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ class SecurityUtils:
|
|||||||
if points == 0:
|
if points == 0:
|
||||||
return False, "分值不能为0"
|
return False, "分值不能为0"
|
||||||
if abs(points) > max_abs:
|
if abs(points) > max_abs:
|
||||||
return f"单次分值变动不能超过{max_abs}分"
|
return False, f"单次分值变动不能超过{max_abs}分"
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'admin') {
|
|||||||
$page_title = '操行分管理';
|
$page_title = '操行分管理';
|
||||||
$role = $_SESSION['role'] ?? '';
|
$role = $_SESSION['role'] ?? '';
|
||||||
|
|
||||||
if (!in_array($role, ['班主任', '班长'])) {
|
if (!in_array($role, ['班主任', '班长', '劳动委员'])) {
|
||||||
header('Location: /admin/dashboard.php');
|
header('Location: /admin/dashboard.php');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,11 @@ loadStudents();
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>分数变动</label>
|
<label>分数变动</label>
|
||||||
<input type="number" id="pointsChange" required placeholder="正数为加分,负数为扣分">
|
<input type="number" id="pointsChange" required placeholder="正数为加分,负数为扣分">
|
||||||
<small><?php echo $role === '班长' ? '班长单次±5分以内' : '班主任无限制'; ?></small>
|
<small><?php
|
||||||
|
if ($role === '班长') echo '班长单次±5分以内';
|
||||||
|
elseif ($role === '劳动委员') echo '劳动委员仅限±1分';
|
||||||
|
else echo '班主任无限制';
|
||||||
|
?></small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>原因</label>
|
<label>原因</label>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ async function loadDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let quickActions = '';
|
let quickActions = '';
|
||||||
if ('<?php echo $role; ?>' === '班主任' || '<?php echo $role; ?>' === '班长') {
|
if ('<?php echo $role; ?>' === '班主任' || '<?php echo $role; ?>' === '班长' || '<?php echo $role; ?>' === '劳动委员') {
|
||||||
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
|
quickActions += '<button class="btn btn-primary" onclick="location.href=\'/admin/conduct.php\'">操行分管理</button>';
|
||||||
}
|
}
|
||||||
if ('<?php echo $role; ?>' === '班主任') {
|
if ('<?php echo $role; ?>' === '班主任') {
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let currentHistoryPage = 1;
|
var currentHistoryPage = 1;
|
||||||
let totalHistoryPages = 1;
|
var totalHistoryPages = 1;
|
||||||
|
|
||||||
async function loadStudentsForSelect() {
|
async function loadStudentsForSelect() {
|
||||||
const res = await apiGet('/api/admin/students');
|
const res = await apiGet('/api/admin/students');
|
||||||
@@ -86,12 +86,14 @@ async function loadHistory(page = 1) {
|
|||||||
const endDate = document.getElementById('historyEndDate').value;
|
const endDate = document.getElementById('historyEndDate').value;
|
||||||
const studentId = document.getElementById('historyStudentId').value;
|
const studentId = document.getElementById('historyStudentId').value;
|
||||||
|
|
||||||
const res = await apiGet('/api/admin/conduct/history', {
|
const params = {
|
||||||
page, page_size: 20,
|
page, page_size: 20,
|
||||||
start_date: startDate,
|
start_date: startDate,
|
||||||
end_date: endDate,
|
end_date: endDate
|
||||||
student_id: studentId
|
};
|
||||||
});
|
if (studentId) params.student_id = studentId;
|
||||||
|
|
||||||
|
const res = await apiGet('/api/admin/conduct/history', params);
|
||||||
|
|
||||||
if (res && res.success) {
|
if (res && res.success) {
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ function handleSubmitPoints() {
|
|||||||
submitBatchPoints();
|
submitBatchPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadStudents();
|
|
||||||
loadStudents();
|
loadStudents();
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/admin.js"></script>
|
<script src="/assets/js/admin.js"></script>
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const userRole = '<?php echo $role; ?>';
|
const userRole = '<?php echo $role; ?>';
|
||||||
let currentPage = 1;
|
var currentPage = 1;
|
||||||
let totalPages = 1;
|
var totalPages = 1;
|
||||||
|
|
||||||
async function loadStudents(page = 1) {
|
async function loadStudents(page = 1) {
|
||||||
currentPage = page;
|
currentPage = page;
|
||||||
|
|||||||
@@ -101,9 +101,17 @@ $_SESSION['real_name'] = $data['real_name'] ?? '';
|
|||||||
$_SESSION['role'] = $data['role'] ?? '';
|
$_SESSION['role'] = $data['role'] ?? '';
|
||||||
$_SESSION['login_time'] = time();
|
$_SESSION['login_time'] = time();
|
||||||
|
|
||||||
// 如果是学生,额外设置 student_id(与 user_id 相同)
|
// 如果是学生,额外设置 student_id
|
||||||
if ($data['user_type'] === 'student') {
|
if ($data['user_type'] === 'student') {
|
||||||
$_SESSION['student_id'] = $data['user_id'];
|
if (empty($data['student_id'])) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode([
|
||||||
|
'success' => false,
|
||||||
|
'message' => '学生类型必须提供 student_id'
|
||||||
|
]);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
$_SESSION['student_id'] = $data['student_id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存 Session
|
// 保存 Session
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ define('JWT_STORAGE_KEY', $config['JWT_STORAGE_KEY']);
|
|||||||
define('USER_STORAGE_KEY', $config['USER_STORAGE_KEY']);
|
define('USER_STORAGE_KEY', $config['USER_STORAGE_KEY']);
|
||||||
define('SITE_NAME', $config['SITE_NAME']);
|
define('SITE_NAME', $config['SITE_NAME']);
|
||||||
define('SESSION_TIMEOUT', (int)$config['SESSION_TIMEOUT']);
|
define('SESSION_TIMEOUT', (int)$config['SESSION_TIMEOUT']);
|
||||||
define('ICP_ENABLED', $config['ICP_ENABLED'] === 'false');
|
define('ICP_ENABLED', $config['ICP_ENABLED'] !== 'false');
|
||||||
define('ICP_NUMBER', $config['ICP_NUMBER'] ?? '');
|
define('ICP_NUMBER', $config['ICP_NUMBER'] ?? '');
|
||||||
|
|
||||||
// 扣分规则配置(有默认值,不强制要求在.env中配置)
|
// 扣分规则配置(有默认值,不强制要求在.env中配置)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/admin/dashboard.php" class="nav-item<?php echo $current_page === 'dashboard' ? ' active' : ''; ?>">首页</a>
|
<a href="/admin/dashboard.php" class="nav-item<?php echo $current_page === 'dashboard' ? ' active' : ''; ?>">首页</a>
|
||||||
<a href="/admin/students.php" class="nav-item<?php echo $current_page === 'students' ? ' active' : ''; ?>">学生管理</a>
|
<a href="/admin/students.php" class="nav-item<?php echo $current_page === 'students' ? ' active' : ''; ?>">学生管理</a>
|
||||||
<?php if ($role === '班主任' || $role === '班长'): ?>
|
<?php if ($role === '班主任' || $role === '班长' || $role === '劳动委员'): ?>
|
||||||
<a href="/admin/conduct.php" class="nav-item<?php echo $current_page === 'conduct' ? ' active' : ''; ?>">操行分管理</a>
|
<a href="/admin/conduct.php" class="nav-item<?php echo $current_page === 'conduct' ? ' active' : ''; ?>">操行分管理</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($role === '班主任' || $role === '学习委员'): ?>
|
<?php if ($role === '班主任' || $role === '学习委员'): ?>
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
|||||||
user_type: userData.user_type,
|
user_type: userData.user_type,
|
||||||
username: userData.username,
|
username: userData.username,
|
||||||
real_name: userData.real_name,
|
real_name: userData.real_name,
|
||||||
role: userData.role || ''
|
role: userData.role || '',
|
||||||
|
student_id: userData.student_id || null
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/parent/dashboard.php" class="nav-item">首页</a>
|
<a href="/parent/dashboard.php" class="nav-item">首页</a>
|
||||||
<a href="/parent/homework.php" class="nav-item">作业情况</a>
|
|
||||||
<a href="/parent/attendance.php" class="nav-item active">考勤记录</a>
|
<a href="/parent/attendance.php" class="nav-item active">考勤记录</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
||||||
<a href="/student/conduct.php" class="nav-item">操行分</a>
|
<a href="/student/conduct_history.php" class="nav-item">操行分</a>
|
||||||
<a href="/student/homework.php" class="nav-item">作业</a>
|
<a href="/student/homework.php" class="nav-item">作业</a>
|
||||||
<a href="/student/attendance.php" class="nav-item active">考勤</a>
|
<a href="/student/attendance.php" class="nav-item active">考勤</a>
|
||||||
<a href="/student/password.php" class="nav-item">修改密码</a>
|
<a href="/student/password.php" class="nav-item">修改密码</a>
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config.php';
|
||||||
|
|
||||||
|
if (!isset($_SESSION['user_id']) || $_SESSION['user_type'] !== 'student') {
|
||||||
|
header('Location: /index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重定向到学生端首页的操行分标签
|
||||||
|
header('Location: /student/dashboard.php');
|
||||||
|
exit();
|
||||||
|
|||||||
@@ -241,7 +241,12 @@ $student_id = $_SESSION['student_id'];
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const API_BASE_URL = '<?php echo API_BASE_URL; ?>';
|
window.API_BASE_URL = '<?php echo API_BASE_URL; ?>';
|
||||||
|
window.JWT_STORAGE_KEY = '<?php echo JWT_STORAGE_KEY; ?>';
|
||||||
|
window.USER_STORAGE_KEY = '<?php echo USER_STORAGE_KEY; ?>';
|
||||||
|
</script>
|
||||||
|
<script src="/assets/js/common.js"></script>
|
||||||
|
<script>
|
||||||
const STUDENT_ID = <?php echo $student_id; ?>;
|
const STUDENT_ID = <?php echo $student_id; ?>;
|
||||||
|
|
||||||
let conductPage = 1;
|
let conductPage = 1;
|
||||||
@@ -392,7 +397,7 @@ $student_id = $_SESSION['student_id'];
|
|||||||
res.data.homework.forEach(hw => {
|
res.data.homework.forEach(hw => {
|
||||||
html += `
|
html += `
|
||||||
<tr>
|
<tr>
|
||||||
<td>${hw.subject}</td>
|
<td>${hw.subject_name}</td>
|
||||||
<td>${hw.title}</td>
|
<td>${hw.title}</td>
|
||||||
<td>${hw.deadline}</td>
|
<td>${hw.deadline}</td>
|
||||||
<td>${getStatusBadge(hw.status, 'homework')}</td>
|
<td>${getStatusBadge(hw.status, 'homework')}</td>
|
||||||
@@ -508,6 +513,5 @@ $student_id = $_SESSION['student_id'];
|
|||||||
loadDashboard();
|
loadDashboard();
|
||||||
checkForceChangePassword();
|
checkForceChangePassword();
|
||||||
</script>
|
</script>
|
||||||
<script src="/assets/js/common.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -24,7 +24,7 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
||||||
<a href="/student/conduct.php" class="nav-item">操行分</a>
|
<a href="/student/conduct_history.php" class="nav-item">操行分</a>
|
||||||
<a href="/student/homework.php" class="nav-item active">作业</a>
|
<a href="/student/homework.php" class="nav-item active">作业</a>
|
||||||
<a href="/student/attendance.php" class="nav-item">考勤</a>
|
<a href="/student/attendance.php" class="nav-item">考勤</a>
|
||||||
<a href="/student/password.php" class="nav-item">修改密码</a>
|
<a href="/student/password.php" class="nav-item">修改密码</a>
|
||||||
@@ -53,7 +53,7 @@ async function loadHomework() {
|
|||||||
let html = '';
|
let html = '';
|
||||||
res.data.homework.forEach(hw => {
|
res.data.homework.forEach(hw => {
|
||||||
html += `<tr>
|
html += `<tr>
|
||||||
<td>${escapeHtml(hw.subject)}</td>
|
<td>${escapeHtml(hw.subject_name)}</td>
|
||||||
<td>${escapeHtml(hw.title)}</td>
|
<td>${escapeHtml(hw.title)}</td>
|
||||||
<td>${hw.deadline}</td>
|
<td>${hw.deadline}</td>
|
||||||
<td>${getStatusBadge(hw.status, 'homework')}</td>
|
<td>${getStatusBadge(hw.status, 'homework')}</td>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
|
|
||||||
<div class="nav">
|
<div class="nav">
|
||||||
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
<a href="/student/dashboard.php" class="nav-item">首页</a>
|
||||||
<a href="/student/conduct.php" class="nav-item">操行分</a>
|
<a href="/student/conduct_history.php" class="nav-item">操行分</a>
|
||||||
<a href="/student/homework.php" class="nav-item">作业</a>
|
<a href="/student/homework.php" class="nav-item">作业</a>
|
||||||
<a href="/student/attendance.php" class="nav-item">考勤</a>
|
<a href="/student/attendance.php" class="nav-item">考勤</a>
|
||||||
<a href="/student/password.php" class="nav-item active">修改密码</a>
|
<a href="/student/password.php" class="nav-item active">修改密码</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user