Commit Graph

281 Commits

Author SHA1 Message Date
dedce247e9 fix(今日脚印): 读不到不编数据 —— 四种显隐模式收口到 fpRender(唯一 owner)(v26092214)
产品口径(2026-09-22):
  · **无档案**(上游查无此人 / 本地未关联)→ 显示引导占位(#tlGuide:「还没有你的脚印 /
    去「数胎动」记一笔,这里就会长出你今天的脚印」)
  · **有档案** → 必须从接口读;**读不到就不显示**(整块 .today-line 收起),不再回退演示行

改动:
- index.html:删掉 4 条**写死的演示行**(胎动 12 次 / 体重 58.2kg / 产检提醒 / 睡前散步 20 分钟)——
  它们只在「接口读不到」时露出来,等于上游一抖页面就开始编数据。换成一行中性「正在获取今天的脚印…」
  +新增 #tlGuide 引导块,并在注释里写明四种模式与判定。
- 新增 fpApply()/fpRender():模块显隐**只有一个 owner**(pending / rows / empty / guide / hide,
  外加「未建档 / 产后」硬门槛优先于接口结论)。
  ⚠️ 之前 syncPregnancy 也直接改 .today-line 的 display,两个 owner 撞出竞态 —— 实测「有档案 +
  上游故障(degraded)」会被 profile 回来后重新显示出来(该收起的没收起)。现在 syncPregnancy 两处
  都只调 fpRender()。
- 没有真实事件时给 .today-line 挂 .no-ai,AI 气泡一并收起:那句「今天你数到我动了 3 次」是写死的
  演示文案,今天没记 / 未关联 / 读不到时显示它就是在说假话。拿到真实事件时才显示气泡
  (把那个数字接到真实次数属另一件事,等产品定文案)。

本地验证(桩后端,五种模式各跑一遍,并把 profile 延迟 1.5s 以复现前面那个竞态):
  rows → 模块显示 + 真实事件 + 气泡显示;empty → 「还没有足迹」+ 无气泡;
  guide → 引导块显示 + 时间轴收起 + 无气泡;degraded → **整块不显示**;
  fail(接口 500) → **整块不显示**;未建档 → 整块不显示。全程无 JS 异常。
2026-09-22 23:48:44 +08:00
67b10aac00 docs(AGENTS): §4 补第 11 条 —— 首页 5 张工具卡的数据源与两条纪律(接口优先/失败回退、名称链接仍以 App 表为准) 2026-09-22 23:02:24 +08:00
d1fff2c248 feat(首页卡): 5 张工具卡改读 box_app 封装的真实数据(接口优先、失败回退本地)(v26092213)
数据源:GET /api/mp/public/mama-box/tool-cards(box_app 封装数胎动平台的 app-cards,
H5 不直连上游、不持有 token)。此前这 5 张卡各自为政:数胎动读本地 records(mama-box 早就不自记
胎动,常年 0)、体重恒 `--`、孕检日历本地按预产期推算、数宫缩显本地孕周、胎儿估重静态文案。

- 新增 applyRemoteCards() / applyRemoteCardsFetch():按 `slot` 落 DOM
  (kick→#kickTodayHome、fweight/curve→.mc-sub、weight→#weightVal、cal→#calNext);
  上游字符串一律 textContent,**绝不用 innerHTML**(同 footprint 的写法)。
- 优先级 = **接口优先、失败回退本地**。两个来源并行返回、先后不定,所以用 cardsOwned 旗子定序,
  而不是赌顺序:#kickTodayHome 让位给卡片接口;#calNext 让位(卡片接口与孕检日历应用同一套排期,
  还支持"改过预约日以预约日为准");curve 卡写值后**摘掉 data-wk**,否则 syncStaticDates 的
  [data-wk] 循环会把它覆盖回孕周。
- 卡片点击与名称仍以 App 表为准(MINI_APP_MAP + APP_BY_ID,AGENTS §4.4);接口的 appId/path 仅诊断
  (上游 app_id 是 URL slug,与 identifier 刻意不同)。
- 版式:固定高度 bento 只留一个状态位 → `.bento .mc-sub` 单行省略;数宫缩那列文本宽仅 ≈73px,
  有数据时改显紧凑 value(「4分12秒」,否则上游 text「最近间隔 4分12秒」会被省略掉数字);
  孕检日历放宽到两行(过期未记时上游给「待补记 9月26日」,一行会把日期省掉)。
