Files
wk-backend/internal/handler/ckwk.go
zhilv 536aa506f9 refactor: 后端代码优化 11 项(codestable/refactors/2026-04-25-backend-cleanup)
- 提取 getWKFromContext 辅助函数,消除 handler 中 5 处重复代码
- 提取 retryCode 函数,消除 Login/performStudy 中验证码重试重复
- 提取 removeSession 内部方法,消除 Del/ClearAll/ClearExpired 中 3 处重复
- 提取 WK.UserKey() 方法,消除 4 处 userKey 手动拼接
- SessionManager.Get() 改用 RLock 优化读性能
- GetRecords 递归分页改为迭代,避免栈溢出
- prepareRequestClient 添加配置缓存,仅在 debug 设置变化时重建
- 修正 schedule.go 时区为 Asia/Shanghai + cron "0 6 * * *"
- 修正 typo "以达到" → "已达到"
- 删除未使用的 QAList struct
- 修复 bufferHub.append 切片内存泄漏

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-26 13:07:45 +08:00

245 lines
5.2 KiB
Go
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.
package handler
import (
"ckwk/internal/ckwk"
"ckwk/internal/dto"
"ckwk/pkg/log"
"errors"
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type WKHandler struct {
Session *ckwk.SessionManager
}
func NewWKHandler() *WKHandler {
return &WKHandler{
Session: ckwk.NewSessionManager(),
}
}
// getWKFromContext 从 gin.Context 中提取 wk_instance不存在时自动返回错误响应
func getWKFromContext(ctx *gin.Context) (*ckwk.WK, bool) {
val, ok := ctx.Get("wk_instance")
if !ok {
ctx.JSON(200, dto.Error(-1, "登录已过期"))
return nil, false
}
return val.(*ckwk.WK), true
}
func (h *WKHandler) Login(ctx *gin.Context) {
var req dto.LoginReq
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(200, dto.Error(-1, "请求参数错误"))
return
}
log.Debug("请求数据", zap.Any("req", req))
var cookies []*http.Cookie
if req.Token != "" {
cookies = []*http.Cookie{
{
Name: "token",
Value: req.Token,
Path: "/"},
}
} else {
cookies = []*http.Cookie{}
}
wk := ckwk.NewWK(req.Username, req.Password, req.Host, cookies)
if wk == nil {
ctx.JSON(200, dto.Error(-1, "登录失败:请提供账号密码或有效的 Token并确保 Host 正确"))
return
}
if req.Token == "" {
ok, err := wk.Login()
if err != nil {
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
if !ok {
ctx.JSON(200, dto.Error(-1, "登录失败"))
return
}
}
sessionID := h.Session.Store(wk)
ctx.JSON(200, dto.Success(map[string]any{
"session_id": sessionID,
}))
}
func (h *WKHandler) Online(ctx *gin.Context) {
wk, ok := getWKFromContext(ctx)
if !ok {
return
}
flag, err := wk.Online()
if err != nil {
if errors.Is(err, ckwk.ErrSessionRemoved) {
ctx.JSON(http.StatusUnauthorized, dto.Error(401, err.Error()))
return
}
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
if !flag {
ctx.JSON(200, dto.Error(-1, "保持账号状态失败"))
return
}
ctx.JSON(200, dto.Ok())
}
func (h *WKHandler) Logout(ctx *gin.Context) {
sessionID := ctx.GetString("session_id")
h.Session.Del(sessionID)
ctx.JSON(200, dto.Ok())
}
func (h *WKHandler) UserInfo(ctx *gin.Context) {
wk, ok := getWKFromContext(ctx)
if !ok {
return
}
userinfo, err := wk.UserInfoGet()
if err != nil {
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
ctx.JSON(200, dto.Success(map[string]any{
"user": userinfo,
}))
}
func (h *WKHandler) Course(ctx *gin.Context) {
var req dto.CourseReq
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(200, dto.Error(-1, "请求参数错误"))
return
}
wk, ok := getWKFromContext(ctx)
if !ok {
return
}
courses, err := wk.CourseGet(req.Status)
if err != nil {
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
ctx.JSON(200, dto.Success(map[string]any{
"courses": courses,
}))
}
func (h *WKHandler) Study(ctx *gin.Context) {
wk, ok := getWKFromContext(ctx)
if !ok {
return
}
var req dto.StudyReq
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(200, dto.Error(-1, "请求参数错误"))
return
}
result, err := wk.Study(req.NodeID, req.StudyID, req.StudyTime, req.Status)
if err != nil {
if errors.Is(err, ckwk.ErrSessionRemoved) {
ctx.JSON(http.StatusUnauthorized, dto.Error(401, err.Error()))
return
}
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
ctx.JSON(200, dto.Success(result))
}
func (h *WKHandler) AllRecord(ctx *gin.Context) {
wk, ok := getWKFromContext(ctx)
if !ok {
return
}
var req dto.AllRecordReq
if err := ctx.ShouldBindJSON(&req); err != nil {
ctx.JSON(200, dto.Error(-1, "请求参数错误"))
return
}
if req.Page < 1 {
req.Page = 1
}
var list any
var pageInfo ckwk.PageInfo
var err error
// 根据类型调用不同的泛型方法
switch req.RecordType {
case ckwk.RecordStudy:
res, e := wk.GetStudyList(req.CourseID, fmt.Sprint(req.Page))
err = e
if e == nil {
list, pageInfo = res.List, res.PageInfo
}
case ckwk.RecordWork:
res, e := wk.GetWorkList(req.CourseID, fmt.Sprint(req.Page))
err = e
if e == nil {
list, pageInfo = res.List, res.PageInfo
}
case ckwk.RecordExam:
res, e := wk.GetExamList(req.CourseID, fmt.Sprint(req.Page))
err = e
if e == nil {
list, pageInfo = res.List, res.PageInfo
}
case ckwk.RecordDiscuss:
res, e := wk.GetDiscussList(req.CourseID, fmt.Sprint(req.Page))
err = e
if e == nil {
list, pageInfo = res.List, res.PageInfo
}
default:
ctx.JSON(200, dto.Error(-1, "不支持的记录类型"))
return
}
if err != nil {
ctx.JSON(200, dto.Error(-1, err.Error()))
return
}
ctx.JSON(200, dto.Success(map[string]any{
"list": list,
"page_info": map[string]any{
"page": pageInfo.Page,
"pageSize": pageInfo.PageSize,
},
}))
}
func (h *WKHandler) Host(ctx *gin.Context) {
ctx.JSON(200, dto.Success(map[string]any{
"list": []map[string]any{
{"host": "cqcst.leykeji.com", "name": "劳动课程测评考试平台"},
{"host": "cqcst.zjxkeji.com", "name": "公益课程平台"},
{"host": "cqcst.suwankj.com", "name": "在线课程测评考试平台"},
{"host": "cqcst.yuruixxkj.com", "name": "在线测评考试平台"},
// {"host": "cqcst.yuncanjykeji.com", "name": "劳动课程测评考试平台"},
// {"host": "cqcst.yuruixxkj.com", "name": "公益课程平台"},
},
}))
}