# 手机端前端设计文档 > 日期:2026-06-15 > 仓库:gamegroup2(http://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 中使用"。完整语音能力待后续打包为原生 App(Capacitor / 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)**:左侧返回按钮(次级页面显示)、中间页面标题、右侧通知铃铛(带未读数徽标) - **底部 Tab(Tabbar)**: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 和占位提示,实际通话能力待打包为原生 App(Capacitor / Tauri Mobile)时实现 - **PWA / 离线支持**:本次不做离线缓存和可安装 Web App - **推送通知(原生)**:本次仅做站内通知,App 级推送待后续 - **桌面端改动**:现有桌面端代码不做任何修改 ## 11. 风险与缓解 | 风险 | 缓解 | |------|------| | Vant 与 Element Plus 样式冲突 | 两套组件库通过路由分流隔离,不同时挂载;Vant 主题变量全部覆盖为 `--gg-*` 值 | | 手机端浏览器实时订阅稳定性 | 复用现有 `useRealtime`,组件卸载自动清理;移动端切后台时 PocketBase SSE 断连,回前台后自动重连(现有机制) | | 构建体积增长 | Vant 按需引入,仅打包手机端实际用到的组件 | | 微信内置浏览器限制 | 语音功能已有占位;如遇其他 API 限制(如某些路由 history 模式),预留 hash 模式降级方案 | ## 12. 验收标准 - [ ] 手机浏览器访问 Dev/UAT 自动进入手机版界面 - [ ] 桌面浏览器访问仍是原桌面版,行为不变 - [ ] 登录 / 注册 / 退出全流程正常 - [ ] 首页:状态切换、群组入口、当前组队卡片显示正常 - [ ] 群组详情:9 个标签全部可访问,数据正确 - [ ] 组队流程:发起 / 邀请 / 接受 / 状态流转正常 - [ ] 投票 / 竞猜:创建 / 参与 / 结算正常 - [ ] 账本 / 资产 / 黑名单:增删改查正常,资产转移正常 - [ ] 回忆:浏览 + 上传正常 - [ ] 游戏库:浏览 + 搜索 + 详情正常 - [ ] 通知:接收 / 标记已读 / 接受拒绝正常 - [ ] 个人中心 / 设置:状态切换、切换桌面版正常 - [ ] 语音房界面完整,占位提示明确