Files
gamegroup2/docs/superpowers/specs/2026-06-15-mobile-frontend-design.md
T
2026-06-15 15:51:08 +08:00

264 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 手机端前端设计文档
> 日期:2026-06-15
> 仓库:gamegroup2http://jiulu-gameplay.com.cn:13001/congsh/gamegroup2.git
> 状态:已确认,待实施
## 1. 目标
为现有 Game Group V2(游戏组队管理平台)增加完整的手机端前端,使移动设备用户通过手机浏览器即可使用全部功能。手机端与桌面端共存于同一项目、同一域名、同一后端,访问时根据设备自动分流。
**成功标准**:手机浏览器打开 `http://192.168.1.14:7033`Dev/ `7034`(UAT),自动进入手机版界面,可完成登录、群组管理、组队、投票、竞猜、账本、资产、黑名单、回忆、游戏库等全部现有功能,交互符合移动端操作习惯。
## 2. 技术决策
### 2.1 方案:单项目双视图层 + 路由分流
在现有 `frontend` 项目内新增手机端视图层,与桌面端共存:
- **共享层(零改动,手机端直接复用)**:`api/`PocketBase 封装)、`stores/`Pinia)、`types/`(接口定义)、`composables/`useRealtime 等)、`assets/design.css`(设计系统变量)
- **桌面层(不动)**:现有 `views/``components/` 保持原样
- **手机层(全新)**`views-mobile/``components-mobile/``mobile/`(布局与设备检测)
理由:业务逻辑全在前端、API 为标准 PocketBase SDK,共享层与 UI 无关;分成独立项目会导致 api/stores/types/composables 要么复制要么抽包,维护成本翻倍。单项目共享核心 + 双视图层是最低成本、最高复用的方案。
### 2.2 手机端组件库:Vant 4
引入 **Vant 4**(Vue 3 移动端组件库)作为手机端 UI 组件库。
- 现有 Element Plus 面向桌面(弹窗、表格、复杂表单),手机端的 Tabbar、ActionSheet、PullRefresh、Toast、SwipeCell、NavBar 等交互它不擅长
- Vant 专注移动端,与 Vite / Vue 3 / TypeScript 无缝集成
- 桌面端继续用 Element Plus,两套通过路由分流隔离,互不干扰
**新增依赖**`vant@^4` + `@vant/auto-import-resolver`(Vant 按需引入插件,确保未使用的组件不打包进桌面端产物)
### 2.3 主题一致性
将 Vant 的 CSS 变量覆盖为现有 `design.css``--gg-*` 值,保证手机端与桌面端视觉统一:
- 主色 `--van-primary-color: var(--gg-primary)` (#059669)
- 背景色、文字色、圆角、阴影等全部映射到 `--gg-*` 对应变量
### 2.4 语音能力
手机端 VoiceRoom 做完整 UI(成员网格、控制条、房间布局),实际 WebRTC 连接与麦克风采集暂不接入。原因:非 HTTPS / 部分手机浏览器(如微信内置)限制 `mediaDevices`,桌面 Electron 端已遇到同类问题。
手机端语音房显示明确占位提示:"语音功能请在 App 中使用"。完整语音能力待后续打包为原生 AppCapacitor / Tauri Mobile)时再接入。
## 3. 目录结构
```
frontend/src/
├─ api/ # 共享(PocketBase 封装,零改动)
├─ stores/ # 共享(Pinia,零改动)
├─ types/ # 共享(接口定义,零改动)
├─ composables/ # 共享(useRealtime 等,零改动)
├─ assets/
│ ├─ design.css # 共享设计系统(桌面+手机)
│ └─ mobile.css # 手机端主题覆盖(Vant 变量映射)
├─ views/ # 桌面端页面(现有,不动)
├─ components/ # 桌面端组件(现有,不动)
├─ views-mobile/ # 手机端页面(全新)
├─ components-mobile/ # 手机端组件(全新)
├─ mobile/ # 手机端专用
│ ├─ MobileLayout.vue # 底部 Tab + 顶部栏 主布局
│ ├─ useDevice.ts # 设备检测 composable
│ └─ DeviceGuard.ts # 路由级设备分流
├─ router/
│ └─ index.ts # 改造:设备检测 + 分流
└─ main.ts # 改造:按需注册 Vant
```
## 4. 设备检测与路由分流
### 4.1 检测策略
- **主判据**`navigator.userAgent` 匹配移动设备关键字(iPhone/Android/Windows Phone 等)
- **辅助判据**`window.innerWidth <= 768`(覆盖平板竖屏)
- 检测结果在应用启动时执行一次,存入 `localStorage``device_mode`)避免重复检测
- 提供手动切换入口(设置页:"切换到桌面版"),少数平板/桌面用户可能需要
### 4.2 路由结构
每个业务路由定义 `desktop``mobile` 两个组件,路由守卫根据设备模式返回对应组件:
```ts
// 示例:路由记录
{
path: '/group/:id',
name: 'GroupView',
meta: { requiresAuth: true },
component: () => isMobile()
? import('@/views-mobile/GroupViewMobile.vue')
: import('@/views/GroupView.vue')
}
```
- 登录态校验(`requiresAuth` / `requiresGuest`)逻辑不变
- 所有路由 URL 与桌面端完全一致(同一 `/group/:id`),只是加载的视图不同
- 切换设备模式后整页刷新以重新走路由解析
## 5. 手机端布局与导航
### 5.1 整体框架
```
┌──────────────────────────┐
│ ← 群组名 🔔(3) │ 顶部栏:返回 / 标题 / 通知
├──────────────────────────┤
│ │
│ 页面内容区 │
│ (下拉刷新、滚动) │
│ │
├──────────────────────────┤
│🏠首页 👥群组 🎮游戏 🔔通知 👤我│ 底部 5 Tab
└──────────────────────────┘
```
- **顶部栏(NavBar)**:左侧返回按钮(次级页面显示)、中间页面标题、右侧通知铃铛(带未读数徽标)
- **底部 TabTabbar)**:5 个固定入口,单手拇指可达
- **内容区**:占满中间空间,支持下拉刷新(列表页)、无限滚动加载
### 5.2 底部 Tab 定义
| Tab | 图标 | 页面 | 说明 |
|-----|------|------|------|
| 首页 | home-o | HomeMobile | 状态 + 当前组队 + 我的群组 + 热门游戏 |
| 群组 | friends-o | GroupsMobile | 群组列表 + 创建/加入入口 |
| 游戏 | game-o | GamesLibraryMobile | 游戏库浏览 + 搜索 |
| 通知 | bell | NotificationsMobile | 全部站内通知(邀请/组队/入群) |
| 我的 | user-o | ProfileMobile | 个人信息 + 状态 + 设置 |
**投票、竞猜、账本、资产、黑名单、回忆、统计** 不占底部位置,通过群组详情内的标签栏进入(见 5.3)。
### 5.3 群组详情的子页面组织
群组详情(`GroupViewMobile`)承载桌面端 GroupView 的全部 Tab 内容,手机端用**可横滑的顶部标签栏**组织:
```
┌──────────────────────────┐
│ ← 群组名 [12人] [⚙] │
├──────────────────────────┤
│ 动态 投票 竞猜 回忆 → │ 可横滑标签(横向滚动)
├──────────────────────────┤
│ │
│ [当前标签内容] │
│ │
└──────────────────────────┘
(其余标签:成员 账本 资产 黑名单 统计)
```
- 9 个标签:动态 / 投票 / 竞猜 / 回忆 / 成员 / 账本 / 资产 / 黑名单 / 统计
- 首次进入默认「动态」Tab
- 横向可滑动,超出屏幕的标签左右滑出
- 群组级独立页面(账本 `/group/:id/ledger`、资产 `/group/:id/assets`、黑名单 `/group/:id/blacklist`)也可从标签进入,URL 保持一致以支持直接跳转和返回
## 6. 全部页面设计
### 6.1 认证
| 页面 | 文件 | 设计要点 |
|------|------|---------|
| 登录 | `views-mobile/LoginMobile.vue` | 全屏卡片式,顶部 Logo + 标语,大号输入框(昵称/邮箱/用户名 + 密码),主按钮全宽,底部"去注册"链接。键盘弹出时内容上推不遮挡。 |
| 注册 | `views-mobile/RegisterMobile.vue` | 步骤化表单:昵称 → 密码 → 确认密码。复用桌面端自动生成 username 的逻辑(`'u' + Date.now().toString(36) + random`)。 |
### 6.2 主功能
| 页面 | 文件 | 设计要点 |
|------|------|---------|
| 首页 | `views-mobile/HomeMobile.vue` | 顶部:当前用户状态卡片(在线/忙碌/离开 + 一键切换 + 状态备注)。中部:当前临时小组卡片(如有,显示成员头像 + 进入语音房按钮)。下方:我的群组横滑卡片列表(点击进群组详情)。底部:热门游戏横滑封面。无群组时显示引导卡(创建/加入)。 |
| 群组列表 | `views-mobile/GroupsMobile.vue` | 群组卡片纵向列表(群名 + 成员数 + 简介 + 未读标记),顶部右侧浮动「+」按钮弹出 ActionSheet(创建群组 / 加入群组)。下拉刷新。 |
| 群组详情 | `views-mobile/GroupViewMobile.vue` | 顶部群信息条(群名 / 成员数 / 群主 / 容量)+ 快捷操作(账本/资产/黑名单图标入口)+ 可横滑标签栏(见 5.3)。 |
| 语音房 | `views-mobile/VoiceRoomMobile.vue` | 成员头像大网格(2-3 列,显示麦克风开关状态、说话动效)。底部固定控制条(麦克风开关 / 静音 / 退出)。顶部显示房间名和在线人数。WebRTC 未接入时显示占位提示。 |
### 6.3 群组内功能(标签栏子页面)
| 功能 | 组件 | 设计要点 |
|------|------|---------|
| 动态 | `components-mobile/group/ActivityFeed.vue` | 当前组队状态卡 + 空闲成员列表 + 所有成员按状态分组列表。 |
| 投票 | `components-mobile/poll/PollListMobile.vue` + `PollDetailMobile.vue` | 卡片列表(标题 / 选项数 / 截止时间 / 状态),下拉刷新,点击进详情投票。创建投票走底部弹出表单。 |
| 竞猜 | `components-mobile/bet/BetListMobile.vue` + `BetDetailMobile.vue` | 卡片列表(标题 / 下注范围 / 截止时间 / 我的下注),点击进详情下注。结算展示结果。 |
| 回忆 | `components-mobile/memory/MemoryGridMobile.vue` | 九宫格图片视频缩略图,点击全屏浏览(支持滑动切换、捏合缩放)。上传走底部弹出(拍照/相册选择)。 |
| 成员 | `components-mobile/group/MemberListMobile.vue` | 按状态分组列表(头像 + 昵称 + 状态备注),群主可管理(踢人/审核入群)。 |
| 账本 | `views-mobile/LedgerMobile.vue` | 顶部月度汇总卡片(总收入/支出/结余),下方账目列表,右下角浮动「+」添加(弹出表单:金额/类型/备注)。 |
| 资产 | `views-mobile/AssetMobile.vue` | 资产卡片列表(名称 / 类型 / 当前持有者),点击查看详情 / 转移。 |
| 黑名单 | `views-mobile/BlacklistMobile.vue` | 顶部 Tab 切换「游戏黑名单 / 玩家黑名单」。游戏:卡片列表(游戏名 + 标签 + 备注)。玩家:列表(昵称 + 标签 + 备注)。 |
| 统计 | `components-mobile/stats/StatsPanelMobile.vue` | 桌面 GroupStatsPanel 的简化只读版,展示群组活跃度、游戏偏好等核心数据(图表用简化柱状/环形,避免手机端图表过密)。 |
### 6.4 全局页面
| 页面 | 文件 | 设计要点 |
|------|------|---------|
| 游戏库 | `views-mobile/GamesLibraryMobile.vue` | 顶部搜索栏,下方游戏封面瀑布流(2 列),点击弹出详情底部面板(封面 / 平台 / 标签 / 评论 / 收藏 / 发起组队)。 |
| 通知 | `views-mobile/NotificationsMobile.vue` | 全部通知列表(类型图标 + 内容 + 时间),按时间倒序,支持标记已读 / 接受 / 拒绝操作。下拉刷新。 |
| 个人中心 | `views-mobile/ProfileMobile.vue` | 头像 + 昵称 + 用户名,状态切换,积分余额,我的群组数 / 组队次数等数据,设置 / 更新日志 / 退出登录入口。 |
| 设置 | `views-mobile/SettingsMobile.vue` | 列表式设置项:通知开关、主题(预留)、切换到桌面版、关于。 |
| 更新日志 | `views-mobile/ChangelogMobile.vue` | 时间线列表展示版本更新记录。 |
## 7. 共享层改动说明
手机端零改动地复用以下现有代码:
| 层 | 内容 | 说明 |
|----|------|------|
| `api/pocketbase.ts` | PocketBase 单例、`getCurrentUser()``isAuthenticated()``logout()` | 手机端直接 import 使用 |
| `api/*` | users / groups / sessions / invitations / games / polls / bets / points / ledgers / assets / memories / notifications / gameBlacklist / playerBlacklist | 全部领域 API 封装,手机端复用 |
| `stores/*` | user / group / team / notification / poll / ledger / asset / memory | Pinia stores,组合式 API,手机端复用(UI 状态可按需扩展) |
| `composables/useRealtime.ts` | PocketBase 实时订阅管理 | 手机端复用,组件卸载自动清理 |
| `types/index.ts` | 全部接口定义 + `displayName()` + 状态映射常量 | 手机端复用 |
**桌面端代码零改动**:现有 `views/``components/` 保持原样,不影响桌面用户。
## 8. 构建与部署
- **Vite 构建合并**:手机端和桌面端在同一份构建产物中,路由层负责分流。Vant 按需引入(`@vant/auto-import-resolver`),不使用的组件不打包,避免桌面端访问时加载手机端组件库。
- **部署不变**:现有 `deploy-dev.sh` / `deploy-uat.sh` 流程不变,nginx 配置不变,同一端口同一域名同时服务两端。
- **环境变量**`.env``VITE_PB_URL``VITE_PORT` 对两端同样生效。
## 9. 实施顺序
分 9 个阶段,每阶段产出可验证的成果(可在手机浏览器实测):
1. **基础设施**:安装 Vant、设备检测(`useDevice`)、路由分流改造、`MobileLayout`(底部 Tab + 顶部栏)、`mobile.css` 主题覆盖
2. **认证**LoginMobile + RegisterMobile(打通登录注册全流程)
3. **首页 + 群组列表**HomeMobile + GroupsMobile(含创建/加入群组弹层)
4. **群组详情核心**GroupViewMobile + 动态标签(组队状态 + 成员列表)+ 成员管理
5. **组队 + 语音房 UI**:发起组队、邀请、接受邀请、状态切换、VoiceRoomMobile(占位)
6. **投票 + 竞猜**:列表 + 详情 + 创建/下注 + 结算
7. **游戏库**GamesLibraryMobile + 详情弹层 + 搜索
8. **账本 + 资产 + 黑名单**:三个管理类页面(列表 + 增删改 + 资产转移)
9. **回忆 + 统计 + 个人/设置/更新日志**:收尾页面
## 10. 不在本次范围内
以下事项明确排除,待后续迭代:
- **语音 WebRTC 实际接入**:手机端语音房仅做 UI 和占位提示,实际通话能力待打包为原生 AppCapacitor / Tauri Mobile)时实现
- **PWA / 离线支持**:本次不做离线缓存和可安装 Web App
- **推送通知(原生)**:本次仅做站内通知,App 级推送待后续
- **桌面端改动**:现有桌面端代码不做任何修改
## 11. 风险与缓解
| 风险 | 缓解 |
|------|------|
| Vant 与 Element Plus 样式冲突 | 两套组件库通过路由分流隔离,不同时挂载;Vant 主题变量全部覆盖为 `--gg-*` 值 |
| 手机端浏览器实时订阅稳定性 | 复用现有 `useRealtime`,组件卸载自动清理;移动端切后台时 PocketBase SSE 断连,回前台后自动重连(现有机制) |
| 构建体积增长 | Vant 按需引入,仅打包手机端实际用到的组件 |
| 微信内置浏览器限制 | 语音功能已有占位;如遇其他 API 限制(如某些路由 history 模式),预留 hash 模式降级方案 |
## 12. 验收标准
- [ ] 手机浏览器访问 Dev/UAT 自动进入手机版界面
- [ ] 桌面浏览器访问仍是原桌面版,行为不变
- [ ] 登录 / 注册 / 退出全流程正常
- [ ] 首页:状态切换、群组入口、当前组队卡片显示正常
- [ ] 群组详情:9 个标签全部可访问,数据正确
- [ ] 组队流程:发起 / 邀请 / 接受 / 状态流转正常
- [ ] 投票 / 竞猜:创建 / 参与 / 结算正常
- [ ] 账本 / 资产 / 黑名单:增删改查正常,资产转移正常
- [ ] 回忆:浏览 + 上传正常
- [ ] 游戏库:浏览 + 搜索 + 详情正常
- [ ] 通知:接收 / 标记已读 / 接受拒绝正常
- [ ] 个人中心 / 设置:状态切换、切换桌面版正常
- [ ] 语音房界面完整,占位提示明确