- 新增 `.mc-extra`:只有 kick / weight 两张有富余竖空间,用来放上游 sub
  (「2 段 · 最近 13:00」/「较孕前 +11.7 kg · 9月22日」);fweight/cal/curve 是固定高度、放不下第二行,
  注释写明要加得先重排 .bento 那笔高度账(158+10+64=232)。
- warn → `.is-warn` 标红(新增 --alert token):胎动偏低 / 宫缩达临产阈值 / 产检过期未记。
- 体重卡:有值时写 value + 小字 unit(不会出现「-- kg」),无值保持中性 `--`。

本地验证(无头浏览器 + 桩后端):接口成功 → kick=12(覆盖本地 records 的 3)、weight=58.7kg +
「较孕前…」、cal=9月26日、curve=4分12秒、kick 标红、无 JS 异常;接口 ok=false → 全部回退本地
(kick=3 / weight=-- / curve 恢复 data-wk),页面不变空。
2026-09-22 23:01:51 +08:00
06f76b4df4 feat(身份): 同源身份缓存兜底 —— H5「返回首页」裸跳不再丢 openid/unionid (v26092212)
问题(实测孕检日历,第三方应用):页面里的「返回首页」是**页面自己发起的同源跳转**,
宿主的 <web-view src> 属性没变 → _applyIdentity() 不触发 → mama-box 的 URL 上没有身份
→ 只能显示「身份不完整」;而 retryIdentity() 只是 location.replace(自己 + 缓存戳),
同一条没有身份的 URL 重载,**永远救不回来**。而且该应用会主动把 openid/phone 从自己的
URL 上擦掉(防分享链接冒名,理由见它的注释)—— 所以那一跳**不可能**带上身份。

做法(方案已与产品确认;在架 12 个应用实测全在 mp.yizhezhe.com,同源共享 storage):
- js/wx-auth.js:新增 identity()(URL 优先 → 同源 sessionStorage 兜底,命中缓存打一条
  日志便于排查)、rememberIdentity()、goHome();并在**库载入时自动采一次**身份 ——
  接入方无需改代码,只要引了本库(孕检日历就引了,且它是绝对地址 + ETag 兜底,
  我们改库即可自动生效),宿主注入过的身份就会被存下来。
- js/app.js:hashParam() 对 openid/unionid 两键加同样的缓存回落(其余参数不受影响)。

三条纪律(写在 wx-auth.js 顶部,改前先读):
① URL 永远权威:URL 带 openid 就无条件覆盖缓存(否则切号/换人会串号);
② 只在本 origin 有效:外链应用读不到,所以「跳转要带身份」的规范不能删,缓存只兜底;
③ 只存 openid/unionid(身份键),不碰 token/手机号/昵称头像。
选 sessionStorage 而非 localStorage:同一次会话内够用,且随标签页结束即失效,暴露窗口小。

验证(本地同源:/app 模拟第三方页 + /mama-box 同一 origin):
  模拟应用页自动写缓存 → 裸跳 /mama-box/ → 提示条不显示、日志出现、按缓存身份拉数据;
  回归:无缓存且无身份 → 提示条照旧显示(fail-closed 保留);URL 带身份 → 缓存被写下且不显示提示条。
2026-09-22 21:36:52 +08:00
3ab8af2bf5 fix(来信提示): 未填孕产期不显示「宝宝来信」提示 —— 卡与红点同一次判定一起收 (v26092211)
产品口径(2026-09-22):**没填孕产期(pregEmpty)就不该出现宝宝来信提示**,
显示了不合理。这条**覆盖**了代码里原先那条决定(「来信与建档是两件事,故意不看
pregEmpty」)—— 那条当时是为了修「红点有、卡没有」,方向反了,见下。

做法:把首页卡与底 tab 红点收进**唯一渲染入口** renderLetterReminder(),用同一个
判据同时决定两处(pregEmpty 是硬门槛 → 建档后看 unread > 0 → 上游降级保持现状),
并把最近一次未读结果存进 _laixinUnread,供建档状态变化时重算:
  · syncLaixinReminder():拿到结果后交给 render(不再自己 toggle 红点);
  · syncPregnancy():未建档分支与建档分支各调一次 render。
于是无论 laixin 与 /profile 谁先回来,都收敛到同一结果(时序无关)。

