Files
crmeb-mp/AGENTS.md
Karlcarlo dcc84dd7b7 docs(AGENTS): 补 §4.3 —— 回到首页要清 last_app(首页壳 + mama-box 两侧互补)
- 表格列出三条返回路径分别由谁清、判定依据是什么
- 明确禁止「mama-box 每次加载都清」(会把恢复落点加载误清,毁掉记录)
- 首页壳只在重载目标命中 /mama-box 时清
2026-09-22 11:58:12 +08:00

8.9 KiB
Raw Blame History

AGENTS.md · CRMEB 小程序(web-view 宿主)

在本仓库工作前先读。跨仓库的权威约定在 box_app/AGENTS.md(WSL:/home/jone/workspace/box_app/AGENTS.md)—— 三仓布局、身份契约、接口命名、部署流程都在那里。本文件只写小程序侧特有的部分。


1. 这是什么

CRMEB 商城小程序(uniapp,manifest name=DoubaShop),同时是整个 H5 生态的 web-view 宿主:

  • 首页壳 pages/index/index.vue —— tabBar 首页,硬编码加载 https://mp.yizhezhe.com/mama-box/; H5 应用宫格在 mama-box 内用 location.href 换应用,本页不会重新 onLoad。
  • 容器页 pages/annex/web_view/index.vue —— 太阳码 / 分享落地 / 商城宫格 / JumpPath 的通用宿主。
  • H5 应用(30+)只在 box_app 后台登记,本仓库没有它们的源码。
项 值
本地路径 /mnt/c/Users/Jone/Documents/HBuilderProjects/crmeb(Windows:C:\Users\Jone\Documents\HBuilderProjects\crmeb)
发布 HBuilderX 发行 → 微信小程序上传 → 微信审核 → 发布(没有 git remote,本仓库是纯本地库)
版本 manifest.json 的 versionName / versionCode

2. 关键文件

文件 作用
pages/index/index.vue 首页壳:身份 fail-closed、加载 mama-box、冷启动恢复 last_app、分享卡片、tabBar 显隐
pages/annex/web_view/index.vue 容器页:太阳码 scene 解析、身份注入(query)、_reportLastApp 上报
mixins/webviewHost.js 宿主公共能力:postMessage 分发(location/share/copyLink/setTitle/requestProfile)、原生授权面板、授权回传、静默登录复用
mixins/shareCard.js 分享图:按当前 H5 URL 反查 box_app App 表;朋友圈本地图转换
App.vue 冷启动静默登录、globalData(spid / appShowAt)、onShow(前台化时间戳)
pages/annex/auth/index.vue 独立授权页(navigateTo 进入,成功写 __AUTH_RESULT__ 后 navigateBack)
pages/guide/index.vue pages.json 第一个页面(冷启动入口,无广告时 switchTab 到首页壳)

