测一测 v2:广场「经验」后加「测一测」分类 + 信息流穿插测试卡、删祈福树下横滑条;测试页按妈妈类型卡样式重做并配插画;v26110219

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
deploy
2026-11-02 11:44:23 +00:00
parent 9b29af6dc3
commit 96ca17261c
137 changed files with 694 additions and 389 deletions

View File

@@ -129,19 +129,25 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
.hot{display:flex;gap:10px;padding:0 12px 2px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scroll-snap-type:x mandatory}
.hot::-webkit-scrollbar{display:none}
.hot::after{content:"";flex:none;width:2px}
/* 11-02 测一测入口:祈福树下面一排横滑小卡,点了进 ceshi/(25 个测试) */
.cs{margin:14px 0 0}
.cs .sh{padding:0 16px}
.cs-l{display:flex;gap:10px;overflow-x:auto;padding:8px 12px 4px;scrollbar-width:none;scroll-snap-type:x proximity}
.cs-l::-webkit-scrollbar{display:none}
.cs-c{flex:none;width:128px;height:96px;padding:11px 12px;border-radius:16px;color:#fff;text-align:left;position:relative;overflow:hidden;scroll-snap-align:start;display:flex;flex-direction:column;box-shadow:0 8px 16px -12px rgba(120,60,40,.6)}
.cs-c:active{transform:scale(.97)}
.cs-c small{font-size:10.5px;font-weight:700;opacity:.88}
.cs-c b{margin-top:4px;font-size:14px;font-weight:900;line-height:1.35}
.cs-c::after{content:"";position:absolute;right:-22px;bottom:-22px;width:64px;height:64px;border-radius:50%;background:rgba(255,255,255,.2)}
.cs-c.q{background:linear-gradient(135deg,#FF9A6B,#F2604A)}.cs-c.p{background:linear-gradient(135deg,#B49CFF,#8461E0)}.cs-c.g{background:linear-gradient(135deg,#5FD3B6,#1C9C86)}
.cs-c.all{background:#fff;color:#2B2320;align-items:center;justify-content:center;text-align:center;width:96px}
.cs-c.all::after{display:none}.cs-c.all b{font-size:22px;color:#F2704E;margin:0}.cs-c.all small{color:#9A8380;opacity:1}
/* 11-02 v2 测一测:广场第 5 个分类「测一测」(经验后面)+「大家在聊」信息流里穿插测试卡。卡片插画 ceshi/img/<id>_s.webp */
.cats .c-ceshi{--cf:#7C5CFC}
.k-ceshi{--kf:#7C5CFC;--kt:#6346B0;--kl:#F1EDFF;--kl2:#E4DDFD}
.g-quiz{--tg:#F0714F;--tl:#FFEFE9}.g-psy{--tg:#7C5CFC;--tl:#F1EDFF}.g-game{--tg:#13A08A;--tl:#E4F6F1}
.nc.tst .cvw{background:var(--tl)}
.nc.tst .cvw img{display:block;width:100%;height:calc(var(--cw) * 1.08);object-fit:cover;object-position:center 30%}
.nc.tst .tb{position:absolute;left:7px;top:7px;display:inline-flex;align-items:center;gap:3px;height:21px;padding:0 8px 0 6px;border-radius:7px;background:var(--tg);color:#fff;font-size:11px;font-weight:800;letter-spacing:.5px;box-shadow:0 3px 8px -3px var(--tg)}
.nc.tst .tb .ic{width:12px;height:12px;stroke-width:2.2}
.nc.tst .tq{position:absolute;left:0;right:0;bottom:0;padding:22px 9px 7px;background:linear-gradient(transparent,rgba(30,20,40,.42));color:#fff;font-size:11.5px;font-weight:700;text-shadow:0 1px 2px rgba(0,0,0,.25)}
.nc.tst .nf{justify-content:space-between}
.nc.tst .gs{font-size:11px;font-weight:700;color:var(--tg)}
.nc.tst .gs.dn{max-width:96px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.nc.tst .gt{flex:none;height:22px;padding:0 9px;border-radius:99px;background:var(--tl);color:var(--tg);font-size:11.5px;font-weight:800;line-height:22px}
.csh{position:relative;margin:2px 12px 0;padding:16px 16px 14px;border-radius:20px;overflow:hidden;background:linear-gradient(135deg,#F1EDFF,#FFEFF4 60%,#FFF3EA)}
.csh b{display:block;font-size:20px;font-weight:900;color:#2A1E1E;letter-spacing:.5px}
.csh p{margin-top:3px;font-size:12.5px;color:#7A6A66;line-height:1.55;max-width:58%}
.csh .gn{display:flex;gap:6px;margin-top:10px}
.csh .gn span{height:22px;padding:0 8px;border-radius:99px;background:rgba(255,255,255,.85);font-size:11.5px;font-weight:700;line-height:22px;color:var(--tg)}
.csh img{position:absolute;right:-6px;bottom:-8px;width:132px;height:132px;object-fit:cover;border-radius:50%;border:4px solid rgba(255,255,255,.8);box-shadow:0 8px 20px -10px rgba(124,92,252,.6)}
.htl{margin:0 12px;padding:4px 12px 2px;border-radius:18px;background:#fff;box-shadow:0 6px 18px -12px rgba(120,60,40,.25)}
.htl .hr{display:flex;align-items:center;gap:10px;padding:11px 0;border-bottom:1px dashed #F0E2DC;--hk:var(--kf)}
.htl .hr:last-of-type{border-bottom:0}
@@ -512,9 +518,10 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
<div id="sheet" role="dialog" aria-modal="true"><i class="sg"></i><div class="sbd" id="sbd"></div></div>
<div class="toast" id="toast"></div>
<script src="topics.js?v=26110218"></script>
<script src="data.js?v=26110218"></script>
<script src="feed.js?v=26110218"></script>
<script src="topics.js?v=26110219"></script>
<script src="data.js?v=26110219"></script>
<script src="feed.js?v=26110219"></script>
<script src="ceshi/meta.js?v=26110219"></script>
<script>
(function () {
'use strict';
@@ -644,7 +651,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
var cur = '', catF = '';
var UBAND = (function () { try { var g = JSON.parse(localStorage.getItem('mmbox.gcwk.v1') || 'null'); return !g ? -1 : g.pp ? 'pp' : g.w && window.GC_BAND ? window.GC_BAND('孕' + g.w + '周') : -1; } catch (e) { return -1; } })();
/* 11-01 用户:家庭+婚姻合成「家庭婚姻」,母婴改「经验」→ 三块(marriage 话题在 topics.js 里已并进 family) */
var CATS = [['', '全部', 'i-grid'], ['family', '家庭婚姻', 'i-home'], ['work', '职场', 'i-bag'], ['baby', '经验', 'i-baby']];
var CATS = [['', '全部', 'i-grid'], ['family', '家庭婚姻', 'i-home'], ['work', '职场', 'i-bag'], ['baby', '经验', 'i-baby'], ['ceshi', '测一测', 'i-spark']];
var CAT_ORDER = ['family', 'work', 'baby'];
var CAT_NAME = { family: '家庭婚姻', work: '职场方向', baby: '孕育经验' };
var inCat = function (t) { return !catF || t.cat === catF; };
@@ -662,7 +669,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
}).join('') + '<span class="bar"></span>';
moveBar();
}
function catCnt(c) { return NOTES.filter(function (n) { return !c || TBY[n.t].cat === c; }).length; }
function catCnt(c) { if (c === 'ceshi') return TM.length; return NOTES.filter(function (n) { return !c || TBY[n.t].cat === c; }).length; }
/* 胶囊挪到选中标签文字下方,宽度跟文字走(取文字宽的一半,偏小红书) */
function moveBar() {
var on = $('#cats .on'), bar = $('#cats .bar'); if (!on || !bar) return;
@@ -697,18 +704,38 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
} catch (e) {}
haptic(); location.href = target;
}
/* 11-02 用户:「把这 25 个测试放到孕妈广场里,点进去就是这 25 个测试」→ 祈福树下一排横滑卡,题库在 ceshi/tests.js,这里只挑几张露出 */
var CS_PICK = [['t11', 'p', '趣味心理', '松弛型还是内卷型妈妈?'], ['t01', 'q', '知识考卷', '孕妈孕期知识考卷'], ['t21', 'g', '闯关挑战', '准爸爸胎教合格大挑战'],
['t16', 'p', '趣味心理', '夫妻育儿默契大测试'], ['t03', 'q', '知识考卷', '新手妈妈育儿摸底考卷'], ['t24', 'g', '趣味测试', '宝宝气质预判小测试']];
function ceshiURL(id) {
var q = new URLSearchParams(location.search); ['t', 'n', 'c', 'id'].forEach(function (k) { q.delete(k); });
if (id) q.set('id', id); var s = q.toString();
return 'ceshi/' + (s ? '?' + s : '') + location.hash;
/* 11-02 v2 用户:「测一测放到『经验』后边;孕妈广场上现在那个测一测删掉;『大家在聊』里穿插几个测一测,点了进对应的测试」
→ CATS 加第 5 个分类 ceshi;选中时 #head 放说明卡、#fh 放分组胶囊、#wf 瀑布流放 25 张测试卡;「全部」信息流按 CS_AT 位置穿插 CS_MIX 里的测试卡。
测试目录只引轻量 ceshi/meta.js;题库在 ceshi/tests.js,只在测试页加载。 */
var TM = window.GC_TESTS_META || [], TMBY = {};
TM.forEach(function (x) { TMBY[x.id] = x; });
var TG = { quiz: '知识考卷', psy: '趣味心理', game: '趣味闯关' }, tGrp = '';
var CS_MIX = ['t11', 't01', 't24', 't16', 't03', 't14', 't21', 't18', 't05'], CS_AT = [3, 11, 20, 30, 41, 53, 66, 80, 95];
function csDone() { try { return (JSON.parse(localStorage.getItem('mmbox.gcts.v1') || '{}')[param('openid') || '_guest']) || {}; } catch (e) { return {}; } }
function ceshiURL(id, fromTab) {
var q = new URLSearchParams(location.search); ['t', 'n', 'c', 'id', 'mine'].forEach(function (k) { q.delete(k); });
if (fromTab) q.set('c', 'ceshi');
q.set('id', id);
return 'ceshi/?' + q.toString() + location.hash;
}
function ceshiHTML() {
return '<div class="cs"><div class="sh"><svg class="fire"><use href="#i-spark"/></svg><h2>测一测</h2><button type="button" class="more" data-cs="">全部 25 个<svg class="ic" style="width:13px;height:13px"><use href="#i-right"/></svg></button></div>' +
'<div class="cs-l">' + CS_PICK.map(function (x) { return '<button type="button" class="cs-c ' + x[1] + '" data-cs="' + x[0] + '"><small>' + x[2] + '</small><b>' + x[3] + '</b></button>'; }).join('') +
'<button type="button" class="cs-c all" data-cs=""><b>25</b><small>全部测试 ›</small></button></div></div>';
function testCardHTML(x, done) {
var d = done && done[x.id];
return '<button type="button" class="nc tst g-' + x.group + '" data-test="' + x.id + '"><div class="cvw"><img src="ceshi/img/' + x.id + '_s.webp" alt="" loading="lazy">' +
'<span class="tb"><svg class="ic"><use href="#i-spark"/></svg>测一测</span><span class="tq">' + x.n + ' 题 · 约 ' + x.min + ' 分钟</span></div>' +
'<div class="nb"><h3>' + esc(x.title) + '</h3><div class="nf">' + (d ? '<span class="gs dn">已测 · ' + esc(d.title) + '</span>' : '<span class="gs">' + TG[x.group] + '</span>') +
'<span class="gt">' + (d ? '再测' : '去测') + ' ›</span></div></div></button>';
}
function ceshiHead() {
var n = function (g) { return TM.filter(function (x) { return x.group === g; }).length; };
return '<div class="csh"><b>孕育测一测</b><p>知识考卷、趣味心理、闯关挑战,测完就有专属结果卡</p>' +
'<div class="gn"><span class="g-quiz">考卷 ' + n('quiz') + '</span><span class="g-psy">心理 ' + n('psy') + '</span><span class="g-game">闯关 ' + n('game') + '</span></div>' +
'<img src="ceshi/img/t11_s.webp" alt=""></div>';
}
function ceshiFh(fh) {
fh.className = 'lvw k-ceshi';
var all = [['', '全部', TM.length]].concat(['quiz', 'psy', 'game'].map(function (g) { return [g, TG[g], TM.filter(function (x) { return x.group === g; }).length]; }));
fh.innerHTML = '<div class="lv"><h2>测一测</h2><small>' + TM.length + ' 个测试 · 每个 12 题以上</small></div>' +
'<div class="tcs">' + all.map(function (x) { return '<button type="button" data-tg="' + x[0] + '"' + (tGrp === x[0] ? ' class="on"' : '') + '>' + x[1] + '<i>' + x[2] + '</i></button>'; }).join('') + '</div>';
}
function rewardHTML(sm) {
return '<button type="button" class="rw' + (sm ? ' sm' : '') + '" data-rule="1"><span class="gf"><svg class="ic"><use href="#i-gift"/></svg></span>' +
@@ -726,9 +753,10 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
}
function renderHead() {
var t = TBY[cur], el = $('#head'), fh = $('#fh');
if (catF === 'ceshi') { el.innerHTML = ceshiHead(); ceshiFh(fh); return; }
if (!t) {
var hl = hotList();
el.innerHTML = qifuHTML() + ceshiHTML() +
el.innerHTML = qifuHTML() +
'<div class="sh"><svg class="fire"><use href="#i-fire"/></svg><h2>热门话题</h2><button type="button" class="more" data-all="1">全部 ' + hl.length + ' 个<svg class="ic" style="width:13px;height:13px"><use href="#i-right"/></svg></button></div>' +
/* 11-02 用户:「热门话题不要一块一块的,改成井号、偏列表的形式」→ 排行列表:名次 + #话题# + 一行简介 + 篇数/热,右侧「参与」
投稿奖励从顶部大横幅挪到这里当列表头一行(用户:「30 现金 + 500 兜豆看放哪」→ 跟「参与」放一起,点了看规则) */
@@ -773,7 +801,30 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
wf.style.setProperty('--cw', cw + 'px');
/* 真瀑布流:每张卡放进当前更矮的那一列(逐张量高,标题一行/两行也算进去) */
var hs = [0, 0], tmp = document.createElement('div'), STY = ['', 'ov', '', '', 'tg', '', '', 'ov', '', 'tg', '', ''];
if (catF === 'ceshi') {
var done = csDone();
TM.filter(function (x) { return !tGrp || x.group === tGrp; }).forEach(function (x, k) {
tmp.innerHTML = testCardHTML(x, done);
var el = tmp.firstChild; el.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
var c = hs[0] <= hs[1] ? 0 : 1; cols[c].appendChild(el); hs[c] += el.offsetHeight + 8;
});
$('#more').innerHTML = ''; return;
}
/* 「全部」信息流:按 CS_AT 位置穿插测试卡 */
if (!cur && !catF && TM.length) {
var dn = csDone(), mixed = [], ci = 0;
list.forEach(function (n, k) { while (ci < CS_AT.length && CS_AT[ci] === mixed.length) { if (TMBY[CS_MIX[ci]]) mixed.push({ test: TMBY[CS_MIX[ci]] }); ci++; } mixed.push(n); });
list = mixed;
}
var nk = 0;
list.forEach(function (n, k) {
if (n.test) {
tmp.innerHTML = testCardHTML(n.test, dn);
var te = tmp.firstChild; te.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
var tc0 = hs[0] <= hs[1] ? 0 : 1; cols[tc0].appendChild(te); hs[tc0] += te.offsetHeight + 8;
return;
}
k = nk++;
tmp.innerHTML = cardHTML(n, !cur, STY[k % STY.length]);
var el = tmp.firstChild; el.style.animationDelay = Math.min(k, 10) * 30 + 'ms';
var c = hs[0] <= hs[1] ? 0 : 1;
@@ -878,6 +929,8 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
sc.addEventListener('touchcancel', function () { if (mode === 'h') { pane.style.transform = ''; pane.style.opacity = ''; moveBar(); } ok = false; }, { passive: true });
})();
$('#fh').addEventListener('click', function (e) {
var tg = e.target.closest('[data-tg]');
if (tg) { tGrp = tg.dataset.tg; haptic(); ceshiFh($('#fh')); renderFeed(); return; }
var b = e.target.closest('[data-t]'); if (!b || b.dataset.t === cur) return;
haptic(); var sl = $('#fh .tcs') ? $('#fh .tcs').scrollLeft : 0;
selectTopic(b.dataset.t, false);
@@ -886,7 +939,6 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
$('#more').addEventListener('click', function (e) { if (e.target.closest('[data-t]')) { haptic(); selectTopic(''); } });
$('#head').addEventListener('click', function (e) {
if (e.target.closest('#qfBanner')) { goQifu(); return; }
var csb = e.target.closest('[data-cs]'); if (csb) { haptic(); location.href = ceshiURL(csb.dataset.cs); return; }
var j = e.target.closest('[data-join]'); if (j) { haptic(); openRule(j.dataset.join); return; }
if (e.target.closest('[data-rule]')) { openRule(''); return; }
if (e.target.closest('[data-all]')) { openTopics(); return; }
@@ -948,6 +1000,8 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
});
}
$('#wf').addEventListener('click', function (e) {
var ts = e.target.closest('[data-test]');
if (ts) { haptic(); location.href = ceshiURL(ts.dataset.test, catF === 'ceshi'); return; }
var lk = e.target.closest('[data-like]');
if (lk) { e.stopPropagation(); toggleLike(lk.dataset.like); syncCardLike(lk.dataset.like); return; }
var c = e.target.closest('.nc');
@@ -1311,7 +1365,7 @@ button{font:inherit;color:inherit;border:0;background:none;padding:0;cursor:poin
/* ---------- 启动 ---------- */
var deep = new URLSearchParams(location.search).get('n'); /* 先读:selectTopic 会 replaceState 把 n 去掉 */
var c0 = new URLSearchParams(location.search).get('c');
if (CAT_ORDER.indexOf(c0) >= 0) catF = c0;
if (CAT_ORDER.indexOf(c0) >= 0 || c0 === 'ceshi') catF = c0;
selectTopic(param('t') && TBY[param('t')] ? param('t') : '', false);
if (deep && NBY[deep]) openNote(deep, false);
loadApproved();