baaa6ca2f8
- student.html: 学员详情页,支持编辑/添加/删除问题 - plan_edit.html: 方案编辑页 - plans.html: 方案列表页 - home.html: 首页
117 lines
4.1 KiB
HTML
117 lines
4.1 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}方案详情 - 钢琴练习方案系统{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||
<h4><i class="bi bi-file-text"></i> 方案详情</h4>
|
||
<div>
|
||
<button onclick="history.back()" class="btn btn-outline-secondary">
|
||
<i class="bi bi-arrow-left"></i> 返回
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="planContent" class="card">
|
||
<div class="card-body">
|
||
<div class="text-center text-muted py-5">
|
||
<i class="bi bi-hourglass fs-4"></i>
|
||
<p class="mt-2">加载中...</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block extra_js %}
|
||
<script>
|
||
var currentPlanId = null;
|
||
|
||
async function loadPlan() {
|
||
currentPlanId = window.location.pathname.split('/').pop();
|
||
try {
|
||
const resp = await fetch(`/api/plans/${currentPlanId}`);
|
||
const data = await resp.json();
|
||
window.currentStudentId = data.student_id;
|
||
|
||
let html = `
|
||
<div class="mb-3">
|
||
<strong>学员:</strong>${data.student_name}
|
||
<strong>练习时间:</strong>${data.content.practice_time}
|
||
<strong>生成时间:</strong>${data.created_at}
|
||
<strong>模板:</strong>${data.template_name || '无'}
|
||
<div class="mt-2">
|
||
<a href="/?student_id=${data.student_id}&from=${encodeURIComponent(window.location.href)}" class="btn btn-sm btn-outline-primary">
|
||
<i class="bi bi-person"></i> 查看学员
|
||
</a>
|
||
<a href="/plan/${currentPlanId}/edit" class="btn btn-sm btn-warning">
|
||
<i class="bi bi-edit"></i> 编辑
|
||
</a>
|
||
<button onclick="downloadPDF()" class="btn btn-sm btn-primary">
|
||
<i class="bi bi-download"></i> 下载PDF
|
||
</button>
|
||
<button onclick="downloadMD()" class="btn btn-sm btn-outline-primary">
|
||
<i class="bi bi-file-markdown"></i> 下载MD
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<hr>
|
||
<h6>问题诊断</h6>
|
||
<div class="mb-3">
|
||
`;
|
||
|
||
data.content.problems.forEach(p => {
|
||
html += `<span class="problem-tag severity-${p.severity}">${p.name}(${p.severity})</span> `;
|
||
});
|
||
|
||
html += `</div>`;
|
||
|
||
if (data.content.ai_report) {
|
||
const aiReportHtml = marked.parse(data.content.ai_report);
|
||
html += `
|
||
<h6>AI个性化练习报告</h6>
|
||
<div class="mb-3 p-3 bg-light rounded">${aiReportHtml}</div>
|
||
`;
|
||
} else if (data.content.ai_report_error) {
|
||
html += `
|
||
<h6>AI报告</h6>
|
||
<div class="mb-3 p-3 bg-warning rounded">AI生成失败: ${data.content.ai_report_error}</div>
|
||
`;
|
||
}
|
||
|
||
html += `
|
||
<h6>每日练习计划(共${data.content.total_daily_minutes}分钟)</h6>
|
||
<table class="table table-sm">
|
||
<thead><tr><th>环节</th><th>时长</th><th>内容</th><th>目的</th></tr></thead>
|
||
<tbody>
|
||
`;
|
||
|
||
data.content.daily_schedule.forEach(item => {
|
||
html += `<tr><td>${item.phase}</td><td>${item.duration}</td><td>${item.content}</td><td>${item.purpose}</td></tr>`;
|
||
});
|
||
|
||
html += '</tbody></table>';
|
||
|
||
document.getElementById('planContent').innerHTML = html;
|
||
} catch (e) {
|
||
document.getElementById('planContent').innerHTML = `
|
||
<div class="card-body text-center text-danger py-5">
|
||
<i class="bi bi-exclamation-triangle fs-4"></i>
|
||
<p class="mt-2">加载失败: ${e.message}</p>
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
function downloadPDF() {
|
||
window.open(`/api/plans/${currentPlanId}/pdf`, '_blank');
|
||
}
|
||
|
||
function downloadMD() {
|
||
window.open(`/api/plans/${currentPlanId}/md`, '_blank');
|
||
}
|
||
|
||
window.currentStudentId = null;
|
||
|
||
loadPlan();
|
||
</script>
|
||
{% endblock %} |