Files
mama-box/topic/zhunbei/index.html

804 lines
56 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<meta name="format-detection" content="telephone=no">
<title>测一测:迎接宝宝,你准备好几成了?</title>
<!-- 孕期专题 · 趣味测试 3:「迎接宝宝,你准备好几成了?」(2026-11-02 新建)。
结构 / 交互 / 视觉完全照 ../ceshi/ 与 ../duiyou/,只换内容与主色:主色天蓝 #4A8FD8、浅底 #EAF3FC。
和前两个「类型测试」不同,这是**计分自查**:12 题 = 12 件待产准备,每题 4 档选项计 3/2/1/0 分(顺序已打散),满分 36。
按总分分 4 档:随时可以出发(≥30)/ 大体就绪(21–29)/ 还差几步(12–20)/ 今天开始准备(≤11)。
12 件事分 4 组(生产准备 / 月子与宝宝 / 产检与手续 / 家人与心态),结果卡上「几成」圆环 + 4 组完成度条。
结果页:状态卡 + 结合作答的解读 + 已做好的(满分项)/ 在路上(2 分项)+ 接下来最该做的 3 件事(取最低分项,附「建议孕 N 周前」;
拿到孕周时已过建议周数改标「建议尽快」)+ 给你的一句话 + 推荐工具 + 保存结果卡。
按用户要求:结果页不放「复制发给 xx」类按钮,只保留「保存结果卡」。仅生活层面自查,结果页注明不能代替医生判断。
结果存 localStorage「mmbox.zhunbei.v1」(含每题作答)。插画 img/*.webp(hero + 4 档同一画风)。
自成一页:不引 app.js;返回走 history 或相对路径 ../../,推荐工具走 ../_shared/tools.js。
纯本机计算,不采集、不上报答题数据;不造「已有 N 人测过」数字(TESTED_COUNT=0 不显示)。 -->
<style>
:root{--c:#4A8FD8;--cbg:#EAF3FC;--c06:rgba(74,143,216,.06);--c10:rgba(74,143,216,.10);--c20:rgba(74,143,216,.20);--ink:#1F2329;--txt:#4E5969;--sub:#86909C;--line:#EEF0F3;--soft:#F7F8FA}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%;overflow:hidden;background:#fff;color:var(--txt);font:15px/1.75 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif}
#scroll{position:fixed;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none;padding-bottom:calc(24px + env(safe-area-inset-bottom))}
img{display:block;max-width:100%}
button{font:inherit;border:0;background:none;color:inherit;cursor:pointer}
.ic{width:20px;height:20px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.hide{position:absolute;width:0;height:0;overflow:hidden}
[hidden]{display:none !important}
.num{font-variant-numeric:tabular-nums}
mark{background:linear-gradient(transparent 62%,var(--c20) 0);color:inherit;padding:0 1px}
/* 顶栏 */
.bar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:4px;height:48px;padding:0 8px;padding-top:env(safe-area-inset-top);background:transparent;border-bottom:1px solid transparent;transition:background .2s,border-color .2s}
.bar.sh{background:#fff;border-bottom-color:var(--line)}
.bar .back{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;color:var(--ink)}
.bar .back .ic{width:22px;height:22px}
.bar .t{font-weight:600;font-size:16px;color:var(--ink)}
/* 三屏 */
.view{display:none}
.view.on{display:block;animation:vin .35s ease both}
@keyframes vin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.wrap{padding:0 20px}
.btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;height:46px;border-radius:99px;font-size:16px;font-weight:700;transition:transform .15s,opacity .15s}
.btn.pri{background:var(--c);color:#fff;box-shadow:0 6px 16px rgba(74,143,216,.28)}
.btn.sec{background:#fff;color:var(--c);border:1px solid var(--c)}
.btn:active,.tap:active{transform:scale(.98)}
/* 区块标题:小号序号 + 标题 */
.sh2{display:flex;align-items:baseline;gap:8px;margin-bottom:14px}
.sh2 i{font-style:normal;font-size:13px;font-weight:800;color:var(--c);letter-spacing:.5px}
.sh2 b{font-size:18px;font-weight:800;color:var(--ink);line-height:1.4}
.sh2 span{margin-left:auto;font-size:12.5px;color:var(--sub)}
/* ---------- ① 开始 ---------- */
#vStart{margin-top:-48px}
.hero{position:relative;overflow:hidden;min-height:470px;padding:72px 20px 0;background:linear-gradient(160deg,var(--cbg) 0%,#fff 72%)}
.hero .o1,.hero .o2{position:absolute;border-radius:50%;background:var(--c10);pointer-events:none}
.hero .o1{width:260px;height:260px;right:-90px;top:-70px}
.hero .o2{width:150px;height:150px;left:-60px;bottom:40px;background:var(--c06)}
.hero .eb{position:relative;display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 12px;border-radius:99px;background:#fff;color:var(--c);font-size:12.5px;font-weight:700;letter-spacing:.5px;box-shadow:0 2px 8px var(--c10)}
.hero h1{position:relative;margin-top:16px;font-size:30px;font-weight:800;line-height:1.32;color:var(--ink);letter-spacing:.5px}
.hero .meta{position:relative;display:flex;flex-direction:column;gap:8px;margin-top:18px;width:150px}
.hero .meta span{display:flex;align-items:center;gap:6px;font-size:13.5px;color:var(--txt);line-height:1.4}
.hero .meta .ic{width:18px;height:18px;color:var(--c)}
.hero .meta b{color:var(--ink);font-weight:800}
.hero .pic{position:absolute;right:-18px;bottom:0;width:min(228px,calc(100vw - 162px));height:min(228px,calc(100vw - 162px));object-fit:cover;object-position:center 30%;border-radius:28px 0 0 0;box-shadow:0 8px 24px var(--c10)}
.types{margin-top:28px}
.tgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.tcard{display:flex;align-items:center;gap:8px;padding:10px;border-radius:18px;background:var(--soft)}
.tcard img{flex:none;width:42px;height:42px;border-radius:50%;object-fit:cover;object-position:center 22%;border:2px solid #fff;box-shadow:0 2px 8px var(--c10)}
.tcard b{display:block;font-size:14.5px;color:var(--ink);line-height:1.35;white-space:nowrap}
.tcard small{display:block;font-size:12px;color:var(--sub);line-height:1.4}
.startbox{margin-top:28px;text-align:center}
.startbox .note{margin-top:10px;font-size:12.5px;color:var(--sub)}
/* ---------- ② 答题 ---------- */
#vQuiz{padding-top:4px}
.qtop{display:flex;align-items:center;justify-content:space-between;height:34px}
.qtop button{display:inline-flex;align-items:center;gap:2px;font-size:13.5px;color:var(--sub);padding:4px 8px 4px 0}
.qtop button .ic{width:16px;height:16px}
.qtop button:disabled{visibility:hidden}
.qtop .no{font-size:13px;color:var(--sub)}
.qtop .no b{font-size:18px;color:var(--c);font-weight:800}
.feet{display:flex;justify-content:space-between;align-items:center;height:30px;margin-top:4px;padding:0 2px}
.feet svg{width:15px;height:15px;fill:#CFE2F6;transition:fill .3s,transform .3s}
.feet svg:nth-child(odd){transform:translateY(-4px) rotate(-12deg)}
.feet svg:nth-child(even){transform:translateY(4px) rotate(12deg) scaleX(-1)}
.feet svg.done{fill:var(--c)}
.feet svg.cur{fill:var(--c)}
.feet svg.cur:nth-child(odd){transform:translateY(-4px) rotate(-12deg) scale(1.35)}
.feet svg.cur:nth-child(even){transform:translateY(4px) rotate(12deg) scaleX(-1) scale(1.35)}
.stage{margin-top:14px;transition:opacity .22s ease,transform .22s ease}
.stage.outL{opacity:0;transform:translateX(-36px)}
.stage.outR{opacity:0;transform:translateX(36px)}
.stage.inR{opacity:0;transform:translateX(36px);transition:none}
.stage.inL{opacity:0;transform:translateX(-36px);transition:none}
.qcard{position:relative;overflow:hidden;padding:20px 20px 18px;border-radius:24px;background:linear-gradient(160deg,var(--cbg),#fff 78%);box-shadow:0 8px 24px var(--c10)}
.qcard:after{content:"";position:absolute;width:120px;height:120px;right:-40px;top:-40px;border-radius:50%;background:var(--c10)}
.qcard .hd{position:relative;display:flex;align-items:center;justify-content:space-between}
.qcard .qi{width:56px;height:56px;border-radius:18px;display:grid;place-items:center;background:#fff;color:var(--c);box-shadow:0 4px 12px var(--c10)}
.qcard .qi .ic{width:30px;height:30px;stroke-width:1.6}
.qcard .cat{position:relative;z-index:1;height:24px;padding:0 10px;border-radius:99px;background:#fff;color:var(--c);font-size:12px;font-weight:700;line-height:24px}
.qcard h2{position:relative;margin-top:16px;font-size:21px;font-weight:800;line-height:1.45;color:var(--ink);min-height:61px;text-wrap:balance}
.opts{display:flex;flex-direction:column;gap:10px;margin-top:16px}
.opt{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:56px;padding:11px 46px 11px 14px;border-radius:18px;background:#fff;border:1.5px solid var(--line);text-align:left;font-size:15.5px;line-height:1.45;color:var(--ink);transition:border-color .2s,background .2s,transform .15s}
.opt:active{transform:scale(.98)}
.opt .l{flex:none;width:26px;height:26px;border-radius:9px;display:grid;place-items:center;background:var(--soft);color:var(--sub);font-size:13px;font-weight:800;transition:background .2s,color .2s}
.opt .ck{position:absolute;right:14px;top:50%;width:22px;height:22px;margin-top:-11px;border-radius:50%;background:var(--c);color:#fff;display:grid;place-items:center;transform:scale(0);transition:transform .25s cubic-bezier(.3,1.6,.5,1)}
.opt .ck .ic{width:14px;height:14px;stroke-width:2.6}
.opt.sel{border-color:var(--c);background:#F5F9FE;font-weight:600}
.opt.sel .l{background:var(--c);color:#fff}
.opt.sel .ck{transform:scale(1)}
.qtip{margin-top:16px;text-align:center;font-size:12.5px;color:var(--sub)}
/* ---------- ③ 结果 ---------- */
#vResult{padding-top:6px}
.rcard{position:relative;overflow:hidden;padding:22px 20px 18px;border-radius:28px;background:linear-gradient(170deg,#DCEBFA 0%,#EFF6FD 44%,#fff 100%);box-shadow:0 8px 24px var(--c10);text-align:center}
.rcard .o1,.rcard .o2{position:absolute;border-radius:50%;pointer-events:none}
.rcard .o1{width:220px;height:220px;right:-80px;top:-60px;background:rgba(255,255,255,.55)}
.rcard .o2{width:140px;height:140px;left:-50px;top:150px;background:var(--c06)}
.rcard .top{position:relative;display:flex;justify-content:space-between;align-items:center;font-size:12px;line-height:24px}
.rcard .top b{padding:0 10px;border-radius:99px;background:#fff;color:var(--c);font-weight:700}
.rcard .top span{color:var(--sub)}
.rcard .ava{position:relative;width:172px;height:172px;margin:14px auto 0;border-radius:32px;overflow:hidden;border:5px solid #fff;box-shadow:0 8px 24px var(--c10)}
.rcard .ava img{width:100%;height:100%;object-fit:cover;object-position:center 30%}
.rcard .you{position:relative;margin-top:14px;font-size:13px;color:var(--sub);letter-spacing:2px}
.rcard h1{position:relative;font-size:28px;font-weight:800;line-height:1.3;color:var(--ink)}
.rcard .slo{position:relative;margin-top:6px;font-size:14.5px;color:var(--txt);line-height:1.6;text-wrap:balance}
.rtags{position:relative;display:flex;justify-content:center;gap:8px;margin-top:14px}
.rtags span{height:30px;padding:0 12px;border-radius:99px;background:#fff;color:var(--c);font-size:13.5px;font-weight:700;line-height:30px;white-space:nowrap;box-shadow:0 2px 8px var(--c10)}
.dims{position:relative;display:flex;align-items:center;gap:12px;margin-top:18px;padding:14px 14px 14px 8px;border-radius:20px;background:rgba(255,255,255,.85);text-align:left}
.dims svg{flex:none;width:132px;height:128px}
.dl{flex:1;min-width:0;display:flex;flex-direction:column;gap:9px}
.dr{display:grid;grid-template-columns:1fr auto;align-items:center;row-gap:3px;font-size:12.5px;color:var(--txt);line-height:1.3}
.dr .p{font-weight:700;color:var(--ink)}
.dr .tr{grid-column:1/3;height:5px;border-radius:5px;background:#E3EEFA;overflow:hidden}
.dr .tr i{display:block;height:100%;width:0;border-radius:5px;background:#A9CBF0;transition:width .8s cubic-bezier(.3,.7,.2,1)}
.dr.me{color:var(--c);font-weight:700}
.dr.me .p{color:var(--c)}
.dr.me .tr i{background:var(--c)}
.rcard .brand{position:relative;margin-top:14px;font-size:11.5px;color:var(--sub);letter-spacing:.5px}
.racts{display:flex;gap:10px;margin-top:16px}
.racts .btn{flex:1;font-size:15px}
.blk{margin-top:36px}
.read{padding:18px;border-radius:24px;background:var(--soft)}
.read p{font-size:15px;line-height:1.8;color:var(--txt);text-wrap:pretty}
.read p+p{margin-top:10px}
.read b{color:var(--ink)}
.read q{quotes:"「" "」";color:var(--c);font-weight:700}
/* 已做好的 / 在路上 */
.dn h3{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:700;color:var(--sub);margin-bottom:8px}
.dn h3+.chips{margin-bottom:0}
.dn .chips+h3{margin-top:14px}
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chips span{display:inline-flex;align-items:center;gap:4px;height:32px;padding:0 12px 0 9px;border-radius:99px;background:#fff;border:1px solid var(--c20);color:var(--ink);font-size:13.5px;font-weight:600;white-space:nowrap}
.chips span .ic{width:15px;height:15px;color:var(--c);stroke-width:2.4}
.chips.way span{border-style:dashed;border-color:#C9D9EC;color:var(--txt);font-weight:500}
.chips.way span .ic{color:#9DB8D8;stroke-width:2}
.dn .empty{font-size:14.5px;line-height:1.75;color:var(--txt)}
.tips{display:flex;flex-direction:column;gap:10px}
.tp{display:flex;gap:14px;align-items:flex-start;padding:14px 16px;border-radius:18px;background:#fff;border:1px solid var(--line)}
.tp .n{flex:none;width:30px;font-size:30px;font-weight:800;line-height:1;color:transparent;-webkit-text-stroke:1.4px var(--c);font-variant-numeric:tabular-nums}
.tp p{font-size:14.5px;line-height:1.65;color:var(--ink);text-wrap:pretty}
.tp .tx{flex:1;min-width:0}
.tp .tx b{display:block;font-size:15.5px;color:var(--ink);line-height:1.5}
.tp .tx p{margin-top:2px;color:var(--txt)}
.tp .wk{display:inline-flex;align-items:center;gap:4px;margin-top:8px;height:24px;padding:0 9px;border-radius:99px;background:var(--cbg);color:var(--c);font-size:12px;font-weight:700}
.tp .wk .ic{width:14px;height:14px}
.tp .wk.now{background:#FFF3E8;color:#E07B2E}
.mate{display:flex;align-items:center;gap:14px;padding:14px 16px;border-radius:24px;background:linear-gradient(110deg,var(--cbg),#fff 80%)}
.mate img{flex:none;width:60px;height:60px;border-radius:50%;object-fit:cover;object-position:center 22%;border:3px solid #fff;box-shadow:0 4px 12px var(--c10)}
.mate small{display:block;font-size:12px;color:var(--sub);line-height:1.5}
.mate b{display:block;font-size:16px;color:var(--ink);line-height:1.4}
.mate p{margin-top:2px;font-size:13.5px;color:var(--txt);line-height:1.55}
.disc{margin-top:14px;font-size:12.5px;line-height:1.6;color:var(--sub);text-align:center}
#tools{margin-top:36px !important}
.again{margin-top:24px}
.rend{display:flex;gap:10px;margin-top:24px}.rend .btn{flex:1;min-width:0}
.foot{margin:28px 20px 0;font-size:12px;color:var(--sub);text-align:center}
.toast{position:fixed;left:50%;bottom:calc(80px + env(safe-area-inset-bottom));transform:translate(-50%,8px);max-width:300px;padding:10px 16px;border-radius:12px;background:rgba(31,35,41,.88);color:#fff;font-size:13.5px;line-height:1.6;text-align:center;opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;z-index:60}
.toast.on{opacity:1;transform:translate(-50%,0)}
/* 保存结果卡弹层 */
.mask{position:fixed;inset:0;z-index:50;display:none;flex-direction:column;align-items:center;justify-content:center;padding:24px 28px calc(24px + env(safe-area-inset-bottom));background:rgba(14,28,46,.82)}
.mask.on{display:flex;animation:vin .25s ease both}
.mask img{max-width:100%;max-height:calc(100% - 96px);border-radius:16px;box-shadow:0 12px 32px rgba(0,0,0,.25);-webkit-touch-callout:default;user-select:auto}
.mask p{margin-top:14px;color:#fff;font-size:14.5px;font-weight:600;display:flex;align-items:center;gap:6px}
.mask .row{display:flex;gap:16px;margin-top:10px}
.mask .row button,.mask .row a{height:34px;padding:0 18px;border-radius:99px;border:1px solid rgba(255,255,255,.6);color:#fff;font-size:13.5px;line-height:32px;text-decoration:none}
.fade{opacity:0;transform:translateY(12px);transition:opacity .45s ease,transform .45s ease}
.fade.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.fade,.stage,.view.on,.mask.on{opacity:1;transform:none;transition:none;animation:none}}
</style>
<link rel="stylesheet" href="../_shared/quiz-skin.css?v=26110643"><!-- 11-07 答题页底色 / 卡片 -->
<script src="../../js/host-nav.js?v=26110905"></script>
</head>
<body>
<!-- 单色线性图标(每题一个场景图标 q-*) -->
<svg class="hide" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<symbol id="i-back" viewBox="0 0 24 24"><path d="M15 5l-7 7 7 7"/></symbol>
<symbol id="i-arrow" viewBox="0 0 24 24"><path d="M5 12h13M13 6.5l5.5 5.5-5.5 5.5"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></symbol>
<symbol id="i-list" viewBox="0 0 24 24"><path d="M9 6.5h10M9 12h10M9 17.5h10M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="5" y="10.5" width="14" height="10" rx="3"/><path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5"/></symbol>
<symbol id="i-down" viewBox="0 0 24 24"><path d="M12 4v11M7.5 11l4.5 4.5 4.5-4.5M5 19.5h14"/></symbol>
<symbol id="i-refresh" viewBox="0 0 24 24"><path d="M20 12a8 8 0 1 1-2.4-5.7M20 4v4.5h-4.5"/></symbol>
<symbol id="i-hand" viewBox="0 0 24 24"><path d="M9 11V5.5a1.5 1.5 0 0 1 3 0V10M12 9.5V4.5a1.5 1.5 0 0 1 3 0V10M15 9.5V6a1.5 1.5 0 0 1 3 0v8a6.5 6.5 0 0 1-6.5 6.5h-.6a6 6 0 0 1-4.6-2.2L4 15.5a1.6 1.6 0 0 1 2.4-2.1L9 15.5V11"/></symbol>
<symbol id="i-foot" viewBox="0 0 24 24"><path d="M12 9c3 0 4.6 2.7 4.6 6.3S14.8 22 12 22s-4.6-3.1-4.6-6.7S9 9 12 9z"/><circle cx="7.6" cy="6.6" r="1.6"/><circle cx="10.6" cy="4.4" r="1.75"/><circle cx="14" cy="4.6" r="1.6"/><circle cx="16.8" cy="6.8" r="1.35"/></symbol>
<symbol id="i-dash" viewBox="0 0 24 24"><circle cx="12" cy="12" r="7" stroke-dasharray="3 3"/></symbol>
<!-- 题目场景 -->
<symbol id="q-bag" viewBox="0 0 24 24"><rect x="3.5" y="8" width="17" height="12.5" rx="3"/><path d="M8.5 8V6a3.5 3.5 0 0 1 7 0v2M3.5 13h17M11 13v2h2v-2"/></symbol>
<symbol id="q-route" viewBox="0 0 24 24"><path d="M12 21s-6.5-5.6-6.5-11a6.5 6.5 0 0 1 13 0c0 5.4-6.5 11-6.5 11z"/><path d="M12 7v5M9.5 9.5h5"/></symbol>
<symbol id="q-wait" viewBox="0 0 24 24"><path d="M7 3h10M7 21h10M8 3c0 4.5 4 5.5 4 9s-4 4.5-4 9M16 3c0 4.5-4 5.5-4 9s4 4.5 4 9M10 18.5h4"/></symbol>
<symbol id="q-pot" viewBox="0 0 24 24"><path d="M4.5 10h15v6a4.5 4.5 0 0 1-4.5 4.5H9A4.5 4.5 0 0 1 4.5 16zM2.5 12h2M19.5 12h2M9 3.5c-.8 1 .8 2 0 3M12 3c-.8 1 .8 2 0 3M15 3.5c-.8 1 .8 2 0 3"/></symbol>
<symbol id="q-cloth" viewBox="0 0 24 24"><path d="M9 3.5a3 3 0 0 0 6 0l5 2.5-1.8 4-2.2-1V20.5H8V9l-2.2 1L4 6z"/></symbol>
<symbol id="q-bottle" viewBox="0 0 24 24"><path d="M10 2.5h4M10.5 2.5v2.5L9 6.5V9h6V6.5L13.5 5V2.5M8 9h8v10a2.5 2.5 0 0 1-2.5 2.5h-3A2.5 2.5 0 0 1 8 19zM8 13h3M8 16.5h3"/></symbol>
<symbol id="q-board" viewBox="0 0 24 24"><rect x="5" y="4.5" width="14" height="17" rx="2.5"/><path d="M9 3h6v3H9zM8.5 11l1.5 1.5 3-3M8.5 16.5h7"/></symbol>
<symbol id="q-doc" viewBox="0 0 24 24"><path d="M6.5 2.5h8l4 4v13a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2z"/><path d="M14.5 2.5v4h4M8.5 12.5h7M8.5 16.5h4.5"/></symbol>
<symbol id="q-cal" viewBox="0 0 24 24"><rect x="3.5" y="5" width="17" height="15.5" rx="3"/><path d="M3.5 10h17M8 3v4M16 3v4M14 15.2l1.4 1.4 2.6-2.6"/></symbol>
<symbol id="q-family" viewBox="0 0 24 24"><circle cx="8" cy="7" r="2.8"/><circle cx="16.5" cy="8" r="2.3"/><path d="M3 20v-1.5A5 5 0 0 1 8 13.5a5 5 0 0 1 5 5V20M13.5 14.2a4.2 4.2 0 0 1 7 3.1V20"/></symbol>
<symbol id="q-book" viewBox="0 0 24 24"><path d="M12 6.5C10.3 5 7.8 4.5 4 4.5v14c3.8 0 6.3.5 8 2 1.7-1.5 4.2-2 8-2v-14c-3.8 0-6.3.5-8 2zM12 6.5v14"/></symbol>
<symbol id="q-heart" viewBox="0 0 24 24"><path d="M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0 1 12 7.5 4.3 4.3 0 0 1 19.5 10c0 5.4-7.5 10-7.5 10z"/></symbol>
</svg>
<div id="scroll">
<header class="bar" id="bar">
<button class="back" id="back" aria-label="返回"><svg class="ic"><use href="#i-back" xlink:href="#i-back"/></svg></button>
<span class="t">孕期专题</span>
</header>
<!-- ① 开始 -->
<main class="view" id="vStart">
<section class="hero">
<i class="o1"></i><i class="o2"></i>
<span class="eb">孕期自查 · READY CHECK</span>
<h1>测一测<br>迎接宝宝<br>你准备好<mark>几成</mark>了?</h1>
<div class="meta">
<span><svg class="ic"><use href="#i-list" xlink:href="#i-list"/></svg><b class="num">12</b>题 · 约<b class="num">2</b>分钟</span>
<span><svg class="ic"><use href="#i-lock" xlink:href="#i-lock"/></svg>只在本机算,不上传</span>
<span id="tested" hidden><svg class="ic"><use href="#q-heart" xlink:href="#q-heart"/></svg>已有<b class="num" id="testedN"></b>位妈妈测过</span>
</div>
<img class="pic" src="img/hero.webp" alt="孕妈坐在地毯上整理待产包">
</section>
<div class="wrap">
<section class="types fade">
<div class="sh2"><i>4 LEVELS</i><b>4 个档位,你在哪一档?</b></div>
<div class="tgrid" id="tgrid"></div>
</section>
<div class="startbox fade">
<button class="btn pri" id="startBtn">开始自查<svg class="ic"><use href="#i-arrow" xlink:href="#i-arrow"/></svg></button>
<p class="note">按现在的真实情况选,没准备的也没关系</p>
</div>
</div>
</main>
<!-- ② 答题 -->
<main class="view wrap" id="vQuiz">
<div class="qtop">
<button id="prevBtn"><svg class="ic"><use href="#i-back" xlink:href="#i-back"/></svg>上一题</button>
<span class="no num"><b id="qNo">1</b> / <span id="qTotal">12</span></span>
</div>
<div class="feet" id="feet" aria-hidden="true"></div>
<div class="stage" id="stage">
<div class="qcard">
<div class="hd">
<span class="qi"><svg class="ic"><use id="qIc" href="#q-bag" xlink:href="#q-bag"/></svg></span>
<span class="cat" id="qCat"></span>
</div>
<h2 id="qTitle"></h2>
</div>
<div class="opts" id="qOpts"></div>
</div>
<p class="qtip">选完自动进入下一题</p>
</main>
<!-- ③ 结果 -->
<main class="view wrap" id="vResult">
<article class="rcard" id="rCard">
<i class="o1"></i><i class="o2"></i>
<div class="top"><b>我的待产准备卡</b><span id="rLast"></span></div>
<div class="ava"><img id="rImg" src="" alt=""></div>
<p class="you" id="rYou">迎接宝宝,我准备好了</p>
<h1><mark id="rName"></mark></h1>
<p class="slo" id="rLine"></p>
<div class="rtags" id="rTags"></div>
<div class="dims">
<svg id="rRing" viewBox="0 0 132 128" role="img" aria-label="准备完成度"></svg>
<div class="dl" id="rDims"></div>
</div>
<p class="brand">兜爸心选 · 孕期专题 · 迎接宝宝准备自查</p>
</article>
<div class="racts">
<button class="btn pri" id="saveBtn"><svg class="ic"><use href="#i-down" xlink:href="#i-down"/></svg>保存结果卡</button>
</div>
<section class="blk fade">
<div class="sh2"><i>01</i><b>你现在的状态</b></div>
<div class="read" id="rRead"></div>
</section>
<section class="blk fade">
<div class="sh2"><i>02</i><b>已经做好的</b><span id="rDoneN"></span></div>
<div class="read dn" id="rDone"></div>
</section>
<section class="blk fade">
<div class="sh2"><i>03</i><b>接下来最该做的 3 件事</b></div>
<div class="tips" id="rTips"></div>
</section>
<section class="blk fade">
<div class="sh2"><i>04</i><b>想对你说</b></div>
<div class="mate" id="rMate"></div>
<p class="disc">仅供参考,不能代替医生判断,有不适请及时就医</p>
</section>
<div id="tools" class="fade"></div>
<!-- 11-07 用户:「所有测一测的结果页要有一个『返回首页』按钮,返回到测试入口,也就是列表页」→ 孕妈广场「测一测」列表(guangchang/?c=ceshi) -->
<div class="rend">
<button class="btn sec" id="againBtn"><svg class="ic"><use href="#i-refresh" xlink:href="#i-refresh"/></svg>重新测试</button>
<button class="btn pri" id="listBtn"><svg class="ic"><use href="#i-list" xlink:href="#i-list"/></svg>返回首页</button>
</div>
</main>
<p class="foot">生活小自查,仅供参考;具体安排以产检医生意见为准</p>
</div>
<div class="mask" id="mask">
<img id="maskImg" alt="我的待产准备卡">
<p><svg class="ic"><use href="#i-hand" xlink:href="#i-hand"/></svg>长按图片,保存到相册</p>
<div class="row"><a id="dlBtn" download="待产准备卡.png" hidden>下载图片</a><button id="maskClose">关闭</button></div>
</div>
<div class="toast" id="toast"></div>
<script src="../_shared/tools.js"></script>
<script>
(function () {
'use strict';
var $ = function (s) { return document.querySelector(s); };
var sc = $('#scroll');
var KEY = 'mmbox.zhunbei.v1';
var TESTED_COUNT = 0; /* 「已有 N 位妈妈测过」:只有接上真实统计后才填,0 = 不显示(不造数字) */
var XL = 'http://www.w3.org/1999/xlink';
function useRef(el, id) { el.setAttribute('href', '#' + id); el.setAttributeNS(XL, 'xlink:href', '#' + id); }
function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
var openid = (function () {
var m = (location.hash + '&' + location.search).match(/[#?&]openid=([^&#]+)/);
return m ? decodeURIComponent(m[1]) : '';
})();
/* 返回:从首页点进来就 back;直接打开(分享 / 刷新)就回同目录的首页,身份 hash 原样带回 */
$('#back').addEventListener('click', function () {
if (window.MBHost && MBHost.back(function () { location.href = '../../' + location.search + location.hash; })) return; /* 11-09 容器页:回小程序上一页 */
if (document.referrer && document.referrer.indexOf(location.host) >= 0 && history.length > 1) history.back();
else location.href = '../../' + location.search + location.hash;
});
sc.addEventListener('scroll', function () { $('#bar').classList.toggle('sh', sc.scrollTop > 4); }, { passive: true });
/* ================= 4 组(结果卡上的完成度条,每组 3 题) ================= */
var GROUPS = {
sheng: { dim: '生产准备', ax: '生产' },
yue: { dim: '月子与宝宝', ax: '月子' },
shou: { dim: '产检与手续', ax: '手续' },
xin: { dim: '家人与心态', ax: '心态' }
};
var GORDER = ['sheng', 'yue', 'shou', 'xin'];
/* ================= 12 道题 = 12 件待产准备 =================
* 每个选项 = [分数 3/2/1/0, 文案],顺序已人工打散。
* g:所属组;c:题卡标签;s:场景短语(解读里「说到 X,你选了…」);ok:做好时的小标签;
* todo/d:没做好时「接下来该做的事」+ 一句怎么做;wk:建议在孕几周前完成(0 = 随时)。
* 语气:温柔、不说教、不吓人;只做生活层面的自查。 */
var QS = [
{ g: 'sheng', c: '待产包', ic: 'q-bag', s: '待产包', q: '说到待产包,你现在是?', ok: '待产包',
todo: '把待产包收齐,放在门口', d: '照着清单分「妈妈 / 宝宝 / 证件」三袋装,家人都知道放哪儿。', wk: 35, o: [
[2, '买得差不多,还没装包'], [0, '还没想过这件事'], [3, '已收好,放门口随时拎走'], [1, '收藏了清单,还没开始买'] ] },
{ g: 'sheng', c: '医院与路线', ic: 'q-route', s: '在哪生、怎么去', q: '要在哪家医院生、怎么去,你?', ok: '医院与路线',
todo: '定下医院,路线提前走一遍', d: '白天和晚上各试一次,记下大概要多久,顺便看看停车和急诊入口。', wk: 32, o: [
[1, '还在几家医院间犹豫'], [3, '定好医院,路线也走过'], [0, '还没开始考虑'], [2, '医院定了,路线还没试'] ] },
{ g: 'sheng', c: '入院时机', ic: 'q-wait', s: '什么时候去医院', q: '什么情况该去医院,你心里?', ok: '入院时机',
todo: '弄清什么时候该去医院', d: '产检时问问医生:见红、破水、宫缩多密时出发,把答案记在手机里。', wk: 34, o: [
[3, '见红破水宫缩都分得清'], [1, '只知道肚子疼就去'], [2, '大概知道,细节再查'], [0, '还完全不清楚'] ] },
{ g: 'yue', c: '月子安排', ic: 'q-pot', s: '月子谁照顾', q: '月子谁来照顾,定下来了吗?', ok: '月子安排',
todo: '定好月子谁来照顾', d: '家人、月嫂还是月子中心,先聊开;请月嫂或住月子中心的话要早点预约。', wk: 28, o: [
[0, '还没聊过这个话题'], [2, '有人选,细节要商量'], [1, '家里意见还不统一'], [3, '定好了,细节也谈妥'] ] },
{ g: 'yue', c: '宝宝用品', ic: 'q-cloth', s: '宝宝的衣物用品', q: '宝宝的衣服、尿布和小床?', ok: '宝宝用品',
todo: '备齐宝宝的衣物和小床', d: '先买最基础的:几身衣服、尿布、包被和睡觉的地方,小衣服提前洗晒好。', wk: 34, o: [
[1, '只买了几件可爱的'], [3, '备齐了,衣服也洗晒好'], [2, '买了大半,还差一些'], [0, '还没开始准备'] ] },
{ g: 'yue', c: '喂养知识', ic: 'q-bottle', s: '怎么喂宝宝', q: '关于怎么喂宝宝,你了解多少?', ok: '喂养知识',
todo: '了解一点喂养基础', d: '看看喂奶姿势、怎么判断宝宝吃饱,再存好医院或社区的咨询电话。', wk: 36, o: [
[2, '看过一些,到时再学'], [0, '还没顾上了解'], [3, '学过喂奶姿势和开奶'], [1, '知道要喂,具体不懂'] ] },
{ g: 'shou', c: '产检计划', ic: 'q-board', s: '产检安排', q: '接下来的产检安排?', ok: '产检计划',
todo: '把剩下的产检排进日历', d: '建档后把每次产检的时间和项目记下来,设个提醒,提前约好陪同的人。', wk: 13, o: [
[3, '都排进日历,有提醒'], [2, '记得下一次,后面再看'], [0, '还没建档或不清楚'], [1, '医生说了才知道'] ] },
{ g: 'shou', c: '证件与生育保险', ic: 'q-doc', s: '生育保险和证件', q: '生育保险报销、住院要带的证件?', ok: '证件与保险',
todo: '问清生育保险,备好证件', d: '问问单位或当地医保怎么报销、要哪些材料,证件统一放进文件袋。', wk: 30, o: [
[1, '听说过,还没去问'], [3, '问清楚了,资料备好'], [0, '完全没头绪'], [2, '大概知道,资料没理'] ] },
{ g: 'shou', c: '产假安排', ic: 'q-cal', s: '产假和交接', q: '产假和工作交接,你?', ok: '产假安排',
todo: '确认产假,安排好交接', d: '和单位确认能休多久、什么时候开始休,手头工作列个交接单。', wk: 32, o: [
[0, '还没开始考虑'], [3, '安排妥当,或不需要'], [1, '打算快生了再说'], [2, '问过天数,交接没想'] ] },
{ g: 'xin', c: '家人分工', ic: 'q-family', s: '半夜发动谁送', q: '如果半夜发动,谁送、谁拿包?', ok: '家人分工',
todo: '和家人把分工说清楚', d: '谁开车、谁拿包、谁陪产、谁管证件,定下来再存一个备用联系人。', wk: 34, o: [
[2, '大概有数,没细说过'], [3, '早商量好,各管一摊'], [0, '还没和家人聊过'], [1, '到时候再看吧'] ] },
{ g: 'xin', c: '了解分娩', ic: 'q-book', s: '顺产剖宫产和镇痛', q: '顺产、剖宫产、分娩镇痛这些?', ok: '了解分娩',
todo: '上一次分娩课', d: '医院的孕妇学校多半免费,了解生产过程和镇痛方式,心里会踏实很多。', wk: 32, o: [
[1, '听身边人讲过一点'], [2, '自己查过一些资料'], [3, '上过课,和医生聊过'], [0, '还没开始了解'] ] },
{ g: 'xin', c: '心理准备', ic: 'q-heart', s: '想到生宝宝那天', q: '想到生宝宝那天,你的心情?', ok: '心理准备',
todo: '把担心说出来', d: '说给伴侣、家人或产检医生听;紧张是正常的,有人分担会轻松不少。', wk: 0, o: [
[3, '有点紧张,但挺踏实'], [0, '不太敢去想这件事'], [2, '期待多,偶尔会慌'], [1, '常担心,不知跟谁说'] ] }
];
var MAX = QS.length * 3;
$('#qTotal').textContent = QS.length;
/* ================= 4 个档位 =================
* min:总分下限(满分 36);extra:每件都做好时,「接下来 3 件事」用这里补位。 */
var TIERS = [
{ key: 'go', min: 30, name: '随时可以出发', short: '30 分以上', img: 'img/go.webp', alt: '孕妈提着待产包,和家人站在门口',
line: '包在门口,心里有底,就等宝宝敲门', tags: ['准备充分', '心里有数', '从容'],
desc: '该想的你几乎都想到了,大事小事都有着落。接下来最重要的,是好好休息,养足精神。',
word: '你已经把能准备的都准备好了。剩下的日子,多睡一会儿、多吃点爱吃的,好好享受和肚子里宝宝的最后一段二人时光。',
extra: [
{ todo: '把待产包再过一遍', d: '证件、手机充电线、产妇卫生巾放在最上层,拿起就能走。', wk: 37 },
{ todo: '练练呼吸和放松', d: '每天几分钟腹式呼吸,到时候用得上,也能帮你睡得好一点。', wk: 37 },
{ todo: '留点时间给自己', d: '该做的都做了,剩下的交给时间,去做一件让自己开心的小事吧。', wk: 0 } ],
tools: [
{ id: 'gongsuopinlv', why: '发动时记宫缩,间隔一目了然' },
{ id: 'taidong', why: '最后几周,每天数数胎动' },
{ id: 'yundujinian', why: '把孕肚照存好,留给宝宝看' } ] },
{ key: 'ready', min: 21, name: '大体就绪', short: '21–29 分', img: 'img/ready.webp', alt: '孕妈在婴儿床边整理小衣服',
line: '大部分都安排好了,再补几块拼图就齐', tags: ['安排有序', '稳步推进', '靠谱'],
desc: '大方向都安排好了,只剩几件事还在路上。照着下面的清单补一补,很快就能随时出发。',
word: '你已经走完了大半的路,剩下的几件事不难,一周做一件就好。别给自己太大压力,你做得已经很好了。',
extra: [
{ todo: '把待产包再过一遍', d: '证件、手机充电线、产妇卫生巾放在最上层,拿起就能走。', wk: 37 },
{ todo: '练练呼吸和放松', d: '每天几分钟腹式呼吸,到时候用得上。', wk: 37 },
{ todo: '留点时间给自己', d: '去做一件让自己开心的小事吧。', wk: 0 } ],
tools: [
{ id: 'daichanqingdan', why: '照清单补齐,一样不落' },
{ id: 'gongsuopinlv', why: '提前熟悉,发动时不慌' },
{ id: 'chanjianrili', why: '剩下的产检排好,到点提醒' } ] },
{ key: 'steps', min: 12, name: '还差几步', short: '12–20 分', img: 'img/steps.webp', alt: '孕妈坐在沙发上,在本子上做计划',
line: '方向都对,接下来把几件大事落地', tags: ['有想法', '正在推进', '来得及'],
desc: '很多事你已经放在心上了,只是还没完全落地。时间来得及,先挑最急的几件做起来就好。',
word: '还差几步不是落后,是刚好走在路上。把下面 3 件事写进这周的计划,一件一件来,你会越来越踏实。',
extra: [],
tools: [
{ id: 'daichanqingdan', why: '一份清单,从待产包开始' },
{ id: 'chanjianrili', why: '把产检排进日历,不怕忘' },
{ id: 'yunqinengbuchi', why: '吃之前查一查,少操心' } ] },
{ key: 'start', min: 0, name: '今天开始准备', short: '11 分及以下', img: 'img/start.webp', alt: '孕妈坐在窗边,手放在肚子上望着晨光',
line: '不着急,时间够,一件一件慢慢来', tags: ['刚起步', '时间充裕', '慢慢来'],
desc: '如果你还在孕早中期,这个分数再正常不过。准备不用一口气做完,从最简单的一件开始就好。',
word: '每个妈妈都是从「还什么都没准备」开始的。今天能停下来想一想这些事,就已经是很好的开始了。',
extra: [],
tools: [
{ id: 'chanjianrili', why: '先把产检安排好,最省心' },
{ id: 'daichanqingdan', why: '提前看看要准备些什么' },
{ id: 'yunqitizhong', why: '体重变化随手记,心里有数' } ] }
];
function tierOf(score) { for (var i = 0; i < TIERS.length; i++) if (score >= TIERS[i].min) return TIERS[i]; return TIERS[TIERS.length - 1]; }
function cheng(score) { return Math.round(score / MAX * 10); }
/* 开始页:4 个档位小卡 + 测过人数(仅真实数据) */
$('#tgrid').innerHTML = TIERS.map(function (t) {
return '<div class="tcard"><img src="' + t.img + '" alt=""><span><b>' + t.name + '</b><small>' + t.short + '</small></span></div>';
}).join('');
if (TESTED_COUNT > 0) { $('#testedN').textContent = TESTED_COUNT.toLocaleString('zh-CN'); $('#tested').hidden = false; }
/* 进场动画:按顺序 60ms 错开 */
var views = { start: $('#vStart'), quiz: $('#vQuiz'), result: $('#vResult') };
var io = 'IntersectionObserver' in window ? new IntersectionObserver(function (es) {
var n = 0;
es.forEach(function (e) {
if (!e.isIntersecting) return;
var el = e.target; io.unobserve(el);
setTimeout(function () { el.classList.add('in'); }, 60 * n++);
});
}, { root: sc, threshold: .08 }) : null;
/* 11-03 用户:「重新测试后退回首页,再进来还是结果页」→ 记住最后停在哪(开始 / 第几题 / 结果),再进来回到那里 */
function pos(v) {
if (v) pos.v = v;
try { localStorage.setItem(KEY + '.pos', JSON.stringify({ v: pos.v, cur: cur, ans: ans })); } catch (e) {}
}
function resume() {
var p = null; try { p = JSON.parse(localStorage.getItem(KEY + '.pos') || 'null'); } catch (e) {}
if (!p) return false; /* 旧用户没有记录:照原来的(有结果看结果) */
if (p.v === 'start') { show('start'); return true; }
if (p.v === 'quiz' && Array.isArray(p.ans)) { cur = Math.max(0, Math.min(+p.cur || 0, QS.length - 1)); ans = p.ans.slice(0, QS.length); paint(); show('quiz'); return true; }
return false;
}
function show(name) {
pos(name);
Object.keys(views).forEach(function (k) { views[k].classList.toggle('on', k === name); });
sc.scrollTop = 0;
[].forEach.call(views[name].querySelectorAll('.fade'), function (el) {
el.classList.remove('in');
if (io) { io.unobserve(el); io.observe(el); } else el.classList.add('in');
});
}
/* ================= 答题 ================= */
var cur = 0, ans = [], busy = false;
var stage = $('#stage');
$('#feet').innerHTML = QS.map(function () { return '<svg viewBox="0 0 24 24"><use href="#i-foot" xlink:href="#i-foot"/></svg>'; }).join('');
var feet = document.querySelectorAll('#feet svg');
function paint() {
var q = QS[cur];
$('#qNo').textContent = cur + 1;
[].forEach.call(feet, function (f, i) { f.setAttribute('class', i < cur ? 'done' : i === cur ? 'cur' : ''); });
useRef($('#qIc'), q.ic);
$('#qCat').textContent = q.c;
$('#qTitle').textContent = q.q;
$('#qOpts').innerHTML = q.o.map(function (o, i) {
return '<button class="opt' + (ans[cur] === i ? ' sel' : '') + '" data-i="' + i + '"><span class="l">' + 'ABCD'[i] + '</span><span>' + esc(o[1]) +
'</span><span class="ck"><svg class="ic"><use href="#i-check" xlink:href="#i-check"/></svg></span></button>';
}).join('');
$('#prevBtn').disabled = cur === 0;
if (pos.v === 'quiz') pos();
}
/* 左右滑动:前进 → 当前向左滑出、新题从右滑入;上一题反过来 */
function swap(dir, after) {
busy = true;
stage.classList.add(dir > 0 ? 'outL' : 'outR');
setTimeout(function () {
after();
stage.classList.remove('outL', 'outR');
stage.classList.add(dir > 0 ? 'inR' : 'inL');
void stage.offsetWidth;
stage.classList.remove('inR', 'inL');
setTimeout(function () { busy = false; }, 220);
}, 220);
}
$('#qOpts').addEventListener('click', function (e) {
var b = e.target.closest('.opt'); if (!b || busy) return;
busy = true;
ans[cur] = +b.dataset.i;
[].forEach.call(document.querySelectorAll('#qOpts .opt'), function (x) { x.classList.toggle('sel', x === b); });
setTimeout(function () {
if (cur < QS.length - 1) swap(1, function () { cur++; paint(); });
else { busy = false; finish(); }
}, 380);
});
$('#prevBtn').addEventListener('click', function () {
if (busy || cur === 0) return;
swap(-1, function () { cur--; paint(); });
});
function startQuiz() {
cur = 0; ans = []; busy = false;
stage.classList.remove('outL', 'outR', 'inL', 'inR');
paint();
show('quiz');
}
$('#startBtn').addEventListener('click', startQuiz);
$('#againBtn').addEventListener('click', startQuiz);
/* 11-07 结果页「返回首页」= 回测试列表(孕妈广场「测一测」分类),查询参数和身份 hash 原样带上 */
$('#listBtn').addEventListener('click', function () { var q = new URLSearchParams(location.search); ['id', 'c', 'n', 't'].forEach(function (k) { q.delete(k); }); q.set('c', 'ceshi'); location.href = '../../guangchang/?' + q.toString() + location.hash; });
/* ================= 计分 ================= */
function pts(a) { return a.map(function (i, qi) { return QS[qi].o[i][0]; }); }
function groupPct(p) {
var g = {};
GORDER.forEach(function (k) { var s = 0, n = 0; QS.forEach(function (q, qi) { if (q.g === k) { s += p[qi]; n += 3; } }); g[k] = Math.round(s / n * 100); });
return g;
}
function finish() {
var p = pts(ans), total = p.reduce(function (a, b) { return a + b; }, 0);
var rec = { score: total, ans: ans.slice(), at: Date.now() };
try { localStorage.setItem(KEY, JSON.stringify(rec)); } catch (e) {}
render(rec, false);
}
/* ================= 解读:引用作答 ================= */
function reading(rec, p, g, t) {
var done = p.filter(function (x) { return x === 3; }).length, way = p.filter(function (x) { return x === 2; }).length;
var html = '<p>' + (done ? '12 件事里,你已经稳稳做好了 <b class="num">' + done + '</b> 件' + (way ? ',还有 <b class="num">' + way + '</b> 件在路上' : '') + '。'
: way ? '12 件事里,有 <b class="num">' + way + '</b> 件已经在路上了。' : '') + esc(t.desc) + '</p>';
var byHi = GORDER.slice().sort(function (x, y) { return g[y] - g[x]; });
var hi = byHi[0], lo = byHi[byHi.length - 1];
/* 最好的一组里,分最高的那一题;最高也不到 2 分(还没真正开始)就不引用,免得把「还不清楚」当亮点 */
var best = -1; QS.forEach(function (q, qi) { if (q.g === hi && (best < 0 || p[qi] > p[best])) best = qi; });
if (p[best] >= 2) {
html += '<p>准备得最好的是「' + GROUPS[hi].dim + '」(<span class="num">' + g[hi] + '%</span>):说到' + QS[best].s + ',你选了<q>' + esc(QS[best].o[rec.ans[best]][1]) + '</q>。</p>';
}
if (g[lo] < 100 && lo !== hi) {
html += '<p>「' + GROUPS[lo].dim + '」目前 <span class="num">' + g[lo] + '%</span>,是接下来最值得花点时间的地方,具体做法在下面。</p>';
} else if (g[lo] === 100) {
html += '<p>四个方面都准备到位了,真的很不容易,给自己点个赞。</p>';
}
return html;
}
function doneHTML(rec, p) {
var ok = [], way = [];
QS.forEach(function (q, qi) { if (p[qi] === 3) ok.push(q.ok); else if (p[qi] === 2) way.push(q.ok); });
var chip = function (s, ic) { return '<span><svg class="ic"><use href="#' + ic + '" xlink:href="#' + ic + '"/></svg>' + esc(s) + '</span>'; };
var h = '';
if (ok.length) h += '<h3>已经搞定</h3><div class="chips">' + ok.map(function (s) { return chip(s, 'i-check'); }).join('') + '</div>';
if (way.length) h += '<h3>正在路上</h3><div class="chips way">' + way.map(function (s) { return chip(s, 'i-dash'); }).join('') + '</div>';
if (!h) h = '<p class="empty">现在还没有完全落地的事,这很正常。下面这 3 件事,就是最好的起点。</p>';
$('#rDoneN').textContent = ok.length ? '搞定 ' + ok.length + ' / 12' : '';
return h;
}
/* 接下来 3 件事:分数最低的优先;同分时建议周数越早越靠前(「随时」排最后) */
function nextThree(p, t) {
var list = QS.map(function (q, qi) { return { qi: qi, s: p[qi], todo: q.todo, d: q.d, wk: q.wk }; })
.filter(function (x) { return x.s < 3; })
.sort(function (a, b) { return a.s - b.s || (a.wk || 99) - (b.wk || 99) || a.qi - b.qi; })
.slice(0, 3);
var ex = t.extra.length ? t.extra : TIERS[0].extra;
for (var i = 0; list.length < 3 && i < ex.length; i++) list.push(ex[i]);
return list;
}
function tipsHTML(list) {
return list.map(function (x, i) {
var late = x.wk && wk && wk >= x.wk;
var lab = !x.wk ? '随时都可以' : late ? '建议尽快' : '建议孕 ' + x.wk + ' 周前';
return '<div class="tp"><span class="n">' + (i + 1) + '</span><div class="tx"><b>' + esc(x.todo) + '</b><p>' + esc(x.d) + '</p>' +
'<span class="wk' + (late ? ' now' : '') + '"><svg class="ic"><use href="#i-clock" xlink:href="#i-clock"/></svg>' + lab + '</span></div></div>';
}).join('');
}
/* ================= 完成度圆环(SVG 手写) ================= */
function ringSVG(score) {
var cx = 66, cy = 64, r = 50, C = 2 * Math.PI * r, f = score / MAX;
return '<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#E3EEFA" stroke-width="11"/>' +
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#4A8FD8" stroke-width="11" stroke-linecap="round" stroke-dasharray="' +
(C * f).toFixed(1) + ' ' + C.toFixed(1) + '" transform="rotate(-90 ' + cx + ' ' + cy + ')"/>' +
'<text x="' + cx + '" y="' + (cy + 9) + '" text-anchor="middle" font-size="34" font-weight="800" fill="#1F2329">' + cheng(score) +
'<tspan font-size="15" font-weight="700" fill="#4A8FD8" dx="2">成</tspan></text>' +
'<text x="' + cx + '" y="' + (cy + 30) + '" text-anchor="middle" font-size="11" fill="#86909C">' + score + ' / ' + MAX + ' 分</text>';
}
/* ================= 渲染结果 ================= */
var curRec = null, curP = null, curG = null, curT = null, wk = 0;
function render(rec, fromCache) {
var p = pts(rec.ans), g = groupPct(p), t = tierOf(rec.score);
curRec = rec; curP = p; curG = g; curT = t;
$('#rImg').src = t.img; $('#rImg').alt = t.alt;
$('#rYou').textContent = '迎接宝宝,我准备好了 ' + cheng(rec.score) + ' 成';
$('#rName').textContent = t.name;
$('#rLine').textContent = t.line;
var d = new Date(rec.at || Date.now());
$('#rLast').textContent = (fromCache ? '上次测试 · ' : '') + (d.getMonth() + 1) + '月' + d.getDate() + '日';
$('#rTags').innerHTML = t.tags.map(function (a) { return '<span>' + esc(a) + '</span>'; }).join('');
$('#rRing').innerHTML = ringSVG(rec.score);
var lo = GORDER.slice().sort(function (x, y) { return g[x] - g[y]; })[0];
$('#rDims').innerHTML = GORDER.map(function (k) {
return '<div class="dr' + (k === lo && g[k] < 100 ? ' me' : '') + '"><span>' + GROUPS[k].dim + '</span><span class="p num">' + g[k] + '%</span><span class="tr"><i data-w="' + g[k] + '"></i></span></div>';
}).join('');
$('#rRead').innerHTML = reading(rec, p, g, t);
$('#rDone').innerHTML = doneHTML(rec, p);
renderTips();
$('#rMate').innerHTML = '<img src="' + t.img + '" alt=""><span><small>给正在准备的你</small><b>' + t.name + '的你</b><p>' + esc(t.word) + '</p></span>';
renderTools();
show('result');
setTimeout(function () { [].forEach.call(document.querySelectorAll('#rDims i'), function (b) { b.style.width = Math.max(b.dataset.w, 2) + '%'; }); }, 250);
}
function renderTips() { if (curRec) $('#rTips').innerHTML = tipsHTML(nextThree(curP, curT)); }
function renderTools() {
if (!curRec || !window.TopicTools) return;
var el = $('#tools'); el.className = 'fade in';
TopicTools.render(el, curT.tools, { title: '用得上的工具', color: '#4A8FD8', bg: '#EAF3FC', wk: wk });
}
/* 孕周:给推荐工具打「孕N周开放」标签;「3 件事」已过建议周数改标「建议尽快」 */
if (openid) {
fetch('/api/mp/public/mama-box/pregnancy?openid=' + encodeURIComponent(openid))
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (j) {
var p = j && j.code === 200 && j.result;
if (p && !p.postpartum && !p.empty && p.week != null) { wk = +p.week || 0; renderTools(); renderTips(); }
}).catch(function () {});
}
/* ================= 提示(用户要求结果页不放「复制发给 xx」类按钮) ================= */
var tt;
function toast(msg) {
var el = $('#toast'); el.textContent = msg; el.classList.add('on');
clearTimeout(tt); tt = setTimeout(function () { el.classList.remove('on'); }, 2400);
}
/* ================= 保存结果卡:canvas 画图 → <img> 长按保存 ================= */
var FONT = '-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif';
function rr(ctx, x, y, w, h, r) {
ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath();
}
function loadImg(src) { return new Promise(function (ok, no) { var im = new Image(); im.onload = function () { ok(im); }; im.onerror = no; im.src = src; }); }
function drawCard(im) {
var t = curT, g = curG, score = curRec.score, W = 750, H = 1200;
var cv = document.createElement('canvas'); cv.width = W; cv.height = H;
var ctx = cv.getContext('2d');
var gr = ctx.createLinearGradient(0, 0, W * .3, H);
gr.addColorStop(0, '#DCEBFA'); gr.addColorStop(.45, '#EFF6FD'); gr.addColorStop(1, '#FFFFFF');
ctx.fillStyle = gr; ctx.fillRect(0, 0, W, H);
ctx.fillStyle = 'rgba(255,255,255,.55)'; ctx.beginPath(); ctx.arc(660, 90, 230, 0, 7); ctx.fill();
ctx.fillStyle = 'rgba(74,143,216,.06)'; ctx.beginPath(); ctx.arc(40, 470, 150, 0, 7); ctx.fill();
ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic';
/* 顶部胶囊 */
ctx.font = '700 24px ' + FONT;
var lb = '我的待产准备卡', lw = ctx.measureText(lb).width + 44;
ctx.fillStyle = '#fff'; rr(ctx, (W - lw) / 2, 52, lw, 48, 24); ctx.fill();
ctx.fillStyle = '#4A8FD8'; ctx.fillText(lb, W / 2, 84);
/* 插画 */
var S = 320, ix = (W - S) / 2, iy = 132;
ctx.save(); ctx.shadowColor = 'rgba(74,143,216,.18)'; ctx.shadowBlur = 36; ctx.shadowOffsetY = 12;
ctx.fillStyle = '#fff'; rr(ctx, ix - 10, iy - 10, S + 20, S + 20, 60); ctx.fill(); ctx.restore();
ctx.save(); rr(ctx, ix, iy, S, S, 52); ctx.clip();
var sw = im.naturalWidth, sh = im.naturalHeight, side = Math.min(sw, sh);
ctx.drawImage(im, (sw - side) / 2, (sh - side) * .3, side, side, ix, iy, S, S); ctx.restore();
/* 档位名 */
ctx.fillStyle = '#86909C'; ctx.font = '400 26px ' + FONT; ctx.fillText('迎接宝宝,我准备好了 ' + cheng(score) + ' 成', W / 2, 520);
ctx.font = '800 60px ' + FONT;
var nm = t.name, nw = ctx.measureText(nm).width;
ctx.fillStyle = 'rgba(74,143,216,.20)'; ctx.fillRect((W - nw) / 2 - 4, 566, nw + 8, 24);
ctx.fillStyle = '#1F2329'; ctx.fillText(nm, W / 2, 588);
ctx.fillStyle = '#4E5969'; ctx.font = '400 28px ' + FONT; ctx.fillText(t.line, W / 2, 640);
/* 关键词 */
ctx.font = '700 26px ' + FONT;
var ws = t.tags.map(function (s) { return ctx.measureText(s).width + 44; }), gap = 16;
var tx = (W - ws.reduce(function (a, b) { return a + b; }, 0) - gap * 2) / 2;
t.tags.forEach(function (s, i) {
ctx.save(); ctx.shadowColor = 'rgba(74,143,216,.12)'; ctx.shadowBlur = 14; ctx.shadowOffsetY = 4;
ctx.fillStyle = '#fff'; rr(ctx, tx, 680, ws[i], 56, 28); ctx.fill(); ctx.restore();
ctx.fillStyle = '#4A8FD8'; ctx.fillText(s, tx + ws[i] / 2, 717); tx += ws[i] + gap;
});
/* 完成度面板:左圆环 + 右 4 组 */
ctx.fillStyle = 'rgba(255,255,255,.9)'; rr(ctx, 40, 776, 670, 300, 36); ctx.fill();
var cx = 200, cy = 926, R = 98;
ctx.lineWidth = 22; ctx.lineCap = 'round';
ctx.strokeStyle = '#E3EEFA'; ctx.beginPath(); ctx.arc(cx, cy, R, 0, Math.PI * 2); ctx.stroke();
if (score > 0) { ctx.strokeStyle = '#4A8FD8'; ctx.beginPath(); ctx.arc(cx, cy, R, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * score / MAX); ctx.stroke(); }
ctx.lineCap = 'butt';
ctx.textAlign = 'center';
ctx.font = '800 68px ' + FONT; var cs = String(cheng(score)), cw = ctx.measureText(cs).width;
ctx.font = '700 30px ' + FONT; var uw = ctx.measureText('成').width;
var sx = cx - (cw + 4 + uw) / 2;
ctx.textAlign = 'left'; ctx.fillStyle = '#1F2329'; ctx.font = '800 68px ' + FONT; ctx.fillText(cs, sx, cy + 18);
ctx.fillStyle = '#4A8FD8'; ctx.font = '700 30px ' + FONT; ctx.fillText('成', sx + cw + 4, cy + 18);
ctx.textAlign = 'center'; ctx.fillStyle = '#86909C'; ctx.font = '400 22px ' + FONT; ctx.fillText(score + ' / ' + MAX + ' 分', cx, cy + 58);
var lo = GORDER.slice().sort(function (x, y) { return g[x] - g[y]; })[0];
GORDER.forEach(function (k, i) {
var y = 838 + i * 64, me = k === lo && g[k] < 100;
ctx.textAlign = 'left'; ctx.font = (me ? '700' : '400') + ' 25px ' + FONT; ctx.fillStyle = me ? '#4A8FD8' : '#4E5969'; ctx.fillText(GROUPS[k].dim, 370, y + 10);
ctx.textAlign = 'right'; ctx.font = '700 25px ' + FONT; ctx.fillStyle = me ? '#4A8FD8' : '#1F2329'; ctx.fillText(g[k] + '%', 674, y + 10);
ctx.fillStyle = '#E3EEFA'; rr(ctx, 370, y + 24, 304, 10, 5); ctx.fill();
ctx.fillStyle = me ? '#4A8FD8' : '#A9CBF0'; rr(ctx, 370, y + 24, Math.max(10, 304 * g[k] / 100), 10, 5); ctx.fill();
});
/* 底部 */
ctx.textAlign = 'center';
ctx.fillStyle = '#1F2329'; ctx.font = '700 26px ' + FONT; ctx.fillText('测一测:迎接宝宝,你准备好几成了?', W / 2, 1128);
ctx.fillStyle = '#86909C'; ctx.font = '400 21px ' + FONT; ctx.fillText('兜爸心选 · 孕期专题 · 生活小自查,仅供参考', W / 2, 1164);
return cv.toDataURL('image/png');
}
var isWx = /MicroMessenger/i.test(navigator.userAgent);
$('#saveBtn').addEventListener('click', function () {
if (!curRec) return;
toast('正在生成结果卡…');
loadImg(curT.img).then(function (im) {
var url = drawCard(im);
$('#maskImg').src = url;
var dl = $('#dlBtn'); dl.href = url; dl.hidden = isWx;
$('#toast').classList.remove('on');
$('#mask').classList.add('on');
}).catch(function () { toast('生成失败,截个图保存也可以'); });
});
$('#maskClose').addEventListener('click', function () { $('#mask').classList.remove('on'); });
$('#mask').addEventListener('click', function (e) { if (e.target === this) this.classList.remove('on'); });
/* 入口:有上次结果直接看结果,否则开始页 */
var saved = null;
try { saved = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) {}
if (resume()) ;
else if (saved && saved.ans && saved.ans.length === QS.length && typeof saved.score === 'number') render(saved, true);
else show('start');
/* 禁止下拉回弹:固定外壳 + 容器滚动 + 到顶/到底时拦 touchmove */
var y0 = 0;
sc.addEventListener('touchstart', function (e) { y0 = e.touches[0].clientY; }, { passive: true });
sc.addEventListener('touchmove', function (e) {
var dy = e.touches[0].clientY - y0;
if ((sc.scrollTop <= 0 && dy > 0) || (sc.scrollTop + sc.clientHeight >= sc.scrollHeight - 1 && dy < 0)) e.preventDefault();
}, { passive: false });
document.addEventListener('touchmove', function (e) { if (!sc.contains(e.target)) e.preventDefault(); }, { passive: false });
})();
</script>
<script src="../../js/last-sub.js?v=26110905"></script> <!-- 11-07 小程序刷新回到这一页(见 js/last-sub.js) -->
<script src="../../js/pv.js?v=26110653"></script> <!-- 11-07 页面访问记录(推送效果看板,见 js/pv.js) -->
</body>
</html>