chore: 入库生产基线(2026-10-26 工作树快照)

- 含首页壳/容器页/授权页/分享图/首页配置等此前未入库的在途改动
- 新增未跟踪的 pages/index/mall.vue(第 5 个 tabBar 页,pages.json 已引用)
- 排除本地备份文件(*.bak* / *.origin-bak)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-26 17:07:49 +08:00
parent 91f1ee849c
commit b45a190a59
14 changed files with 4116 additions and 2446 deletions

View File

@@ -9,34 +9,54 @@
```
[box_app 管理后台]
新建/编辑应用 → 上传"分享图片"
新建/编辑应用 → 上传"分享图片" + 填"分享标题"
→ 存入 App.shareImageUrl = https://mp.yizhezhe.com/upload/picture/xxx.png
→ 存入 App.shareTitle(留空 = 用应用名 App.name)
[box_app API]
GET /api/mp/apps?identifier=xxx&isPublished=1 (单个应用,太阳码场景)
GET /api/mp/public/share-images (分享图反查表:所有配了图的应用,
**不过滤上架状态**,2026-09-22 起)
→ 返回 { url, shareImageUrl } 精简结构
GET /api/mp/public/share-images (分享卡片反查表:所有有 url 的应用,
**不过滤上架状态**,2026-09-22 起;
2026-10-13 起每行多回 shareTitle)
→ 返回 { url, shareImageUrl, shareTitle } 精简结构
(shareImageUrl 为空串 = 没配图;shareTitle 是服务端算好的生效值,
后台留空已回退成应用名 —— 客户端不再实现回退链)
[小程序宿主页(两个,见第三节)]
pages/annex/web_view/index.vue 容器页:扫码 / JumpPath / 分享落地
pages/index/index.vue 首页壳:兜爸心选应用宫格 location.href 进入的 H5
① 获取 shareImageUrl(网络图)→ 内存 + 本地缓存(mixins/shareCard.js)
② 用户点 ··· 转发给好友 → 卡片图 = shareImageUrl(网络图,微信支持)
① 获取 shareImageUrl(网络图)+ shareTitle → 内存 + 本地缓存(mixins/shareCard.js)
② 用户点 ··· 转发给好友 → 卡片图 = shareImageUrl(网络图,微信支持);标题 = shareTitle
③ 用户点 ··· 分享到朋友圈 → getImageInfo 转本地路径 → 卡片图 = 本地路径
```
### 分享标题的优先级(2026-10-13)
| 优先级 | 来源 | 落点 |
| --- | --- | --- |
| ① | H5 上报(`location`/`share`/`setTitle` 消息的 `title`) | `webviewHost.handleHostMessage` → `shareTitle` + `shareTitleSource='h5'` |
| ② | 后台该应用「分享标题」= `App.shareTitle` | `shareCard.resolveShareCard` → `_matchAppShareTitle` |
| ③ | 应用名 `App.name`(后台留空时的服务端回退) | 同上(服务端已回退,客户端拿到的就是生效标题) |
| ④ | 首页壳 `'兜爸心选 · 孕育陪伴'` / 容器页 `'分享'` | 两个宿主页的 `onShareAppMessage` 兜底 |
⚠️ 三条纪律(与分享图同款,别拆开改):
1. **`shareTitleSource==='h5'` 不被后台标题覆盖**,否则 H5 上报的页级标题会被应用级标题吃掉;
2. **换应用要清标题**(`syncShareCardTarget` → `_clearShareCard`),否则 B 应用沿用 A 的标题;
3. 反查数据的本地缓存 key 是 `share_apps_index_v3`(v2 的 items 没有 `shareTitle`)——
**加字段必须 bump key**,否则老客户端要等 1h TTL 才生效。
## 二、box_app 侧配置(已实现)
### 后端(backend/app/models/app.py + services/app_serv.py)
- `App` 模型新增字段:`shareImageUrl: str | None`(微信分享卡片图,公网 https URL)
- `AppCreate` / `AppUpdate` / `AppOut` 均含 `shareImageUrl`,查询/写入透传(find / find_all / find_one / create / update 共 5 处)
- `App` 模型字段:`shareImageUrl: str | None`(微信分享卡片图,公网 https URL)、
`shareTitle: str | None`(分享卡片标题,**留空 = 用应用名**,2026-10-13 加)
- `AppCreate` / `AppUpdate` / `AppOut` 均含两字段,查询/写入透传(find / find_all / find_one / create / update 共 5 处)
- 上传接口:`POST /api/upload`(返回公网 URL)
### 管理后台前端(frontend/src/pages/ProductManagement.jsx)
- 新建/编辑应用表单新增 **"分享图片 (Share Image)"** 上传项
- 新建/编辑应用表单:**"分享图片 (Share Image)"** 上传项 + **"分享标题 (Share Title)"** 输入项(maxLength 40)
- 支持上传 `/api/upload`、编辑回填、单图(maxCount=1)
- extra 提示:建议 5:4 比例,公网可访问
- 分享图 extra 提示:建议 5:4 比例,公网可访问;分享标题 extra 提示:留空 = 用应用名称
## 三、小程序端获取逻辑(两个宿主页共用 `mixins/shareCard.js`)
@@ -78,11 +98,13 @@
页面加载时执行,用户点转发时图已就绪。`_shareFetched` 标志保证页面内只做一次异步兜底。
### ③ H5 postMessage 覆盖(`handleMessage`)
### ③ H5 postMessage 覆盖(`webviewHost.handleHostMessage`)
```
H5 bridge.share({ title, imageUrl }) → postMessage → handleMessage 'share'
→ if (data.imageUrl) this.shareImageUrl = data.imageUrl // 有值才覆盖
H5 wxAuth.reportLocation({ title, imageUrl }) / bridge.share({ title, imageUrl })
→ postMessage → handleHostMessage 'location' / 'share'
→ if (data.title) { this.shareTitle = data.title; this.shareTitleSource = 'h5'; } // 有值才覆盖
→ if (data.imageUrl) this.shareImageUrl = data.imageUrl // 有值才覆盖
→ 为空则保留 box_app 预取的分享图片
```
@@ -95,11 +117,11 @@ H5 bridge.share({ title, imageUrl }) → postMessage → handleMessage 'share'
→ 卡片图为空 → 微信回退默认截图。
```
onLoad → _loadShareApps() // 预热全量应用表:内存 shareApps + 本地缓存 share_apps_index(1h)
onLoad → _loadShareApps() // 预热反查表:内存 shareApps + 本地缓存 share_apps_index_v3(1h)
点 ··· → onShareAppMessage(options)
→ target = options.webViewUrl || this.shareHref || this.webUrl // 当前 web-view 真实地址
→ this.resolveShareCard(target) // 见下:先做应用切换检测,再按当前地址反查
→ imageUrl = this.shareImageUrl || ''
→ this.resolveShareCard(target) // 见下:先做应用切换检测,再按当前地址反查图 + 标题
→ imageUrl = this.shareImageUrl || '' ;title = this.shareTitle || info.title || '兜爸心选 · 孕育陪伴'
```
`_lookupShareImage` 是**同步**的:先内存应用表,再单应用缓存。因此首次转发就能出图,