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

739 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">
<!-- 11-04 UGC 总开关关着时本页不展示,直接回首页(js/ugc.js) -->
<script src="../../js/ugc.js?v=26110443" data-guard></script>
<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 用户:测试首页要一屏放下,「开始测试」不用往下滑就能看到 → 头图缩成右上小图、信息横排、结果类型一行四个;按钮再贴底兜底(小屏/有上次结果时) */
#vStart{margin-top:-48px}
.hero{position:relative;overflow:hidden;padding:58px 20px 16px;background:linear-gradient(160deg,var(--cbg) 0%,#fff 78%)}
.hero .o1,.hero .o2{position:absolute;border-radius:50%;background:var(--c10);pointer-events:none}
.hero .o1{width:220px;height:220px;right:-80px;top:-80px}
.hero .o2{width:120px;height:120px;left:-50px;bottom:-30px;background:var(--c06)}
.hero .eb{position:relative;display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 11px;border-radius:99px;background:#fff;color:var(--c);font-size:12px;font-weight:700;letter-spacing:.5px;box-shadow:0 2px 8px var(--c10)}
.hero h1{position:relative;z-index:1;margin-top:10px;padding-right:118px;font-size:23px;font-weight:800;line-height:1.38;color:var(--ink);letter-spacing:.5px;text-wrap:balance}
.hero h1 small{display:block;font-size:14px;font-weight:700;color:var(--txt);letter-spacing:1px}
.hero .meta{position:relative;z-index:1;display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:12px}
.hero .meta span{display:flex;align-items:center;gap:4px;font-size:12.5px;color:var(--txt);line-height:1.4}
.hero .meta .ic{width:15px;height:15px;color:var(--c)}
.hero .meta b{color:var(--ink);font-weight:800}
.hero .pic{position:absolute;z-index:1;right:18px;top:62px;width:100px;height:100px;object-fit:cover;object-position:center 30%;border-radius:24px;border:3px solid #fff;box-shadow:0 8px 20px var(--c20);background:var(--cbg)}
.lead{margin-top:4px;padding:12px 14px;border-radius:16px;background:var(--soft);font-size:13.5px;line-height:1.7;color:var(--txt)}
.lastr{display:flex;align-items:center;gap:10px;margin-top:10px;padding:8px 12px;border-radius:14px;background:var(--cbg);font-size:13px;color:var(--ink)}
.lastr img{width:30px;height:30px;border-radius:50%;object-fit:cover;border:2px solid #fff}
.lastr b{color:var(--c)}
.lastr span{flex:1}
.types{margin-top:16px}
.types .sh2 b{font-size:15.5px}
.tgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px 6px;margin-top:-2px}
.tcard{display:flex;flex-direction:column;align-items:center;gap:5px;min-width:0;text-align:center}
.tcard img{flex:none;width:46px;height:46px;border-radius:50%;object-fit:cover;object-position:center 26%;border:2px solid #fff;box-shadow:0 2px 8px var(--c10);background:var(--cbg)}
.tcard span{min-width:0;width:100%}
.tcard b{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;font-size:11.5px;font-weight:600;color:var(--ink);line-height:1.35;word-break:break-all}
.tcard small{display:none}
.startbox{position:sticky;bottom:0;z-index:5;margin:6px -20px 0;padding:12px 20px calc(4px + env(safe-area-inset-bottom));text-align:center;background:linear-gradient(rgba(255,255,255,0),#fff 14px)}
.startbox .note{margin-top:7px;font-size:12px;color:var(--sub)}
/* 11-03 用户:一屏放下后底下空太多 → 开始页撑满一屏(减去底部免责一行),多出的高度均分到各块之间;屏越高图越大 */
#vStart.on{display:flex;flex-direction:column;min-height:calc(100vh - 69px);min-height:calc(100dvh - 69px - env(safe-area-inset-bottom))}
#vStart .wrap{flex:1;display:flex;flex-direction:column;width:100%}
#vStart .lead{margin-top:clamp(4px,(100dvh - 640px) * .12 + 4px,22px)}
#vStart .types{margin-top:auto;padding-top:16px}
#vStart .startbox{margin-top:auto}
#vStart .types + .startbox{padding-top:clamp(12px,(100dvh - 640px) * .25 + 12px,40px)}
@media (min-height:680px){
.hero{padding-top:66px;padding-bottom:22px}
.hero h1{padding-right:132px;font-size:24px}
.hero .pic{top:70px;width:116px;height:116px;border-radius:28px}
.hero .meta{margin-top:16px}
.lead{padding:14px 16px;font-size:14px;line-height:1.8}
.tcard img{width:56px;height:56px}
.tcard b{font-size:12.5px}
.tgrid{gap:12px 6px}
}
@media (min-height:760px){
.hero{padding-top:74px;padding-bottom:28px}
.hero h1{padding-right:146px;font-size:26px}
.hero h1 small{font-size:15px;margin-bottom:2px}
.hero .pic{top:76px;width:130px;height:130px}
.hero .meta{margin-top:20px}
.hero .meta span{font-size:13.5px}
.types .sh2 b{font-size:17px}
.tcard img{width:64px;height:64px}
.tcard b{font-size:13px}
.tgrid{gap:16px 6px}
.startbox .note{margin-top:10px;font-size:12.5px}
}
@media (min-height:790px){
.hero{padding-top:80px;padding-bottom:32px}
.hero h1{padding-right:160px;font-size:28px}
.hero .pic{top:80px;width:146px;height:146px;border-radius:32px}
.lead{padding:16px 18px;font-size:14.5px}
.tcard{gap:6px}
.tcard img{width:70px;height:70px}
.tcard small{display:block;font-size:11.5px;color:var(--sub);line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
}
/* ---------- ② 答题 ---------- */
#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>
<!-- ① 开始 -->
<main class="view" id="vStart">
<section class="hero">
<i class="o1"></i><i class="o2"></i>
<span class="eb" id="sEb"></span>
<h1 id="sTitle"></h1>
<div class="meta">
<span><svg class="ic"><use href="#i-list"/></svg><b class="num" id="sN"></b>题 · 约<b class="num" id="sMin"></b>分钟</span>
<span id="sKind"></span>
<span id="sCnt"><svg class="ic"><use href="#i-user"/></svg><b class="num" id="sCntN"></b></span>
</div>
<img class="pic" id="sPic" src="" alt="">
</section>
<div class="wrap">
<p class="lead fade" id="sLead"></p>
<div class="lastr" id="sLast" hidden></div>
<section class="types fade">
<div class="sh2"><i id="sTyEn"></i><b id="sTyT"></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"/></svg></button>
<p class="note" id="sNote"></p>
</div>
</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=26110443"></script>
<script src="tests.js?v=26110443"></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 });
/* ================= ① 开始 ================= */
function titleHTML() {
/* 「…测试 / 考卷 / 大挑战」:前面的主体加荧光笔,后缀不加 */
var s = t.title, m = s.match(/^(.*?)(小测试|大测试|测试|考卷|小考卷|大挑战)$/);
if (m && m[1].length > 2) return '<mark>' + esc(m[1]) + '</mark>' + esc(m[2]);
return '<mark>' + esc(s) + '</mark>';
}
function renderStart() {
$('#sEb').textContent = G.name + ' · ' + G.en;
$('#sTitle').innerHTML = '<small>测一测</small>' + titleHTML();
$('#sN').textContent = N; $('#sMin').textContent = t.minutes || 3;
$('#sKind').innerHTML = '<svg class="ic"><use href="#' + (isQuiz ? 'i-bulb' : 'i-heart') + '"/></svg>' + (isQuiz ? '答完当场看解析' : '没有对错之分');
$('#sPic').src = IMG(0); $('#sPic').alt = t.title;
$('#sLead').textContent = t.intro;
if (window.gcTestedText) $('#sCntN').textContent = gcTestedText(t.id); else $('#sCnt').hidden = true;
$('#sTyEn').textContent = R.length + (isType ? ' TYPES' : ' LEVELS');
$('#sTyT').textContent = isType ? R.length + ' 种结果,你是哪一种?' : isQuiz ? R.length + ' 个称号,你能拿到哪个?' : R.length + ' 种状态,看看你在哪一档';
$('#tgrid').innerHTML = R.map(function (r) { return '<div class="tcard"><img src="' + rImg(r) + '" alt="" loading="lazy"><span><b>' + esc(r.title) + '</b><small>' + esc(r.tag) + '</small></span></div>'; }).join('');
$('#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').innerHTML = (lr ? '再测一次' : '开始测试') + '<svg class="ic"><use href="#i-arrow"/></svg>';
}
/* ================= ② 答题 ================= */
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>