顺带消掉上一版残留的竞态:此前红点与卡各写一份判据 —— laixin 先回来(亮红点 + 显示卡)、
/profile 后回来(只藏卡),就得到「红点有、卡没有」。现在同源同判。
另外把已不存在的 applyLaixinReminder() 的注释引用一并改掉(js + index.html 共 3 处)。

无头浏览器 + 桩后端实测(profile 延迟 0 / 1.5 / 3s,覆盖两种返回顺序):
  未建档 unread=1 → 卡与红点**都无**(三档一致)
  已建档 unread=1 → **都有**(确认没把建档用户一起关掉)
  已建档 unread=0 → 都无
  访客(无 openid)→ 都无
2026-09-22 21:20:46 +08:00
ab8a3a5ea0 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 与访客态仍两者都收。
2026-09-22 21:12:19 +08:00
e349907463 docs(AGENTS): §2 补 assets/img 命名规则(文件名 = 内容 md5 前 12 位)
换顾问二维码时靠比对 md5 才推出来的规则,属于「新人必须知道」的一类,
补进文件地图:内容寻址,换图即换 URL,别起描述性名字。
2026-09-22 20:35:21 +08:00
307f6182e4 feat(记一下/顾问码): 隐藏未实现的「今天已使用」快捷区 + 顾问二维码换真图 (v26092207)
记一下弹层:
- 日期/「今天已记 N 条」那行 + 「今天已使用」快捷区(数胎动/孕期体重/胎心记录)
  功能尚未实现、数据是写死的演示值,按要求先整体隐藏。
- 只挂 .tbd-hide,**不删 DOM**:js 里 $('#quickKick') 没有判空,且
  #kickCount / #todayCount / #noteWhen 会被回填,删掉会直接抛错。
- dedupeApps 在快捷区隐藏时跳过:否则首个可见小标题会变成没有指代对象的
  「其他孕期工具」;renderAppGrid 补写 data-toast,避免点「共 N 个」时退回
  index.html 里写死的「共 16 个」。

企业微信顾问二维码:
- 占位 svg(is-stub)换成真图 assets/img/4834fe8d686a.png。
  文件名 = 文件内容 md5 前 12 位,与该目录另外 34 张图一致(内容寻址,换码即换 URL)。
- .wx-qr 挂在元素本身、svg/img 通吃,CSS 未改;14px 圆角只裁到四角白色静默区,
  切不到码点。
2026-09-22 20:25:58 +08:00
849cf7a521 feat(孕期): 产后态不再显示「孕 42 周」,改「宝宝已出生 N 天」(v26092205)
上游 journey_stage=postpartum / 有 baby_birth_date 时,后端 /pregnancy 返回 postpartum=true
且 week=null。H5 侧补齐:

- applyRemoteProfile:**先判 postpartum 再判 empty/week==null**
  (产后返回体的 week 也是 null,落错分支会给已生产用户弹「完善孕期信息」)
- syncPregnancy:新增产后分支(文案集中在这里)
  · hero:孕周位「已出生」+ 清空紧邻的「孕周」标签 + 出生天数 / 「来到这个世界」
  · 我的孕期卡:宝宝已出生 N 天 · 记录宝宝的成长时光(进度 100%)
  · 档案页:宝宝已出生 N 天 · 孕期陪伴已结束;[data-ga]/[data-wk] 归 '--'
- 拦住 syncPregnancy 之后按 state.week 重算的链(syncStaticDates):
  week=null 会算出「看着正常但全错」的日期
- fillProfileForm:产后不再按已过的预产期回填「孕 42 周」,孕周两格留空并锁住
- renderPoster:week 为 null 时不再拼出「第 null 周档案」,退化成完整档案

⚠️ 文案(首页/孕期卡/档案页三处)如需调整只改 syncPregnancy 的产后分支
版本 v26092204 → v26092205
2026-09-22 13:37:05 +08:00
4c4c00f636 fix(档案): 保存资料失败要提示 —— 配合后端「先推上游、失败即 400 不落库」(v26092204)
后端方案 A:PUT /profile 改预产期/昵称时先推上游用户中心,推失败返回 400 且不落库。
原来这里 .then() 不看响应、.catch() 静默 —— 用户会以为保存成功,下次加载被上游值覆盖回去
("改了没生效")。现在:非 200 或网络失败都 toast 提示,且不触发 bustReload。

