fix(占位/来信): 工具卡演示占位归中性 + 档案屏空态 + 修来信「红点有、卡没有」(v26092210)

一、占位数据(新用户实测)
- 首页工具卡:孕期体重「58.2kg」是写死的演示值(后端也确无体重数据源,
  GET /records 只给当日聚合)→ 改中性占位 '--';数胎动「今天 3 次」默认
  3 在访客态/records 失败时没人覆盖 → HTML 默认 '--'、state.kickToday 改 0。
- 孕检日历 #calNext:init 先按内置默认(预产期=今天+3月 → 孕27周)写下
  演示日期,而 pregEmpty 分支只清 [data-ga]/[data-wk] 两种钩子、**漏了它**
  (它没有这两种属性),applyRemoteProfile 又提前 return → 假日期留在首页。
  两条空态分支各补一行显式归 '--'。
- 档案屏「成长数据」:三张统计卡 + 体重曲线 + 双顶径/股骨长/腹围等测量值
  全部无接口数据源,空态(未建档/产后)整块隐藏改显示引导;#favCount 从
  写死的 18 改为按 DOM 里点亮的星标实时统计(18 与屏幕上的 6 张对不上)。
  ⚠️ 该屏真机到不了(go('archive') 无条件跳 chanjian-rili),属防御性改动。
- **明确不动**的两处真实数据,都已加注释防止再被当演示值删掉:
  · 指南区「128 份孕育资料」= 后端准备总数(按孕周陆续发放,目前上架 8 份,
    其余可扫码找小助手索要)——「数字与列表条数不符」是对的;
  · 三张卡「12.8 / 20.4 / 9.6 万妈妈已领取」= 真实领取量(手工同步的静态文案)。

二、宝宝来信「tab 红点有、首页提醒卡没有」
根因:syncPregnancy 的未建档分支里那句 hideLetterCard() 只藏卡、**不动 #tabBadge**,
而它旁边的理由(「applyLaixinReminder 里也判 pregEmpty」)是错的 —— 后者明确
故意不看 pregEmpty(来信与建档是两件事,历史上加过一版就是这个症状)。
于是 laixin 先回来(亮红点 + 显示卡)、/profile 后回来(走该分支)时,卡被藏回去、
红点留下。定时复现:profile 延迟 1.5s 必现(卡内文案已写好却带 .hide,即「先显示后被藏」);
同时返回则正常。删掉那句后 0/1.5/3s 三档都一致;未读 0 与访客态仍两者都收。
This commit is contained in:
2026-09-22 21:12:19 +08:00
parent e349907463
commit ab8a3a5ea0
3 changed files with 95 additions and 17 deletions

View File

