Compare commits

...

3 Commits

Author SHA1 Message Date
becomer 27d83f193f fix: 智慧教育网站更新后 ParseJsUrl 无法匹配新的 chunk URL 结构
ci/woodpecker/tag/build Pipeline was successful
网站将 chunk-vendors 改为了 chunk-libs/chunk-elementUI,
且首页组件被合并到多模块组合 chunk 中。
更新正则:匹配 chunk-libs 或 chunk-elementUI 的 URL,
提取 base 路径和 hash,构造新的组合 chunk 文件 URL。
2026-08-09 21:56:58 +08:00
becomer f4c2b8de4c fix: 提交验证码识别失败 — 调用分类器时缺少 X-Api-Key 请求头
ci/woodpecker/tag/build Pipeline was successful
NormalSubmitCaptchaResolver.getResultFromItStar 调用验证码分类服务
/classifier 时没有传 X-Api-Key 请求头,而分类服务已启用 ApiKeyAuth
中间件,导致返回 401,最终报"提交验证码识别失败"。
2026-07-08 23:02:48 +08:00
becomer d454ecc7cf fix: 无历史时保底使用管理员配置的签到范围信息
ci/woodpecker/tag/build Pipeline was successful
- 有历史签到数据 → 优先使用历史中的真实地址和经纬度
- 无历史签到数据 → 保底从 signPlaceSelected 提取管理员配置的范围信息
2026-07-04 01:04:10 +08:00
4 changed files with 53 additions and 13 deletions
@@ -146,8 +146,10 @@ func (r *NormalSubmitCaptchaResolver) getResultFromItStar(rawResponse json.RawMe
utils.OkOrPanic(err)
url := r.getITStarUrl()
apiKey := g.Config().MustGetWithEnv(gctx.GetInitCtx(), cst.ConfigCaptchaApiKey).String()
resp, err := r.client.R().
SetHeader("X-Api-Key", apiKey).
SetBody(responseMap).
Post(url)
utils.OkOrPanic(err)
+21 -4
View File
@@ -21,6 +21,7 @@ import (
"github.com/gogf/gf/v2/container/gvar"
"github.com/google/uuid"
"github.com/samber/oops"
"github.com/tidwall/gjson"
"github.com/tidwall/match"
"resty.dev/v3"
)
@@ -457,11 +458,9 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
histSignPhotoUrl := ""
histIsMalposition := ""
// 只有有真实的已签到历史数据时,才从历史数据中提取地址和经纬度
// 否则 rows 中包含的是管理员圈定的范围配置数据,不是用户实际签到地址
// signPlaceSelected 始终是管理员圈定范围,不应使用
// 优先使用历史签到数据(真实地址),无历史时保底使用管理员配置的范围信息
if hasHistory {
// 先从 longitude/latitude/position/signAddress 提取
// 从历史签到数据中提取用户真实的地址和经纬度
if lon := histRows["longitude"]; lon != nil && lon.String() != "" {
if lat := histRows["latitude"]; lat != nil && lat.String() != "" {
histLatAndLon = lon.String() + "," + lat.String()
@@ -488,6 +487,24 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
}
}
}
// 无历史签到数据时,保底使用管理员配置的范围信息
if histLatAndLon == "" && histAddress == "" {
if sps := rows["signPlaceSelected"]; sps != nil && sps.String() != "" && sps.String() != "[]" {
placeArr := gjson.Parse(sps.String()).Array()
if len(placeArr) > 0 {
place := placeArr[0]
lng := place.Get("longitude").String()
lat := place.Get("latitude").String()
addr := place.Get("address").String()
if lng != "" && lat != "" {
histLatAndLon = lng + "," + lat
}
if addr != "" {
histAddress = addr
}
}
}
}
dto := &formtype.CpTaskFormItem{
Title: "经纬度",
@@ -535,11 +535,9 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
histSignPhotoUrl := ""
histIsMalposition := ""
// 只有有真实的已签到历史数据时,才从历史数据中提取地址和经纬度
// 否则 rows 中包含的是管理员圈定的范围配置数据,不是用户实际签到地址
// signPlaceSelected 始终是管理员圈定范围,不应使用
// 优先使用历史签到数据(真实地址),无历史时保底使用管理员配置的范围信息
if hasHistory {
// 先从 longitude/latitude/position/signAddress 提取
// 从历史签到数据中提取用户真实的地址和经纬度
if lon := histRows["longitude"]; lon != nil && lon.String() != "" {
if lat := histRows["latitude"]; lat != nil && lat.String() != "" {
histLatAndLon = lon.String() + "," + lat.String()
@@ -566,6 +564,24 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
}
}
}
// 无历史签到数据时,保底使用管理员配置的范围信息
if histLatAndLon == "" && histAddress == "" {
if sps := rows["signPlaceSelected"]; sps != nil && sps.String() != "" && sps.String() != "[]" {
placeArr := gjson.Parse(sps.String()).Array()
if len(placeArr) > 0 {
place := placeArr[0]
lng := place.Get("longitude").String()
lat := place.Get("latitude").String()
addr := place.Get("address").String()
if lng != "" && lat != "" {
histLatAndLon = lng + "," + lat
}
if addr != "" {
histAddress = addr
}
}
}
}
dto := &formtype.CpTaskFormItem{
Title: "经纬度",
+10 -5
View File
@@ -166,13 +166,18 @@ func (c *Course) Refresh(ctx context.Context, c2 model.Course, ch model.Chapter,
}
func ParseJsUrl(str string) string {
// <script defer src="https://cdnbasic.scbdc.edu.cn/%E7%9C%81%E7%BA%A7%E8%B5%84%E6%BA%90/hd/chunk-vendors.5e79f5ce155849.js">
re := regexp.MustCompile(`https://[^"'\s]+chunk-vendors[^"'\s]+\.js`)
match := re.FindString(str)
if match == "" {
// 网站已更新,chunk-vendors 不再存在。
// 现在从 HTML 中找到任一 chunk-*.js 的 URL,提取其 base 路径和 hash,
// 然后构造包含 src_views_home_index_vue 的组合 chunk 文件 URL。
re := regexp.MustCompile(`(https://[^"'\s]+/)chunk-(?:libs|elementUI)\.([0-9a-f]+)\.js`)
match := re.FindStringSubmatch(str)
if len(match) < 3 {
return ""
}
return strings.Replace(match, "chunk-vendors", "src_views_home_index_vue", 1)
basePath := match[1]
hash := match[2]
// 用已知的组合 chunk 名称拼出 URL:该 chunk 同时包含首页和 CourseList 组件
return basePath + "src_views_home_index_vue-src_views_noPermission_index_vue-src_views_components_CourseList_vue." + hash + ".js"
}
func (c *Course) GetCourseProcees(ctx context.Context, courseId string) (finished string, total string) {
post, err := c.Client.R().SetHeader("X-Token", c.Token).SetBody(map[string]any{