feat(conduct): add restore revoked record functionality and update history view

This commit is contained in:
2026-04-23 11:19:35 +08:00
parent 03aaaa53a9
commit bf0314f098
5 changed files with 115 additions and 13 deletions

View File

@@ -82,7 +82,8 @@ class ConductModel:
offset: int = 0,
start_date: str = None,
end_date: str = None,
student_id: int = None
student_id: int = None,
include_revoked: bool = True
) -> List[Dict[str, Any]]:
"""获取所有记录(班主任/班长专用)"""
# 空字符串转为None
@@ -96,8 +97,10 @@ class ConductModel:
FROM conduct_records cr
JOIN students s ON cr.student_id = s.student_id
JOIN users u ON cr.recorder_id = u.user_id
WHERE cr.is_revoked = 0
WHERE 1=1
"""
if not include_revoked:
sql += " AND cr.is_revoked = 0"
params = []
if student_id:
@@ -210,6 +213,21 @@ class ConductModel:
logger.error(f"撤销记录失败: {e}")
return False
@staticmethod
async def restore_record(record_id: int, restorer_id: int) -> bool:
"""反撤销(恢复)已撤销的记录"""
try:
sql = """
UPDATE conduct_records
SET is_revoked = 0, revoked_by = NULL, revoked_at = NULL
WHERE record_id = %s AND is_revoked = 1
"""
result = await execute_update(sql, (record_id,))
return result > 0
except Exception as e:
logger.error(f"恢复记录失败: {e}")
return False
@staticmethod
async def batch_create_records(records_data: List[Dict]) -> List[Dict]:
"""批量创建操行分记录"""

View File

@@ -231,6 +231,33 @@ async def revoke_conduct_record(request: Request, req: RevokeRequest):
return error_response(message=result["message"])
@router.post("/conduct/restore")
async def restore_conduct_record(request: Request, req: RevokeRequest):
"""反撤销(恢复)已撤销的记录"""
user = await get_current_user(request)
result = await ConductService.restore_record(
record_id=req.record_id,
restorer_id=user["user_id"]
)
if result["success"]:
record = result.get("record", {})
await LogService.write_operation_log(
operator_id=user["user_id"], operator_name=user["username"],
operator_role="班主任", operation_type="restore_record",
target_type="conduct", target_id=req.record_id,
details=(
f"反撤销记录ID: {req.record_id}, "
f"原操作人: {record.get('recorder_name', '未知')}, "
f"原分值变动: {'+' if record.get('points_change', 0) > 0 else ''}{record.get('points_change', 0)}分, "
f"反撤销操作人: {user['username']}"
),
ip=request.client.host
)
return success_response(message="反撤销成功")
else:
return error_response(message=result["message"])
@router.get("/conduct/history")
async def get_conduct_history(
request: Request,

View File

@@ -152,6 +152,42 @@ class ConductService:
else:
return {"success": False, "message": "撤销失败"}
@staticmethod
async def restore_record(record_id: int, restorer_id: int) -> Dict[str, Any]:
"""反撤销(恢复)已撤销的记录"""
# 检查权限:只有班主任可以反撤销
role = await PermissionChecker.get_user_role(restorer_id)
if role != "班主任":
return {"success": False, "message": "仅班主任可反撤销记录"}
# 获取原记录信息
record = await ConductModel.get_record_by_id(record_id)
if not record:
return {"success": False, "message": "记录不存在"}
if not record.get("is_revoked"):
return {"success": False, "message": "该记录未被撤销,无需恢复"}
# 恢复记录
result = await ConductModel.restore_record(record_id, restorer_id)
if result:
# 恢复学生总分(重新加上原来的分数变动)
await StudentModel.update_total_points(record["student_id"], record["points_change"])
logger.info(f"用户[{restorer_id}] 反撤销了记录[{record_id}]")
return {
"success": True,
"message": "反撤销成功",
"record": {
"student_id": record["student_id"],
"recorder_name": record.get("recorder_name", "未知"),
"points_change": record["points_change"],
"reason": record.get("reason", "")
}
}
else:
return {"success": False, "message": "反撤销失败"}
@staticmethod
async def get_history(
user_id: int,
@@ -193,7 +229,7 @@ class ConductService:
# 获取总数
from utils.database import execute_one
count_conditions = ["cr.is_revoked = 0"]
count_conditions = ["1=1"]
count_params = []
if student_id:
count_conditions.append("cr.student_id = %s")