- 新增 topic/_shared/quiz-skin.css:主色浅底渐变 + 柔光 + 小圆点底纹,题目卡白卡+顶部色条,选项白卡带阴影 - guangchang/ceshi(30 个测试)和 topic/ceshi、duiyou、yali、yinshi、zhunbei 共 6 页引入 Co-Authored-By: AI 助手 <noreply@local>
794 lines
55 KiB
HTML
794 lines
55 KiB
HTML
<!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}
|
||
|
||
.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 答题页底色 / 卡片 -->
|
||
</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>
|
||
|
||
<button class="btn sec again" id="againBtn"><svg class="ic"><use href="#i-refresh" xlink:href="#i-refresh"/></svg>重新测试</button>
|
||
</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 { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); }
|
||
var openid = (function () {
|
||
var m = (location.hash + '&' + location.search).match(/[#?&]openid=([^&#]+)/);
|
||
return m ? decodeURIComponent(m[1]) : '';
|
||
})();
|
||
|
||
/* 返回:从首页点进来就 back;直接打开(分享 / 刷新)就回同目录的首页,身份 hash 原样带回 */
|
||
$('#back').addEventListener('click', function () {
|
||
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);
|
||
|
||
/* ================= 计分 ================= */
|
||
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=26110703"></script> <!-- 11-07 小程序刷新回到这一页(见 js/last-sub.js) -->
|
||
</body>
|
||
</html>
|