更新学期功能
This commit is contained in:
@@ -137,6 +137,73 @@ class SemesterModel:
|
||||
GROUP BY hs.student_id, hs.status
|
||||
"""
|
||||
return await execute_query(sql, (start_date, end_date))
|
||||
|
||||
@staticmethod
|
||||
async def update(
|
||||
semester_id: int,
|
||||
semester_name: str = None,
|
||||
start_date: str = None,
|
||||
end_date: str = None
|
||||
) -> bool:
|
||||
"""编辑学期信息(仅未归档)"""
|
||||
sets = []
|
||||
params = []
|
||||
if semester_name is not None:
|
||||
sets.append("semester_name = %s")
|
||||
params.append(semester_name)
|
||||
if start_date is not None:
|
||||
sets.append("start_date = %s")
|
||||
params.append(start_date)
|
||||
if end_date is not None:
|
||||
sets.append("end_date = %s")
|
||||
params.append(end_date)
|
||||
if not sets:
|
||||
return False
|
||||
params.append(semester_id)
|
||||
sql = f"UPDATE semesters SET {', '.join(sets)} WHERE semester_id = %s AND is_archived = 0"
|
||||
result = await execute_update(sql, tuple(params))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def delete(semester_id: int) -> bool:
|
||||
"""删除学期"""
|
||||
sql = "DELETE FROM semesters WHERE semester_id = %s"
|
||||
result = await execute_update(sql, (semester_id,))
|
||||
return result > 0
|
||||
|
||||
@staticmethod
|
||||
async def count_archives(semester_id: int) -> int:
|
||||
"""统计学期的归档数据数量"""
|
||||
sql = "SELECT COUNT(*) as cnt FROM semester_archives WHERE semester_id = %s"
|
||||
result = await execute_one(sql, (semester_id,))
|
||||
return result['cnt'] if result else 0
|
||||
|
||||
@staticmethod
|
||||
async def associate_records_by_date_range(
|
||||
semester_id: int,
|
||||
start_date: str,
|
||||
end_date: str
|
||||
) -> Dict[str, int]:
|
||||
"""按日期范围关联记录到学期"""
|
||||
# 关联操行分记录(created_at 为 TIMESTAMP,需包含 end_date 当天)
|
||||
conduct_sql = """
|
||||
UPDATE conduct_records
|
||||
SET semester_id = %s
|
||||
WHERE semester_id IS NULL
|
||||
AND created_at BETWEEN %s AND CONCAT(%s, ' 23:59:59')
|
||||
"""
|
||||
conduct_count = await execute_update(conduct_sql, (semester_id, start_date, end_date))
|
||||
|
||||
# 关联考勤记录
|
||||
attendance_sql = """
|
||||
UPDATE attendance_records
|
||||
SET semester_id = %s
|
||||
WHERE semester_id IS NULL
|
||||
AND `date` BETWEEN %s AND %s
|
||||
"""
|
||||
attendance_count = await execute_update(attendance_sql, (semester_id, start_date, end_date))
|
||||
|
||||
return {"conduct": conduct_count, "attendance": attendance_count}
|
||||
|
||||
|
||||
class SemesterArchiveModel:
|
||||
|
||||
@@ -18,7 +18,7 @@ from middleware.permission import (
|
||||
)
|
||||
from services.semester_service import SemesterService
|
||||
from services.log_service import LogService
|
||||
from schemas.semester import CreateSemesterRequest
|
||||
from schemas.semester import CreateSemesterRequest, UpdateSemesterRequest
|
||||
from utils.response import success_response, error_response
|
||||
from utils.logger import get_logger
|
||||
|
||||
@@ -103,8 +103,90 @@ async def activate_semester(request: Request, semester_id: int):
|
||||
return error_response(message=result["message"])
|
||||
|
||||
|
||||
@router.put("/update/{semester_id}")
|
||||
async def update_semester(request: Request, semester_id: int, req: UpdateSemesterRequest):
|
||||
"""编辑学期(班主任)"""
|
||||
user = await get_current_user(request)
|
||||
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
||||
if not is_teacher:
|
||||
return error_response(message="仅班主任可编辑学期", code=403)
|
||||
|
||||
result = await SemesterService.update_semester(
|
||||
semester_id=semester_id,
|
||||
semester_name=req.semester_name,
|
||||
start_date=req.start_date,
|
||||
end_date=req.end_date,
|
||||
operator_id=user["user_id"]
|
||||
)
|
||||
if result["success"]:
|
||||
await LogService.write_operation_log(
|
||||
operator_id=user["user_id"], operator_name=user["username"],
|
||||
operator_role="班主任", operation_type="update_semester",
|
||||
target_type="semester", target_id=semester_id,
|
||||
details=f"编辑学期ID: {semester_id}",
|
||||
ip=request.client.host
|
||||
)
|
||||
return success_response(message=result["message"])
|
||||
else:
|
||||
return error_response(message=result["message"])
|
||||
|
||||
|
||||
@router.delete("/delete/{semester_id}")
|
||||
async def delete_semester(request: Request, semester_id: int):
|
||||
"""删除学期(班主任)"""
|
||||
user = await get_current_user(request)
|
||||
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
||||
if not is_teacher:
|
||||
return error_response(message="仅班主任可删除学期", code=403)
|
||||
|
||||
result = await SemesterService.delete_semester(
|
||||
semester_id=semester_id,
|
||||
operator_id=user["user_id"]
|
||||
)
|
||||
if result["success"]:
|
||||
await LogService.write_operation_log(
|
||||
operator_id=user["user_id"], operator_name=user["username"],
|
||||
operator_role="班主任", operation_type="delete_semester",
|
||||
target_type="semester", target_id=semester_id,
|
||||
details=f"删除学期ID: {semester_id}",
|
||||
ip=request.client.host
|
||||
)
|
||||
return success_response(message=result["message"])
|
||||
else:
|
||||
return error_response(message=result["message"])
|
||||
|
||||
|
||||
@router.post("/{semester_id}/associate")
|
||||
async def associate_records(request: Request, semester_id: int):
|
||||
"""关联记录到学期(班主任)"""
|
||||
user = await get_current_user(request)
|
||||
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
||||
if not is_teacher:
|
||||
return error_response(message="仅班主任可关联数据", code=403)
|
||||
|
||||
result = await SemesterService.associate_records(
|
||||
semester_id=semester_id,
|
||||
operator_id=user["user_id"]
|
||||
)
|
||||
if result["success"]:
|
||||
await LogService.write_operation_log(
|
||||
operator_id=user["user_id"], operator_name=user["username"],
|
||||
operator_role="班主任", operation_type="associate_records",
|
||||
target_type="semester", target_id=semester_id,
|
||||
details=f"关联数据到学期ID: {semester_id}, 结果: {result.get('data', {})}",
|
||||
ip=request.client.host
|
||||
)
|
||||
return success_response(data=result.get("data"), message=result["message"])
|
||||
else:
|
||||
return error_response(message=result["message"])
|
||||
|
||||
|
||||
@router.post("/archive/{semester_id}")
|
||||
async def archive_semester(request: Request, semester_id: int):
|
||||
async def archive_semester(
|
||||
request: Request,
|
||||
semester_id: int,
|
||||
reset_scores: bool = Query(False)
|
||||
):
|
||||
"""归档学期(班主任)"""
|
||||
user = await get_current_user(request)
|
||||
is_teacher = await PermissionChecker.check_is_teacher(user["user_id"])
|
||||
@@ -113,14 +195,18 @@ async def archive_semester(request: Request, semester_id: int):
|
||||
|
||||
result = await SemesterService.archive_semester(
|
||||
semester_id=semester_id,
|
||||
operator_id=user["user_id"]
|
||||
operator_id=user["user_id"],
|
||||
reset_scores=reset_scores
|
||||
)
|
||||
if result["success"]:
|
||||
log_detail = f"归档学期ID: {semester_id}"
|
||||
if reset_scores:
|
||||
log_detail += " 并重置学生操行分"
|
||||
await LogService.write_operation_log(
|
||||
operator_id=user["user_id"], operator_name=user["username"],
|
||||
operator_role="班主任", operation_type="archive_semester",
|
||||
target_type="semester", target_id=semester_id,
|
||||
details=f"归档学期ID: {semester_id}",
|
||||
details=log_detail,
|
||||
ip=request.client.host
|
||||
)
|
||||
return success_response(message=result["message"])
|
||||
|
||||
@@ -18,3 +18,10 @@ class CreateSemesterRequest(BaseModel):
|
||||
semester_name: str = Field(..., min_length=1, max_length=100, description="学期名称")
|
||||
start_date: Optional[str] = Field(None, description="学期开始日期 (YYYY-MM-DD)")
|
||||
end_date: Optional[str] = Field(None, description="学期结束日期 (YYYY-MM-DD)")
|
||||
|
||||
|
||||
class UpdateSemesterRequest(BaseModel):
|
||||
"""编辑学期请求"""
|
||||
semester_name: Optional[str] = Field(None, min_length=1, max_length=100, description="学期名称")
|
||||
start_date: Optional[str] = Field(None, description="学期开始日期 (YYYY-MM-DD)")
|
||||
end_date: Optional[str] = Field(None, description="学期结束日期 (YYYY-MM-DD)")
|
||||
|
||||
@@ -127,9 +127,110 @@ class SemesterService:
|
||||
return {"success": False, "message": f"激活学期失败: {str(e)}"}
|
||||
|
||||
@staticmethod
|
||||
async def archive_semester(
|
||||
async def update_semester(
|
||||
semester_id: int,
|
||||
semester_name: str = None,
|
||||
start_date: str = None,
|
||||
end_date: str = None,
|
||||
operator_id: int = None
|
||||
) -> Dict[str, Any]:
|
||||
"""编辑学期信息"""
|
||||
try:
|
||||
semester = await SemesterModel.get_by_id(semester_id)
|
||||
if not semester:
|
||||
return {"success": False, "message": "学期不存在"}
|
||||
|
||||
if semester['is_archived']:
|
||||
return {"success": False, "message": "已归档的学期不能编辑"}
|
||||
|
||||
result = await SemesterModel.update(
|
||||
semester_id=semester_id,
|
||||
semester_name=semester_name,
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
|
||||
if result:
|
||||
logger.info(f"用户[{operator_id}] 编辑了学期: {semester['semester_name']}")
|
||||
return {"success": True, "message": "学期信息已更新"}
|
||||
else:
|
||||
return {"success": False, "message": "更新失败,请检查参数"}
|
||||
except Exception as e:
|
||||
logger.error(f"编辑学期失败: {e}")
|
||||
return {"success": False, "message": f"编辑学期失败: {str(e)}"}
|
||||
|
||||
@staticmethod
|
||||
async def delete_semester(
|
||||
semester_id: int,
|
||||
operator_id: int = None
|
||||
) -> Dict[str, Any]:
|
||||
"""删除学期"""
|
||||
try:
|
||||
semester = await SemesterModel.get_by_id(semester_id)
|
||||
if not semester:
|
||||
return {"success": False, "message": "学期不存在"}
|
||||
|
||||
# 检查是否有关联归档数据
|
||||
archive_count = await SemesterModel.count_archives(semester_id)
|
||||
if archive_count > 0:
|
||||
return {"success": False, "message": f"该学期有 {archive_count} 条归档数据,无法删除"}
|
||||
|
||||
result = await SemesterModel.delete(semester_id)
|
||||
|
||||
if result:
|
||||
logger.info(f"用户[{operator_id}] 删除了学期: {semester['semester_name']}")
|
||||
return {"success": True, "message": "学期已删除"}
|
||||
else:
|
||||
return {"success": False, "message": "删除失败"}
|
||||
except Exception as e:
|
||||
logger.error(f"删除学期失败: {e}")
|
||||
return {"success": False, "message": f"删除学期失败: {str(e)}"}
|
||||
|
||||
@staticmethod
|
||||
async def associate_records(
|
||||
semester_id: int,
|
||||
operator_id: int = None
|
||||
) -> Dict[str, Any]:
|
||||
"""关联记录到学期"""
|
||||
try:
|
||||
semester = await SemesterModel.get_by_id(semester_id)
|
||||
if not semester:
|
||||
return {"success": False, "message": "学期不存在"}
|
||||
|
||||
if semester['is_archived']:
|
||||
return {"success": False, "message": "已归档的学期不能关联数据"}
|
||||
|
||||
start_date = semester.get('start_date')
|
||||
if not start_date:
|
||||
return {"success": False, "message": "学期未设置开始日期,无法关联数据"}
|
||||
|
||||
end_date = semester.get('end_date') or datetime.date.today().isoformat()
|
||||
|
||||
counts = await SemesterModel.associate_records_by_date_range(
|
||||
semester_id=semester_id,
|
||||
start_date=start_date,
|
||||
end_date=end_date
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"用户[{operator_id}] 关联数据到学期: {semester['semester_name']}, "
|
||||
f"操行分 {counts['conduct']} 条, 考勤 {counts['attendance']} 条"
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"关联完成:操行分 {counts['conduct']} 条,考勤 {counts['attendance']} 条",
|
||||
"data": counts
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"关联记录失败: {e}")
|
||||
return {"success": False, "message": f"关联记录失败: {str(e)}"}
|
||||
|
||||
@staticmethod
|
||||
async def archive_semester(
|
||||
semester_id: int,
|
||||
operator_id: int = None,
|
||||
reset_scores: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
"""归档学期"""
|
||||
try:
|
||||
@@ -231,6 +332,18 @@ class SemesterService:
|
||||
# 标记学期为已归档
|
||||
await SemesterModel.archive(semester_id)
|
||||
|
||||
# 归档成功后按需重置学生操行分
|
||||
if reset_scores:
|
||||
reset_result = await SemesterService.reset_student_points()
|
||||
logger.info(
|
||||
f"用户[{operator_id}] 归档学期: {semester['semester_name']} 并重置学生操行分, "
|
||||
f"共 {total_students} 名学生"
|
||||
)
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"学期归档成功,共归档 {total_students} 名学生数据,已重置学生操行分"
|
||||
}
|
||||
|
||||
logger.info(
|
||||
f"用户[{operator_id}] 归档了学期: {semester['semester_name']}, "
|
||||
f"共 {total_students} 名学生"
|
||||
|
||||
Reference in New Issue
Block a user