- §4 硬约定新增第 9 条,说明这个接口的失败语义,避免以后又把失败吞掉
- 版本 v26092203 → v26092204
2026-09-22 13:23:06 +08:00
d77b163b1a docs(AGENTS): 补「返回首页要清 last_app」硬约定与踩坑
- §4.8:clearLastAppOnBackHome → DELETE,只认三种返回情形,禁止改成每次加载都清
- §5:修回被误合并的一行
2026-09-22 11:57:37 +08:00
2c55e6737e fix(宿主恢复): 返回首页时清除 last_app —— 不再冷启动被送回刚退出的应用 (v26092203)
问题(用户实测):进入 H5 应用(如孕期血糖记录)→ 退回 mama-box 首页 →
再冷启动进小程序,又被送回那个应用。记录的是「最后进入的 H5 应用」,
用户已经回到首页了,首页才是最后待的地方 → 必须清掉。

- clearLastAppOnBackHome():DELETE /api/mp/public/last-app?openid=
- 只认「这次是返回回到本页」三种情形,**不能每次加载都清**(宿主恢复会把本页当返回落点加载,
  那时清掉会毁掉刚用上的记录):
    ① bfcache 恢复 → 复用文件末尾已有的 pageshow 监听(persisted=true)
    ② 后退导致整页重载 → navigation.type === 'back_forward'(init() 里判)
    ③ 从应用页 location.href 回本页 → document.referrer 是 https://mp.yizhezhe.com/<app>/
- 宿主恢复/落点那两次加载都是 navigate + referrer 空 → 不会误清
- 版本 v26092202 → v26092203
2026-09-22 11:56:25 +08:00
b71a773476 docs(AGENTS): 新增 AGENTS.md —— 本仓库开发约定与踩坑(跨仓约定指向 box_app/AGENTS.md)
- 文件地图(含 js/core.js 已无引用的提醒)、发布方式、版本号两处同步 bump 规则
- 硬约定:身份只从 URL 读 / fail-closed 不造假数据 / 跳应用一律走 jumpApp / 不写死应用名单 /
  授权走 navigateTo 授权页 / postMessage 非实时要预上报 / 换应用前上报 last_app
- 踩坑:别追加 #openid(破坏 hash 路由)、bustReload 拼回 hash、init 末尾再拉远程数据、
  resumeLastApp 只是兜底且要认 #norestore=1、wx-auth.js 是全生态共享件
2026-09-22 11:08:28 +08:00
79c1971cd6 feat(宿主恢复): 支持 #norestore=1 —— 小程序首页壳已决策时不再自行恢复 (v26092202)
档 3:首页壳自己读 last_app 并直接进容器页(不加载 mama-box、无首页闪屏)。
此时 mama-box 只是它留在身后的「返回落点」,必须禁止再自行恢复 —— 否则
mama-box 会在容器页底下把落点也换成目标应用,back 回不到首页。

- 收到 #norestore=1:既不跳,也先用 sessionStorage 闸门占住,
  免得后续宿主 ?t= 重载(不带该标记)时又跳一次
- 无该标记时行为不变:浏览器直访 / 首页壳取数失败回落加载时仍是兜底恢复
- 版本 v26092201 → v26092202
2026-09-22 05:19:07 +08:00
8c6b18c5e1 feat(宿主恢复): 换应用上报 last_app + 首屏恢复上次 H5 应用 (v26092201)
需求:小程序里进入某个 H5 应用后退出小程序,再次冷启动要恢复那个应用。

- jumpApp / goArchiveH5 跳转前 reportLastApp():navigator.sendBeacon 上报**净地址**
  (实时、由浏览器保证投递,不依赖微信 postMessage 的延迟批量派发)
- init() 首屏 resumeLastApp():sessionStorage 一次性闸门内 GET /api/mp/public/last-app,
  命中就带当前 openid/unionid location.replace 过去 —— 冷启动才恢复,
  同一会话切回首页 tab / 宿主 ?t= 重载都不会再跳;replace 不留 history、back 不会来回弹
