feat(gdgxk): 课程卡片显示培训年度 / 学时 / 完成状态
- list_courses 解析 showCourse 卡片里的「培训年度」「课程学时」「未完成/已完成」, 返回 section / info / status_label,前端拼成「2026年公需课 · 未完成 · 30 学时」 - 修正完成判定:以平台状态为准(需所有教学活动 100% + 试卷考核 ≥60), 不再用视频秒数够不够来推断,避免把未完成的课当已学完跳过
This commit is contained in:
@@ -142,17 +142,32 @@ def profile(s):
|
||||
return m.group(1) if m else ""
|
||||
|
||||
|
||||
def _parse_courses(html):
|
||||
"""课程列表页:每个 `showCourse('id','名称')` 前面就是这张卡片的信息。"""
|
||||
out = []
|
||||
for m in re.finditer(r"showCourse\('([^']+)','([^']*)'\)", html):
|
||||
block = html[max(0, m.start() - 2500):m.start()]
|
||||
year = re.search(r"培训年度:\s*<[^>]*>(\d{4})<", block)
|
||||
hours = re.search(r"课程学时:\s*<[^>]*>(\d+)<", block)
|
||||
st = re.search(r">\s*(未完成|已完成)\s*<", block)
|
||||
out.append({
|
||||
"plan_id": m.group(1),
|
||||
"project_id": "",
|
||||
"name": m.group(2).strip(),
|
||||
"section": ("%s年公需课" % year.group(1)) if year else "",
|
||||
"status_label": st.group(1) if st else "",
|
||||
"info": ("%s 学时" % hours.group(1)) if hours else "",
|
||||
"in_study": True,
|
||||
"platform": PLATFORM_ID,
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
def list_courses(s):
|
||||
html = s.get(X + "/uc/store/courseRegister", timeout=30).text
|
||||
out, seen = [], set()
|
||||
for cid, name in re.findall(r"showCourse\('([^']+)','([^']*)'\)", html):
|
||||
if cid in seen:
|
||||
continue
|
||||
seen.add(cid)
|
||||
out.append({"plan_id": cid, "project_id": "", "name": name.strip(),
|
||||
"in_study": True, "platform": PLATFORM_ID})
|
||||
out = _parse_courses(html)
|
||||
if not out:
|
||||
if "loginBtn" in html or "showLogin" in html:
|
||||
if "logout" not in html:
|
||||
raise _expired("学习平台会话已失效,请重新登录")
|
||||
return []
|
||||
return out
|
||||
@@ -217,14 +232,21 @@ def discover(s, plan_id, project_id, name=""):
|
||||
cw["sid"] = sid
|
||||
sign = _sign(s, {"aid": cw["aid"], "id": cw["id"], "sid": sid}, cw["uid"])
|
||||
cur = _view_time(s, cw, cw["uid"], sign)
|
||||
done = cw["total"] > 0 and cur >= cw["total"]
|
||||
# 完成与否以平台状态为准:要「所有教学活动 100% + 试卷考核 ≥60」,视频秒数够不代表完成
|
||||
status = ""
|
||||
for c in _parse_courses(s.get(X + "/uc/store/courseRegister", timeout=30).text):
|
||||
if c["plan_id"] == cid:
|
||||
status = c["status_label"]
|
||||
break
|
||||
done = status == "已完成"
|
||||
return {
|
||||
"user": profile(s),
|
||||
"course": name or cw["title"],
|
||||
"progress": "%d/%d 秒" % (cur, cw["total"]),
|
||||
"progress": "%d/%d 秒%s" % (cur, cw["total"], "(课程已完成)" if done else ""),
|
||||
"info": cw["video"],
|
||||
"courseware": [{"id": cw["id"], "title": cw["title"], "href": page,
|
||||
"total": cw["total"], "viewTime": cur, "done": done,
|
||||
"status": status,
|
||||
"aid": cw["aid"], "uid": cw["uid"]}],
|
||||
"feedback": [], "test": [],
|
||||
"platform": PLATFORM_ID, "generation": "gxk",
|
||||
@@ -253,6 +275,11 @@ def study(key, s, d, **opts):
|
||||
continue
|
||||
runtime.log(key, "开始学习:%s(总长 %d 秒,已看 %d 秒)"
|
||||
% (cw["title"], cw["total"], cw["viewTime"]))
|
||||
if cw["total"] and cw["viewTime"] >= cw["total"]:
|
||||
runtime.log(key, "视频已播完,但课程仍显示「%s」:还差试卷考核或其他教学活动"
|
||||
% (cw.get("status") or "未完成"), level="warn")
|
||||
runtime.set_state(key, done=i)
|
||||
continue
|
||||
_learn(key, s, cw, speed, beat)
|
||||
runtime.set_state(key, done=i)
|
||||
runtime.set_state(key, status="done", done=total)
|
||||
|
||||
Reference in New Issue
Block a user