Skip to content

Commit 4c4cc0e

Browse files
author
FixBot
committed
fix+feat: AI报告apiFetch修复 + 错题练习独立页面 SW v1.8.1
AI分析报告修复(根因:raw fetch 缺少 session token): - 改用 apiFetch() 代替 raw fetch,自动携带 X-Session-Token 和 X-User-ID - loadingEl.remove() 加 parentNode 守卫,防止重复删除报错 - 错误信息包含 HTTP 状态码,便于调试 - console.error 记录详细错误 错题练习独立页面(与「我的收藏」页面结构一致): - 新增 s-wrongbook screen:顶部统计(全部题数)+ 科目列表 - 主页「错题练习」按钮改为 openWrongBook() 打开新页面 - 科目列表用 data-unit + 事件委托,避免引号冲突 - 点击科目行直接进入该章节错题练习 - 空状态提示
1 parent 4f3bb10 commit 4c4cc0e

3 files changed

Lines changed: 106 additions & 17 deletions

File tree

assets/static/quiz.js

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3764,20 +3764,19 @@ async function showAIReport() {
37643764

37653765
// ── 发起流式请求,用 makeStreamingRenderer 渲染 ─────────────
37663766
try {
3767-
const headers = {
3768-
'Content-Type': 'application/json',
3769-
'X-Session-Token': window.SESSION_TOKEN || '',
3770-
};
3771-
const uid = typeof _getUIDCookie === 'function' ? _getUIDCookie() : '';
3772-
if (uid) headers['X-User-ID'] = uid;
3773-
3774-
const res = await fetch('/api/ai/report?' + bankQS(), {
3775-
method: 'POST', headers, body: JSON.stringify(payload),
3767+
// 使用 apiFetch 确保携带正确的 session token 和 user-id
3768+
const res = await apiFetch('/api/ai/report?' + bankQS(), {
3769+
method: 'POST',
3770+
headers: { 'Content-Type': 'application/json' },
3771+
body: JSON.stringify(payload),
37763772
});
3777-
if (!res.ok) throw new Error('HTTP ' + res.status);
3773+
if (!res.ok) {
3774+
const errText = await res.text().catch(() => '');
3775+
throw new Error('HTTP ' + res.status + (errText ? ': ' + errText.slice(0,100) : ''));
3776+
}
37783777

37793778
// 清除 loading,创建内容容器
3780-
loadingEl.remove();
3779+
if (loadingEl.parentNode) loadingEl.remove();
37813780
const contentEl = document.createElement('div');
37823781
contentEl.className = 'ai-report-msg';
37833782
messagesEl.appendChild(contentEl);
@@ -3809,23 +3808,22 @@ async function showAIReport() {
38093808
if (renderer) {
38103809
renderer.push(obj.content);
38113810
} else {
3812-
// fallback:纯文字追加
38133811
contentEl.textContent += obj.content;
38143812
}
3815-
// 自动滚动到底部
38163813
messagesEl.scrollTop = messagesEl.scrollHeight;
38173814
}
3818-
} catch(e) { /* ignore parse errors */ }
3815+
} catch(parseErr) { /* ignore parse errors */ }
38193816
}
38203817
}
38213818
if (renderer) renderer.end();
38223819

38233820
} catch(e) {
3824-
loadingEl.remove();
3821+
if (loadingEl.parentNode) loadingEl.remove();
38253822
const errEl = document.createElement('p');
38263823
errEl.style.cssText = 'color:var(--danger);padding:16px;font-size:13px';
38273824
errEl.textContent = '⚠ 报告生成失败:' + (e.message || '网络错误');
38283825
messagesEl.appendChild(errEl);
3826+
console.error('[AI Report]', e);
38293827
}
38303828
}
38313829

@@ -4639,6 +4637,66 @@ function refreshFavBadge() {
46394637
}
46404638