- 宫格 / 工具卡 / 宝宝来信 / 孕检日历入口补 identifier,便于服务端在架校验
- 抽出 withIdentity(),jumpApp 行为不变(身份仍走 query,不追加 hash)
- 版本 v26092009 → v26092201
2026-09-22 05:11:24 +08:00
3b70f63dce fix(身份): bustReload 重载时拼回 hash —— 退出登录/首次完善资料后不再丢身份误报未获取身份 (v26092009) 2026-09-21 14:04:54 +08:00
932e42e050 fix(身份): 宿主未注入 openid 时给出可见提示 + jumpApp 带 __no_identity 标记 (v26092008)
背景(2026-09-20 线上排查):小程序首页壳拿不到 openid 时会**匿名加载**本页,
页面照常渲染但全是占位(孕周 `--`、档案查不到),而跳应用时 jumpApp 因为没有身份
就跳**裸 URL** —— 从商城返回首页加载本页时很容易被误判成「数据丢了」。
根因在小程序侧(App.vue 丢掉无 token 分支的 openid;首页壳没有像 web_view 那样的
silenceAuthNoLogin 兜底),H5 这侧先做**可见 + 可观测**两件缓解:

· 新增顶部提示条(#idNotice):仅在没有 openid 时显示,文案「未获取到微信身份,
  页面数据可能不完整」;带「重试」按钮(location.replace 换 URL 重载,重试过一次后
  文案升级为「请退出小程序后重新进入」,状态落 sessionStorage,活过那次跳转)。
  有身份加载时(applyRemoteProfile 拿到 openid)自动隐藏。
  ⚠️ 刻意不做自动轮询/自动 reload:宿主只在它自己重设 web-view src 或 onShow 时注入身份,
     页面自己刷同一 URL 并不会让身份出现,反而可能循环。
· jumpApp():一个身份都没有时显式带 `__no_identity=1` —— 目标应用能区分「宿主没注入身份」
  与「参数被平台丢了」,nginx/后端日志里也能一眼查到(排查 openid 为空的关键指纹)。

验证(本地代理 + 浏览器):访客态提示可见且默认文案正确;有 openid 时隐藏;
点重试后 URL 变 `?t=…`、提示仍在且文案升级;点宫格:无身份 → `…/?__no_identity=1`,
有身份 → `?openid=…&unionid=…`(无标记);卡片/红点/资源库 8 份/弹窗/我的页/tab 顺序
全部回归正常,errors 与 console 为空。
2026-09-20 23:08:26 +08:00
340fc911b1 fix(工具列表): 去掉「排除授权示例」的前端过滤,应用可见性交由后台上下架决定 (v26092007)
原逻辑:loadPublishedApps() 里 `.filter(a => a.url && !/wx-h5-demo/i.test(a.url))`
单独屏蔽「H5应用授权示例」,于是已上架 14 个只显示 13 个。

去掉的两个理由:
1)同一份数据在别的端不一致 —— 商城小程序「我的应用」(myApps) 直接铺
   /api/mp/apps 全量,没有任何过滤,所以那边能看到它;
2)mama-box 端要用这个应用排查「openid 为空」的场景,前端把它藏掉就没法从宫格进去。

现在只保留「必须有 url」这一条(没配链接的点了没反应),谁能出现完全由后台
「应用管理」的上架/下架(isPublished)人工决定;注释里写清了历史与「别在前端
重新引入名单」。顺带说明:原来那条过滤是按 URL 正则匹配的,本身就是脆的
(demo 换域名就自动失效)。

验证:本地代理实测宫格 14 个、含「H5应用授权示例」,标题「共 14 个 ›」;
点它 → https://mp.yizhezhe.com/wx-h5-demo/?openid=…(有身份);
无 openid 时 → https://mp.yizhezhe.com/wx-h5-demo/(正好是排查要的干净入口);errors 空。
2026-09-20 02:57:27 +08:00
31d153b513 refactor(来信): 彻底删除内置来信屏及全部功能代码,来信整体由第三方 laixin 承接(v26092006)
「宝宝来信」功能已全部由第三方应用 laixin(mp.yizhezhe.com/laixin/)承接,
mama-box 只保留两个入口/提醒,二者逻辑一行未改:
· 底 tab「宝宝来信」#tabLetter → openLetterApp() 跳 laixin
· 首页提醒卡 #homeLetter + 底 tab 红点 #tabBadge → syncLaixinReminder()/applyLaixinReminder()
  (读 /api/mp/public/laixin/unread)

删除的界面:#screen-letter(来信列表屏)、#detailLetter(来信详情)、
#detailCard(来信分享卡)、#fabWrite(写回信钮)、#modalReply(回信弹窗)。

