补全9月11日至13日课评:为13名学生创建请假文档,为5个班级创建总结文档

This commit is contained in:
chengzi
2026-09-13 19:34:34 +08:00
parent 167d832353
commit 21001eccf5
1322 changed files with 37510 additions and 4136 deletions

View File

@@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
"""
Fetch final submission code per (student, problem) for CSP04 lesson 01 (基础回顾).
Targets both CSP04 sections (0830 & 1400). Saves to JSON.
"""
import io, sys, json, re, httpx
from collections import defaultdict
from pathlib import Path
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
env = {}
for line in (PROJECT_ROOT / '.env').read_text(encoding='utf-8').split('\n'):
line = line.strip()
if line and not line.startswith('#') and '=' in line:
k, v = line.split('=', 1)
env[k] = v
base = env.get('OJ_BASE_URL', 'https://oj.qonnwolf.com')
TID = '6a8c6a8b8499477a04169f85' # CSP04 lesson 01 基础回顾 (A包)
# 数字题目 -> 展示名(参考课件 OJ ID)
PID_MAP = {
6775: 'S0401P1 小杨的回文串',
6776: 'S0401P2 小杨有序去重',
6777: 'S0401P3 小杨的进制数位',
6968: 'S0401P4 小杨的幸运数字',
6969: 'S0401P5 小杨的报数游戏',
}
CLASSES = {
'0830': ['欧俊宇', '汪子杰', '谢明泓', '王佳琳', '魏铭轩', '张立坤'],
'1400': ['郑子煜', '张雨禾', '苏俊宇', '卢华琛', '鲍佳音'],
}
ALL_TARGETS = sorted({n for lst in CLASSES.values() for n in lst})
STATUS_NAMES = {1: 'AC', 2: 'WA', 3: 'CE', 4: 'RE', 5: 'TLE', 6: 'MLE', 7: 'PE', 8: 'OLE'}
client = httpx.Client(base_url=base, follow_redirects=True, timeout=30)
r = client.post('/login', json={'uname': env.get('OJ_USERNAME'), 'password': env.get('OJ_PASSWORD')})
ok = any(c.name == 'sid' for c in client.cookies.jar)
print('LOGIN:', 'OK' if ok else 'FAIL')
if not ok:
raise SystemExit('login failed')
# 1. fetch all records for the homework
records = []
seen = set()
for page in range(1, 40):
r = client.get(f'/d/system/record?tid={TID}&page={page}', headers={'Accept': 'application/json'})
if r.status_code != 200:
break
try:
rdocs = r.json().get('rdocs', [])
except Exception:
break
if not rdocs:
break
for rec in rdocs:
rid = rec.get('_id')
if rid in seen:
continue
seen.add(rid)
records.append({
'rid': rid, 'uid': rec.get('uid'), 'pid': rec.get('pid'),
'status': rec.get('status'), 'score': rec.get('score', 0),
'judgeAt': rec.get('judgeAt', ''), 'lang': rec.get('lang'),
})
if len(rdocs) < 100:
break
print('TOTAL RECORDS:', len(records))
# 2. build uid -> name
uids = {rec['uid'] for rec in records}
uid_name = {}
for uid in sorted(uids):
try:
rr = client.get(f'/user/{uid}')
m = re.search(r'<title>([^<]+)</title>', rr.text)
if m:
nm = m.group(1).split(' - ')[0].strip()
uid_name[uid] = nm
except Exception:
pass
print('UID->NAME mapped:', len(uid_name))
for rec in records:
rec['name'] = uid_name.get(rec['uid'], '')
# 3. for each target student, per problem pick the LAST submission (max judgeAt by iso)
last_by_key = {}
for rec in records:
if rec['name'] not in ALL_TARGETS:
continue
if rec['pid'] not in PID_MAP:
continue
key = (rec['name'], rec['pid'])
if key not in last_by_key or rec['judgeAt'] > last_by_key[key]['judgeAt']:
last_by_key[key] = rec
print('LAST-SUB keys:', len(last_by_key))
# 4. fetch code per (name, pid)
result = {}
sample_shown = 0
for (name, pid), rec in last_by_key.items():
try:
rr = client.get(f"/d/system/record/{rec['rid']}", headers={'Accept': 'application/json'})
j = rr.json()
rdoc = j.get('rdoc', {})
code = rdoc.get('code', '')
lang = rdoc.get('lang') or rec.get('lang')
except Exception as e:
code = ''
lang = None
entry = {
'key': PID_MAP[pid],
'code': code,
'lang': lang,
'status': STATUS_NAMES.get(rec['status'], '?'),
'score': rec.get('score'),
'attempts': sum(1 for x in records if x['name'] == name and x['pid'] == pid),
'judgeAt': rec.get('judgeAt'),
}
result.setdefault(name, {})[str(pid)] = entry
if sample_shown < 2 and code:
sample_shown += 1
print(f"SAMPLE CODE [{name} / {PID_MAP[pid]}] lang={lang}:\n{code[:300]}")
client.close()
out = {
'tid': TID,
'classes': CLASSES,
'pid_map': {str(k): v for k, v in PID_MAP.items()},
'students': result,
}
out_path = PROJECT_ROOT / '.claude' / 'memory' / 'temp' / 'student_code_CSP04_L01.json'
out_path.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding='utf-8')
print('SAVED ->', out_path)
print('students with code:', sorted(result.keys()))