fix: 修复6个bug并接入CodeStable工作流

Bug修复:
- GetWorkList 使用了错误的 RecordType (RecordStudy→RecordWork)
- AllRecord handler 返回错误的分页信息 (page硬编码1, pageSize用RecordsCount)
- CourseParse creditNode nil panic (加nil检查)
- WebSocket CheckOrigin 安全漏洞 (release模式限制为同源)
- math/rand 可预测 (替换为 crypto/rand)
- GetDiscussList 未实现 (补全实现, 移除重复路由)

其他:
- 接入 CodeStable 工作流体系 (codestable/ 骨架 + AGENTS.md)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 19:55:57 +08:00
parent 83ee4bb5ea
commit 2a6732ffe7
23 changed files with 1561 additions and 23 deletions

View File

@@ -193,6 +193,7 @@ func (wk *WK) Login() (bool, error) {
return true, nil
}
// parseLoginResp: 解析登录响应
func (wk *WK) parseLoginResp(body []byte) (LoginResp, error) {
var result LoginResp
if len(body) == 0 {
@@ -273,12 +274,14 @@ func (wk *WK) CourseParse(content string) ([]Course, error) {
var credit float32
creditNode := htmlquery.FindOne(node, `.//div[@class="note"]/div[@class="number"]/span`)
creditStr := strings.TrimSpace(htmlquery.InnerText(creditNode))
creditVal, err := strconv.ParseFloat(creditStr, 32)
if err == nil {
credit = float32(creditVal)
} else {
log.Warn("课程学分转换失败", zap.Error(err))
if creditNode != nil {
creditStr := strings.TrimSpace(htmlquery.InnerText(creditNode))
creditVal, err := strconv.ParseFloat(creditStr, 32)
if err == nil {
credit = float32(creditVal)
} else {
log.Warn("课程学分转换失败", zap.Error(err))
}
}
typeNode := htmlquery.FindOne(node, `.//div[@class="note"]/div[@class="kind"]/span`)
@@ -352,6 +355,11 @@ func (wk *WK) UserInfoParse(content string) (User, error) {
return user, nil
}
// QuestionAnswerParse: 解析题目答案
func (wk *WK) QuestionAnswerParse(content string) (string, error) {
return "", nil
}
// UserGet: 用户信息获取
func (wk *WK) UserInfoGet() (User, error) {
var user User
@@ -467,10 +475,9 @@ func (wk *WK) GetStudyList(courseID, page string) (*AllRecordResp[StudyList], er
return GetRecords[StudyList](wk, RecordStudy, courseID, page)
}
// GetExamList: 获取作业记录
// todo
func (wk *WK) GetWorkList(courseID, page string) (*AllRecordResp[ExamList], error) {
return GetRecords[ExamList](wk, RecordStudy, courseID, page)
// GetWorkList: 获取作业记录
func (wk *WK) GetWorkList(courseID, page string) (*AllRecordResp[WorkList], error) {
return GetRecords[WorkList](wk, RecordWork, courseID, page)
}
// GetExamList: 获取考试记录
@@ -478,10 +485,9 @@ func (wk *WK) GetExamList(courseID, page string) (*AllRecordResp[ExamList], erro
return GetRecords[ExamList](wk, RecordExam, courseID, page)
}
// GetExamList: 获取讨论记录
// todo
func (wk *WK) GetDiscussList(courseID, page string) (*AllRecordResp[ExamList], error) {
return GetRecords[ExamList](wk, RecordStudy, courseID, page)
// GetDiscussList: 获取讨论记录
func (wk *WK) GetDiscussList(courseID, page string) (*AllRecordResp[StudyList], error) {
return GetRecords[StudyList](wk, RecordDiscuss, courseID, page)
}
func isLoginTimeoutBody(body []byte) bool {