86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"log/slog"
|
||
|
||
"schedule_converter/client"
|
||
"schedule_converter/models"
|
||
"schedule_converter/parser"
|
||
apperr "schedule_converter/pkg/errors"
|
||
|
||
pb "schedule_converter/proto/runner"
|
||
)
|
||
|
||
// GetGrades 获取成绩:登录 → 优先 GPA 页面 → 回退到成绩页面 → 解析 → 转换为 pb 结果。
|
||
func (s *Service) GetGrades(ctx context.Context, req *pb.GetGradesPayload) (*pb.GradesResultData, error) {
|
||
log := slog.With("username", req.Username, "semester", req.Semester)
|
||
|
||
httpClient, err := s.newAuthenticatedClient(ctx, req.Username, req.Password, "")
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var gpaSummary *pb.GpaSummary
|
||
|
||
gpaHTML, err := client.FetchHTML(ctx, httpClient, "GET", "/xfj/queryListXfj", nil, "", "")
|
||
if err != nil {
|
||
log.Warn("获取GPA页面失败,尝试成绩页面", "error", err)
|
||
gradesHTML, ferr := client.FetchHTML(ctx, httpClient, "GET", "/cjcx/queryQmcj", nil, "", "")
|
||
if ferr != nil {
|
||
return nil, apperr.New("fetch_grades", ferr, "获取成绩失败")
|
||
}
|
||
grades, perr := parser.ParseGradesHTML(gradesHTML)
|
||
if perr != nil {
|
||
return nil, apperr.New("parse_grades", perr, "解析成绩失败")
|
||
}
|
||
return &pb.GradesResultData{
|
||
StudentId: req.Username,
|
||
Semester: req.Semester,
|
||
Grades: convertGrades(grades),
|
||
}, nil
|
||
}
|
||
|
||
summary, grades, err := parser.ParseGPAHTML(gpaHTML)
|
||
if err != nil {
|
||
return nil, apperr.New("parse_gpa", err, "解析学分绩失败")
|
||
}
|
||
if summary != nil {
|
||
gpaSummary = &pb.GpaSummary{
|
||
AverageGpa: summary.AverageGPA,
|
||
Rank: summary.Rank,
|
||
ExamTotalGpa: summary.ExamTotalGPA,
|
||
ExamTotalCredits: summary.ExamTotalCredits,
|
||
FailCredits: summary.FailCredits,
|
||
Semesters: summary.Semesters,
|
||
}
|
||
}
|
||
|
||
return &pb.GradesResultData{
|
||
StudentId: req.Username,
|
||
Semester: req.Semester,
|
||
Grades: convertGrades(grades),
|
||
GpaSummary: gpaSummary,
|
||
}, nil
|
||
}
|
||
|
||
// convertGrades 将内部成绩模型转换为 pb.Grade 列表。
|
||
func convertGrades(grades []models.GradeEntry) []*pb.Grade {
|
||
result := make([]*pb.Grade, 0, len(grades))
|
||
for _, g := range grades {
|
||
result = append(result, &pb.Grade{
|
||
Term: g.Term,
|
||
CourseCode: g.Code,
|
||
CourseName: g.Name,
|
||
Nature: g.Nature,
|
||
Category: g.Category,
|
||
Credit: g.Credit,
|
||
Score: g.Score,
|
||
GradePoint: g.GradePoint,
|
||
IsExam: g.IsExam,
|
||
IsRetake: g.IsRetake,
|
||
})
|
||
}
|
||
return result
|
||
}
|