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 为空。
This commit is contained in:
2026-09-20 23:08:26 +08:00
parent 340fc911b1
commit 932e42e050
3 changed files with 90 additions and 2 deletions

View File

@@ -3,7 +3,7 @@
(function () {
'use strict';
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
var VER = '26092007';
var VER = '26092008';
const $ = (s, c) => (c || document).querySelector(s);
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
@@ -192,6 +192,12 @@
const q = [];
if (oid) q.push('openid=' + encodeURIComponent(oid));
if (uid) q.push('unionid=' + encodeURIComponent(uid));
/* ⚠️ 2026-09-20:一个身份都没有时**显式标记**,别让目标应用/日志去猜
「是宿主没注入身份」还是「参数在路上被平台丢了」。
· 被跳的 H5 可以据此显示自己的身份提示(或走自己的兜底);
· nginx/后端日志里 __no_identity=1 一眼可查(排查 openid 为空时很快)。
排查背景见 docs/mama-box-change-list-20260919.md 与 showIdNotice() 的注释。 */
if (!oid && !uid) q.push('__no_identity=1');
if (q.length) url += (url.indexOf('?') >= 0 ? '&' : '?') + q.join('&');
reportHostLocation(url);
location.href = url;
@@ -2470,6 +2476,51 @@
return m ? decodeURIComponent(m[1]).split('?')[0] : '';
} catch (e) { return ''; }
}
/* ---------- 身份未就绪提示(2026-09-20) ----------
宿主(小程序首页壳)拿不到 openid 时会**匿名加载**本页 —— 页面照常渲染,
但全是占位数据(孕周 `--`、档案空、跳应用不带身份)。以前这种情况完全静默,
排查时只能靠服务端日志反推;现在给一条可见提示。
⚠️ 只在「确实没有 openid」时显示;一旦宿主把身份注入回来(onShow 重载),
applyRemoteProfile 会再跑一次,这里要 hide。
⚠️ 不做自动轮询/自动 reload:宿主只在它自己重设 web-view src 或 onShow 时注入身份,
页面自己 reload 同一 URL 并不会让身份出现(反而可能循环),所以只留手动重试。 */
function showIdNotice(reason) {
const el = $('#idNotice'), txt = $('#idNoticeTxt');
if (!el) return;
if (txt) {
/* ⚠️ 重试过一次之后(sessionStorage 计数)文案要保留「请退出小程序重进」,
否则重载回来又变回温和版,用户以为重试没发生过(重试是 location.replace,
文案状态活不过那一次跳转,只能落到 sessionStorage)。 */
let tried = reason === 'retried';
if (!tried) {
try { tried = (parseInt(sessionStorage.getItem('mmbox.idretry') || '0', 10) || 0) > 0; } catch (e) {}
}
txt.textContent = tried
? '仍未获取到微信身份,请退出小程序后重新进入'
: '未获取到微信身份,页面数据可能不完整';
}
el.classList.remove('hide');
}
function hideIdNotice() {
const el = $('#idNotice');
if (el) el.classList.add('hide');
}
/* 重试:只做一次「换 URL 重载」——带上 ?t= 让宿主/缓存放行。
宿主 onShow 也会重新注入身份(切到别的 tab 再回来即可),提示文案里已说明。 */
function retryIdentity() {
let n = 0;
try { n = parseInt(sessionStorage.getItem('mmbox.idretry') || '0', 10) || 0; } catch (e) {}
try { sessionStorage.setItem('mmbox.idretry', String(n + 1)); } catch (e) {}
showIdNotice('retried');
setTimeout(() => {
try {
const u = location.href.split('#')[0].split('?')[0] + '?t=' + Date.now();
location.replace(u);
} catch (e) { location.reload(); }
}, 500);
}
$('#idNoticeRetry').addEventListener('click', retryIdentity);
let _profileApplied = false;
function applyRemoteProfile() {
if (_profileApplied) return; // init 只跑一次,防重复 fetch
@@ -2479,6 +2530,9 @@
⚠️ 绝不能停在内置演示默认值上(小汤圆 / 孕27周 都是前端现算的假数据)——
全部切占位/引导;宿主拿到身份后会带 openid 重载本页,届时自动切真实数据。 */
if (!openid) {
/* ⚠️ 可见提示(2026-09-20):宿主没注入身份时别静默装正常。
排查路径见 showIdNotice() 上方那段注释。 */
showIdNotice();
state.pregEmpty = true;
state.due = null; state.week = null; state.day = null;
state.babyName = ''; state.userName = '';
@@ -2492,6 +2546,8 @@
- profile:babyName/userName/babySex/dueDate(身份 + 建档字段)
- pregnancy:week/day/due 以服务端权威派生为准(避免客户端重复算、口径统一)
拉不到(无 openid / 未返回 200 / 断网)就静默保持内置默认值,页面照常可用。 */
/* 走到这里说明这次加载是带身份的(openid 非空)→ 把上一次的提示收掉 */
hideIdNotice();
Promise.all([
fetch(base + 'profile?openid=' + encodeURIComponent(openid)).then(r => (r.ok ? r.json() : null)),
fetch(base + 'pregnancy?openid=' + encodeURIComponent(openid)).then(r => (r.ok ? r.json() : null))