Files
LoveACE-EndF/loveace/router/endpoint/jwc/academic.py
Sibuxiangx bbc86b8330 ⚒️ 重大重构 LoveACE V2
引入了 mongodb
对数据库进行了一定程度的数据加密
性能改善
代码简化
统一错误模型和响应
使用 apifox 作为文档
2025-11-20 20:44:25 +08:00

246 lines
9.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import re
from fastapi import APIRouter, Depends
from fastapi.responses import JSONResponse
from pydantic import ValidationError
from loveace.router.endpoint.jwc.model.academic import (
AcademicInfo,
AcademicInfoTransformer,
CourseSelectionStatus,
CourseSelectionStatusTransformer,
TrainingPlanInfo,
TrainingPlanInfoTransformer,
)
from loveace.router.endpoint.jwc.model.base import JWCConfig
from loveace.router.schemas.error import ProtectRouterErrorToCode
from loveace.router.schemas.uniresponse import UniResponseModel
from loveace.service.remote.aufe import AUFEConnection
from loveace.service.remote.aufe.depends import get_aufe_conn
jwc_academic_router = APIRouter(
prefix="/academic",
responses=ProtectRouterErrorToCode.gen_code_table(),
)
ENDPOINTS = {
"academic_info": "/main/academicInfo?sf_request_type=ajax",
"training_plan": "/main/showPyfaInfo?sf_request_type=ajax",
"course_selection_status": "/main/checkSelectCourseStatus?sf_request_type=ajax",
}
@jwc_academic_router.get(
"/info", response_model=UniResponseModel[AcademicInfo], summary="获取学业信息"
)
async def get_academic_info(
conn: AUFEConnection = Depends(get_aufe_conn),
) -> UniResponseModel[AcademicInfo] | JSONResponse:
"""
获取用户的学业信息GPA、学分等
✅ 功能特性:
- 获取当前学期学业情况
- 获取平均学分绩点GPA
- 实时从教务系统查询
💡 使用场景:
- 个人中心查看学业成绩概览
- 了解学业进展情况
- 毕业时验证学业要求
Returns:
AcademicInfo: 包含 GPA、学分、学业状态等信息
"""
try:
conn.logger.info(f"获取用户 {conn.userid} 的学业信息")
academic_info = await conn.client.post(
JWCConfig().to_full_url(ENDPOINTS["academic_info"]),
data={"flag": ""},
follow_redirects=True,
timeout=conn.timeout,
)
if not academic_info.status_code == 200:
conn.logger.error(
f"获取用户 {conn.userid} 的学业信息失败,状态码: {academic_info.status_code}"
)
return ProtectRouterErrorToCode().remote_service_error.to_json_response(
conn.logger.trace_id
)
try:
data = academic_info.json()
# 数组格式特殊处理
data_to_validate = data[0]
result = AcademicInfoTransformer.model_validate(
data_to_validate
).to_academic_info()
return UniResponseModel[AcademicInfo](
success=True,
data=result,
message="获取学业信息成功",
error=None,
)
except ValidationError as ve:
conn.logger.error("数据验证失败")
conn.logger.debug(f"数据验证失败详情: {ve}")
return ProtectRouterErrorToCode().validation_error.to_json_response(
conn.logger.trace_id
)
except Exception as e:
conn.logger.exception(e)
return ProtectRouterErrorToCode().server_error.to_json_response(
conn.logger.trace_id
)
@jwc_academic_router.get(
"/training_plan",
response_model=UniResponseModel[TrainingPlanInfo],
summary="获取培养方案信息",
)
async def get_training_plan_info(
conn: AUFEConnection = Depends(get_aufe_conn),
) -> UniResponseModel[TrainingPlanInfo] | JSONResponse:
"""
获取用户的培养方案信息
✅ 功能特性:
- 获取所属专业的培养方案
- 获取年级和专业名称
- 提取关键信息(年级、专业)
💡 使用场景:
- 了解培养方案要求
- 查看所属年级和专业
- 课程规划参考
Returns:
TrainingPlanInfo: 包含方案名称、专业名称、年级信息
"""
try:
conn.logger.info(f"获取用户 {conn.userid} 的培养方案信息")
training_plan_info = await conn.client.get(
JWCConfig().to_full_url(ENDPOINTS["training_plan"]),
follow_redirects=True,
timeout=conn.timeout,
)
if not training_plan_info.status_code == 200:
conn.logger.error(
f"获取用户 {conn.userid} 的培养方案信息失败,状态码: {training_plan_info.status_code}"
)
return ProtectRouterErrorToCode().remote_service_error.to_json_response(
conn.logger.trace_id
)
try:
data = training_plan_info.json()
transformer = TrainingPlanInfoTransformer.model_validate(data)
if transformer.count > 0 and len(transformer.data) > 0:
first_plan = transformer.data[0]
if len(first_plan) >= 2:
plan_name = first_plan[0]
# 提取年级信息 - 假设格式为"20XX级..."
grade_match = re.search(r"(\d{4})级", plan_name)
grade = grade_match.group(1) if grade_match else ""
# 提取专业名称 - 假设格式为"20XX级XXX本科培养方案"
major_match = re.search(r"\d{4}级(.+?)本科", plan_name)
major_name = major_match.group(1) if major_match else ""
result = TrainingPlanInfo(
plan_name=plan_name, major_name=major_name, grade=grade
)
return UniResponseModel[TrainingPlanInfo](
success=True,
data=result,
message="获取培养方案信息成功",
error=None,
)
else:
conn.logger.error("培养方案数据格式不正确,字段数量不足")
return ProtectRouterErrorToCode().validation_error.to_json_response(
conn.logger.trace_id
)
else:
conn.logger.error("培养方案数据为空")
return ProtectRouterErrorToCode().validation_error.to_json_response(
conn.logger.trace_id
)
except ValidationError as ve:
conn.logger.error("数据验证失败")
conn.logger.debug(f"数据验证失败详情: {ve}")
return ProtectRouterErrorToCode().validation_error.to_json_response(
conn.logger.trace_id
)
except Exception as e:
conn.logger.exception(e)
return ProtectRouterErrorToCode().server_error.to_json_response(
conn.logger.trace_id
)
@jwc_academic_router.get(
"/course_selection_status",
response_model=UniResponseModel[CourseSelectionStatus],
summary="获取选课状态信息",
)
async def get_course_selection_status(
conn: AUFEConnection = Depends(get_aufe_conn),
) -> UniResponseModel[CourseSelectionStatus] | JSONResponse:
"""
获取用户的选课状态
✅ 功能特性:
- 获取当前选课时间窗口
- 获取选课开放状态
- 显示选课时间提醒
💡 使用场景:
- 查看当前是否在选课时间内
- 获取选课开始和结束时间
- 选课前的状态检查
Returns:
CourseSelectionStatus: 包含选课状态、开始时间、结束时间等
"""
try:
conn.logger.info(f"获取用户 {conn.userid} 的选课状态信息")
course_selection_status = await conn.client.get(
JWCConfig().to_full_url(ENDPOINTS["course_selection_status"]),
follow_redirects=True,
timeout=conn.timeout,
)
if not course_selection_status.status_code == 200:
conn.logger.error(
f"获取用户 {conn.userid} 的选课状态信息失败,状态码: {course_selection_status.status_code}"
)
return ProtectRouterErrorToCode().remote_service_error.to_json_response(
conn.logger.trace_id
)
try:
data = course_selection_status.json()
result = CourseSelectionStatus(
can_select=(
True
if CourseSelectionStatusTransformer.model_validate(data).status_code
== "1"
else False
)
)
return UniResponseModel[CourseSelectionStatus](
success=True,
data=result,
message="获取选课状态成功",
error=None,
)
except ValidationError as ve:
conn.logger.error("数据验证失败")
conn.logger.debug(f"数据验证失败详情: {ve}")
return ProtectRouterErrorToCode().validation_error.to_json_response(
conn.logger.trace_id
)
except Exception as e:
conn.logger.exception(e)
return ProtectRouterErrorToCode().server_error.to_json_response(
conn.logger.trace_id
)