🐛 学习通完善

This commit is contained in:
sugarBecomer
2025-11-29 11:34:48 +08:00
parent 498c51c585
commit 1ad0c285f2
@@ -0,0 +1,128 @@
package schedule
import (
"bytes"
"context"
"encoding/gob"
"likedream-goframe/internal/application/xuexitong"
"likedream-goframe/internal/common/db"
errors2 "likedream-goframe/internal/common/errors"
"likedream-goframe/internal/ent"
"likedream-goframe/internal/ent/courseentity"
"likedream-goframe/internal/framework/errors"
"likedream-goframe/internal/utils"
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/hibiken/asynq"
"github.com/samber/oops"
)
type XuexitongTaskHandler struct{}
func (h *XuexitongTaskHandler) ProcessTask(ctx context.Context, task *asynq.Task) (err error) {
defer utils.Pass(&err)
// 解码payload
var taskPayload XuexitongTaskPayload
e := gob.NewDecoder(bytes.NewReader(task.Payload())).Decode(&taskPayload)
utils.OkOrPanic(e, oops.WithContext(ctx).With("payload", task.Payload(), "type", task.Type()).In("XuexitongTask.DecodePayload").Wrap)
// 查询课程信息
targetCourse, e := db.Global.CourseEntity.Query().Where(courseentity.ID(taskPayload.CourseID)).First(ctx)
if ent.IsNotFound(e) {
utils.OkOrPanic(oops.WithContext(ctx).With("course_id", taskPayload.CourseID).In("XuexitongTask.ProcessTask").Wrap(e))
}
utils.OkOrPanic(e, oops.WithContext(ctx).With("course_id", taskPayload.CourseID).In("XuexitongTask.ProcessTask").Wrap)
// 检查是否暂停
if targetCourse.Status == courseentity.StatusPause {
g.Log().Debugf(ctx, "课程ID %d 已暂停,跳过执行", targetCourse.ID)
return nil
}
// 检查时间限制(非暴力模式)
if targetCourse.Violence == courseentity.ViolenceNo {
currentTime := time.Now()
currentHour := currentTime.Hour()
currentMinute := currentTime.Minute()
// 只在 8:30-17:30 之间执行
startTime := 8*60 + 30 // 8:30
endTime := 17*60 + 30 // 17:30
currentMinutes := currentHour*60 + currentMinute
if currentMinutes < startTime || currentMinutes >= endTime {
g.Log().Debugf(ctx, "课程ID %d 非暴力模式,当前时间 %02d:%02d 不在执行时间范围内(8:30-17:30),跳过执行",
targetCourse.ID, currentHour, currentMinute)
return nil
}
}
// 更新状态为执行中
db.Global.CourseEntity.UpdateOneID(taskPayload.CourseID).SetStatus(courseentity.StatusDoing).ExecX(ctx)
defer utils.HandleError(func(err error) {
// 执行失败更新状态
e := db.Global.CourseEntity.UpdateOneID(taskPayload.CourseID).SetStatus(courseentity.StatusFail).Exec(ctx)
utils.LogError(ctx, "设置课程状态失败", oops.With("course_id", taskPayload.CourseID).Wrap(e))
var errorMessage string
if e1, ok := utils.Of[*errors.BusinessError](err); ok {
errorMessage = e1.Message()
} else if e1, ok := utils.Of[*errors2.BusinessError](err); ok {
errorMessage = e1.Message
} else {
errorMessage = "未知的错误导致任务执行失败: " + err.Error()
}
g.Log().Errorf(ctx, "学习通刷课失败 - 课程: %s, 错误: %s", targetCourse.CourseName, errorMessage)
panic(err)
})
// 创建学习通登录客户端
loginClient := xuexitong.NewXuexitongLogin(ctx)
// 登录学习通
err = loginClient.Login(ctx, targetCourse.Username, targetCourse.Password, 3)
if err != nil {
utils.OkOrPanic(errors.NewBusinessErrorWithDetail(400, "登录失败,请检查账号密码", err))
}
// 获取客户端
client := loginClient.GetClient()
// 创建课程服务
courseService := xuexitong.NewXuexitongCourse(client)
// 执行刷课
err = courseService.AutoStudyByCourseID(ctx, targetCourse.CourseID)
if err != nil {
utils.OkOrPanic(errors.NewBusinessErrorWithDetail(503, "刷课失败", err))
}
// 刷课完成后,统计任务情况
g.Log().Infof(ctx, "刷课完成,正在统计任务情况...")
// 获取章节列表
chapters := courseService.PullCourseChapterList(ctx, targetCourse.CourseID)
// 统计总任务数(累加所有章节的JobCount)
totalTasks := 0
for _, chapter := range chapters {
totalTasks += chapter.JobCount
}
g.Log().Infof(ctx, "课程 %s 统计完成: 总任务点 %d", targetCourse.CourseName, totalTasks)
// 更新数据库(暂时不统计完成数,只统计总数)
db.Global.CourseEntity.UpdateOneID(taskPayload.CourseID).
SetStatus(courseentity.StatusDone).
SetTaskCount(totalTasks).
ExecX(ctx)
g.Log().Infof(ctx, "学习通刷课完成 - 课程: %s", targetCourse.CourseName)
return nil
}