Files

221 lines
6.9 KiB
HTML
Raw Permalink 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>
.dashboard { max-width: 900px; margin: 0 auto; }
.summary-bar {
background: var(--card);
border-radius: var(--radius-md);
padding: 20px 24px;
margin: 16px 0;
box-shadow: var(--shadow-sm);
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.summary-bar .progress-ring {
width: 80px; height: 80px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
font-weight: 900;
flex-shrink: 0;
}
.progress-incomplete { background: var(--amber-light); color: var(--amber); border: 3px solid var(--amber); }
.progress-complete { background: var(--green-light); color: var(--green); border: 3px solid var(--green); }
.summary-bar .stat { font-size: 14px; }
.summary-bar .stat strong { font-size: 22px; }
.status-table { width: 100%; border-collapse: collapse; margin: 16px 0; }
.status-table th {
background: var(--navy-700);
color: var(--white);
padding: 10px 14px;
text-align: left;
font-weight: 600;
font-size: 13px;
}
.status-table td { padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 14px; }
.status-table tbody tr { background: var(--card); }
.status-table tbody tr:hover { background: var(--navy-light); }
.status-done { color: var(--green); font-weight: 700; }
.status-pending { color: var(--amber); font-weight: 700; }
.tag-sm {
display: inline-block;
font-size: 10px;
font-weight: 700;
padding: 2px 8px;
border-radius: 4px;
margin-left: 6px;
}
.tag-tianheng { background: #DCE9F7; color: var(--navy-600); }
.tag-parents { background: #FEF4E4; color: var(--amber); }
.btn-group { display: flex; gap: 10px; margin: 20px 0; flex-wrap: wrap; }
.refresh-time { font-size: 12px; color: var(--text-muted); text-align: center; margin-top: 8px; }
.empty-state { text-align: center; padding: 40px; color: var(--text-muted); }
.empty-state .icon-big { font-size: 48px; margin-bottom: 12px; }
</style>
</head>
<body>
<div class="top-bar">
DOCUMENT ID: ZJ-2026-TH-001 &nbsp;|&nbsp; 仅供家庭成员查阅
</div>
<div class="container dashboard">
<div style="margin:20px 0;">
<a href="/" style="color:var(--navy-600);text-decoration:none;font-size:13px;font-weight:600;">← 返回首页</a>
</div>
<div class="hero" style="padding:24px 20px 20px;">
<h1>📋 问卷完成情况</h1>
<p class="sub">6项测评:2份线上问卷 + 2份自评测试 + 2份独立测试</p>
</div>
<!-- 总览条 -->
<div class="summary-bar" id="summaryBar">
<div class="progress-ring progress-incomplete" id="progressRing">--</div>
<div class="stat">
<div>已完成 <strong id="completedCount">--</strong> / <span id="totalCount">6</span></div>
<div style="font-size:13px;color:var(--text-muted);" id="statusText">正在加载...</div>
</div>
</div>
<!-- 状态表 -->
<div class="card" style="margin:16px 0;">
<h3 style="font-size:16px;color:var(--navy-700);margin-bottom:12px;">📊 详细状态</h3>
<table class="status-table">
<thead>
<tr>
<th>测评项</th>
<th>填写人</th>
<th>状态</th>
<th>结果摘要</th>
<th>完成时间</th>
</tr>
</thead>
<tbody id="statusBody">
<tr><td colspan="5" style="text-align:center;color:var(--text-muted);">加载中...</td></tr>
</tbody>
</table>
</div>
<!-- 操作按钮 -->
<div class="btn-group" style="justify-content:center;">
<a href="/" class="btn btn-outline" id="btnHome">🏠 返回首页</a>
<a href="/summary.html" class="btn btn-gold" id="btnSummary" style="display:none;">📄 查看汇总报告</a>
</div>
<div class="refresh-time" id="refreshTime"></div>
</div>
<script>
(async function() {
try {
const resp = await fetch('/api/completion-status');
const data = await resp.json();
renderDashboard(data);
} catch(e) {
document.getElementById('statusBody').innerHTML =
'<tr><td colspan="5" style="text-align:center;color:var(--amber);">无法连接后端服务,请确保 Flask 已启动</td></tr>';
document.getElementById('statusText').textContent = '连接失败';
}
})();
const TEST_LABELS = {
holland: '霍兰德职业兴趣测试',
mbti: 'MBTI 性格测试'
};
function renderDashboard(data) {
const done = data.completed_count;
const total = data.total;
const allDone = data.all_completed;
// 进度环
const ring = document.getElementById('progressRing');
ring.textContent = done + '/' + total;
ring.className = 'progress-ring ' + (allDone ? 'progress-complete' : 'progress-incomplete');
document.getElementById('completedCount').textContent = done;
document.getElementById('totalCount').textContent = total;
document.getElementById('statusText').textContent = allDone
? '✅ 全部问卷已完成!可生成汇总报告'
: '还剩 ' + (total - done) + ' 项未完成,请继续填写';
// 状态表
const rows = [];
// API 问卷
(data.questionnaires || []).forEach(q => {
const tag = q.target_user === '父母'
? '<span class="tag-sm tag-parents">父母</span>'
: '<span class="tag-sm tag-tianheng">天恒</span>';
const status = q.completed
? '<span class="status-done">✅ 已完成</span>'
: '<span class="status-pending">⏳ 待填写</span>';
const summary = q.latest_respondent
? q.latest_respondent.user_name + ' · ' + q.response_count + '份答卷'
: '—';
const time = q.latest_respondent
? q.latest_respondent.created_at
: '—';
rows.push({
name: q.title + tag,
target: q.target_user,
status, summary, time
});
});
// 独立测评
const std = data.standalone || {};
['holland', 'mbti'].forEach(key => {
const s = std[key] || {};
const name = (TEST_LABELS[key] || key)
+ ' <span class="tag-sm tag-tianheng">天恒</span>';
const status = s.completed
? '<span class="status-done">✅ 已完成</span>'
: '<span class="status-pending">⏳ 待填写</span>';
const summary = s.completed ? s.result : '—';
const time = s.completed ? s.completed_at : '—';
rows.push({ name, target: '天恒', status, summary, time });
});
document.getElementById('statusBody').innerHTML = rows.map(r => `
<tr>
<td><strong>${r.name}</strong></td>
<td>${r.target}</td>
<td>${r.status}</td>
<td>${r.summary}</td>
<td style="font-size:12px;color:var(--text-muted);">${r.time}</td>
</tr>
`).join('');
// 汇总按钮
if (allDone) {
document.getElementById('btnSummary').style.display = 'inline-flex';
}
// 刷新时间
const t = new Date(data.updated_at);
document.getElementById('refreshTime').textContent =
'数据更新时间:' + t.toLocaleString('zh-CN');
}
</script>
</body>
</html>