@@ -7,7 +7,7 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>兜爸心选 · 孕育陪伴</title>
<!-- V:26092207 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
<!-- V:26092210 缓存版本标记:改 css/js 时同步 bump 该值(与 js/app.js 的 VER 同源),静态资源按 mtime 走 ETag 自动刷新 -->
<link rel="stylesheet" href="mama-box.css">
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<!-- 共享助手:授权/跳商城/位置上报(分享卡片同步,见 docs/h5-auth-standard.md 第四节) -->
@@ -200,7 +200,11 @@
<button class="mini-card kick ripple" data-mini="kick">
<div class="mc-head">
<div class="mc-title">数胎动</div>
<div class="mc-sub">今天 <b id="kickTodayHome">3</b> 次</div>
<!-- ⚠️ 默认值必须是中性占位,**不能写演示数字**:访客态(无 openid)与
records 接口失败/超时这两种情况下没人会改它,写死 3 就是假数据。
真实值由 __applyRecords() 写入(未记录的新用户是 0)。
(2026-09-22 新用户实测:工具卡上的演示占位值一律归中性。) -->
<div class="mc-sub">今天 <b id="kickTodayHome">--</b> 次</div>
</div>
<span class="mc-btn">记录</span>
<img class="mc-art" src="assets/img/7980160b80b0.png" alt="" aria-hidden="true">
@@ -225,7 +229,13 @@
<button class="mini-card weight ripple" data-mini="weight">
<img class="mc-art big" src="assets/img/b2066fd752bf.png" alt="" aria-hidden="true">
<div class="mc-title">孕期体重</div>
<div class="mc-big">58.2 <small>kg</small></div>
<!-- ⚠️ 这里原来是写死的演示值「58.2 kg」,**任何用户**(含未建档案的新用户)
都会看到 —— 属演示数据泄漏(2026-09-22 新用户实测)。
体重目前**没有数据源**:GET /records 只返回当日聚合(kickCount/total),
没有「最近一次体重」字段。所以先给中性占位 '--',与右列「数宫缩」
卡的 data-wk 占位同一口径(不要写成 0,0 是个看着像真的假值)。
将来接入真实体重:给这行加 id 并由 JS 写(同时把 <small>kg</small> 补回来)。 -->
<div class="mc-big">--</div>
</button>
<div class="bento-col">
<button class="mini-card cal ripple" data-mini="cal">
@@ -345,8 +355,6 @@
封面给了固定高度(80px + object-fit:contain),底行靠
.sb-row{margin-top:auto} 顶到卡底,中间的简介统一截两行,
三张就自然等高、四段横着都成列了。
简介和「x 万妈妈已领取」都直接取自 js/app.js 里 RES 的同名字段,
和资源详情页显示的是同一份文案,不是这里另编的。
⚠️ 原来第一张那颗「立即领取」删掉了:整张卡本身就是个 <button>,
点哪儿都是进详情页,那颗 span 长得像按钮却并不真的领取,是个假承诺;
而且三张卡并列时三颗橙色大按钮也太吵。领取动作留在详情页底部。
@@ -358,7 +366,14 @@
assets/ 里没有人像图,也不该为这点装饰新增二进制资源,
所以整叠头像是纯 CSS 画的(圆底 + ::before 头 + ::after 肩)。
aria-hidden:读屏念到这行应该只听见「12.8 万妈妈已领取」,
而不是六个没有内容的空节点。 -->
而不是六个没有内容的空节点。
⚠️ 上面那三个数(12.8 / 20.4 / 9.6 万)是**真实领取量**,不是编的 ——
2026-09-22 有人按「人气数看着像演示值」把它们连同头像叠一起删了,
属**误判**,已恢复。**别再删**。它们是**手工同步的静态文案**:
接口虽返回同源的 got(已领),但 __applyResources 明确「有意不读」
(9.19 起 H5 已无「已领」概念),所以更新领取量时要**手工改这三处**;
要改成读接口,得先把这个口径捋清再动。 -->
<div class="shelf-rail">
<button class="shelf-book sb-book ripple" data-open="detailRes" data-res="book">
<img class="sb-cover" src="assets/img/9f3fa8edf4aa.png" alt="" aria-hidden="true">
@@ -384,7 +399,14 @@
#shelfLeadTxt 靶子和该函数一起删了)。
旁边「查看全部 ›」是个 <a data-open>,它的点击监听是 init 时一次性
绑上去的 —— 谁要是图省事对整个 <p> 写 innerHTML,链接会连同监听被静默
换掉(看着一模一样,就是点不动),别再引入这种写法。 -->
换掉(看着一模一样,就是点不动),别再引入这种写法。
⚠️ 128 是**后端准备好的资料总数**,不是「资源列表里当前有多少条」——
2026-09-22 有人按「数字与列表条数不符」把它改成 RES 的条数,属**误判**,已回退:
· 资料按孕周陆续发放,目前上架 8 份,其余会陆续跟进;
· 没上架的**并非拿不到** —— 扫码加小助手可以直接索要(见顾问二维码弹窗)。
所以「128 份等你来领」是邀请口径(含找小助手要的),跟「列表当前 8 条」
是两件事,**数字不一样是对的**,别再"修"。 -->
<p class="unlock"><b>128</b> 份孕育资料等你来领 · <a data-open="detailResList">查看全部 ›</a></p>
</section>
</div>
@@ -481,13 +503,21 @@
<button class="seg-btn is-active" data-seg="data">成长数据</button>
<button class="seg-btn" data-seg="timeline">时光轴</button>
<!-- 收藏数原本在下面那行 sec-title 里,那行整条删了,
数字搬到标签上(和分段控件里其它计数同一种写法),#favCount 仍由 JS 更新 -->
<button class="seg-btn" data-seg="moment">珍贵时刻 <i id="favCount">18</i></button>
数字搬到标签上(和分段控件里其它计数同一种写法),#favCount 仍由 JS 更新。
⚠️ 这里原来写死 18,而屏幕上点亮的星标只有 6 个 —— 数字与内容对不上。
现在默认 0,由 app.js 启动时按 DOM 里 `.star.is-on` 的**实际个数**回填
(档案页不是首屏,用户看不到中间态;点星标时再 ±1)。 -->
<button class="seg-btn" data-seg="moment">珍贵时刻 <i id="favCount">0</i></button>
</div>
<!-- 成长数据 -->
<div class="seg-panel is-active" data-panel="data">
<div class="stat-row">
<!-- ⚠️ 空态(未建档 / pregEmpty):syncPregnancy 会给本面板加 .is-empty,
把下面三块**全无数据源**的演示内容整块隐藏,改显示这行引导。
三块里没有一个数字来自接口:58.2kg / 31 次 / 600g / 双顶径 6.1cm 都是设计稿数字,
未建档用户看到就是纯假数据(2026-09-22 实测)。 -->
<div class="data-empty">还没有可统计的记录<br>去「数胎动」或「孕期体重」记一笔,这里会生成趋势</div>
<div class="stat-row data-demo">
<div class="stat-card">
<div class="sc-label">体重</div>
<div class="sc-value">58.2<small>kg</small></div>
@@ -508,7 +538,7 @@
</div>
</div>
<div class="chart-card">
<div class="chart-card data-demo">
<div class="cc-title">妈妈体重 · 孕12–24周</div>
<svg class="chart" viewBox="0 0 320 150">
<line class="grid" x1="4" y1="20" x2="316" y2="20"/>
@@ -524,7 +554,7 @@
<div class="cc-legend"><span class="lg lg-line">我的体重</span><span class="lg lg-band">推荐区间</span></div>
</div>
<div class="meas-card">
<div class="meas-card data-demo">
<div class="meas"><span class="m-name">双顶径</span><div class="m-bar" style="--p:54%"><i></i></div><div class="m-val">6.1<small>cm</small><em>P58</em></div></div>
<div class="meas"><span class="m-name">股骨长</span><div class="m-bar" style="--p:50%"><i></i></div><div class="m-val">4.4<small>cm</small><em>P52</em></div></div>
<div class="meas"><span class="m-name">腹围</span><div class="m-bar" style="--p:60%"><i></i></div><div class="m-val">19.6<small>cm</small><em>P61</em></div></div>

