feat: complete huihui square avatar workflows

This commit is contained in:
stefanfeng
2026-07-24 14:04:21 +08:00
parent 2ef58a44b8
commit e3bda469bb
68 changed files with 8062 additions and 132 deletions

126
uniapp-avatar/README.md Normal file
View File

@@ -0,0 +1,126 @@
# 会会数字分身 · uniapp + H5 混合架构
> 移动端采用 **uniapp 原生壳 + web-view 内嵌现有 H5** 的混合模式,与会会主 App 一致。
> 业务页面(数字分身管理 / 知识库 / 对话等)继续用 `digital-avatar-app`Vue3 SPA开发并构建为 H5
> 由本工程的 uniapp 壳通过 `<web-view>` 加载,原生侧只负责登录、会会资料、导航壳。
---
## 1. 整体架构
```
┌─────────────────────────────────────────────┐
│ 会会 Appuniapp 原生壳) uniapp-avatar/ │
│ ├─ 会会统一登录token / userId / 资料) │
│ ├─ 原生导航壳(自定义导航栏 / 可选 tabBar
│ └─ <web-view :src="H5?token=...&userId=..."> │
└───────────────────────┬─────────────────────┘
│ web-view
┌─────────────────────────────────────────────┐
│ 会会数字分身 H5 digital-avatar-app/ │
│ ├─ Vue3 + Vite SPA构建产物即 H5
│ ├─ 从 URL / window.__uniBridgeHandle__ 取认证 │
│ └─ 通过 uni.webView.postMessage 回传原生事件 │
└─────────────────────────────────────────────┘
│ HTTPS /api
FastAPI 后端(:8000
```
**职责边界**
| 层 | 负责 |
|----|------|
| uniapp 壳 | 会会登录与会话、注入 token/用户、原生导航与返回、可承载原生能力(推送/分享/支付) |
| H5 业务 | 全部数字分身业务 UI 与交互、调用后端 API、知识库/问答/对话 |
| 后端 | 业务数据与 AI 能力(维持不变) |
---
## 2. 桥接协议(壳 ↔ H5
### 2.1 握手URL 注入,最可靠)
壳加载 web-view 时把认证与会会资料拼进 H5 地址的 query
```
H5_BASE_URL/?token=<accessToken>&userId=<uid>&nickname=<urlencode>&avatar=<urlencode>&ts=<ms>
```
H5 在 `main.ts` 启动前用 `getLaunchParams()` 解析;`nickname` / `avatar``encodeURIComponent`
### 2.2 H5 → 原生(`uni.webView.postMessage`
H5 引入 uniapp web-view bridge 后调用:
| type | payload | 含义 |
|------|---------|------|
| `ready` | — | H5 已完成首屏渲染 |
| `needLogin` | — | token 失效,请求壳重新登录 |
| `setTitle` | `title` | 设置原生导航栏标题 |
| `navigate` | `path` | 请求原生跳转(打开原生页/新 web-view |
| `back` | — | 请求原生返回 |
### 2.3 原生 → H5壳主动推送
壳通过 `web-view.evalJS` 调用 H5 全局函数 `window.__uniBridgeHandle__(message)`
| type | payload | 含义 |
|------|---------|------|
| `context` | `platform, version` | 注入运行环境信息 |
| `tokenRefresh` | `token` | 登录刷新后下发新 token |
| `userUpdate` | `user` | 会会资料变更 |
> H5 侧用 `onNativeMessage(cb)` 注册 `window.__uniBridgeHandle__`,见 `digital-avatar-app/src/utils/uniapp-bridge.ts`。
---
## 3. 项目结构uni CLI / src 布局,已验证可编译)
```
uniapp-avatar/
├── index.html # H5 入口模板项目根uni h5 在此找入口)
├── vite.config.js # 注册 @dcloudio/vite-plugin-uni.vue 编译必须)
├── package.json
├── README.md
└── src/ # 源码根uni CLI 要求 manifest/pages 在此)
├── manifest.json # 应用配置(名称/AppID/模块)
├── pages.json # 页面路由
├── uni.scss # 全局样式变量
├── App.vue # 启动即做会会登录onLaunch → userStore.init
├── main.js # createSSRApp + pinia
├── pages/index/index.vue # web-view 容器(内嵌 digital-avatar-app H5
├── store/user.js # 会会会话token/资料,本地缓存)
└── utils/
├── bridge.js # H5 URL 构造 + 原生→H5 推送
└── huihui.js # 会会登录MOCK留真实接入位
```
> 构建产物:`npm run build:h5` → `dist/build/h5/`(含 index.html + assets
## 4. 运行与打包
### 方式一HBuilderX推荐与生产一致
1. HBuilderX → 导入 `uniapp-avatar/` 目录(已含 `manifest.json`/`pages.json`)。
2. 顶部菜单「运行」→ 运行到手机/模拟器/浏览器H5
3. 修改 `src/pages/index/index.vue``H5_BASE_URL` 指向你的 H5 部署地址:
- 本地联调用的**局域网 IP + Vite 端口**(如 `http://192.168.1.100:5173`),不要用 `localhost`
- 生产填 digital-avatar-app 构建后的 H5 线上域名。
4. 打包:发行 → 原生 App云打包/本地打包)。
### 方式二CLIdev:h5 本地自测,已验证通过)
```bash
cd uniapp-avatar
npm install # 依赖版本已对齐本机 HBuilderX3.0.0-4010520240507001
npm run dev:h5 # 起 H5 版壳web-view 会加载 H5_BASE_URL 指向的 H5
npm run build:h5 # 生产构建 → dist/build/h5/
```
> 若 npm 依赖版本与本地 HBuilderX 不一致,执行 `npx @dcloudio/uvm` 对齐。
### 会会登录接入
- 当前 `utils/huihui.js`**MOCK**`MOCK_AUTH = true`),便于联调。
- 生产接入:把 `MOCK_AUTH` 改为 `false`,在 `loginHuihui()` 接入会会开放平台授权,
换取 `access_token``userId``getUserInfo()` 请求会会 `usercenter` 真实资料接口
(接口基址见 `docs/production-interface-inventory.md`)。
---
## 4. H5 侧改动清单digital-avatar-app
- 新增 `src/utils/uniapp-bridge.ts`:环境探测、参数解析、双向消息。
- `src/api/index.ts``baseURL` 改为可配置(支持 web-view 内绝对地址)。
- `src/store/avatar.ts`:优先采用壳传入的会会资料;新增 `setNativeProfile`
- `src/main.ts`:挂载前注入 token/用户,注册原生消息处理,渲染后发 `ready`
- `src/router/index.ts`:改用 `createWebHashHistory()`web-view 下返回键更稳)。
- `index.html`:引入 uniapp web-view bridge 脚本,注入 `apiBase` 配置。

17
uniapp-avatar/index.html Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(safe-area-inset-top)') || CSS.supports('top: constant(safe-area-inset-top)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title>会会数字分身</title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>