Files
2026gaokaozhiyuan/deploy/nginx/html/results.html
T

284 lines
8.6 KiB
HTML
Raw Normal View History

2026-06-24 13:11:34 +08:00
<!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">
<style>
/* 汇总页特有样式 */
.member-card {
background: var(--card);
border-radius: var(--radius);
padding: 20px;
margin-bottom: 16px;
border: 1px solid var(--border);
}
.member-card h3 {
font-size: 16px;
color: var(--blue);
margin-bottom: 4px;
}
.member-card .time {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 12px;
}
.answer-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 8px;
}
.answer-item {
padding: 8px 12px;
background: var(--bg);
border-radius: 6px;
font-size: 13px;
}
.answer-item .q-label {
color: var(--text-muted);
font-size: 11px;
margin-bottom: 2px;
}
.answer-item .q-val {
font-weight: 600;
color: var(--text);
}
.highlight-diff {
background: #FFF3E0;
border-left: 3px solid var(--amber);
}
.empty-state {
text-align: center;
padding: 40px 0;
color: var(--text-muted);
}
/* 对比表格 */
.compare-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
margin-top: 12px;
}
.compare-table th {
background: var(--blue-light);
padding: 10px 12px;
text-align: left;
font-weight: 600;
font-size: 12px;
}
.compare-table td {
padding: 10px 12px;
border-bottom: 1px solid var(--border);
vertical-align: top;
}
.compare-table tr:hover td {
background: #fafbfc;
}
</style>
</head>
<body>
<div class="container">
<div id="app">
<div id="loading" style="text-align:center;padding:60px;">
<p style="color:var(--text-muted);">加载汇总数据...</p>
</div>
</div>
</div>
<script>
// ============================================================
// 问卷结果汇总页 — 展示所有成员的答卷,并高亮差异
// ============================================================
const params = new URLSearchParams(window.location.search);
const qid = params.get('id');
if (!qid) {
document.getElementById('app').innerHTML =
'<div style="text-align:center;padding:60px;"><p style="color:var(--red);">缺少问卷ID</p><a href="/" class="btn btn-primary" style="margin-top:16px;">← 返回首页</a></div>';
} else {
loadResults(qid);
}
async function loadResults(qid) {
try {
// 并行加载问卷信息和答案
const [qResp, rResp] = await Promise.all([
fetch(`/api/questionnaire/${qid}`),
fetch(`/api/results/${qid}`)
]);
if (!qResp.ok) throw new Error('问卷不存在');
const questionnaire = await qResp.json();
const results = await rResp.json();
let html = `
<div style="margin-bottom:20px;display:flex;justify-content:space-between;align-items:center;">
<a href="/" style="color:var(--blue);text-decoration:none;font-size:13px;">← 返回首页</a>
<a href="/questionnaire.html?id=${qid}" class="btn btn-outline btn-sm">📝 我也填一份</a>
</div>
<div class="hero" style="padding:20px 0 16px;">
<h1>📊 ${questionnaire.title} · 汇总</h1>
<p class="sub">共 ${results.length} 份答卷</p>
</div>
`;
if (results.length === 0) {
html += '<div class="empty-state"><p>📭 还没有人填写这份问卷</p><a href="/questionnaire.html?id=' + qid + '" class="btn btn-primary" style="margin-top:16px;">✍️ 我来填第一份</a></div>';
} else {
// 判断问卷类型,选择合适的展示方式
const qData = questionnaire.questions;
if (qData.type === 'likert') {
// Holland 评估:按维度汇总得分
html += renderHollandSummary(qData, results);
} else {
// 普通选择题问卷:横向对比表格
html += renderComparisonTable(qData, results);
}
}
document.getElementById('app').innerHTML = html;
} catch (err) {
document.getElementById('app').innerHTML = `
<div style="text-align:center;padding:60px;">
<p style="color:var(--red);">加载失败:${err.message}</p>
<a href="/" class="btn btn-primary" style="margin-top:16px;">← 返回首页</a>
</div>`;
}
}
// ============ Holland 评估:雷达图 + 维度得分表 ============
function renderHollandSummary(qData, results) {
const dims = qData.dimensions;
const dimNames = { R: '现实型', I: '研究型', A: '艺术型', S: '社会型', E: '企业型', C: '常规型' };
const dimDescs = {
R: '动手操作·机械·户外',
I: '分析思考·科学·研究',
A: '创造表达·艺术·审美',
S: '助人教学·沟通·服务',
E: '领导说服·管理·商业',
C: '秩序规范·数据·流程'
};
let html = '<div class="section-title">🎯 各维度得分对比</div>';
// 每个人一行卡片
results.forEach(r => {
// 按维度汇总得分
const scores = {};
dims.forEach(d => { scores[d] = 0; });
let count = {};
Object.entries(r.answers).forEach(([qid, val]) => {
const item = qData.items.find(i => i.id === qid);
if (item) {
scores[item.dimension] = (scores[item.dimension] || 0) + parseInt(val);
count[item.dimension] = (count[item.dimension] || 0) + 1;
}
});
// 算平均分
dims.forEach(d => {
scores[d] = count[d] ? (scores[d] / count[d]).toFixed(1) : 0;
});
// 找出最高分维度(前2
const sorted = dims.map(d => ({ dim: d, score: parseFloat(scores[d]) }))
.sort((a, b) => b.score - a.score);
const top2 = sorted.slice(0, 2);
html += `
<div class="member-card">
<h3>👤 ${r.user_name}</h3>
<p class="time">提交时间:${r.created_at}</p>
<p style="font-size:14px;margin-bottom:12px;">
🏆 主导类型:<strong>${dimNames[top2[0].dim]}${top2[0].score}分)</strong>、
${dimNames[top2[1].dim]}${top2[1].score}分)
</p>
<table class="compare-table">
<tr>
${dims.map(d => `<th>${dimNames[d]}<br><span style="font-weight:400;font-size:10px;">${dimDescs[d]}</span></th>`).join('')}
</tr>
<tr>
${dims.map(d => {
const score = parseFloat(scores[d]);
const isTop = top2.some(t => t.dim === d);
return `<td style="text-align:center;${isTop ? 'font-weight:700;color:var(--blue);' : ''}">
${'⭐'.repeat(Math.round(score))}<br>${scores[d]}
</td>`;
}).join('')}
</tr>
</table>
</div>
`;
});
return html;
}
// ============ 普通问卷:横向对比表格 ============
function renderComparisonTable(qData, results) {
let html = '<div class="section-title">📋 逐题对比</div>';
// 构建对比表格:行=题目,列=成员
const members = results.map(r => r.user_name);
const memberAnswers = {};
results.forEach(r => {
memberAnswers[r.user_name] = r.answers;
});
html += '<div style="overflow-x:auto;">';
html += '<table class="compare-table">';
html += '<tr><th style="min-width:40px;">#</th><th style="min-width:200px;">题目</th>';
members.forEach(m => {
html += `<th style="min-width:150px;">${m}</th>`;
});
html += '</tr>';
qData.forEach((q, idx) => {
// 检查所有成员的答案是否一致
const values = members.map(m => memberAnswers[m] ? memberAnswers[m][q.id] || '-' : '-');
const allSame = values.every(v => v === values[0] && v !== '-');
const someBlank = values.some(v => v === '-');
html += `<tr class="${!allSame && !someBlank ? 'highlight-diff' : ''}">`;
html += `<td>${idx + 1}</td>`;
html += `<td style="font-size:12px;">${q.text}</td>`;
members.forEach(m => {
const val = memberAnswers[m] ? (memberAnswers[m][q.id] || '-') : '-';
// 把选项值映射为标签
let display = val;
if (q.options && val !== '-') {
const vals = val.split(',');
display = vals.map(v => {
const opt = q.options.find(o => o.value === v.trim());
return opt ? opt.label : v;
}).join('、');
}
html += `<td>${display}</td>`;
});
html += '</tr>';
});
html += '</table></div>';
// 差异提示
html += `
<div style="background:#FFF3E0;border-radius:8px;padding:12px 16px;margin-top:16px;font-size:13px;color:var(--amber);">
💡 橙色高亮行 = 家人之间答案不一致的题目。这些差异点建议在填报前专门讨论,达成共识。
</div>
`;
return html;
}
</script>
</body>
</html>