v26110805 首页孕期假数据与加载性能修复——接口未返回/失败时不再按默认预产期显示假孕周(显示正在加载/点击重试);去掉演示名小汤圆/小满妈妈,空昵称小名不提交,孕期未加载时禁止保存;预产期范围校验(今天-14天~+280天,仅改动时校验);「已连续记录42天」写死值改为「和宝宝一起走过N天」,去掉我的页设计稿占位;/profile+/pregnancy 改为脚本解析时预取(原来等 window load 约10秒后才发),birth-flow 复用、ugc 的 /config 合并;首页广场图改用缩略图(首页图片约4MB→1.9MB)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
deploy
2026-11-08 14:13:15 +00:00
parent c8755223b2
commit 95a24ca21c
381 changed files with 135 additions and 58 deletions

136
js/app.js
View File

@@ -3,7 +3,7 @@
(function () {
'use strict';
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
var VER = '26110804';
var VER = '26110805';
const $ = (s, c) => (c || document).querySelector(s);
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
@@ -54,7 +54,9 @@
resCat: 'all',
resKey: 'book',
resFav: [], // 已收藏的资源 key,数组顺序即收藏顺序
babyName: '小汤圆',
/* 2026-11-08(测试会话 150e0991):原为演示名「小汤圆」。资料还没回来时打开「我的资料」点保存,
会把它当真名 PUT 进库(实测 body.babyName='小汤圆')。初值留空,称呼走 babyWord() 的「宝宝」兜底。 */
babyName: '',
/* 这三项一进门就是真值(默认预产期 = 今天 +3 个月,见上面 DEFAULT_DUE)。
以前它们是写死的占位 24/3/null,等 init() 才补 —— 但那之前就有按孕周
现算的展示(首页孕周环、档案页),拿到的就全是假的。 */
@@ -73,7 +75,7 @@
那正是下面 userBio 那条注释警告过的「最难发现的死代码」。
将来要恢复它,除了 state 字段,还得补上「选图 → 压缩(canvas 缩到 ~128px
再 toDataURL,原图可能几 MB)→ localStorage 落盘」这几步。 */
userName: '小满妈妈',
userName: '', /* 同上:原为演示昵称「小满妈妈」,会被回填进表单再存进库 */
/* ⚠️ 这里原来还有一条 userBio(一句话签名)。整块已按用户要求删除,
连同 #pfBio 输入框、#meBio 展示行、syncBio()。别只加回这一条 ——
一个没人读的 state 字段是最难发现的死代码。 */
@@ -413,7 +415,7 @@
}
/* 现在孕几天;拿不准(访客、未建档、产后)返回 null → 不拦 */
function knownGA() {
if (state.postpartum || state.pregEmpty || state.week == null) return null;
if (state.postpartum || state.pregEmpty !== false || state.week == null) return null;
return state.week * 7 + (state.day || 0);
}
function stageLocked(g) { const ga = knownGA(); return !!g && ga != null && ga < g.wk * 7; }
@@ -1658,7 +1660,9 @@
pgWeek.value = '';
pgDay.value = '';
lockWeekFields(true);
} else if (state.due) {
} else if (state.due && state.pregEmpty === false) {
/* ⚠️ 只认 /pregnancy 已确认的预产期(pregEmpty === false):接口没回来/失败时 state.due 还是
内置默认(今天 +3 个月),回填进表单再一保存,假预产期就进库了(2026-11-08) */
pgDue.value = toISO(state.due);
const ga = gaFromDue(state.due);
pgWeek.value = Math.floor(ga / 7);
@@ -1976,12 +1980,15 @@
/* 把当前孕期状态广播给首页彩蛋 js/bump.js(宝宝在肚皮底下动按孕周分阶段,2026-10-04)。
syncPregnancy 有好几个提前 return 的分支,所以用微任务等它整个跑完再发,拿到的是最终状态。 */
function pubPreg() {
const d = { week: (state.postpartum || state.pregEmpty) ? null : state.week, day: state.day,
postpartum: !!state.postpartum, empty: !!state.pregEmpty,
due: (state.due && !state.pregEmpty) ? [state.due.getFullYear(), state.due.getMonth() + 1, state.due.getDate()] : null }; // 2026-10-04 头图星座牌按预产期算
/* pregEmpty 只有 === false 才算「孕周已确认」:undefined(接口没回来/失败)时 state.week 是 DEFAULT_DUE 推的假值,
原来照发给头图,星座牌就挂出「水瓶宝宝」(2026-11-08) */
const _ok = state.pregEmpty === false && !state.postpartum;
const d = { week: _ok ? state.week : null, day: state.day,
postpartum: !!state.postpartum, empty: !state.postpartum && state.pregEmpty !== false,
due: (state.due && _ok) ? [state.due.getFullYear(), state.due.getMonth() + 1, state.due.getDate()] : null }; // 2026-10-04 头图星座牌按预产期算
window.__mbPreg = d;
/* 11-02 孕妈广场页(guangchang/)按孕周段排帖子,它不加载 app.js,靠这个键拿孕周:{w 孕周|0, pp 产后} */
try { localStorage.setItem('mmbox.gcwk.v1', JSON.stringify({ w: d.week || 0, pp: d.postpartum ? 1 : 0 })); } catch (e) {}
if (state.pregEmpty !== undefined || state.postpartum) try { localStorage.setItem('mmbox.gcwk.v1', JSON.stringify({ w: d.week || 0, pp: d.postpartum ? 1 : 0 })); } catch (e) {}
window.dispatchEvent(new CustomEvent('mb-preg', { detail: d }));
}
function syncPregnancy() {
@@ -2051,16 +2058,21 @@
}
/* ---- 新用户空态:未完善资料(无预产期)→ 全部显示引导占位,不读演示数据 ----
me 页已有两条引导(授权卡 + 孕期信息必填卡);这里把首页/档案页的
孕周数字换成引导文案,避免新用户看到"孕 27 周"这类假数据。 */
if (state.pregEmpty) {
孕周数字换成引导文案,避免新用户看到"孕 27 周"这类假数据。
2026-11-08(测试会话 150e0991):pregEmpty 还是 undefined(/pregnancy 没回来 / 失败)也走这里。
原来这时落到下面的正常分支,按 DEFAULT_DUE(今天 +3 个月)画出「26 周+6 天 · 距离见面 92 天 ·
孕检日历 11月16日」一整套假数据;接口挂了它就一直留在首页,用户会当成自己的。
现在三种文案:未建档 → 引导填预产期;加载中 → 「正在加载」;失败(state.pregFail)→ 点击重试。 */
if (state.pregEmpty !== false) {
const nm = state.babyName || '宝宝';
const _unk = state.pregEmpty === undefined, _fail = _unk && state.pregFail;
/* 脚印时间轴:未建档整块隐藏 —— 交给 fpRender() 统一判(它同时看 footprint 的结论),
别再直接改 display:与本模块的另一个 owner 撞竞态(2026-09-22 实测漏过 degraded 场景)。 */
fpRender();
/* ① 我的 · 孕期卡 → 引导 */
$('#pcTitle').textContent = OUT() ? '已退出登录' : '待完善孕期信息';
$('#pcTitle').textContent = OUT() ? '已退出登录' : _fail ? '孕期信息没加载出来' : _unk ? '正在加载孕期信息…' : '待完善孕期信息';
setMeTag('');
$('#pcSub').textContent = OUT() ? '登录后查看你的孕期信息和记录' : '填好预产期,开启孕期陪伴';
$('#pcSub').textContent = OUT() ? '登录后查看你的孕期信息和记录' : _fail ? '网络不太好,点首页顶部重试' : _unk ? '' : '填好预产期,开启孕期陪伴';
$('#pcBar').style.setProperty('--p', '0%');
const rg = $('#pcRing');
if (rg) {
@@ -2076,18 +2088,18 @@
$('#heroPlus').textContent = '';
$('#heroDays').textContent = '--';
$('#heroWho').textContent = nm;
setHero({ due: OUT() ? '登录后查看宝宝这周的变化' : '填好预产期,开启倒计时', emoji: '🌱', hi: 'sprout', size: '', pct: 0 });
setHero({ due: OUT() ? '登录后查看宝宝这周的变化' : _fail ? '<u class="hero-retry">没加载出来,点这里重试</u>' : _unk ? '正在加载…' : '填好预产期,开启倒计时', emoji: '🌱', hi: 'sprout', size: '', pct: 0 });
/* ③ 档案页 → 占位 */
$('#arTitleName').textContent = nm;
$('#arLine1').textContent = '完善孕期信息后开启';
$('#arLine1').textContent = _fail ? '孕期信息没加载出来' : _unk ? '正在加载…' : '完善孕期信息后开启';
$('#arDays').textContent = '--';
$('#arLine2').textContent = '先去「孕期档案」填预产期';
$('#arLine2').textContent = _fail ? '请稍后重新打开' : _unk ? '' : '先去「孕期档案」填预产期';
$('#arPct').textContent = '0%';
setArBar(0);
$('#genWeekTag').textContent = '--';
/* ⑤ 用户卡记录行:未完善 → 引导文案(数据源未定,先不给演示数字) */
const _rl = $('#meRecordLine');
if (_rl) _rl.textContent = '完善孕期信息,记录宝宝的成长记忆';
if (_rl) _rl.textContent = _unk ? '' : '完善孕期信息,记录宝宝的成长记忆';
/* ⑥ 孕期衍生的静态演示位(生长曲线周数/孕检日历/时光轴日期)一并归中性占位,
不保留 HTML 里的演示默认值(孕27周/9月15日…) */
$$('[data-ga]').forEach(n => { n.textContent = '--'; });
@@ -2200,9 +2212,10 @@
/* ④ 称呼:小名一改,全站写着小名的地方(首页三个模块名、来信提醒卡文案)跟着换 */
syncBabyWords();
/* ⑤ 用户卡记录行:已完善 → 保留「已连续记录 N 天」(数据源确认前先维持原型值) */
/* ⑤ 用户卡记录行:原为写死的「已连续记录 42 天」(原型值,所有人都一样、和记没记无关 —— 2026-11-08 测试会话 150e0991)。
连续记录天数没有数据源,改成按孕周算的真实天数;以后有了连续打卡接口再换回来。 */
const _rl2 = $('#meRecordLine');
if (_rl2) _rl2.innerHTML = '已连续记录 <b>42</b> 天';
if (_rl2) _rl2.innerHTML = '和宝宝一起走过 <b>' + days + '</b> 天';
/* ⑥ 页面里那些示例日期(时光轴、珍贵时刻、小卡、热词…)也按新孕周重刷。
改预产期会连带改孕周,这些跟着一起动才不会前后矛盾。 */
syncStaticDates();
@@ -2318,13 +2331,28 @@
一个按钮就该是一次原子的「保存」。 */
$('#pfSave').addEventListener('click', () => {
/* 预产期是一切的源头:孕周、剩余天数、信里的日期全从它算。没有它没什么可存的。 */
/* 2026-11-08:孕期信息还没拉到(接口慢/失败)时,表单里的预产期、小名都不可信,不让保存 */
if (hashParam('openid') && state.pregEmpty === undefined && !DEMO) {
toast('资料还没加载出来,请稍等几秒再保存');
return;
}
if (!parseDay(pgDue.value)) {
toast('先填一下预产期,孕周会自动算出来');
openPicker('week');
return;
}
const name = $('#pfName').value.trim() || '妈妈';
const babyName = pgName.value.trim() || '宝宝';
/* 预产期范围(2026-11-08 测试:选 2025-01-01 / 2027-12-31 都能存进库):
只校验**改过的**预产期 —— 没动过的旧值(例如已经超期几周的老用户)不拦,免得改个昵称都存不了。
下限 = 今天 -14 天(42 周封顶);上限 = 今天 +280 天(再往后就是「还没怀上」)。 */
if (pgDue.value !== filledDue || state.pregEmpty) {
const _d = parseDay(pgDue.value), _t = midnight(new Date());
const _left = Math.round((_d - _t) / DAY_MS);
if (_left < -14) { toast('预产期已经过去太久了,请检查一下日期'); openPicker('week'); return; }
if (_left > TERM) { toast('预产期离现在超过 40 周,请检查一下日期'); openPicker('week'); return; }
}
/* 空着不填就不改:原来兜底成「妈妈 / 宝宝」,会把这两个字当真名推给上游(2026-11-08) */
const name = $('#pfName').value.trim();
const babyName = pgName.value.trim();
const week = Math.min(42, Math.max(0, parseInt(pgWeek.value, 10) || 0));
const day = Math.min(6, Math.max(0, parseInt(pgDay.value, 10) || 0));
const sexBtn = $('#pgSex .pick.is-active');
@@ -2343,13 +2371,13 @@
⚠️ 这里原来还有一行 state.userBio = bio 和一次 syncBio() 调用。
一句话签名整块已按用户要求删除(输入框 #pfBio、展示行 #meBio、
syncBio()、state.userBio 四处一起删),别只加回其中一处。 */
if (!_unauth) {
if (!_unauth && name) {
$('#meName').textContent = name;
state.userName = name;
if (avatarUrl) { $('#meAvatar').classList.add('has-img'); meAvatarImg.src = avatarUrl; }
}
/* ---- 宝宝那半(原 #pgSave) ---- */
state.babyName = babyName;
if (babyName) state.babyName = babyName;
/* 2026-10-22:产后态孕周两格是空的(见上面回填),parseInt 出来是 0 → 原来会把 state.week 写成 0、
提示「孕 0 周」。产后不碰孕周,提示里也不带孕周 */
if (!state.postpartum) {
@@ -2364,7 +2392,7 @@
少调这一句,弹窗里改完了、外面还是旧数字,而且没有任何报错。 */
syncPregnancy();
closeModal();
setTimeout(() => toast('资料已更新 · ' + name + ' · ' + babyName +
setTimeout(() => toast('资料已更新 · ' + (state.userName || '妈妈') + ' · ' + (state.babyName || '宝宝') +
(state.postpartum ? '' : ' 孕 ' + week + ' 周' + (day ? '+' + day + ' 天' : ''))), 260);
}
@@ -2382,16 +2410,14 @@
}
function _putProfile(avatarUrl) {
if (!_oid) { applyLocal(avatarUrl); setBusy(false); return; }
var body = {
babyName: babyName,
babySex: babySex,
};
var body = { babySex: babySex };
if (babyName) body.babyName = babyName;
/* 预产期没改就不传:表单可能是几分钟前回填的,别的应用这期间改过的话会被旧值盖回去 */
var _due = due ? toISO(due) : '';
/* 2026-10-31:登记过出生的人在这里保存孕周 = 回到孕期 → 预产期没改也要传,后台据此把账号翻回孕期 */
var _wasPost = !!state.postpartum;
if (_due !== filledDue || _wasEmpty || (_wasPost && _due)) body.dueDate = _due;
if (!_unauth) body.userName = name;
if (!_unauth && name) body.userName = name;
if (avatarUrl && !_unauth) body.avatar = avatarUrl;
fetch('/api/mp/public/mama-box/profile?openid=' + encodeURIComponent(_oid), {
method: 'PUT',
@@ -4006,6 +4032,26 @@
window.addEventListener('pageshow', function (e) { if (e.persisted) refreshPregnancy(); });
let _profileApplied = false;
/* 11-08 资料预取(测试会话 150e0991):init() 挂在 window load 上,要等首页 4MB 图片全下完才开始拉
/profile + /pregnancy —— 实测资料 11~12 秒才落地,这之间首页一直是占位。
现在脚本解析时就把请求发出去,init 里 applyRemoteProfile 直接用这份结果(仍在 init 渲染之后才**写** state,
不违反下面那条「必须放在 init() 渲染之后」)。js/birth-flow.js 首次加载也复用它(window.__mbPfPre),不再各拉一遍。 */
function pfFetchPair(openid) {
const base = '/api/mp/public/mama-box/', u = hashParam('unionid');
const qs = 'openid=' + encodeURIComponent(openid) + (u ? '&unionid=' + encodeURIComponent(u) : '');
return Promise.all([
fetch(base + 'profile?' + qs).then(r => (r.ok ? r.json() : null)),
fetch(base + 'pregnancy?openid=' + encodeURIComponent(openid)).then(r => (r.ok ? r.json() : null))
]);
}
const _pfPre = (function () {
const o = hashParam('openid');
if (!o) return null;
const p = pfFetchPair(o);
p.catch(function () {}); /* 失败交给 applyRemoteProfile 的 catch,这里只防「未处理的 rejection」告警 */
window.__mbPfPre = { openid: o, p: p };
return window.__mbPfPre;
})();
/* ⚠️ 返回 Promise:调用方要**等资料落地**再取应用数据(预产期/小名来自上游同步,
它决定 state.pregEmpty,而今日脚印的显隐依赖它)。别改成 fire-and-forget。 */
function applyRemoteProfile() {
@@ -4036,19 +4082,14 @@
映射(Member),映射缺失的老用户(资料全靠 CRMEB 同步来的)会先取失败,
预产期/孕周永远预填不上,而第三方应用因为 URL 自带 unionid 一直有数据。
与 footprint/today 同款:hash 里有就带上,服务端成功后会回写映射。 */
const _pfUnionid = hashParam('unionid');
const _pfQs = 'openid=' + encodeURIComponent(openid) +
(_pfUnionid ? '&unionid=' + encodeURIComponent(_pfUnionid) : '');
/* (拼 openid + unionid 的查询串已挪进 pfFetchPair) */
/* 并行拉 个人档案 + 孕期状态:
- profile:babyName/userName/babySex/dueDate(身份 + 建档字段)
- pregnancy:week/day/due 以服务端权威派生为准(避免客户端重复算、口径统一)
拉不到(无 openid / 未返回 200 / 断网)就静默保持内置默认值,页面照常可用。 */
/* 走到这里说明这次加载是带身份的(openid 非空)→ 把上一次的提示收掉 */
hideIdNotice();
return Promise.all([
fetch(base + 'profile?' + _pfQs).then(r => (r.ok ? r.json() : null)),
fetch(base + 'pregnancy?openid=' + encodeURIComponent(openid)).then(r => (r.ok ? r.json() : null))
]).then(function (rs) {
return (_pfPre && _pfPre.openid === openid ? _pfPre.p : pfFetchPair(openid)).then(function (rs) {
const pj = rs[0], pg = rs[1];
if (pj && pj.code === 200 && pj.result) {
const p = pj.result;
@@ -4087,6 +4128,8 @@
}
}
applyPregnancy(pg);
/* /pregnancy 没拿到(非 200 / 断网)→ 标失败,syncPregnancy 显示「点这里重试」,别留默认孕周(2026-11-08) */
if (state.pregEmpty === undefined && !DEMO) state.pregFail = true;
if (DEMO) { // 示例模式:固定孕 29 周 0 天,预产期 = 今天 + (280 - 203) 天
state.postpartum = false; state.pregEmpty = false;
state.week = DEMO_WEEK; state.day = 0;
@@ -4103,11 +4146,18 @@
刚写好的占位会被改回「孕 27 周 / 9月15日」演示值。
⚠️ 产后态同样要拦:syncPregnancy 的产后分支已写好「已出生」与 '--' 占位,
而 state.week 是 null → syncStaticDates 会按 ga=0 算出**看着正常但全错**的日期。 */
if (state.pregEmpty || state.postpartum) { return; }
if (state.pregEmpty !== false || state.postpartum) { return; } /* 含 undefined:没拿到孕周,别按默认值重算日期 */
syncBabyWords();
syncStaticDates();
}).catch(function () { /* 静默回退内置值 */ });
}).catch(function () {
/* 2026-11-08:原为「静默回退内置值」—— 内置值就是今天 +3 个月推出来的假孕周,不能静默留着 */
if (state.pregEmpty === undefined && !DEMO) { state.pregFail = true; syncPregnancy(); }
});
}
/* 首页头图「没加载出来,点这里重试」 */
document.addEventListener('click', function (e) {
if (state.pregFail && e.target.closest && e.target.closest('.hero-retry')) { e.stopPropagation(); bustReload(); }
}, true);
/* ---------- 远程数据(box_app,统一改H5 · 第一批:资料库/记录/内容) ----------
applyRemoteProfile 已拉 profile/pregnancy/config;
@@ -4396,11 +4446,14 @@
背景一条虚线小路从每个头像脚下穿过,空地上零星散着几个在逛的小头像。隔一个气泡带照片(topics.js 的 ph);「全部」里都是热门,不再逐个挂「热」。 */
const CAT_CN = { family: '家庭婚姻', work: '职场', baby: '经验' };
const POOL = (window.MB_AVA && MB_AVA.S.gbWalk) || AVA_FEED.concat(AVA_TOP).filter(n => /^(p|m|mom-)\d/.test(n)); // 11-05 改用分配表 gbWalk(不和「此刻」撞)
/* 11-08:这块默认会被 js/gch/v6 整块换掉,但换之前 innerHTML 已经把 7 张 720×960 原图(约 800KB)拉下来了。
改用 guangchang/img/s/ 宽 200 的同名缩略图(见 guangchang/img/SOURCES.txt) */
const gbThumb = src => String(src || '').replace(/^guangchang\/img\/([0-9a-f]{12}\.jpg)$/, 'guangchang/img/s/$1');
function bubble(t, i, allHot) {
const ph = i % 2 === 0 && t.ph;
return '<button type="button" class="gb-b' + (ph ? ' ph' : '') + (t.hot ? ' hot' : '') + '" data-t="' + esc(t.id) + '" style="--c1:' + t.c[0] + ';--c2:' + t.c[1] + ';--ink:' + t.ink + ';--d:' + (i % 5) * -.8 + 's">' +
'<span class="gb-in">' +
(ph ? '<img class="gb-ph" src="' + esc(t.ph) + '" alt="" loading="lazy">' : '') +
(ph ? '<img class="gb-ph" src="' + esc(gbThumb(t.ph)) + '" alt="" loading="lazy">' : '') +
'<span class="gb-k">' + (CAT_CN[t.cat] || '') + (t.hot && !allHot ? '<em>热</em>' : '') + '</span>' +
'<span class="gb-n">' + esc(t.name) + '</span>' +
'<span class="gb-m"><i></i>' + kfmt(t.talk) + ' 人在聊</span></span>' +
@@ -5842,7 +5895,7 @@
if (!bank.length) { openTips(); return; }
/* 2026-11-02 按孕周排:生娃计算器 → 当前孕周段(按热度)→ 其余按库里顺序;分类条第 2 个是「孕 N 周」只看本段
⚠️ band 必须在用它的标题之前声明(11-02 曾写反 → const 暂时性死区报错,「查看全部」点了没反应) */
const band = (state.postpartum || state.pregEmpty) ? 0 : qaBand(state.week);
const band = (state.postpartum || state.pregEmpty !== false) ? 0 : qaBand(state.week);
$('#qaTitle').textContent = '其他孕妈也在搜';
/* 11-03 用户:「孕期百问列表太素、看的人少,做得有设计感一点」→
Banner 加头像叠 + 「N 万孕妈在这找答案」;前 3 条做成「本周热问」大卡(渐变名次 + 答案摘要);其余为卡片行:问题 + 分类彩签 + 火苗人数 + 一行答案摘要 */
@@ -6377,7 +6430,8 @@
sheetPaint = function () {
const n = new Date(Date.now() + 8 * 3600e3); // 北京时间
const wd = '日一二三四五六'[n.getUTCDay()];
const wk = state.week ? '孕' + state.week + '周' + (state.day ? '+' + state.day + '天' : '') + ' · ' : '';
/* 只认已确认的孕周:未建档/没加载出来时 state.week 是默认值(实测「孕26周+6天」,2026-11-08) */
const wk = (state.week && state.pregEmpty === false && !state.postpartum) ? '孕' + state.week + '周' + (state.day ? '+' + state.day + '天' : '') + ' · ' : '';
$('#skSub').textContent = wk + (n.getUTCMonth() + 1) + '月' + n.getUTCDate() + '日 周' + wd;
const r = _fpMode === 'rows' || _fpMode === 'guide' ? (_fpData || {}) : null;
const today = $('#skToday'), go = $('#skGo');

View File

@@ -395,6 +395,7 @@
}
}
var loadedOnce = false;
function load() {
if (DEMO) {
var t = midnight(new Date());
@@ -405,10 +406,14 @@
mountCards(); maybeAsk(); return;
}
if (!openid) return;
Promise.all([
/* 11-08:首次加载复用 app.js 已经发出去的 /profile + /pregnancy(window.__mbPfPre,顺序是 [profile, pregnancy]),
不再同一时刻各拉一遍;之后的重读(回到前台、保存资料后)照旧自己拉 */
var pre = !loadedOnce && window.__mbPfPre && window.__mbPfPre.openid === openid ? window.__mbPfPre.p : null;
loadedOnce = true;
(pre ? pre.then(function (r) { return [r[1], r[0]]; }, function () { return [null, null]; }) : Promise.all([
getJSON(API + 'mama-box/pregnancy?openid=' + encodeURIComponent(openid)),
getJSON(API + 'mama-box/profile?openid=' + encodeURIComponent(openid))
]).then(function (r) {
])).then(function (r) {
apply(r[0] && r[0].code === 200 ? r[0].result : null, r[1] && r[1].code === 200 ? r[1].result : null);
mountCards(); maybeAsk();
});

View File

@@ -6,6 +6,12 @@
if (!sec || !Array.isArray(T) || !T.length) return;
function init() {
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); };
/* 11-08 首页只显示小图:原图 720×960、70~160KB,首页一屏就拉了 2MB+。改用 guangchang/img/{s,m}/ 同名缩略图
(s 宽 200,m 宽 540;生成命令见 guangchang/img/SOURCES.txt)。缩略图缺了(新加的图还没生成)onerror 退回原图 */
var thumb = function (src, sz) {
var m = /^guangchang\/img\/([0-9a-f]{12})\.jpg$/.exec(src || '');
return m ? 'src="guangchang/img/' + sz + '/' + m[1] + '.jpg" onerror="this.onerror=null;this.src=\'' + src + '\'"' : 'src="' + esc(src) + '"';
};
var kfmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1).replace(/\.0$/, '') + '万' : n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : String(n); };
var ava = function (n) { return /:|^\//.test(n) && window.MB_AVA ? MB_AVA.src(n, '') : 'assets/img/mom/' + n + '.jpg'; }; /* 11-05 支持分配表编码 */
var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
@@ -61,7 +67,7 @@
function storyCard(n) {
var tp = TOP[n.t] || {}, cat = tp.cat || 'family';
return '<div class="g4-card st c-' + cat + '" data-t="' + esc(n.t) + '" data-n="' + esc(n.id) + '" role="button" tabindex="0">' +
'<img class="g4-ph" src="' + esc(n.photo) + '" alt="" loading="lazy" decoding="async" draggable="false">' +
'<img class="g4-ph" ' + thumb(n.photo, 'm') + ' alt="" loading="lazy" decoding="async" draggable="false">' +
'<span class="g4-k">' + CAT_CN[cat] + '</span>' +
'<span class="g4-bot"><b class="g4-tt">' + esc(n.title) + '</b>' +
'<span class="g4-by"><img src="' + ava(n.av) + '" alt="" loading="lazy" draggable="false"><em>' + esc(n.author) + '</em><i>' + esc(n.stage) + '</i>' +

View File

@@ -8,12 +8,18 @@
if (!sec) return;
var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = 'js/gch/v4.css?v=26110464';
document.head.appendChild(l);
var s = document.createElement('script'); s.src = 'js/gch/v4.js?v=26110464';
var s = document.createElement('script'); s.src = 'js/gch/v4.js?v=26110805';
s.onload = function () { if (sec.querySelector('.g4-foot')) merge(); else sec.addEventListener('gc4-ready', merge, { once: true }); }; /* v4 要先拉 feed.js 才渲染 */
document.body.appendChild(s);
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"/><path d="M12 19.5a2.6 2.6 0 01-2.6-2.6c0-1.6 1.3-2.5 2-3.6.3 1 .9 1.6 1.6 1.9.9.4 1.6 1.2 1.6 2.1A2.6 2.6 0 0112 19.5z" fill="#FFD36B"/></svg>';
var FIRE_W = '<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="#FFE07A"/></svg>';
/* 11-08 首页只显示小图:原图 720×960、70~160KB,首页一屏就拉了 2MB+。改用 guangchang/img/{s,m}/ 同名缩略图
(s 宽 200,m 宽 540;生成命令见 guangchang/img/SOURCES.txt)。缩略图缺了(新加的图还没生成)onerror 退回原图 */
function thumb(src, sz) {
var m = /^guangchang\/img\/([0-9a-f]{12})\.jpg$/.exec(src || '');
return m ? 'src="guangchang/img/' + sz + '/' + m[1] + '.jpg" onerror="this.onerror=null;this.src=\'' + src + '\'"' : 'src="' + esc(src) + '"';
}
function esc(t) { return String(t == null ? '' : t).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
function merge() {
@@ -99,7 +105,7 @@
var q = new URLSearchParams(location.search); q.set('n', x.id);
return '<a class="ms-it ripple g6-nt" href="' + esc('guangchang/?' + q.toString() + location.hash) + '"><i class="ms-no">' + (i + 1) + '</i>' +
'<span class="ms-m"><span class="ms-q">' + esc(x.title) + '</span>' + heat + '</span>' +
(x.photo ? '<img class="g6-ph" src="' + esc(x.photo) + '" alt="" loading="lazy">' : '<i class="ms-go">›</i>') + '</a>';
(x.photo ? '<img class="g6-ph" ' + thumb(x.photo, 's') + ' alt="" loading="lazy">' : '<i class="ms-go">›</i>') + '</a>';
}).join('');
all.textContent = '去广场看更多 ›';
all.classList.remove('hide');

View File

@@ -25,8 +25,10 @@
预览站想临时看效果用 ?gift=1 */
var pvSite = /\/mama-box-preview\//.test(location.pathname) && /[?&#]gift=1/.test(location.search + location.hash);
if (!pvSite) try { de.classList.toggle('gift-off', localStorage.getItem('mmbox.gift.v1') === '0'); } catch (e) {}
if (!pvSite) fetch('/api/mp/public/mama-box/config', { cache: 'no-store' })
.then(function (r) { return r.json(); })
/* 11-08:giftEnabled 和下面的 ugcEnabled 在同一个 /config 里,原来各发一次 → 合成一个请求 */
var cfgP = null;
function cfg() { return cfgP || (cfgP = fetch('/api/mp/public/mama-box/config', { cache: 'no-store' }).then(function (r) { return r.json(); })); }
if (!pvSite) cfg()
.then(function (j) {
var g = !(j && j.result && j.result.giftEnabled === false);
de.classList.toggle('gift-off', !g);
@@ -47,8 +49,7 @@
}
window.__mbUgcReady = new Promise(function (res) {
var t = setTimeout(function () { res(null); }, 4000);
fetch('/api/mp/public/mama-box/config', { cache: 'no-store' })
.then(function (r) { return r.json(); })
cfg()
.then(function (j) { clearTimeout(t); res(!!(j && j.result && j.result.ugcEnabled)); })
.catch(function () { clearTimeout(t); res(null); });
}).then(function (v) {