3. 硬约定

  1. 两个宿主页必须共用 mixin:mixins/webviewHost.js + mixins/shareCard.js。历史上两页各写一份导致能力分叉(首页壳缺 copyLink / 授权回传 / unionid),别再分叉。
  2. 身份注入走 query、授权结果走 hash:容器页 _applyIdentity() 负责按当前 openid 重写 URL(含 _v= 缓存击穿);授权回传只走 hash(#openid=&phone=&nickname=&avatar=)——微信 web-view 首次加载丢 query、不丢 hash。
  3. 拿不到 openid 就不加载 H5(fail-closed):重试 → 兜底屏 → 手动重试;不要匿名加载(H5 会进访客态,反而更难排查)。
  4. 分享深链必须 stripAuthParams():别把发送者的 openid/unionid/t 泄露给接收者;接收者由容器页按自己身份重新注入。
  5. 分享图/标题按 onShareAppMessage(options).webViewUrl 当场解析:postMessage 是延迟投递,首页壳又不随 H5 换应用 onLoad,沿用上次结果会「B 应用带 A 应用的图」。
  6. tabBar 是全局状态:首页壳必须 uni.hideTabBar()(web-view 盖不住原生条,H5 自带底栏会双条);严禁在商城页主动 showTabBar 配对 —— 会与 DIY 底栏同显成双 tabBar。
  7. 恢复/落地统一 navigateTo 容器页,并保留首页壳作为返回落点;不要直接把首页壳的 web-view src 指向第三方应用(首页壳的 buildWebUrl 是 hash 注入,会破坏自带 hash 路由的应用)。
  8. 只用 options.url 当显式落地判据:options.scene 每次冷启动都有值(1001 最近使用 / 1007 分享 / 1011 扫码…),拿它判落地会导致恢复永远不执行。

4. 踩坑:宿主生命周期(2026-09-22,都付过线上代价)

4.1 热启动 vs 冷启动

  • 用户点右上角胶囊圆点「关闭」不是销毁,只是切后台。马上再进是热启动:页面栈与 web-view 都在, 只触发 onShow,不触发 onLoad;被回收后才是冷启动。
  • 所以「退出小程序再进要回到上次的 H5 应用」这类需求,只写在 onLoad 里会失败 —— 用户测的正是「关闭后马上再进」。
  • 反过来,onShow 里无条件重载 web-view 会把用户从 H5 应用踢回首页。首页壳曾有一段「切回首页 tab 就重载」的老逻辑, 热启动也走它,于是把恢复好的应用冲掉(shareHref 因 postMessage 延迟还停在 mama-box)。
  • 判据:切 tab 不触发 App.onShow,热启动会。做法:App.vue onShow 记 globalData.appShowAt, 页面 onShow 里 Date.now() - appShowAt < 2000 视为热启动恢复 → 跳过重载。
  • 改任何 onShow 逻辑前,先想清楚触发来源(App 前后台切换 / 页内跳转 / 切 tab)。

4.2 显式落地后点「小房子」回首页,不能被恢复逻辑再送回去

  • 扫码(太阳码)/ 分享落地时,用户直接落在容器页,页面栈只有它 → 左上角是**「小房子」**,点它回小程序首页。
  • 如果这时「上次应用恢复」还生效,就会把用户又送回刚扫码的那个应用:表现为点了小房子回不了家, 而且因为多push了一层容器页,左上角变成返回箭头,得再点一次返回才真回首页(用户实测)。
  • 修法两层,缺一不可:
    1. 入口判定:App.vue onLaunch 用 option.path 置 globalData.restoreArmed —— 只有 pages/index/index / pages/guide/index 且无 query.url 才为 true;首页壳 onLoad 一次性消费。 (用 path 不用时间窗:引导页可能停很久看开屏广告。)
    2. 抑制 H5 兜底:这类「明确不恢复」的首页加载,以及显式落地/恢复后的返回落点, loadMamaBox(true) / _loadWithCachedIdentity / onShow 重载 / retryLoad 都要带 #norestore=1, 否则 mama-box 的兜底恢复会绕开小程序判定又把用户送走。
  • 反向:小程序尝试恢复但取数失败/超时时不带 norestore,让 mama-box 兜底重试一次。

4.3 回到首页要清 last_app(两侧互补,2026-09-22)

现象:进入 H5 应用 → 返回回到 mama-box 首页 → 再冷启动进小程序,又被送回刚退出的应用。 记录的是「最后进入的 H5 应用」,人已经回到首页了 → 必须清掉。清除动作分两侧,互补覆盖:

路径 谁清 判定
H5 应用自己的返回(history.back() / 后退重载) mama-box clearLastAppOnBackHome() pageshow.persisted / navigation.type === 'back_forward'
H5 应用以 location.href 回 mama-box mama-box(同上) document.referrer 是 https://mp.yizhezhe.com/<app>/
容器页返回箭头回首页(host 重载,不带 referrer) 首页壳 _clearLastApp() onShow 决定重载回 mama-box 时(reloadBase 命中 /mama-box)
  • 接口:DELETE /api/mp/public/last-app?openid=(幂等、fail-soft)。
  • ⚠️ 绝不能改成「mama-box 每次加载都清」:恢复流程会把 mama-box 当返回落点加载, 误清会毁掉刚用上的记录(实测:普通加载与 #norestore=1 落点加载都不清)。
  • ⚠️ 首页壳只在重载目标是 mama-box 时清;重载目标是某个应用(shareHref 指向它)时不能清。

5. 本仓库状态提醒

  • ⚠️ mixins/shareCard.js 未被 git 跟踪(untracked),但两个宿主页都 import 它 —— 提交时别漏,否则一旦丢工作区这份文件就没了。
  • pages/index/index.vue.origin-bak(及若干 .bak_*)是原装修首页/历史备份,别当改动目标,也别删(回退时要用)。
  • 仓库里有多次会话遗留的未提交改动(manifest.json / pages.json / pages/index/mall.vue 等),动手前先 git status 分清哪些是本次的。

6. 自测

微信开发者工具(HBuilderX 运行到小程序)。Console 过滤 [enter-app] 可看到完整判定链 (入口路径 / restoreArmed / last-app 请求与响应 / 是否命中 / 热启动判定 / 容器页加载与上报):

  1. 冷启动:点「编译」→ 有 last_app 记录时应直接进上次的 H5 应用(不经过首页)。
  2. 热启动:点工具栏「切后台」再「切前台」→ 应停在原 H5,不应重载回首页。
  3. 扫码入口:编译模式选「通过二维码编译」(或扫太阳码)→ 进应用后点左上角「小房子」→ 应停在首页, 不应被送回应用、也不应出现返回箭头。
  4. 无记录 / 断网冷启动 → 最多约 1.5s 后照常进首页。
  5. 授权页返回、分享卡片、商城宫格进应用各走一遍。 接口契约与后端验证清单见 box_app/AGENTS.md §5、§6。