Files
schedule_converter/service/exams.go

80 lines
2.2 KiB
Go
Raw Normal View History

package service
import (
"context"
"fmt"
"log/slog"
"strings"
"schedule_converter/client"
"schedule_converter/models"
"schedule_converter/parser"
apperr "schedule_converter/pkg/errors"
pb "schedule_converter/proto/runner"
)
var allExamTypes = []models.ExamType{models.ExamTypeFinal, models.ExamTypeMidterm, models.ExamTypeMakeup}
// GetExams 获取考试安排:登录 → 遍历各考试类型抓取并解析 → 合并 → 转换为 pb 结果。
func (s *Service) GetExams(ctx context.Context, req *pb.GetExamsPayload) (*pb.ExamsResultData, 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 allExams []models.ExamEntry
var lastErr error
for _, et := range allExamTypes {
data := fmt.Sprintf("xnxq=&kssjd=%s", parser.ExamTypeCode(et))
html, ferr := client.FetchHTML(ctx, httpClient, "POST", "/kscx/queryKsForXs", strings.NewReader(data), "application/x-www-form-urlencoded", "")
if ferr != nil {
log.Warn("获取考试数据失败", "exam_type", string(et), "error", ferr)
lastErr = ferr
continue
}
exams, perr := parser.ParseExamHTML(html, et)
if perr != nil {
log.Warn("解析考试数据失败", "exam_type", string(et), "error", perr)
lastErr = perr
continue
}
allExams = append(allExams, exams...)
}
if len(allExams) == 0 && lastErr != nil {
return nil, apperr.New("fetch_exams", lastErr, "所有考试类型获取均失败")
}
return &pb.ExamsResultData{
StudentId: req.Username,
Semester: req.Semester,
Exams: convertExams(allExams),
}, nil
}
// convertExams 将内部考试模型转换为 pb.Exam 列表。
func convertExams(exams []models.ExamEntry) []*pb.Exam {
result := make([]*pb.Exam, 0, len(exams))
for _, e := range exams {
examTypeStr := "期末"
switch e.Type {
case models.ExamTypeMidterm:
examTypeStr = "期中"
case models.ExamTypeMakeup:
examTypeStr = "补考"
}
result = append(result, &pb.Exam{
CourseName: e.Course,
ExamType: examTypeStr,
Date: e.Date,
Time: e.Time,
Week: e.Week,
Weekday: e.Weekday,
})
}
return result
}