From d7410500cf2067067db7a39fc35a924f522ff11c Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Tue, 22 Sep 2026 23:59:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E5=8A=A0=E8=BD=BD=E9=A1=BA=E5=BA=8F):=20?= =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E6=95=B0=E6=8D=AE=E6=8C=89=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E5=8F=96=20=E2=80=94=E2=80=94=20=E8=BA=AB?= =?UTF-8?q?=E4=BB=BD=20=E2=86=92=20=E8=B5=84=E6=96=99=EF=BC=88=E5=90=AB?= =?UTF-8?q?=E4=B8=8A=E6=B8=B8=E5=90=8C=E6=AD=A5=EF=BC=89=E2=86=92=20?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E6=95=B0=E6=8D=AE=20(v26092215)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 产品口径:上游有档案且有预产期时,页面应按 ①身份(openid/unionid/phone) → ②用户资料 (box_app /profile,会从上游同步预产期/小名/宝宝名)→ ③应用数据(今日足迹等)这个顺序加载。 - applyRemoteProfile() 改为**返回 Promise**(访客分支与已跑过也返回已决议的 Promise), init() 里改为 `Promise.race([applyRemoteProfile(), 10s 超时]).then(() => { 应用数据 })`: 显式等 ② 落地再取 ③(资料库/记录/内容、今日脚印、首页工具卡、来信未读)。 ⚠️ 加兜底超时的原因:② 万一挂住(上游不响应),③ 也必须照常发出,别让首页空等。 ⚠️ 原来这五个 fetch 一起发、谁先回来谁写 DOM —— 竞态都是这么来的(今日脚印整块显隐被 profile 回来后又翻回去;来信提示的红点与卡各写一份判据)。顺序化后两者都收敛。 为什么这条重要(与今日脚印的显隐口径直接相关):上游有预产期时,第 ② 步会把预产期同步进来 (方案 A:读时同步覆盖),state.pregEmpty 因此为 false → 今日脚印不会被「未建档」门槛挡住。 即「上游有档案且有预产期」与「mama-box 未建档」不会同时成立(除非第 ② 步失败/超时)。 本地验证(桩后端,profile 故意延迟 0.6s 以观察顺序): 已建档(上游有预产期)→ 请求顺序 profile/pregnancy 先、footprint/tool-cards/laixin 后, 今日脚印整块显示并渲染 2 条真实事件;未建档 → 同样先取资料,今日脚印按口径隐藏。均无 JS 异常。 --- index.html | 2 +- js/app.js | 47 ++++++++++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 366986a..78bfad9 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 兜爸心选 · 孕育陪伴 - + diff --git a/js/app.js b/js/app.js index faa9221..c3153b9 100644 --- a/js/app.js +++ b/js/app.js @@ -3,7 +3,7 @@ (function () { 'use strict'; /* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */ - var VER = '26092214'; + var VER = '26092215'; const $ = (s, c) => (c || document).querySelector(s); const $$ = (s, c) => Array.from((c || document).querySelectorAll(s)); @@ -2713,19 +2713,27 @@ 两者在 syncLaixinReminder() 拉到数之前保持隐藏/收起(index.html 里就是默认态)。 */ // 让档案页的分段控件在首次布局后归位 setTimeout(() => { $('#archiveSeg')._reflow && $('#archiveSeg')._reflow(); }, 60); - /* 最后再拉远程档案:必须在 init() 渲染完之后异步覆盖 —— 若在脚本解析时就拉, - fetch 的 then 往往比 init() 先跑,随后 init() 又会把 state 重置回默认值, - 档案数据被覆盖。放在 init 末尾,等 fetch then 回来时再回刷展示。 */ - applyRemoteProfile(); - // 第二批远程数据(资料库/记录/内容)—— 随 init 一起拉,失败回退内置 - applyRemoteAll(); - // 第三批远程数据(今日脚印,来自数胎动)—— 渲染首页 .today-line 时间轴, - // 拉不到/未关联都各有回退,见 applyRemoteFootprint 内的分支说明 - applyRemoteFootprint(); - // 首页 5 张工具卡的业务数据(box_app 封装数胎动平台;失败保留卡上现有值) - applyRemoteCardsFetch(); - // 底 tab「宝宝来信」未读角标(box_app 代理第三方 laixin 未读数) - syncLaixinReminder(); + /* 远程数据按**依赖顺序**取,别并发(2026-09-22 收口): + ① 身份 —— hashParam('openid'/'unionid')(URL → 同源缓存兜底,见 wx-auth.js) + ② 资料 —— box_app /profile + /pregnancy:**会从上游同步预产期/小名/宝宝名**, + 也是决定 state.pregEmpty 的唯一来源 + ③ 应用数据 —— 今日脚印 / 首页工具卡 / 来信未读(都依赖 ①,足迹的显隐还依赖 ②) + ⚠️ 原来这五个 fetch 一起发、谁先回来谁写 DOM —— 竞态都是这么来的: + 今日脚印整块显隐被 profile 回来后又翻回去;来信提示的红点与卡各写一份判据。 + 所以这里显式**等 ② 落地**再取 ③。 + ⚠️ 加兜底超时:② 万一挂住(上游不响应),③ 也必须照常发出,别让首页空等。 + ⚠️ 必须放在 init() 渲染之后(若在脚本解析时就拉,fetch 的 then 常比 init 先跑, + 随后 init 又把 state 重置回默认值 → 档案数据被覆盖)。 */ + Promise.race([ + applyRemoteProfile(), + new Promise(resolve => setTimeout(resolve, REMOTE_PROFILE_WAIT_MS)), + ]).then(() => { + // 第三批:应用数据(资料库/记录/内容 + 今日脚印 + 首页工具卡 + 来信未读) + applyRemoteAll(); + applyRemoteFootprint(); + applyRemoteCardsFetch(); + syncLaixinReminder(); + }); } /* ---------- 远程配置(box_app 后台下发):已下线 ---------- ⚠️ 2026-09-19(9.19 需求 1.2):这里原来拉 /api/mp/public/mama-box/config, @@ -2818,9 +2826,14 @@ } $('#idNoticeRetry').addEventListener('click', retryIdentity); + /* ② 资料最多等这么久(ms)就让 ③ 应用数据照常发出:上游慢/挂住时首页不能空等 */ + const REMOTE_PROFILE_WAIT_MS = 10000; + let _profileApplied = false; + /* ⚠️ 返回 Promise:调用方要**等资料落地**再取应用数据(预产期/小名来自上游同步, + 它决定 state.pregEmpty,而今日脚印的显隐依赖它)。别改成 fire-and-forget。 */ function applyRemoteProfile() { - if (_profileApplied) return; // init 只跑一次,防重复 fetch + if (_profileApplied) return Promise.resolve(); // init 只跑一次,防重复 fetch _profileApplied = true; const openid = hashParam('openid'); /* 访客态:宿主未注入身份(冷启动 silenceAuth 失败走「匿名加载 H5」兜底)。 @@ -2837,7 +2850,7 @@ /* 兜底再算一次:访客态不该出现任何「你有新信」的暗示(卡 + 红点一起收)。 唯一渲染入口是 renderLetterReminder(),别再这里单独 hideLetterCard()。 */ renderLetterReminder(); - return; + return Promise.resolve(); } const base = '/api/mp/public/mama-box/'; /* ⚠️ profile 拉取要带上 unionid(2026-09-21 排查「首页个人信息为空」): @@ -2854,7 +2867,7 @@ 拉不到(无 openid / 未返回 200 / 断网)就静默保持内置默认值,页面照常可用。 */ /* 走到这里说明这次加载是带身份的(openid 非空)→ 把上一次的提示收掉 */ hideIdNotice(); - Promise.all([ + 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) {