246 lines
9.0 KiB
Python
246 lines
9.0 KiB
Python
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
|
||
)
|