View File

@@ -3,7 +3,7 @@
(function () {
'use strict';
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
var VER = '26092207';
var VER = '26092210';
const $ = (s, c) => (c || document).querySelector(s);
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
@@ -45,10 +45,12 @@
/* ---------- 全局状态 ---------- */
const state = {
screen: 'home',
kickToday: 3,
kickToday: 0, /* ⚠️ 原为演示值 3:访客态/接口失败时它会直接落到首页数胎动卡上,
现已改 0 且 HTML 默认渲染 '--'(真实值由 __applyRecords 写) */
kickQuick: 1,
todayCount: 4,
favCount: 18,
favCount: 0, /* ⚠️ 原为演示值 18(与屏幕上的星标数不符);
启动时按 DOM 里 .star.is-on 的实际个数回填,见「珍贵时刻收藏」那段 */
resCat: 'all',
resKey: 'book',
resFav: [], // 已收藏的资源 key,数组顺序即收藏顺序
@@ -505,6 +507,12 @@
});
/* ================= 珍贵时刻收藏 ================= */
/* ⚠️ 计数不能写死(原来 #favCount=18、state.favCount=18,而屏幕上点亮的星标只有 6 个,
数字与内容对不上)。启动时按 DOM 里 `.star.is-on` 的**实际个数**回填,
点星标时再 ±1 —— 这样标签上的数永远等于卡上看得见的收藏。
(档案页不是首屏,用户看不到"先 0 再回填"的中间态。) */
state.favCount = $$('.star.is-on').length;
(function () { const fc = $('#favCount'); if (fc) fc.textContent = state.favCount; })();
$$('.star').forEach(st => st.addEventListener('click', e => {
e.stopPropagation();
const on = st.classList.toggle('is-on');
@@ -1006,6 +1014,15 @@
}
/* 把 state 里的孕期信息刷到「我的」孕期卡 + 首页头部 + 档案页顶部 */
/* 成长数据面板的空态开关(CSS 见 mama-box.css 的 .data-empty 段):
未建档 / 产后 = 面板里那些数字(58.2kg、日均胎动 31 次、双顶径 6.1cm、体重曲线)
**一个都没有接口数据源**,对这类用户是纯假数据 → 整块隐藏改显示引导。
⚠️ 有真实孕周的用户仍看演示值:这是与「AI 小结演示文案」同一批的遗留,
要一起清得先有数据源,别只在这里删。 */
function setGrowthDataEmpty(on) {
const p = $('.seg-panel[data-panel="data"]');
if (p) p.classList.toggle('is-empty', !!on);
}
function syncPregnancy() {
/* ---- 产后态:宝宝已出生 → 一律不显示孕周数字(2026-09-22) ----
⚠️ 必须放在 pregEmpty 之前:产后返回体的 week 也是 null,
@@ -1060,6 +1077,12 @@
const gwt = $('#genWeekTag'); if (gwt) gwt.textContent = '产后';
$$('[data-ga]').forEach(n => { n.textContent = '--'; });
$$('[data-wk]').forEach(n => { n.textContent = '--'; });
/* ⚠️ #calNext(首页「孕检日历」卡)**没有 data-wk / data-ga 钩子**,上面两条循环抓不到它。
而 init 早已按内置默认(孕 27 周)把它写成「9月29日」这类演示日期,
产后分支之后没人再改 → 会以假日期留在首页。这里显式归占位。
(2026-09-22 新用户实测:孕检日历 9月29日 / 孕期体重 58.2kg 两处漏网。) */
const _cnPost = $('#calNext'); if (_cnPost) _cnPost.textContent = '--';
setGrowthDataEmpty(true); /* 产后同样没有这些数据的来源,别留演示数字 */
syncBabyWords();
return;
}
@@ -1105,13 +1128,30 @@
不保留 HTML 里的演示默认值(孕27周/9月15日…) */
$$('[data-ga]').forEach(n => { n.textContent = '--'; });
$$('[data-wk]').forEach(n => { n.textContent = '--'; });
/* ⚠️ 上面注释里的「孕检日历」**并不被那两条循环覆盖**:#calNext 没有 data-wk / data-ga
属性,选择器抓不到。而 init 早已按内置默认(孕 27 周)把它写成「9月29日」,
且 applyRemoteProfile 在 pregEmpty 时提前 return —— 于是新用户首页上
只剩这一个孕周派生的假日期(2026-09-22 实测)。这里显式归占位。 */
const _cn = $('#calNext'); if (_cn) _cn.textContent = '--';
setGrowthDataEmpty(true);
const _t = new Date();
$('#noteWhen').textContent = mdTxt(_t);
syncBabyWords();
hideLetterCard();
/* ⚠️ 这里**不能** hideLetterCard()(2026-09-22 修「红点有、首页卡没有」):
本分支(未建档)原来顺手把来信卡收起了,理由是「applyLaixinReminder 里也判 pregEmpty」
—— 那个理由**是错的**:applyLaixinReminder 明确故意不看 pregEmpty(见它的注释),
来信卡与红点的唯一 owner 是 syncLaixinReminder → applyLaixinReminder。
两边规则打架的后果是一个**竞态**:
· laixin 先回来(快)→ 红点亮 + 卡显示;
· /profile 后回来(它可能要先打上游用户中心,常见更慢)→ 走到这里 → 只把卡藏了。
而 hideLetterCard() **不动 #tabBadge** → 最终「红点在、卡没有」,与「红点说有新信、
卡里什么都没有」那类自相矛盾的屏完全一致(定时复现:profile 延迟 1.5s 必现;
同时返回则正常。卡里的文案已经写好、只是被 .hide 盖住,正是「先显示后藏掉」的痕迹)。
卡在 HTML 里**默认就是 .hide + .no-letter**,不需要谁来收;让它只由 laixin 结果决定。 */
return;
}
const week = state.week, day = state.day, name = state.babyName;
setGrowthDataEmpty(false); /* 有真实孕周了:恢复面板(数据源接入前仍是演示值,见函数注释) */
const _tl2 = document.querySelector('.today-line');
if (_tl2) _tl2.style.display = '';
const days = week * 7 + day; // 一起生活了多少天
@@ -2756,7 +2796,8 @@
state.due = null; state.week = null; state.day = null;
state.babyName = ''; state.userName = '';
syncPregnancy(); /* 占位 + 隐藏脚印时间轴 */
/* 首页来信卡归 laixin(applyLaixinReminder 里也判 pregEmpty/无身份),这里直接收起 */
/* 首页来信卡归 laixin(红点与卡都由 syncLaixinReminder 一处落,见它的无 openid 早退分支),
这里直接收起是**兜底**:访客态不该出现任何「你有新信」的暗示。 */
hideLetterCard();
return;
}

View File

@@ -1021,6 +1021,13 @@ a.skip:focus{left:16px;top:16px}
.seg-panel.is-active{display:block;animation:fadeUp .38s var(--ease)}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
/* 成长数据空态(未建档):.is-empty 由 syncPregnancy 的 pregEmpty 分支挂上。
演示数字(体重 58.2kg / 日均胎动 31 次 / 双顶径 6.1cm / 体重曲线…)全部无接口数据源,
对未建档用户是纯假数据,整块隐藏改显示引导;健康态下这层完全不参与,原型观感不变。 */
.data-empty{display:none;font-size:13px;color:var(--ink-2);line-height:1.9;text-align:center;padding:26px 18px;background:#fff;border-radius:22px;box-shadow:var(--sh)}
.seg-panel[data-panel="data"].is-empty .data-demo{display:none}
.seg-panel[data-panel="data"].is-empty .data-empty{display:block}
/* 时光轴 */
.tl-card{background:#fff;border-radius:22px;padding:20px 18px 6px;box-shadow:var(--sh)}
.tl-item{position:relative;padding:0 0 24px 22px}