From 587aa79c162d7f5214ba83a776659fb1e967e5a2 Mon Sep 17 00:00:00 2001 From: hmo Date: Fri, 24 Apr 2026 00:33:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AD=A6=E5=91=98=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5=E6=94=B9=E4=B8=BA=E5=AD=A6=E4=B9=A0=E5=8E=86=E7=A8=8B?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=BA=BF=EF=BC=8C=E6=98=BE=E7=A4=BA=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E5=90=AF=E5=8A=A8/=E8=BE=BE=E6=88=90=E5=92=8C?= =?UTF-8?q?=E6=96=B9=E6=A1=88=E7=94=9F=E6=88=90=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/templates/student.html | 154 +++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 32 deletions(-) diff --git a/app/templates/student.html b/app/templates/student.html index 6d8f1f3..7ad5558 100644 --- a/app/templates/student.html +++ b/app/templates/student.html @@ -46,7 +46,7 @@
-
问题记录
+
当前问题
@@ -474,50 +474,140 @@ function renderProblemList(problems) { `).join(''); } +// 学习历程时间线(替代原 loadPlans) async function loadPlans() { - try { - const resp = await fetch(`/api/students/${currentStudentId}/plans`); - const plans = await resp.json(); - renderPlanList(plans); - } catch (e) { - document.getElementById('planList').innerHTML = '

加载失败

'; - } + await loadTimeline(); } -function renderPlanList(plans) { +// 学习历程时间线 +async function loadTimeline() { + const [plansRes, goalsRes] = await Promise.all([ + fetch(`/api/students/${currentStudentId}/plans`), + fetch(`/api/students/${currentStudentId}/goals`) + ]); + const plans = await plansRes.json(); + const goals = await goalsRes.json(); + + // 构建时间线条目 + const timeline = []; + + // 添加目标开始记录 + goals.forEach(g => { + if (g.start_date) { + const startDate = new Date(g.start_date); + const endDate = g.assessment_date ? new Date(g.assessment_date) : null; + const days = endDate ? Math.ceil((endDate - startDate) / (1000*60*60*24)) : null; + timeline.push({ + date: startDate, + type: 'goal_start', + goal: g, + days: days, + endDate: endDate + }); + } + // 添加目标达成记录 + if (g.achievement_date) { + timeline.push({ + date: new Date(g.achievement_date), + type: 'goal_achieved', + goal: g + }); + } + }); + + // 添加方案生成记录 + plans.forEach(p => { + timeline.push({ + date: new Date(p.created_at), + type: 'plan', + plan: p + }); + }); + + // 按时间逆序排序 + timeline.sort((a, b) => b.date - a.date); + + renderTimeline(timeline); +} + +function renderTimeline(timeline) { const container = document.getElementById('planList'); - if (plans.length === 0) { - container.innerHTML = '

暂无练习方案

'; + if (timeline.length === 0) { + container.innerHTML = '

暂无学习记录

'; return; } - container.innerHTML = plans.map(p => ` -
-
- - -
-
-
-
- ${p.created_at ? p.created_at.substring(0, 16) : '未知'} - ${p.is_typical ? '典型' : ''} + + container.innerHTML = timeline.map(entry => { + if (entry.type === 'goal_start') { + const g = entry.goal; + return ` +
+
+ 目标启动 +
+
+
+
+ ${escapeHtml(g.goal_name)} + ${formatDate(entry.date)} +
+ 预期 ${entry.days} 天 +
+
+ ${g.goal_level || '入门'} | ${g.goal_category || '综合'} | 评估日期: ${entry.endDate ? formatDate(entry.endDate) : '未设置'}
-
-
- ${p.problem_names && p.problem_names.length > 0 ? '问题: ' + p.problem_names.join(', ') : ''} - ${p.template_name ? ' | 模板: ' + p.template_name : ''} +
`; + } else if (entry.type === 'goal_achieved') { + const g = entry.goal; + const stars = '⭐'.repeat(g.mastery_level || 1); + return ` +
+
+ 目标达成
-
-
- `).join(''); +
+
+
+ ${escapeHtml(g.goal_name)} + ${formatDate(entry.date)} +
+ ${stars} +
+ ${g.comment ? `
"${escapeHtml(g.comment)}"
` : ''} +
+
`; + } else { + const p = entry.plan; + return ` +
+
+ + +
+
+
+
+ ${formatDate(entry.date)} + ${p.is_typical ? '典型' : ''} +
+ +
+
+ ${p.problem_names && p.problem_names.length > 0 ? '问题: ' + p.problem_names.join(', ') : ''} + ${p.template_name ? ' | 模板: ' + p.template_name : ''} +
+
+
`; + } + }).join(''); } async function toggleTypical(planId) { await fetch(`/api/plans/${planId}/typical`, {method: 'POST'}); - loadPlans(); + loadTimeline(); } function showEditStudentModal() {