46414639
/** 打开收藏页 */
4640+
/** 打开错题练习独立页面 */
4641+
async function openWrongBook() {
4642+
showScreen('s-wrongbook');
4643+
await _renderWrongBookScreen();
4644+
}
4645+
4646+
async function _renderWrongBookScreen() {
4647+
const bankNameEl = document.getElementById('wb-bank-name');
4648+
if (bankNameEl) bankNameEl.textContent = (S.bankInfo && S.bankInfo.name) || '';
4649+
4650+
const listEl = document.getElementById('wb-unit-list');
4651+
const emptyEl = document.getElementById('wb-empty');
4652+
const cntAll = document.getElementById('wb-cnt-all');
4653+
4654+
if (listEl) listEl.innerHTML = '<div style="padding:16px;color:var(--muted);font-size:13px">加载中…</div>';
4655+
if (emptyEl) emptyEl.style.display = 'none';
4656+
4657+
try {
4658+
const res = await apiFetch('/api/wrongbook?' + bankQS()).then(r => r.json());
4659+
const allItems = res.items || [];
4660+
4661+
if (!allItems.length) {
4662+
if (listEl) listEl.innerHTML = '';
4663+
if (emptyEl) emptyEl.style.display = '';
4664+
if (cntAll) cntAll.textContent = '0';
4665+
return;
4666+
}
4667+
4668+
if (cntAll) cntAll.textContent = allItems.length;
4669+
4670+
// 按 unit 分组
4671+
const unitMap = {};
4672+
allItems.forEach(it => {
4673+
const unit = it.unit || '未分类';
4674+
if (!unitMap[unit]) unitMap[unit] = 0;
4675+
unitMap[unit]++;
4676+
});
4677+
4678+
if (listEl) {
4679+
listEl.innerHTML = Object.entries(unitMap).map(([unit, cnt]) =>
4680+
`<div class="fav-unit-row" data-unit="${esc(unit)}">
4681+
<div class="fav-unit-left">
4682+
<div class="fav-unit-name">${esc(unit)}</div>
4683+
<div class="fav-unit-count">${cnt} 题</div>
4684+
</div>
4685+
<span class="fav-unit-chevron">›</span>
4686+
</div>`
4687+
).join('');
4688+
4689+
listEl.onclick = function(e) {
4690+
const row = e.target.closest('.fav-unit-row');
4691+
if (!row || !row.dataset.unit) return;
4692+
startWrongBookReview(row.dataset.unit, allItems);
4693+
};
4694+
}
4695+
} catch(e) {
4696+
if (listEl) listEl.innerHTML = '<div style="padding:16px;color:var(--danger);font-size:13px">⚠ 加载失败</div>';
4697+
}
4698+
}
4699+
46424700
function openFavorites() {
46434701
showScreen('s-favorites');
46444702
_renderFavoritesScreen();

assets/static/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Service Worker for 医考练习 PWA
2-
const CACHE_NAME = 'med-quiz-v1.8.0';
2+
const CACHE_NAME = 'med-quiz-v1.8.1';
33

44
const STATIC_ASSETS = [
55
'/static/common.css',

assets/templates/quiz.html

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ <h2>选择题库</h2>
316316
<span class="home-quick-icon">🔄</span><span>今日复习</span>
317317
<span class="due-badge" id="due-badge" style="display:none">0</span>
318318
</button>
319-
<button class="home-quick-btn" onclick="startWrongBookReview()" id="wrongbook-btn">
319+
<button class="home-quick-btn" onclick="openWrongBook()" id="wrongbook-btn">
320320
<span class="home-quick-icon">📕</span><span>错题练习</span>
321321
<span class="due-badge err" id="wrong-badge" style="display:none">0</span>
322322
</button>
@@ -389,6 +389,37 @@ <h2>学习统计</h2>
389389
</div>
390390
</div>
391391

392+
<!-- ═══ WRONGBOOK ══════════════════════════════════════════════════ -->
393+
<div id="s-wrongbook" class="screen slide-right">
394+
<div class="fav-header">
395+
<button class="back-btn" onclick="showScreen('s-home')"></button>
396+
<div class="fav-header-center">
397+
<h2>错题练习</h2>
398+
<span class="fav-header-sub" id="wb-bank-name"></span>
399+
</div>
400+
<span style="width:34px"></span>
401+
</div>
402+
403+
<!-- 统计卡片 -->
404+
<div class="fav-stat-card">
405+
<div class="fav-stat-item" id="wb-stat-all" onclick="startWrongBookReview('__all__')">
406+
<div class="fav-stat-num" id="wb-cnt-all">0</div>
407+
<div class="fav-stat-label">全部 <span class="fav-arrow"></span></div>
408+
</div>
409+
</div>
410+
411+
<!-- 科目列表 -->
412+
<div class="section-label" style="margin-top:8px">科目列表</div>
413+
<div id="wb-unit-list" class="fav-unit-list"></div>
414+
415+
<!-- 空状态 -->
416+
<div id="wb-empty" class="fav-empty" style="display:none">
417+
<div class="fav-empty-icon">📗</div>
418+
<div class="fav-empty-text">暂无错题记录</div>
419+
<div class="fav-empty-hint">做完题目后答错的题会出现在这里</div>
420+
</div>
421+
</div>
422+
392423
<!-- ═══ FAVORITES ══════════════════════════════════════════════════ -->
393424
<div id="s-favorites" class="screen slide-right">
394425
<div class="fav-header">

0 commit comments

Comments
 (0)