Files
simon b6df028839 v1.0.0 高考志愿门户完整修复
变更摘要:
- [fix] 清理根目录 index.html 遗留代码(questionnaire-error + retryLoad 移除)
- [fix] 副标题同步更新为自估591分 + 候选志愿546条数据校准
- [fix] 页脚注入版本号 v1.0.0
- [fix] 部署版 index.html: 取消家长标签,统一 filler-tianheng
- [fix] Dashboard 文案修正(4份→2份线上问卷)
- [fix] 清理冗余部署脚本(v1-v4归档至 archived_scripts/)
- [fix] 等效位次工具纳入 deploy 目录
- [chore] .gitignore 初始化
- [init] Git 仓库初始化
2026-06-24 13:11:34 +08:00

206 lines
8.5 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分析报告 — 天恒高考志愿门户</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div class="container" id="app">
<div style="text-align:center;padding:60px 0;color:var(--text-muted);">
<p>正在加载报告...</p>
</div>
</div>
<script>
// ============================================================
// 报告查看器 — 支持两种模式:
// ?file=xxx.html → 在 iframe 中显示静态报告
// ?id=问卷ID → 调用 API 生成分析报告
// ============================================================
var params = new URLSearchParams(window.location.search);
var qid = params.get('id');
var file = params.get('file');
var app = document.getElementById('app');
if (file) {
// ===== 模式1: 静态HTML报告 =====
app.innerHTML =
'<div style="margin-bottom:14px;">' +
'<a href="/" class="back-link">&#8592; 返回首页</a>' +
'</div>' +
'<iframe class="report-frame" id="report-iframe" src="/reports/' + file + '" title="分析报告"></iframe>';
// 动态调整 iframe 高度
setupIframeResize();
} else if (qid) {
// ===== 模式2: API生成的问卷分析报告 =====
loadReport(qid);
} else {
app.innerHTML =
'<div style="text-align:center;padding:60px;">' +
'<p style="color:var(--red);">缺少报告参数</p>' +
'<a href="/" class="btn btn-primary">&#8592; 返回首页</a>' +
'</div>';
}
// ========== iframe 高度自适应 ==========
function setupIframeResize() {
var iframe = document.getElementById('report-iframe');
if (!iframe) return;
iframe.onload = function() {
try {
// 同源可直接访问 contentWindow
var doc = iframe.contentWindow.document;
var height = Math.max(
doc.body.scrollHeight,
doc.body.offsetHeight,
doc.documentElement.scrollHeight,
doc.documentElement.offsetHeight
);
iframe.style.height = (height + 40) + 'px';
} catch(e) {
// 跨域时退化为固定最小高度
console.warn('iframe 高度自适应失败(可能跨域):', e.message);
}
};
}
// ========== API报告生成逻辑 ==========
function loadReport(qid) {
fetch('/api/report/' + qid)
.then(function(resp) {
if (!resp.ok) throw new Error('生成失败');
return resp.json();
})
.then(function(report) {
var html =
'<div style="margin-bottom:14px;">' +
'<a href="/" class="back-link">&#8592; 返回首页</a>' +
'</div>' +
'<div class="hero" style="padding:20px 0 16px;">' +
'<h1>' + report.questionnaire_title + '</h1>' +
'<p class="sub">分析报告 · ' + report.member_count + '人参与 · ' + report.generated_at + '</p>' +
'</div>';
if (report.report_type === 'holland') {
html += renderHollandReport(report);
} else if (report.report_type === 'preference') {
html += renderPreferenceReport(report);
} else if (report.report_type === 'expectation') {
html += renderExpectationReport(report);
} else {
html += '<div class="alert alert-amber"><p>暂无分析数据</p></div>';
}
html += renderExportBlock(qid);
app.innerHTML = html;
})
.catch(function(err) {
app.innerHTML =
'<div style="text-align:center;padding:60px;">' +
'<p style="color:var(--red);">生成失败:' + err.message + '</p>' +
'<p style="color:var(--text-muted);font-size:13px;">请先填写问卷后再查看报告</p>' +
'<a href="/" class="btn btn-primary" style="margin-top:16px;">&#8592; 返回首页</a>' +
'</div>';
});
}
function renderExportBlock(qid) {
return '' +
'<div style="margin-top:32px;padding:20px;background:var(--card);border-radius:var(--radius-md);border:1px solid var(--border);">' +
'<h3 style="margin:0 0 12px;color:var(--navy-700);">导出为后续分析</h3>' +
'<p style="color:var(--text-muted);font-size:13px;margin-bottom:12px;">点击下方按钮可导出JSON格式,供志愿方案分析使用</p>' +
'<button onclick="exportReport(' + qid + ')" class="btn btn-gold">导出 JSON</button>' +
'<div id="export-area" style="display:none;margin-top:16px;">' +
'<textarea id="export-json" readonly style="width:100%;height:200px;font-family:monospace;font-size:12px;padding:12px;border:1px solid var(--border);border-radius:var(--radius-sm);background:var(--bg);"></textarea>' +
'<p style="font-size:12px;color:var(--text-muted);margin-top:8px;">复制上方内容,或右键另存为 .json 文件</p>' +
'</div>' +
'</div>';
}
function renderHollandReport(report) {
var data = report.data;
var conclusions = report.conclusions;
var names = {"R":"现实型","I":"研究型","A":"艺术型","S":"社会型","E":"企业型","C":"常规型"};
var html = '<div style="background:var(--card);border-radius:var(--radius-md);padding:20px;margin-bottom:20px;border:1px solid var(--border);"><h3 style="margin:0 0 16px;color:var(--navy-700);">Holland 职业兴趣分析</h3>';
if (data.dimension_scores) {
Object.entries(data.dimension_scores).forEach(function(entry) {
var member = entry[0];
var scores = entry[1];
var sorted = Object.entries(scores).sort(function(a,b) { return b[1] - a[1]; });
html += '<div style="margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--border);"><div style="font-weight:600;margin-bottom:8px;">' + member + '</div><div style="display:flex;gap:6px;flex-wrap:wrap;">' + sorted.map(function(s) { return '<span style="background:var(--navy-600);color:#fff;padding:4px 10px;border-radius:4px;font-size:13px;">' + names[s[0]] + ': ' + s[1] + '</span>'; }).join('') + '</div></div>';
});
}
conclusions.forEach(function(c) {
html += '<div style="padding:12px;background:var(--bg);border-radius:var(--radius-sm);margin-bottom:8px;border:1px solid var(--border);"><strong>' + c.member + '</strong>: ' + c.top_dims.join(' > ') + '</div>';
});
html += '</div>';
return html;
}
function renderPreferenceReport(report) {
var data = report.data;
var html = '<div style="background:var(--card);border-radius:var(--radius-md);padding:20px;margin-bottom:20px;border:1px solid var(--border);"><h3 style="margin:0 0 16px;color:var(--navy-700);">院校偏好分析</h3>';
(data.consensus || []).forEach(function(c) {
html += '<div style="padding:8px 12px;background:var(--green-light);color:var(--green);border-radius:4px;margin-bottom:4px;font-size:13px;">&#x2713; ' + c.question + ': ' + c.answer + '</div>';
});
(data.conflicts || []).forEach(function(c) {
var answers = Object.entries(c.answers).map(function(e) { return e[0] + ':' + e[1]; }).join(' vs ');
html += '<div style="padding:8px 12px;background:var(--amber-light);color:var(--amber);border-radius:4px;margin-bottom:4px;font-size:13px;">&#x26A0; ' + c.question + ': ' + answers + '</div>';
});
html += '</div>';
return html;
}
function renderExpectationReport(report) {
var data = report.data;
var html = '<div style="background:var(--card);border-radius:var(--radius-md);padding:20px;margin-bottom:20px;border:1px solid var(--border);"><h3 style="margin:0 0 16px;color:var(--navy-700);">家庭期望对齐分析</h3>';
var textAnswers = data.text || {};
Object.entries(textAnswers).forEach(function(entry) {
var q = entry[0];
var answers = entry[1];
Object.entries(answers).forEach(function(ae) {
var member = ae[0];
var text = ae[1];
html += '<div style="margin-bottom:12px;padding:8px 12px;background:var(--bg);border-radius:var(--radius-sm);"><strong>' + member + '</strong>: ' + text.substring(0,100) + (text.length > 100 ? '...' : '') + '</div>';
});
});
html += '</div>';
return html;
}
function exportReport(qid) {
fetch('/api/export/' + qid)
.then(function(resp) { return resp.json(); })
.then(function(data) {
var jsonStr = JSON.stringify(data, null, 2);
document.getElementById('export-json').value = jsonStr;
document.getElementById('export-area').style.display = 'block';
var blob = new Blob([jsonStr], {type: 'application/json'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'gaokao_q' + qid + '_report_' + Date.now() + '.json';
a.click();
})
.catch(function(err) {
alert('导出失败: ' + err.message);
});
}
</script>
</body>
</html>