Files
mama-box/guangchang/ceshi/index.html

692 lines
54 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>
<!-- 孕妈广场 · 测一测(30 个测试共用这一页,?id=t01…t30)
11-02 v1:列表 + 简版答题。
11-02 v2 用户:「每一个测一测页面都要有设计感,要做插图放进去,跟『你是什么样的妈妈』那个一样;『只在本机算,不上传』删掉」
→ 照 topic/ceshi(妈妈类型卡)重做三屏:
① 开始:大标题 + 插画主图 + 「N 种结果」小卡(每种结果一张插画);
② 答题:一题一屏、左右滑入、小脚印进度;知识题选完当场判对错 + 解析,再点「下一题」;
③ 结果:结果卡(插画 + 称号 + 标签 + 雷达 / 等级条)+ 保存结果卡 + 解读 + 小建议 + 其他结果 / 错题解析 + 再测一个。
· 插画:img/<id>_0.webp 主图,img/<id>_<k>.webp 第 k 个结果(顺序同 tests.js results),img/<id>_s.webp 小图(广场卡片 / 推荐用)。
AI 生成(同 topic/ceshi/img 的水彩画风),统一 600×600。
· 题库 tests.js(window.GC_TESTS);广场列表只引轻量的 meta.js。
· 主色按分组:常识小测(11-02 由「知识考卷」改名)珊瑚橙 / 趣味心理紫 / 闯关青绿。
· 记录:localStorage「mmbox.gcts.v1」(按 openid 分开),只用来显示「上次结果」。
· 不造数字:没有「已有 N 人测过」。
· 无 id 打开:回孕妈广场「测一测」分类。返回:带 ?c=ceshi 进来的回该分类,否则回广场。 -->
<style>
:root{--c:#7C5CFC;--cbg:#F1EDFF;--c06:rgba(124,92,252,.06);--c10:rgba(124,92,252,.10);--c20:rgba(124,92,252,.20);--c2:#E4DDFD;--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))}
#scroll::-webkit-scrollbar{display:none}
img{display:block;max-width:100%}
button{font:inherit;border:0;background:none;color:inherit;cursor:pointer;text-align:inherit}
.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;-webkit-box-decoration-break:clone;box-decoration-break:clone}
/* 顶栏 */
.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;text-align:center}
.btn.pri{background:var(--c);color:#fff;box-shadow:0 6px 16px var(--c20)}
.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)}
/* ---------- ① 开始 ---------- */
/* 11-03 用户发参考图(依恋型人格测试):「每个测试的首页内容不要太多,简明清晰」→ 全部居中、一屏放下:
顶部分组小胶囊 → 插画(圆形 + 身后两团柔光 + 小圆点)→ 大标题 → 「N 道题 · M 分钟」+ 一句话 → 两三个小标签 → 大号胶囊按钮 → 底部一行小字。
原来的「简介段落」「N 种结果插画宫格」撤掉(结果插画在结果页「其他结果」里照样能看到)。 */
#vStart{margin-top:-48px}
#vStart.on{display:flex;flex-direction:column;align-items:center;min-height:100vh;min-height:100dvh;padding:calc(58px + env(safe-area-inset-top)) 28px calc(18px + env(safe-area-inset-bottom));text-align:center;
background:radial-gradient(120% 60% at 50% 0%,var(--cbg) 0%,rgba(255,255,255,0) 70%),linear-gradient(180deg,#FFFBF8,#fff 70%)}
.s-pill{display:inline-flex;align-items:center;gap:8px;height:30px;padding:0 16px;border-radius:99px;background:var(--c06);color:var(--c);font-size:13px;font-weight:700;letter-spacing:2px}
.s-pill i{width:3px;height:3px;border-radius:50%;background:currentColor;opacity:.6}
.s-art{position:relative;width:min(64vw,250px);aspect-ratio:1;margin:clamp(14px,4vh,34px) 0 0}
.s-art .g1,.s-art .g2{position:absolute;border-radius:50%;filter:blur(2px)}
.s-art .g1{left:-14%;top:-6%;width:72%;height:72%;background:radial-gradient(circle at 40% 40%,var(--c2),var(--c06) 70%)}
.s-art .g2{right:-16%;bottom:-8%;width:66%;height:66%;background:radial-gradient(circle at 55% 55%,#E3EEDD,rgba(227,238,221,.25) 70%)}
.s-art .dt{position:absolute;width:8px;height:8px;border-radius:50%;background:var(--c20)}
.s-art .d1{right:-4%;top:6%}.s-art .d2{left:-10%;bottom:16%;width:7px;height:7px}.s-art .d3{right:18%;bottom:-6%;width:6px;height:6px}
.s-art img{position:relative;width:100%;height:100%;border-radius:50%;object-fit:cover;object-position:center 32%;border:5px solid #fff;box-shadow:0 14px 34px -10px var(--c20);background:var(--cbg)}
.s-art .hb{position:absolute;right:2%;bottom:6%;display:grid;place-items:center;width:46px;height:46px;border-radius:50%;background:#fff;color:var(--c);box-shadow:0 6px 16px -4px var(--c20)}
.s-art .hb .ic{width:24px;height:24px;stroke-width:2}
#sTitle{margin-top:clamp(18px,4.2vh,36px);font-size:clamp(25px,7.4vw,30px);font-weight:900;line-height:1.3;color:var(--ink);letter-spacing:2px;text-wrap:balance}
.s-meta{margin-top:10px;font-size:15px;color:var(--sub);letter-spacing:.5px}
.s-meta b{font-weight:600;color:var(--txt)}
.s-line{margin-top:4px;font-size:15.5px;color:var(--txt);letter-spacing:.5px}
.s-chips{display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin-top:clamp(14px,3vh,26px)}
.s-chips span{display:inline-flex;align-items:center;gap:4px;height:32px;padding:0 15px;border-radius:99px;background:#fff;border:1px solid var(--line);box-shadow:0 3px 10px -4px rgba(0,0,0,.08);font-size:13px;color:var(--txt)}
.s-chips .hot{color:#F0704F;font-weight:700}
.s-chips .hot svg{width:13px;height:13px}
.s-go{width:100%;margin-top:auto;padding-top:clamp(18px,4vh,40px)}
#startBtn{height:56px;font-size:18px;letter-spacing:4px;background:linear-gradient(90deg,var(--c),color-mix(in srgb,var(--c) 78%,#fff));box-shadow:0 12px 26px -10px var(--c)}
#startBtn .ic{display:none}
.s-note{margin-top:14px;font-size:12.5px;color:#A9AEB8;letter-spacing:1px}
.lastr{display:inline-flex;align-items:center;gap:8px;margin-top:12px;padding:5px 12px 5px 5px;border-radius:99px;background:var(--c06);font-size:12.5px;color:var(--ink)}
.lastr img{width:24px;height:24px;border-radius:50%;object-fit:cover;border:2px solid #fff}
.lastr b{color:var(--c)}
@media (max-height:700px){.s-art{width:min(48vw,180px)}#sTitle{font-size:23px}.s-line{font-size:14.5px}.s-chips span{height:29px}}
/* ---------- ② 答题 ---------- */
#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}
.qtop .sc{margin-left:10px;padding:0 8px;border-radius:99px;background:var(--cbg);color:var(--c);font-size:12px;font-weight:700;line-height:22px}
.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:var(--c2);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,.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;overflow:hidden;display:grid;place-items:center;background:#fff;box-shadow:0 4px 12px var(--c10)}
.qcard .qi img{width:100%;height:100%;object-fit:cover;object-position:center 28%}
.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:20px;font-weight:800;line-height:1.5;color:var(--ink);min-height:60px;text-wrap:pretty}
.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:var(--c06);font-weight:600}
.opt.sel .l{background:var(--c);color:#fff}
.opt.sel .ck{transform:scale(1)}
/* 知识题判分 */
.opts.lock .opt{pointer-events:none}
.opt.ok{border-color:#2DB37D;background:#EFFAF4;font-weight:600}.opt.ok .l{background:#2DB37D;color:#fff}.opt.ok .ck{background:#2DB37D;transform:scale(1)}
.opt.no{border-color:#F29A9A;background:#FFF4F4}.opt.no .l{background:#EE7070;color:#fff}.opt.no .ck{background:#EE7070;transform:scale(1)}
.exp{margin-top:12px;padding:14px 16px;border-radius:18px;background:var(--soft);font-size:14px;line-height:1.75;color:var(--txt);animation:vin .3s ease both}
.exp b{display:flex;align-items:center;gap:6px;font-size:14.5px;margin-bottom:2px}
.exp.y b{color:#1E9A68}.exp.n b{color:#D9534F}
.nextb{margin-top:14px;animation:vin .3s ease both}
.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,var(--c2) 0%,var(--cbg) 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:180px;height:180px;margin:14px auto 0;border-radius:32px;overflow:hidden;border:5px solid #fff;box-shadow:0 8px 24px var(--c10);background:var(--cbg)}
.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:27px;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}
.rtags{position:relative;display:flex;justify-content:center;flex-wrap:wrap;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:146px;height:128px}
.dl{flex:1;min-width:0;display:flex;flex-direction:column;gap:9px}
.dl.wide{padding-left:8px;display:grid;grid-template-columns:1fr 1fr;column-gap:16px;row-gap:10px}
.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 span:first-child{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.dr .p{font-weight:700;color:var(--ink)}
.dr .tr{grid-column:1/3;height:5px;border-radius:5px;background:var(--cbg);overflow:hidden}
.dr .tr i{display:block;height:100%;width:0;border-radius:5px;background:var(--c20);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)}
/* 计分 / 知识题:环 + 等级条 */
.ring{flex:none;position:relative;width:108px;height:108px;margin-left:4px}
.ring svg{width:100%;height:100%;transform:rotate(-90deg)}
.ring circle{fill:none;stroke-width:10;stroke-linecap:round}
.ring .bgc{stroke:var(--cbg)}
.ring .fg{stroke:var(--c);transition:stroke-dashoffset 1.1s cubic-bezier(.2,.7,.3,1)}
.ring .v{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}
.ring .v b{font-size:30px;font-weight:800;line-height:1;color:var(--c)}
.ring .v b small{font-size:14px;color:var(--sub);font-weight:700}
.ring .v span{margin-top:4px;font-size:11.5px;color:var(--sub);line-height:1.3}
.lvl{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
.lv{display:flex;align-items:center;gap:8px;padding:5px 8px;border-radius:12px;font-size:12.5px;color:var(--sub);line-height:1.3}
.lv img{flex:none;width:26px;height:26px;border-radius:50%;object-fit:cover;object-position:center 26%;opacity:.55;filter:grayscale(.4)}
.lv span{flex:1;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.lv em{font-style:normal;font-size:11px}
.lv.me{background:var(--cbg);color:var(--c);font-weight:800}
.lv.me img{opacity:1;filter:none;box-shadow:0 0 0 2px #fff,0 0 0 3.5px 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)}
.read p+p{margin-top:10px}
.read b{color:var(--ink)}
.read q{quotes:"「" "」";color:var(--c);font-weight:700}
.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)}
.others{display:flex;flex-direction:column;gap:10px}
.oth{display:flex;align-items:center;gap:14px;padding:12px 14px;border-radius:22px;background:linear-gradient(110deg,var(--cbg),#fff 80%)}
.oth img{flex:none;width:58px;height:58px;border-radius:50%;object-fit:cover;object-position:center 26%;border:3px solid #fff;box-shadow:0 4px 12px var(--c10)}
.oth b{display:block;font-size:15.5px;color:var(--ink);line-height:1.4}
.oth small{display:inline-block;margin-left:6px;padding:0 7px;border-radius:99px;background:#fff;color:var(--c);font-size:11.5px;font-weight:700;line-height:19px;vertical-align:2px}
.oth p{margin-top:2px;font-size:13px;color:var(--txt);line-height:1.55;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.rv{border-radius:22px;background:var(--soft);overflow:hidden}
.rv summary{list-style:none;display:flex;align-items:center;gap:8px;padding:15px 18px;font-size:15px;font-weight:800;color:var(--ink);cursor:pointer}
.rv summary::-webkit-details-marker{display:none}
.rv summary small{font-size:12.5px;font-weight:600;color:var(--sub)}
.rv summary .ic{margin-left:auto;width:18px;height:18px;color:var(--sub);transition:transform .2s}
.rv[open] summary .ic{transform:rotate(180deg)}
.rv .it{margin:0 12px 10px;padding:12px 14px;border-radius:16px;background:#fff;font-size:13.5px;line-height:1.7;color:var(--txt)}
.rv .it b{display:block;color:var(--ink);font-size:14.5px;line-height:1.55}
.rv .it .an{display:block;margin:4px 0 2px;color:#1E9A68;font-weight:700}
.rv .it .mi{display:block;color:#D9534F;font-size:12.5px}
.recs{display:flex;flex-direction:column;gap:10px}
.rec{display:flex;align-items:center;gap:12px;width:100%;padding:10px 12px 10px 10px;border-radius:20px;background:#fff;border:1px solid var(--line);text-align:left}
.rec img{flex:none;width:64px;height:64px;border-radius:16px;object-fit:cover;object-position:center 30%;background:var(--soft)}
.rec span{flex:1;min-width:0}
.rec b{display:block;font-size:15px;color:var(--ink);line-height:1.4}
.rec small{display:block;font-size:12.5px;color:var(--sub);line-height:1.5}
.rec em{flex:none;font-style:normal;height:28px;padding:0 12px;border-radius:99px;font-size:12.5px;font-weight:700;line-height:28px}
.rec.g-quiz em{background:#FFEEE8;color:#E8643F}.rec.g-psy em{background:#F1EDFF;color:#7C5CFC}.rec.g-game em{background:#E2F6F1;color:#13917C}.rec.g-shop em{background:#FFEEF3;color:#E9557F}
.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(20,16,40,.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>
</head>
<body>
<svg class="hide" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<symbol id="i-user" viewBox="0 0 24 24"><path d="M16 19v-1a4 4 0 00-4-4H8a4 4 0 00-4 4v1M10 10a3 3 0 100-6 3 3 0 000 6zM20 19v-1a4 4 0 00-3-3.9M15 4.1a3 3 0 010 5.8"/></symbol>
<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-x" viewBox="0 0 24 24"><path d="M7 7l10 10M17 7L7 17"/></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-bulb" viewBox="0 0 24 24"><path d="M9 18h6M10 21h4M12 3a6 6 0 0 0-3.5 10.9c.6.5 1 1.2 1 2.1h5c0-.9.4-1.6 1-2.1A6 6 0 0 0 12 3z"/></symbol>
<symbol id="i-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>
<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-chev" viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></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>
</svg>
<div id="scroll">
<header class="bar" id="bar">
<button class="back" id="back" aria-label="返回"><svg class="ic"><use href="#i-back"/></svg></button>
<span class="t">孕妈广场 · 测一测</span>
</header>
<!-- ① 开始(11-03 参考图版:居中、一屏放下) -->
<main class="view" id="vStart">
<span class="s-pill" id="sEb"></span>
<div class="s-art fade"><i class="g1"></i><i class="g2"></i><i class="dt d1"></i><i class="dt d2"></i><i class="dt d3"></i><img id="sPic" src="" alt=""><span class="hb"><svg class="ic" id="sHb"><use href="#i-heart"/></svg></span></div>
<h1 id="sTitle"></h1>
<p class="s-meta"><b class="num" id="sN"></b> 道题 · <b class="num" id="sMin"></b> 分钟</p>
<p class="s-line" id="sLine"></p>
<div class="s-chips" id="sChips"></div>
<div class="s-go">
<button class="btn pri" id="startBtn">开始测试</button>
<div class="lastr" id="sLast" hidden></div>
<p class="s-note" id="sNote"></p>
</div>
</main>
<!-- ② 答题 -->
<main class="view wrap" id="vQuiz">
<div class="qtop">
<button id="prevBtn"><svg class="ic"><use href="#i-back"/></svg>上一题</button>
<span><span class="no num"><b id="qNo">1</b> / <span id="qTotal"></span></span><span class="sc num" id="qOk" hidden></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"><img id="qPic" src="" alt=""></span><span class="cat" id="qCat"></span></div>
<h2 id="qTitle"></h2>
</div>
<div class="opts" id="qOpts"></div>
<div id="qExp"></div>
</div>
<p class="qtip" id="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 id="rLabel"></b><span id="rDate"></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" id="rDims"></div>
<p class="brand" id="rBrand"></p>
</article>
<div class="racts">
<button class="btn pri" id="saveBtn"><svg class="ic"><use href="#i-down"/></svg>保存结果卡</button>
<button class="btn sec" id="againTop"><svg class="ic"><use href="#i-refresh"/></svg>再测一次</button>
</div>
<section class="blk fade"><div class="sh2"><i>01</i><b id="rReadT"></b></div><div class="read" id="rRead"></div></section>
<section class="blk fade" id="rTipsB"><div class="sh2"><i>02</i><b>给你的小建议</b></div><div class="tips" id="rTips"></div></section>
<section class="blk fade" id="rRvB"><div class="sh2"><i>03</i><b id="rRvT"></b></div><div id="rRv"></div></section>
<section class="blk fade"><div class="sh2"><i>04</i><b>再测一个</b><span>共 30 个测试</span></div><div class="recs" id="rRecs"></div></section>
<button class="btn sec again" id="againBtn"><svg class="ic"><use 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"/></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="meta.js?v=26110279"></script>
<script src="tests.js?v=26110279"></script>
<script>
(function () {
'use strict';
var $ = function (s) { return document.querySelector(s); };
var sc = $('#scroll');
var T = window.GC_TESTS || [], TBY = {};
T.forEach(function (t) { TBY[t.id] = t; });
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
function haptic() { if (navigator.vibrate) navigator.vibrate(8); }
var openid = (function () { var m = (location.hash + '&' + location.search).match(/[#?&]openid=([^&#]+)/); return m ? decodeURIComponent(m[1]) : ''; })();
/* 返回孕妈广场:带 c=ceshi 进来的回「测一测」分类;身份 hash 原样带回 */
function plazaURL() { var q = new URLSearchParams(location.search); q.delete('id'); var s = q.toString(); return '../' + (s ? '?' + s : '') + location.hash; }
var t = TBY[new URLSearchParams(location.search).get('id')];
if (!t) { var q0 = new URLSearchParams(location.search); q0.set('c', 'ceshi'); q0.delete('id'); location.replace('../?' + q0.toString() + location.hash); return; }
/* ---------- 分组主题 ---------- */
var GROUP = {
quiz: { name: '常识小测', en: 'QUIZ', c: '#F0714F', bg: '#FFEFE9', c2: '#FFD9CB', rgb: '240,113,79' },
psy: { name: '趣味心理测试', en: 'MIND TEST', c: '#7C5CFC', bg: '#F1EDFF', c2: '#E4DDFD', rgb: '124,92,252' },
game: { name: '趣味闯关', en: 'CHALLENGE', c: '#13A08A', bg: '#E4F6F1', c2: '#C4EBE1', rgb: '19,160,138' },
shop: { name: '好物配置', en: 'SHOPPING TYPE', c: '#E9557F', bg: '#FFEEF3', c2: '#FFD3E0', rgb: '233,85,127' }
};
var G = GROUP[t.group] || GROUP.psy, R = t.results, N = t.questions.length, KS = 'ABCD';
var st = document.documentElement.style;
st.setProperty('--c', G.c); st.setProperty('--cbg', G.bg); st.setProperty('--c2', G.c2);
st.setProperty('--c06', 'rgba(' + G.rgb + ',.06)'); st.setProperty('--c10', 'rgba(' + G.rgb + ',.10)'); st.setProperty('--c20', 'rgba(' + G.rgb + ',.22)');
document.title = t.title + ' · 测一测';
var IMG = function (k) { return 'img/' + t.id + '_' + k + '.webp'; }; /* k=0 主图;k=i+1 第 i 个结果 */
var rImg = function (r) { return r.img || IMG(R.indexOf(r) + 1); }; /* 好物配置组按类型共用插画:results[].img */
var optT = function (o) { return typeof o === 'string' ? o : o.t; };
var isQuiz = t.type === 'quiz', isType = t.type === 'type';
/* ---------- 记录 ---------- */
var KEY = 'mmbox.gcts.v1', UID = openid || '_guest';
function store() { try { return (JSON.parse(localStorage.getItem(KEY) || '{}')[UID]) || {}; } catch (e) { return {}; } }
function saveRec(rec) { try { var o = JSON.parse(localStorage.getItem(KEY) || '{}'); o[UID] = o[UID] || {}; o[UID][t.id] = rec; localStorage.setItem(KEY, JSON.stringify(o)); } catch (e) {} }
/* ---------- 视图 + 进场动画 ---------- */
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 用户:「重新测试后退回首页,再进来还是结果页;应该以最后所在的页面,再进来呈现对应的页面」
→ 每个测试记住最后停在哪(开始 / 第几题 / 结果),按 openid + 测试 id 存 mmbox.gcts.pos.v1,再进来回到那里 */
var PKEY = 'mmbox.gcts.pos.v1';
function pos(v) {
if (v) pos.v = v;
try { var o = JSON.parse(localStorage.getItem(PKEY) || '{}'); o[UID] = o[UID] || {}; o[UID][t.id] = { v: pos.v, cur: cur, ans: ans }; localStorage.setItem(PKEY, JSON.stringify(o)); } catch (e) {}
}
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'); });
}
$('#back').addEventListener('click', function () {
if (views.quiz.classList.contains('on') && cur > 0) { goPrev(); return; }
if (!views.start.classList.contains('on')) { renderStart(); show('start'); return; }
location.href = plazaURL();
});
sc.addEventListener('scroll', function () { $('#bar').classList.toggle('sh', sc.scrollTop > 4); }, { passive: true });
/* ================= ① 开始 ================= */
/* 开始页一句话(11-03,参考图那种一行说清「测出什么」;原 intro 段落不再上开始页) */
var LINE = { t01: '测测你的孕期常识能打几分', t02: '看看准爸爸到底有多靠谱', t03: '新手妈妈的带娃常识小考', t04: '冲奶换尿布,新手爸爸会几样', t05: '看看待产包准备齐了没有',
t06: '新生儿护理,你知道多少', t07: '月子里的那些事,你答对几个', t08: '宝宝辅食先吃啥、怎么加', t09: '宝宝睡觉的门道,你懂几分', t10: '哺乳期吃喝,避开这些误区',
t11: '测出你是哪一种带娃风格', t12: '给家里的带娃队友打个分', t13: '看看你多快进入爸妈角色', t14: '扫一扫最近的心情小天气', t15: '测出你最信哪一种育儿方式',
t16: '你们俩带娃配合有多默契', t17: '轻松看看最近的孕期心情', t18: '你是精细讲究派,还是随意派', t19: '两个娃的日常,你是哪一款', t20: '你是哪一种带娃的长辈',
t21: '准爸爸闯关,看你能过几关', t22: '那些带娃老经验,哪些是误区', t23: '当了妈妈,你给自己留了多少', t24: '猜猜宝宝会是什么小性格', t25: '测测你的孕期幸福感有多少',
t26: '测出你的母婴选品偏好', t27: '看看你是哪一种采购思路', t28: '囤货党,还是够用就好', t29: '测测你是哪类育儿采购玩家', t30: '看看你的购物清单逻辑' };
var KIND = { quiz: '知识小测', psy: '心理向测试', game: '闯关小游戏', shop: '消费类型测试' };
var FIRE = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12.6 2.5c.4 3-1.6 4.6-3 6.2C8 10.4 7 12 7 14.3A5 5 0 0012 19.5a5 5 0 005-5.2c0-2-1-3.6-1.9-4.6-.2 1.3-.9 2.2-1.9 2.6.6-3.4-.2-7-.6-9.8z" fill="currentColor"/></svg>';
function renderStart() {
$('#sEb').innerHTML = esc(G.name) + '<i></i>' + esc(window.GC_SHORT && GC_SHORT[t.id] || t.title);
$('#sTitle').textContent = t.title;
$('#sN').textContent = N; $('#sMin').textContent = t.minutes || 3;
$('#sLine').textContent = LINE[t.id] || (t.sub || '').split('·').pop().trim();
$('#sPic').src = IMG(0); $('#sPic').alt = t.title;
$('#sHb').innerHTML = '<use href="#' + (isQuiz ? 'i-bulb' : 'i-heart') + '"/>';
var c = [(isType ? R.length + ' 种结果' : isQuiz ? R.length + ' 个称号' : R.length + ' 档状态'), KIND[t.group] || '趣味测试'];
$('#sChips').innerHTML = c.map(function (x) { return '<span>' + esc(x) + '</span>'; }).join('') +
(window.gcTestedText ? '<span class="hot">' + FIRE + gcTestedText(t.id) + '</span>' : '');
$('#sNote').textContent = isQuiz ? '每题选完 · 马上看解析' : '凭第一感觉选 · 没有对错之分';
var last = store()[t.id], lr = last && R.filter(function (r) { return r.title === last.title; })[0], el = $('#sLast');
if (lr) { el.hidden = false; el.innerHTML = '<img src="' + rImg(lr) + '" alt=""><span>上次结果:<b>' + esc(lr.title) + '</b>' + (last.score ? ' · <span class="num">' + esc(last.score) + '</span>' : '') + '</span>'; }
else el.hidden = true;
$('#startBtn').textContent = lr ? '再测一次' : '开始测试';
}
/* ================= ② 答题 ================= */
var cur = 0, ans = [], busy = false, stage = $('#stage');
$('#qTotal').textContent = N;
$('#feet').innerHTML = t.questions.map(function () { return '<svg viewBox="0 0 24 24"><use href="#i-foot"/></svg>'; }).join('');
var feet = document.querySelectorAll('#feet svg');
$('#qPic').src = IMG(0);
$('#qTip').textContent = isQuiz ? '选一个答案,马上看解析' : '选完自动进入下一题';
function okCount() { var n = 0; ans.forEach(function (a, i) { if (a === t.questions[i].a) n++; }); return n; }
function paint() {
var q = t.questions[cur];
$('#qNo').textContent = cur + 1;
[].forEach.call(feet, function (f, i) { f.setAttribute('class', i < cur ? 'done' : i === cur ? 'cur' : ''); });
$('#qCat').textContent = isQuiz ? '单选 · 有标准答案' : G.name;
$('#qTitle').textContent = q.q;
$('#qOpts').className = 'opts';
$('#qOpts').innerHTML = q.opts.map(function (o, i) {
return '<button class="opt" data-i="' + i + '"><span class="l">' + KS[i] + '</span><span>' + esc(optT(o)) + '</span><span class="ck"><svg class="ic"><use href="#i-check"/></svg></span></button>';
}).join('');
$('#qExp').innerHTML = '';
$('#prevBtn').disabled = cur === 0;
if (isQuiz) { var k = $('#qOk'); k.hidden = !ans.length; k.textContent = '答对 ' + okCount(); }
if (ans[cur] != null) mark(ans[cur], true);
if (pos.v === 'quiz') pos();
}
function mark(i, replay) {
var bs = $('#qOpts').querySelectorAll('.opt');
if (!isQuiz) { [].forEach.call(bs, function (x, k) { x.classList.toggle('sel', k === i); }); return; }
var q = t.questions[cur], ok = i === q.a;
$('#qOpts').classList.add('lock');
bs[q.a].classList.add('ok');
if (!ok) { bs[i].classList.add('no'); bs[i].querySelector('.ck').innerHTML = '<svg class="ic"><use href="#i-x"/></svg>'; }
$('#qExp').innerHTML = '<div class="exp ' + (ok ? 'y' : 'n') + '"><b>' + (ok ? '答对啦' : '差一点,正确答案是 ' + KS[q.a]) + '</b>' + esc(q.exp || '') + '</div>' +
'<button class="btn pri nextb" id="nextBtn">' + (cur === N - 1 ? '看我的结果' : '下一题') + '<svg class="ic"><use href="#i-arrow"/></svg></button>';
var k = $('#qOk'); k.hidden = false; k.textContent = '答对 ' + okCount();
if (!replay) setTimeout(function () { var r = $('#nextBtn').getBoundingClientRect(); if (r.bottom > innerHeight - 20) sc.scrollBy({ top: r.bottom - innerHeight + 40, behavior: 'smooth' }); }, 80);
}
function swap(dir, after) {
busy = true;
stage.classList.add(dir > 0 ? 'outL' : 'outR');
setTimeout(function () {
after(); sc.scrollTop = 0;
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);
}
function goNext() { if (cur < N - 1) swap(1, function () { cur++; paint(); }); else { busy = false; finish(); } }
function goPrev() { if (busy || cur === 0) return; swap(-1, function () { cur--; paint(); }); }
$('#qOpts').addEventListener('click', function (e) {
var b = e.target.closest('.opt'); if (!b || busy || this.classList.contains('lock')) return;
haptic(); ans[cur] = +b.dataset.i; mark(ans[cur]);
if (!isQuiz) { busy = true; setTimeout(goNext, 380); }
});
$('#qExp').addEventListener('click', function (e) { if (e.target.closest('#nextBtn') && !busy) { haptic(); goNext(); } });
$('#prevBtn').addEventListener('click', goPrev);
function startQuiz() { cur = 0; ans = []; busy = false; stage.classList.remove('outL', 'outR', 'inL', 'inR'); paint(); show('quiz'); }
$('#startBtn').addEventListener('click', function () { haptic(); startQuiz(); });
$('#againBtn').addEventListener('click', startQuiz);
$('#againTop').addEventListener('click', startQuiz);
/* ================= ③ 计分 ================= */
function band(v) { var r = R[0]; R.forEach(function (x) { if (x.min != null && v >= x.min) r = x; }); return r; }
var res = null;
function finish(old) { /* old = 上次的记录:回到结果页时按存下的答案重算、不重新落记录 */
var qs = t.questions;
if (isQuiz) {
var ok = okCount(); res = { r: band(ok), v: ok, p: ok / N, score: ok + '/' + N };
} else if (t.type === 'score') {
var s = 0, mx = 0;
qs.forEach(function (q, i) { s += (q.opts[ans[i]] || {}).s || 0; mx += Math.max.apply(null, q.opts.map(function (o) { return o.s || 0; })); });
var idx = Math.round(s / (mx || 1) * 100); res = { r: band(s), v: idx, p: idx / 100, score: '指数 ' + idx };
} else {
var cnt = {}, last = {};
R.forEach(function (r) { cnt[r.k] = 0; last[r.k] = -1; });
qs.forEach(function (q, i) { var o = q.opts[ans[i]]; if (o) { cnt[o.k] = (cnt[o.k] || 0) + 1; last[o.k] = i; } });
var max = Math.max.apply(null, R.map(function (r) { return cnt[r.k]; }));
var tied = R.filter(function (r) { return cnt[r.k] === max; });
tied.sort(function (a, b) { return last[b.k] - last[a.k]; }); /* 并列:越靠后的题越接近真实状态 */
var pc = {}, rest = 100; R.forEach(function (r) { pc[r.k] = Math.round(cnt[r.k] / N * 100); rest -= pc[r.k]; }); pc[tied[0].k] += rest;
res = { r: tied[0], cnt: cnt, pc: pc, score: '' };
}
res.ans = ans.slice(); res.at = old ? old.at : Date.now();
if (!old) saveRec({ title: res.r.title, score: res.score, at: res.at, ans: res.ans });
renderResult();
}
/* ================= ③ 渲染结果 ================= */
function ringHTML(p, big, small) {
var C = 2 * Math.PI * 52;
return '<div class="ring"><svg viewBox="0 0 124 124"><circle class="bgc" cx="62" cy="62" r="52"/><circle class="fg" cx="62" cy="62" r="52" stroke-dasharray="' + C.toFixed(1) +
'" stroke-dashoffset="' + C.toFixed(1) + '" data-to="' + (C * (1 - Math.max(.03, Math.min(1, p)))).toFixed(1) + '"/></svg><div class="v"><b class="num">' + big + '</b><span>' + small + '</span></div></div>';
}
function radarSVG() {
var n = R.length, cx = 68, cy = 66, Rr = 44, M = 0, g = '';
R.forEach(function (r) { M = Math.max(M, res.pc[r.k]); }); M = Math.max(40, Math.ceil(M / 10) * 10);
var ang = function (i) { return -Math.PI / 2 + i * 2 * Math.PI / n; };
[1 / 3, 2 / 3, 1].forEach(function (f) {
g += '<polygon points="' + R.map(function (r, i) { return (cx + Math.cos(ang(i)) * Rr * f).toFixed(1) + ',' + (cy + Math.sin(ang(i)) * Rr * f).toFixed(1); }).join(' ') + '" fill="none" stroke="' + G.c2 + '" stroke-width="1"/>';
});
R.forEach(function (r, i) { g += '<line x1="' + cx + '" y1="' + cy + '" x2="' + (cx + Math.cos(ang(i)) * Rr).toFixed(1) + '" y2="' + (cy + Math.sin(ang(i)) * Rr).toFixed(1) + '" stroke="' + G.c2 + '"/>'; });
var pts = R.map(function (r, i) { var d = Math.max(res.pc[r.k] / M, .06) * Rr; return [cx + Math.cos(ang(i)) * d, cy + Math.sin(ang(i)) * d]; });
g += '<polygon points="' + pts.map(function (p) { return p[0].toFixed(1) + ',' + p[1].toFixed(1); }).join(' ') + '" fill="rgba(' + G.rgb + ',.18)" stroke="' + G.c + '" stroke-width="2" stroke-linejoin="round"/>';
pts.forEach(function (p, i) { g += '<circle cx="' + p[0].toFixed(1) + '" cy="' + p[1].toFixed(1) + '" r="' + (R[i] === res.r ? 4.5 : 3.2) + '" fill="' + G.c + '" stroke="#fff" stroke-width="1.5"/>'; });
R.forEach(function (r, i) {
var c = Math.cos(ang(i)), s = Math.sin(ang(i));
var x = cx + c * (Rr + 8), y = cy + s * (Rr + 8) + 4, a = Math.abs(c) < .2 ? 'middle' : c > 0 ? 'start' : 'end';
if (s < -.9) y -= 3; if (s > .9) y += 6;
g += '<text x="' + x.toFixed(1) + '" y="' + y.toFixed(1) + '" text-anchor="' + a + '" font-size="11" font-weight="' + (r === res.r ? 800 : 500) + '" fill="' + (r === res.r ? G.c : '#86909C') + '">' + esc(r.tag) + '</text>';
});
return '<svg viewBox="-16 -2 168 140" role="img" aria-label="各类型占比">' + g + '</svg>';
}
function renderResult() {
var r = res.r;
$('#rLabel').textContent = isType ? '我的类型卡' : isQuiz ? '我的考卷成绩单' : '我的测试结果卡';
var d = new Date(res.at); $('#rDate').textContent = (d.getMonth() + 1) + '月' + d.getDate() + '日';
$('#rImg').src = rImg(r); $('#rImg').alt = r.title;
$('#rYou').textContent = isType ? '你是' : isQuiz ? '你获得了称号' : '你的结果是';
$('#rName').textContent = r.title;
$('#rLine').textContent = r.line || t.title;
var tags = [r.tag, isQuiz ? '答对 ' + res.v + ' / ' + N : isType ? '占 ' + res.pc[r.k] + '%' : '指数 ' + res.v];
$('#rTags').innerHTML = tags.map(function (x) { return '<span>' + esc(x) + '</span>'; }).join('');
if (isType) {
var sorted = R.slice().sort(function (a, b) { return (b === r) - (a === r) || res.pc[b.k] - res.pc[a.k]; });
$('#rDims').innerHTML = (R.length <= 5 ? radarSVG() : '') + '<div class="dl' + (R.length > 5 ? ' wide' : '') + '">' + sorted.map(function (x) {
return '<div class="dr' + (x === r ? ' me' : '') + '"><span>' + esc(x.title) + '</span><span class="p num">' + res.pc[x.k] + '%</span><span class="tr"><i data-w="' + res.pc[x.k] + '"></i></span></div>';
}).join('') + '</div>';
} else {
var ring = isQuiz ? ringHTML(res.p, res.v + '<small>/' + N + '</small>', '答对题数') : ringHTML(res.p, res.v, '满分 100');
$('#rDims').innerHTML = ring + '<div class="lvl">' + R.slice().reverse().map(function (x) {
return '<div class="lv' + (x === r ? ' me' : '') + '"><img src="' + rImg(x) + '" alt=""><span>' + esc(x.title) + '</span>' + '</div>';
}).join('') + '</div>';
}
$('#rBrand').textContent = '兜爸心选 · 孕妈广场 · 测一测';
/* 01 解读:先给结果原文,再结合本次作答说一句 */
$('#rReadT').textContent = isType ? '你是这样的人' : '结果解读';
var html = '<p>' + esc(r.text) + '</p>';
if (isType) {
var picks = []; t.questions.forEach(function (q, i) { var o = q.opts[res.ans[i]]; if (o && o.k === r.k) picks.push(i); });
var qi = picks[picks.length - 1], ex = t.questions[qi];
html += '<p>' + N + ' 道题里,你有 <b class="num">' + picks.length + '</b> 次选了「' + esc(r.title) + '」的答案' +
(ex ? ',比如「' + esc(ex.q.replace(/[??]$/, '')) + '」,你选了<q>' + esc(optT(ex.opts[res.ans[qi]])) + '</q>' : '') + '。</p>';
var sec = R.filter(function (x) { return x !== r && res.cnt[x.k] > 0; }).sort(function (a, b) { return res.cnt[b.k] - res.cnt[a.k]; })[0];
if (sec) html += '<p>你的另一面是<b>「' + esc(sec.title) + '」</b>(<span class="num">' + res.pc[sec.k] + '%</span>),' + esc(sec.tag) + '的那一面也常常冒出来。</p>';
} else if (isQuiz) {
html += '<p>' + N + ' 道题你答对了 <b class="num">' + res.v + '</b> 道' + (res.v === N ? ',一道没错,太厉害了。' : ',没答对的 ' + (N - res.v) + ' 道都在下面「错题解析」里,花一分钟看完就都会了。') + '</p>';
} else {
var full = 0; t.questions.forEach(function (q, i) { var o = q.opts[res.ans[i]], m = Math.max.apply(null, q.opts.map(function (x) { return x.s || 0; })); if (o && o.s === m) full++; });
var nx = R[R.indexOf(r) + 1];
html += '<p>' + N + ' 道题里,有 <b class="num">' + full + '</b> 道你的状态是满格的,综合指数 <b class="num">' + res.v + '</b>。' + (nx ? '离「' + esc(nx.title) + '」不远了,下面的小建议挑一条试试。' : '已经是最高一档啦,继续保持。') + '</p>';
}
$('#rRead').innerHTML = html;
/* 02 小建议 */
$('#rTips').innerHTML = (r.tips || []).map(function (x, i) { return '<div class="tp"><span class="n">' + (i + 1) + '</span><p>' + esc(x) + '</p></div>'; }).join('');
$('#rTipsB').hidden = !(r.tips || []).length;
/* 03 错题解析 / 其他结果 */
if (isQuiz) {
var all = t.questions.map(function (q, i) { return i; }), wrong = all.filter(function (i) { return res.ans[i] !== t.questions[i].a; });
$('#rRvT').textContent = wrong.length ? '错题解析' : '全部解析';
$('#rRv').innerHTML = '<details class="rv"' + (wrong.length && wrong.length <= 3 ? ' open' : '') + '><summary>' + (wrong.length ? '没答对的 ' + wrong.length + ' 道' : '全对!再看一遍解析') + '<small>点开看</small><svg class="ic"><use href="#i-chev"/></svg></summary>' +
(wrong.length ? wrong : all).map(function (i) {
var q = t.questions[i], a = res.ans[i];
return '<div class="it"><b>' + (i + 1) + '. ' + esc(q.q) + '</b><span class="an">正确答案:' + KS[q.a] + '. ' + esc(optT(q.opts[q.a])) + '</span>' +
(a !== q.a && a != null ? '<span class="mi">你选的:' + KS[a] + '. ' + esc(optT(q.opts[a])) + '</span>' : '') + esc(q.exp || '') + '</div>';
}).join('') + '</details>';
} else {
$('#rRvT').textContent = isType ? '其他几种类型' : '其他几档';
$('#rRv').innerHTML = '<div class="others">' + R.filter(function (x) { return x !== r; }).map(function (x) {
return '<div class="oth"><img src="' + rImg(x) + '" alt="" loading="lazy"><span><b>' + esc(x.title) + '<small>' + esc(x.tag) + '</small></b><p>' + esc(x.text) + '</p></span></div>';
}).join('') + '</div>';
}
/* 04 再测一个:没测过的优先,同组 2 个 + 别组 1 个,按 id 错开 */
var done = store(), seed = +t.id.slice(1);
var rk = function (x) { return (+x.id.slice(1) * 7 + seed) % 25; };
var pool = T.filter(function (x) { return x.id !== t.id; }).sort(function (a, b) { return (!!done[a.id] - !!done[b.id]) || rk(a) - rk(b); });
var pick = pool.filter(function (x) { return x.group === t.group; }).slice(0, 2).concat(pool.filter(function (x) { return x.group !== t.group; }).slice(0, 1));
$('#rRecs').innerHTML = pick.map(function (x) {
return '<button class="rec tap g-' + x.group + '" data-go="' + x.id + '"><img src="img/' + x.id + '_s.webp" alt="" loading="lazy"><span><b>' + esc(x.title) + '</b><small>' + x.questions.length + ' 题 · ' + GROUP[x.group].name + '</small></span><em>去测</em></button>';
}).join('');
show('result');
setTimeout(function () {
[].forEach.call(document.querySelectorAll('#rDims .tr i'), function (b) { b.style.width = b.dataset.w + '%'; });
var fg = $('#rDims .fg'); if (fg) fg.style.strokeDashoffset = fg.dataset.to;
}, 250);
}
$('#rRecs').addEventListener('click', function (e) {
var b = e.target.closest('[data-go]'); if (!b) return; haptic();
var q = new URLSearchParams(location.search); q.set('id', b.dataset.go);
location.href = location.pathname + '?' + q.toString() + location.hash;
});
/* ================= 保存结果卡: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 wrapText(ctx, s, x, y, maxW, lh, maxL) {
var line = '', n = 0;
for (var i = 0; i < s.length; i++) {
var tt = line + s[i];
if (ctx.measureText(tt).width > maxW && line) {
if (++n === maxL) { ctx.fillText(line.slice(0, -1) + '…', x, y); return; }
ctx.fillText(line, x, y); y += lh; line = s[i];
} else line = tt;
}
if (line) ctx.fillText(line, x, y);
}
function drawCard(im) {
var r = res.r, W = 750, H = 1180, cv = document.createElement('canvas'); cv.width = W; cv.height = H;
var ctx = cv.getContext('2d');
var g = ctx.createLinearGradient(0, 0, W * .3, H); g.addColorStop(0, G.c2); g.addColorStop(.45, G.bg); g.addColorStop(1, '#FFFFFF');
ctx.fillStyle = g; 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(' + G.rgb + ',.06)'; ctx.beginPath(); ctx.arc(40, 470, 150, 0, 7); ctx.fill();
ctx.textAlign = 'center';
ctx.font = '700 24px ' + FONT;
var lb = $('#rLabel').textContent, lw = ctx.measureText(lb).width + 44;
ctx.fillStyle = '#fff'; rr(ctx, (W - lw) / 2, 52, lw, 48, 24); ctx.fill();
ctx.fillStyle = G.c; ctx.fillText(lb, W / 2, 84);
var S = 340, ix = (W - S) / 2, iy = 132;
ctx.save(); ctx.shadowColor = 'rgba(' + G.rgb + ',.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 side = Math.min(im.naturalWidth, im.naturalHeight); ctx.drawImage(im, (im.naturalWidth - side) / 2, (im.naturalHeight - side) * .3, side, side, ix, iy, S, S); ctx.restore();
ctx.fillStyle = '#86909C'; ctx.font = '500 26px ' + FONT; ctx.fillText($('#rYou').textContent, W / 2, 540);
ctx.font = '800 60px ' + FONT;
var nw = ctx.measureText(r.title).width;
ctx.fillStyle = 'rgba(' + G.rgb + ',.22)'; ctx.fillRect((W - nw) / 2 - 6, 590, nw + 12, 22);
ctx.fillStyle = '#1F2329'; ctx.fillText(r.title, W / 2, 610);
ctx.fillStyle = '#4E5969'; ctx.font = '500 28px ' + FONT; ctx.fillText(t.title, W / 2, 662);
var tags = [].map.call(document.querySelectorAll('#rTags span'), function (s) { return s.textContent; });
ctx.font = '700 26px ' + FONT;
var ws = tags.map(function (s) { return ctx.measureText(s).width + 44; }), tw = ws.reduce(function (a, b) { return a + b; }, 0) + 16 * (tags.length - 1), x = (W - tw) / 2;
tags.forEach(function (s, i) { ctx.fillStyle = '#fff'; rr(ctx, x, 698, ws[i], 54, 27); ctx.fill(); ctx.fillStyle = G.c; ctx.fillText(s, x + ws[i] / 2, 735); x += ws[i] + 16; });
ctx.fillStyle = 'rgba(255,255,255,.9)'; rr(ctx, 60, 790, W - 120, 250, 32); ctx.fill();
ctx.textAlign = 'left'; ctx.fillStyle = '#4E5969'; ctx.font = '400 27px ' + FONT;
wrapText(ctx, r.text, 96, 846, W - 192, 44, 4);
ctx.textAlign = 'center'; ctx.fillStyle = '#86909C'; ctx.font = '500 22px ' + FONT;
ctx.fillText('兜爸心选 · 孕妈广场 · 测一测', W / 2, 1110);
return cv.toDataURL('image/png');
}
var busySave = false;
$('#saveBtn').addEventListener('click', function () {
if (!res || busySave) return; busySave = true;
loadImg($('#rImg').src).then(function (im) {
var url = drawCard(im); busySave = false;
$('#maskImg').src = url; $('#dlBtn').href = url;
$('#dlBtn').hidden = /MicroMessenger/i.test(navigator.userAgent);
$('#mask').classList.add('on');
}).catch(function () { busySave = false; toast('图片还没加载好,稍等再试一次'); });
});
$('#maskClose').addEventListener('click', function () { $('#mask').classList.remove('on'); });
$('#mask').addEventListener('click', function (e) { if (e.target === this) this.classList.remove('on'); });
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); }
/* ---------- 禁止下拉回弹 ---------- */
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)) { if (e.cancelable) e.preventDefault(); }
}, { passive: false });
document.addEventListener('touchmove', function (e) { if (!sc.contains(e.target) && !$('#mask').contains(e.target) && e.cancelable) e.preventDefault(); }, { passive: false });
renderStart();
(function () {
var p = null, rec = store()[t.id];
try { p = ((JSON.parse(localStorage.getItem(PKEY) || '{}'))[UID] || {})[t.id]; } catch (e) {}
if (p && p.v === 'quiz' && Array.isArray(p.ans)) { cur = Math.max(0, Math.min(+p.cur || 0, N - 1)); ans = p.ans.slice(0, N); paint(); show('quiz'); return; }
if (p && p.v === 'result' && rec && Array.isArray(rec.ans) && rec.ans.length === N) { ans = rec.ans.slice(); finish(rec); return; }
show('start'); /* 新进来 / 上次停在开始页 / 旧记录没存答案 */
})();
})();
</script>
</body>
</html>