删除的代码:LETTERS 数据与 stampLetters/renderLetters/filterLetters/buildThread/
renderLetterDetail/openLetter/curLetter/kidText/kidEl、本地延迟投递队列全套
(store/pending、deliverDue、deliverBabyReply、deliverVoiceLetter、语音信)、
syncLetterCounts、信箱头像换图 pickBabyAvatar、回信提交、applyRemoteLetters
(H5 从此不再请求 box_app 的 /mama-box/letters)、滑动 order 里的 letter、
go() 里 #fabWrite 的开关、state.{unread,letterFilter,curLetter,replyCount,babyAvatar}
以及随之无调用方的 fillBaby()。

保留(删前逐个 grep 确认仍有调用方):babyWord()、backAt()(stampAiLogs 在用)、
el()(档案海报在用)、.segmented(档案页在用)、.letter-card(首页提醒卡在用)、
档案页「珍贵时刻」里仅以文案提及来信的装饰卡。

CSS:删掉来信专用规则块与随之失效的变量(--font-round 等);净变化 -2396/+93 行。
2026-09-20 02:47:24 +08:00
0f0af3533d fix(首页): 来信卡不再看 mama-box 是否建档,与红点判据对齐(v26092005)
生产实测发现的漏子:某 openid 在 laixin 有 1 封未读(红点亮),但 mama-box
档案未建档(pregnancy empty → state.pregEmpty=true),而 applyLaixinReminder
里带了这个条件 → 卡不显示。于是又出现「红点说有新信、卡里没有」——
只是这次方向相反:是我自己加的判据把两处口径写歪了。

改法:卡只看 laixin 的未读数(与红点同一套判据),不再看 pregEmpty。
「档案未建档」和「宝宝来信里有没有信」本来就是两件事 —— 用户能从 laixin
收到信,未必在 mama-box 填过预产期。注释里写死了「别再加回来」。

验证:新增本地 mock 场景「laixin 未读=2 + pregnancy empty」→ 卡正常显示
(「小汤圆来信 / 有 1 封新信、1 条新回信 · 最近一封 今天 9:00」)且红点同亮;
访客(无 openid)仍收起。
2026-09-20 02:32:10 +08:00
ee04a26ba3 fix(首页): 来信卡数据源改为 laixin,与底 tab 红点统一(修两套数据不一致)(v26092004)
问题:底 tab 早已改跳 laixin、红点读 /api/mp/public/laixin/unread,但首页那张
「宝宝来信」卡仍由 pushLatestToHome() 按 LETTERS(box_app /mama-box/letters)驱动,
而那条线对多数用户是 0 封 —— 同一屏上会出现「红点说有新信、卡里什么都没有」。

改法(两者共用一个 laixin 未读结果):
- 新增 hideLetterCard() + applyLaixinReminder(r):unread>0 才显示,文案按
  「N 封新信 / M 条新回信」组装并附「最近一封 <时间>」;归零收起;上游降级(ok:false)、
  访客态、未建档一律收起(与角标同一套判据)
- syncLaixinBadge() → syncLaixinReminder():一次 fetch 同时落红点与首页卡(owner 唯一)
- 删除 pushLatestToHome() / lettersResolved / state.homeLetter / openDetail():
  内置来信屏(#screen-letter)与其 /letters 数据仍在,但不再往首页推卡
- 首页卡点击改走 openLetterApp()(跳 laixin),与底 tab 同落点;卡不再打开内置详情
- 卡仍默认 .hide + #homeBody 默认 .no-letter(保住 §9 的不闪规则)

验证(本地四态 mock + 浏览器):
- laixin 未读=2 → 接口回来前 hidden,回来后显示「小汤圆来信 / 有 1 封新信、1 条新回信 ·
  最近一封 今天 9:00」,红点同亮(同一次请求)
- 未读=0 → 全程收起;上游 ok:false → 冷启动收起、已显示则保持显示
- 访客(无 openid)→ 收起
- **box_app 来信有 1 封未读但 laixin 未读=0 → 首页卡仍收起**(内置屏照常渲染,互不影响)
- 点卡 → https://mp.yizhezhe.com/laixin/?openid=…&unionid=…;内置列表点开详情仍正常;errors 空
2026-09-20 02:31:19 +08:00
e29052f107 fix(首页): 来信卡默认收起,等 /letters 结果再决定显示 —— 修掉「先冒出来再缩回去」的闪烁 (v26092003)
现象:从商城切回首页加载 mama-box 时,先渲染出一张「宝宝来信/宝宝回信啦」卡
(用内置样例信 + 本地待投递队列拼的),几百毫秒后 /letters 回来说没有未读,
卡又缩回去,闪一下。

原因:卡在 index.html 里默认可见,pushLatestToHome() 是「先显示、数据回来再决定」;
而首屏渲染远早于 /letters。

改法(反过来:没确定之前一律不显示):
- index.html:#homeLetter 默认带 .hide、#homeBody 默认带 .no-letter(首屏按「无卡」排版,不跳)
- app.js:新增 lettersResolved 开关;pushLatestToHome() 在未确定、访客态(无 openid)、
  或后端明确未建档(pregEmpty)时一律保持收起;applyRemoteLetters 的每条终态
  (成功/空列表/接口挂/无身份)与 applyRemoteProfile 的访客分支都置位并重算
- 访客分支顺手补了一次 pushLatestToHome():此前清空 LETTERS 后没人重算,
  那张卡会顶着一封已不存在的信留在首页

验证(本地 + 延迟代理四态,浏览器实测):
- 有建档 + 0 封信:全程 hidden(修的就是这个)
- 有建档 + 1 封未读:接口回来前 hidden → 回来后显示「小汤圆来信」
- 接口全挂:回退内置样例照旧显示(离线行为不变)
- 访客(无 openid):hidden
2026-09-20 02:02:47 +08:00
e9873040f3 mama-box: 角标改调 /api/mp/public/laixin/unread(接口命名规范)+ 版本 v26092002
按 box_app/docs/api-naming-convention.md:box_app 对外暴露某应用的数据一律走
/api/mp/public/<app>/<资源>,app 段 = App 表 identifier。原先调的是
/api/mp/public/mama-box/laixin/unread,与妈妈盒子自己的来信(mama-box/letters)
同处一个命名空间、容易混,已随之迁到 laixin 命名空间。
2026-09-20 01:48:16 +08:00
aa53d5c6e6 mama-box 9.19 需求: 资料弹窗去兑换码闸门、底tab改回宝宝来信、我的页卡片改兜爸心选商城 (v26092001)
资料详情页(需求 1.1/1.2):
- #modalWx 删掉兑换码输入框与「以后再说」「解锁全部资料」两颗按钮,is-gate/is-gift/is-done
  三模式合并成单态(唯一出口是右上角 .modal-x);二维码下方文案改需求指定句
- 需求方确认「扫码加顾问 → 回复领资料 → 顾问直接发资料」,故「解锁」概念整体取消

死代码清理(D1 的连带):
- 删 PAN/PAN_DEFAULT 网盘链接表、panOf、WX_CODE/wxCodeOK、givePan、#modalPan 弹窗、
  state.wxUnlocked/WXOK_KEY、syncUnlockCopy、fetchRemoteConfig
- 删「已领」整套:state.resGot/RESGOT_KEY/isGot/列表「已领 ✓」标与筛选 chip/详情页「再拿一次链接」

底 tab(需求 2,D2=C):
- 「兜爸心选」→「宝宝来信」,图标换回 ic-letter,点击改走 jumpApp 跳第三方 H5
  mp.yizhezhe.com/laixin/(App 表 identifier=laixin,取不到时兜底硬编码)
- 红点 #tabBadge 挪回该 tab;角标数据源改为 box_app 封装的 /laixin/unread
  (syncLaixinBadge,ok=false 时保持现状,不把红点抹掉)

其它:
- 我的页卡片「兜爸心选」→「兜爸心选商城」(需求 3)
- 内置来信屏 #screen-letter 与 box_app /letters 链路保留不动,但不再有底 tab 入口
2026-09-20 01:36:06 +08:00
d39e52cf4f 授权回传确定性修复:requestProfile/goAuth 跳授权页时把当前 H5 地址作 backUrl 带给授权页(navigateTo query 通道,不赌 postMessage 派发时机);版本 v26091901 2026-09-19 16:55:42 +08:00
627a819e46 底tab「兜爸心选」/「进入商城」落点改商城首页:小程序原装装修首页已恢复为 pages/index/mall(DIY 底部导航第2项),goMall 改 switchTab 该页并补 fail 提示;首页新增今日脚印(数胎动对外 API,box_app 封装,拉不到回退内置);版本 v26091802 2026-09-18 21:12:49 +08:00
3ddcfe3e43 应用宫格: 工具列表改按 seq 倒序(值大靠前,seq 相同按 no 倒序) 2026-09-17 23:48:47 +08:00
f99a4d59eb mama-box: 接入共享 wx-auth.js,首屏/换页向小程序宿主上报 location(分享卡片深链同步);版本 bump v26091602 2026-09-17 21:34:27 +08:00
60bc63a870 mama-box 首页与底tab 第九批: 卡2 生长曲线→数宫缩(gongsuopinlv), 档案tab跳孕检日历, 来信tab改兜爸心选商城(购物袋图标+红点移到首页), 隐藏专属福利; 工具链接统一 mp 业务域名 (v26091601) 2026-09-16 16:34:28 +08:00
7868556042 wx-auth/wx-h5-demo: 授权与商城跳转加 fail 兜底提示; 修环境标签恒显「纯浏览器」; 调试面板转发 navigateTo/switchTab fail (demo v26090901) 2026-09-09 18:41:13 +08:00
1d0b780185 内容指纹缓存推广到 mama-box css/js/index(URL稳定去?v=, ETag+no-cache), 与共享库统一 (v26090817) 2026-09-08 12:06:15 +08:00
fc7160a4f2 落地A: 应用间跳转统一query-only(去hash与identityHash开关), 简化契约 (v26090816) 2026-09-08 11:55:35 +08:00
bd82944f18 身份注入支持 hash 开关: 应用 identityHash=false 时跳转只带 query 不追加#(修复baobao-yingji hash路由被破坏) (v26090815) 2026-09-08 11:49:08 +08:00
3cfe08cd73 商城模块文案 兜爸心选商城→兜爸心选(用户已改, 同步注释+版本bump v26090814) 2026-09-08 11:31:45 +08:00
ced6b1ff08 品牌名整体替换: 「妈妈盒子」→「兜爸心选」(仅中文字样; 目录/路由/类名 ASCII 不变) (v26090813) 2026-09-08 11:23:53 +08:00
81549a4f50 同步 app.js VER 常量到 26090812 2026-09-08 11:01:01 +08:00
7b33902bdc 关于页版本号只显示 v26090812(去掉'妈妈盒子'前缀) 2026-09-08 11:00:40 +08:00
e2d6489393 版本号移入「关于妈妈盒子」页底部(renderSetting about分支), 删全站固定底标 (v26090811) 2026-09-08 10:58:01 +08:00
0598f5b566 共享库 goMall 加环境判定矩阵(与授权同款): 非webview提示「请在小程序中打开商城」; demo加switchTab埋点 (v26090810) 2026-09-08 10:52:13 +08:00
f7691c540f 共享库移到 /mama-box/js/wx-auth.js, 最终地址带版本参数 (v26090805) 2026-09-08 10:26:51 +08:00
21c2e1e4cf 共享库唯一源移至 mama-box 资源目录(/mama-box/wx-auth.js), 撤销/shared挂载, 应用与demo统一引用 (v26090805) 2026-09-08 10:23:01 +08:00
9104dc1c98 访客态: 无openid(匿名加载兜底)时全站占位引导, 隐藏脚印时间轴, 杜绝演示数据落定 (v26090737) 2026-09-08 09:59:44 +08:00
6bfdac8e31 加标准 mobile-web-app-capable meta, 消除 Chrome 弃用警告 (v26090736) 2026-09-08 03:57:05 +08:00
1d7d1c05c8 首页5张工具卡按identifier跳已上架应用(带身份), 替换旧beian域名裸跳 (v26090735) 2026-09-08 03:54:32 +08:00
e1554e8a03 授权完善资料增加环境判定: 非小程序webview提示「请在小程序中完成授权登录」(v26090734) 2026-09-08 03:42:34 +08:00
0e69819165 用户卡记录行按状态显示: 未完善→引导文案, 已完善→已连续记录N天(数据源后定) (v26090733) 2026-09-08 03:37:09 +08:00
e8fba64a91 统一表单输入框最小高度50px(iOS date控件偏矮) (v26090732) 2026-09-08 03:28:57 +08:00
2b87d3cfda 预产期空值时隐藏原生日期提示(due-empty 文字透明), 只显示占位层 (v26090731) 2026-09-08 03:17:47 +08:00
915459f21a 预产期占位改为锚定输入框垂直居中, 修复 iOS webview 下错位 (v26090730) 2026-09-08 03:16:28 +08:00
8f78f5b433 我的资料: 预产期空值占位「- 年 - 月 - 日」(原生date不支持placeholder, 叠加文字层) (v26090729) 2026-09-08 03:11:52 +08:00