|
|
@@ -0,0 +1,201 @@
|
|
|
+# 手机端 UX 优化 + Android 打包 + 推送接入 · 总方案
|
|
|
+
|
|
|
+- **建立日期**:2026-11-14
|
|
|
+- **状态**:阶段 A 已完成并合并 master;阶段 B / C 未开始
|
|
|
+- **评审报告**:`docs/04-quality/review/2026-11-14-手机端UX方案评审.md`
|
|
|
+- **原始外部方案**:<https://s3.fmode.cn/user/K0xKEZANOG/fmode-app-ux/index.html>(FmodeCode / FmodeAgent,2026-11-13)
|
|
|
+
|
|
|
+> 本文档是**后续优化的唯一入口**。下次接手时先读这里,再读评审报告。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 一、用户已裁决的关键决策(2026-11-14)
|
|
|
+
|
|
|
+| # | 议题 | 裁决 | 影响 |
|
|
|
+|---|---|---|---|
|
|
|
+| 1 | 推送厂商 | **坚持极光 JPush** | 见第五章 C4 的风险说明 |
|
|
|
+| 2 | 推送链路 | **仅 App 前台/后台存活时本地通知**,不做服务端推送触发 | 「App 被杀也能收到」**不可实现**,已向用户披露 |
|
|
|
+| 3 | 交付范围 | **三块都做,按顺序**:UX → 打包 → 推送 | 本文档的 A/B/C 三阶段 |
|
|
|
+| 4 | 文件 CORS | **先验证再定** | ✅ 已验证:三个域名全部放行,无断点 |
|
|
|
+| 5 | 外部分享 | **接收外部文件**(企微/微信 → App) | 工作量最大,见 C3 |
|
|
|
+| 6 | 打包签名 | **先出 debug APK** | 正式签名与上架另议 |
|
|
|
+| 7 | 会话改名 | **删除**(PC 端也没有此功能) | 已于 2026-11-14 删除 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 二、阶段 A:手机端 UX 优化 —— ✅ 已完成
|
|
|
+
|
|
|
+提交:`a609ce2`(已合并 master),验证:`tsc` ✅ / `npm test` 1786 全绿 / `build` ✅ / 真机视口实测无报错。
|
|
|
+
|
|
|
+### 已做的改动
|
|
|
+
|
|
|
+| 编号 | 改动 | 文件 | 说明 |
|
|
|
+|---|---|---|---|
|
|
|
+| A2 | **草稿跨会话串台修复** | `core/chat.service.ts` | `_draft` 由全局单例 signal 改为 `Map<会话键, 草稿>` 分桶;`open()` 不再清草稿;新增 `adoptDraft()` 处理键迁移 |
|
|
|
+| A1 | 任务状态可见性 | `mobile/pages/chat/chat.ts` | 接入 `TaskPulseService.describe()`,顶栏副标题可显示「正在处理…」(此前只有「在线」) |
|
|
|
+| A4 | 空态引导 | `mobile/components/m-empty/m-empty.ts`<br>`mobile/pages/messages/messages.ts` | `m-empty` 新增 `actionLabel` / `actionIcon`;列表空态给「+ 新建对话」 |
|
|
|
+| A5 | 容器内快速新建 | `mobile/components/m-drawer/m-drawer.ts`<br>`mobile/pages/chat/chat.ts` | 抽屉多一条「在本容器新建」,复用 `/chat/:id/new` |
|
|
|
+| A6 | 任务完成提醒 | `mobile/pages/chat/chat.ts` | 监听 `finished` 脉冲 → `UiMToastService` 轻提示(含任务名与用时) |
|
|
|
+| A7 | 硬编码色值 | `mobile/pages/messages/messages.ts` | `rgba(0,0,0,.35)` → `var(--overlay)` |
|
|
|
+
|
|
|
+### 已删除的改动
|
|
|
+
|
|
|
+| 项 | 原因 |
|
|
|
+|---|---|
|
|
|
+| 会话标题编辑(A3) | 用户裁决:**PC 端也没有此功能**,为保持双端一致而删除。`ChatSessionService.rename()` 服务层方法保留未动 |
|
|
|
+
|
|
|
+### 明确不做的(评审结论)
|
|
|
+
|
|
|
+| 外部方案主张 | 不做原因 |
|
|
|
+|---|---|
|
|
|
+| 手机端 Enter 改换行 | **伪意见**。`m-dock.ts` 早已是自增高 textarea + 「回车发送、Shift+Enter 换行」 |
|
|
|
+| 标题 LLM 自动重总结 | 每轮一次模型调用,成本/延迟不匹配;且 `patchChatThread` 已有一致性链路 |
|
|
|
+| 会话按交付物 `project` 字段分组 | 依赖的成果/项目路由已于 2026-11-11 下线 |
|
|
|
+| 布局留白压缩 | 主观项,后续如需调整按 `设计令牌.md` 自主处理 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 三、阶段 A 遗留 · 后续 UX 优化候选项
|
|
|
+
|
|
|
+> 以下均为**评审过程中发现但本轮未做**的项,按建议优先级排列。
|
|
|
+
|
|
|
+| 优先级 | 项 | 现状 | 建议 |
|
|
|
+|---|---|---|---|
|
|
|
+| 高 | **`m-dock` 缺 visualViewport 适配** | Android 键盘弹起时 `100dvh` 可能不收缩,输入区被键盘遮挡 | **打包成 App 后必现**,阶段 B 一并处理 |
|
|
|
+| 高 | **移动端无长按菜单** | `m-msg.ts` 全是 `(click)` 按钮,复制靠点按钮 | 符合移动端习惯,长按出「复制 / 转发 / 删除」 |
|
|
|
+| 中 | `chat.ts` 已 1705 行 | 单文件过大 | 后续改动尽量下沉到 service 或新组件 |
|
|
|
+| 中 | `m-drawer` 已 1209 行 | 同上 | 同上 |
|
|
|
+| 中 | 会话列表无「进行中」维度 | 只有 `agent` 排列 + 最近消息预览 | 外部方案核心诉求之一,本轮因改动面大未做 |
|
|
|
+| 低 | 移动端无拖拽/粘贴上传 | 只能调系统文件选择器 | 桌面端已有,可对齐 |
|
|
|
+| 低 | 移动端仅用 5 处 `ui-m-*` 底座组件 | 大量自建 `m-*` 组件 | 规范要求「组件一律取自底座」 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 四、阶段 B:Capacitor 打包 Android —— 未开始
|
|
|
+
|
|
|
+### B0. 前置条件(⚠️ 卡在这里)
|
|
|
+
|
|
|
+| 前置项 | 状态 | 处理 |
|
|
|
+|---|---|---|
|
|
|
+| 真机 / 模拟器 | ❌ **无任何连接设备** | 需用户插手机开 USB 调试,或同意创建 AVD(有 android-36 镜像) |
|
|
|
+| `ANDROID_HOME` | ❌ 未设置 | 需设为 `E:\coding-environment\AndroidSDK` |
|
|
|
+| android-35 platform | ⚠️ 缺(有 31/34/36) | 可用 36 构建,或补装 35 |
|
|
|
+
|
|
|
+### B0. 环境盘点(已实测)
|
|
|
+
|
|
|
+| 组件 | 现状 |
|
|
|
+|---|---|
|
|
|
+| JDK | 21.0.8(Microsoft OpenJDK),`JAVA_HOME=E:\coding-environment\jdks\21` ✅ |
|
|
|
+| Android Studio | AI-251.25410.109(2025.1)✅ |
|
|
|
+| Android SDK | `E:\coding-environment\AndroidSDK`(platforms 31/34/36,build-tools 34/35/36,NDK 27.1)✅ |
|
|
|
+| Gradle | 未装(Capacitor 自带 wrapper,不影响) |
|
|
|
+
|
|
|
+### B1. 技术验证结果(✅ 全部已实测,均为只读探测)
|
|
|
+
|
|
|
+| # | 验证项 | 结果 |
|
|
|
+|---|---|---|
|
|
|
+| V1 | `server.fmode.cn` Parse + 云函数 CORS | ✅ `access-control-allow-origin: *` |
|
|
|
+| V2 | `matrix.fmode.cn` CORS | ✅ `*`,允许 `authorization` 头 |
|
|
|
+| V3 | `s3.fmode.cn` OBS CORS | ✅ **已配置**,任意 Origin 回显,允许 `PUT` + `x-obs-acl` |
|
|
|
+| V3+ | `https://localhost` / `capacitor://localhost` | ✅ 两者都通过 |
|
|
|
+
|
|
|
+> **重要结论**:原以为「打包后 CORS 全断」的**最大风险不存在**。
|
|
|
+> 但 `src/app/core/attachment-fetch.ts:61` 与 `src/app/core/api/parse-api.ts:90`
|
|
|
+> 仍写着「s3.fmode.cn 没配 CORS」—— **该注释已过时,阶段 B 需一并更正并留痕**。
|
|
|
+
|
|
|
+### B2. 待实施步骤
|
|
|
+
|
|
|
+1. 新增依赖:`@capacitor/core` / `@capacitor/cli` / `@capacitor/android`(**不引入 Ionic 全家桶**)
|
|
|
+2. 新增 `capacitor.config.ts`:`appId` / `appName` / `webDir: 'dist/fmode-app-v2/browser'`
|
|
|
+3. 新增脚本 `npm run cap:sync`(`ng build` → `npx cap sync android`)
|
|
|
+4. `android/` 目录纳入版本管理(debug 阶段)
|
|
|
+5. `cd android && ./gradlew assembleDebug` 出包
|
|
|
+6. 真机验证:登录 → 会话列表 → 发/收消息 → ✅ reaction → S3 上传 → 文件预览
|
|
|
+
|
|
|
+### B3. 已知风险
|
|
|
+
|
|
|
+- **旧安卓 WebView 兼容**:`docs/00-tracking/2026-11-13-真机预览问题-PDF崩溃与HTML白屏.md` 记录过 pdfjs 在旧内核崩溃,Capacitor 用系统 WebView,需确认目标机型内核版本
|
|
|
+- `100dvh` 在 Android 键盘弹起时的表现(见第三章「高优先级」项)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 五、阶段 C:推送与分享 —— 未开始
|
|
|
+
|
|
|
+### C1. App scheme + deep link(本期核心,必做)
|
|
|
+
|
|
|
+- `capacitor.config.ts` 配自定义 scheme(如 `fmode://`)
|
|
|
+- `AndroidManifest.xml` 加 `intent-filter`(`VIEW` + `BROWSABLE`)
|
|
|
+- 路由映射:`fmode://chat/:id/:sessionId` → `/mobile/chat/:id/:sessionId`(复用 `mobile.routes.ts`)
|
|
|
+- App 内 `App.addListener('appUrlOpen')` → `Router.navigateByUrl`
|
|
|
+- 验证:`adb shell am start -a android.intent.action.VIEW -d "fmode://chat/xxx"`
|
|
|
+
|
|
|
+### C2. 应用内通知
|
|
|
+
|
|
|
+- 复用阶段 A6 的 `TaskPulseService` 完成提醒
|
|
|
+- 新消息提醒复用 `UnreadService`(`mobile-shell.ts` 已用在其 Tab 角标)
|
|
|
+- **不引入 Web Notification API**(Capacitor WebView 内支持不稳定)
|
|
|
+
|
|
|
+### C3. 接收外部文件分享(企微/微信 → App)
|
|
|
+
|
|
|
+- Android 侧:`ACTION_SEND` / `ACTION_SEND_MULTIPLE` intent-filter + FileProvider
|
|
|
+- 流程:分享 → 选 fmode App → 选目标会话 → 上传发送
|
|
|
+- **需原生 Java/Kotlin + Capacitor 插件开发,建议单独立项**
|
|
|
+
|
|
|
+### C4. JPush 铺路 —— ⚠️ 本期不接入插件
|
|
|
+
|
|
|
+**决策:不 import `ahhxyz/jpush-capacitor-plugin`**
|
|
|
+
|
|
|
+实测该仓库状态:
|
|
|
+
|
|
|
+| 指标 | 实测值 |
|
|
|
+|---|---|
|
|
|
+| Star / Fork | **1 / 0** |
|
|
|
+| 上游源仓库 | `caoguanjie/cordova-plugin-capacitor-jpush`,**7 star,最后推送 2023-07-03** |
|
|
|
+| 近期提交 | 2024–2025 年改动**全部是 `Update package.json`** |
|
|
|
+
|
|
|
+**风险判断**:未适配 Capacitor 7、未适配 Android 14/15 权限模型(`POST_NOTIFICATIONS` 运行时权限)、国产厂商通道支持未知。
|
|
|
+
|
|
|
+**本期只做「推送需要的地基」**:
|
|
|
+- App scheme(C1)
|
|
|
+- 通知点击 → 路由映射(C1)
|
|
|
+- 设备信息上报位(预留)
|
|
|
+- 服务端对接接口定义(预留)
|
|
|
+
|
|
|
+**真接入时机**:① 平台确认可加推送触发链路,或 ② 找到可信插件 / 自行 fork 维护。
|
|
|
+
|
|
|
+### C5. 必须向用户持续披露的限制
|
|
|
+
|
|
|
+> 按决策 2,「仅前台/后台存活时本地通知」意味着:
|
|
|
+> **App 被系统杀掉后(国产 ROM 后台 5-10 分钟即可能清理)收不到任何通知**。
|
|
|
+> 用户描述的「微信发完文件、切到 App 就弹通知」这种真正的到达提醒,
|
|
|
+> **需要服务端推送链路,当前架构没有,本期无法实现**。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 六、任务清单(下次接手从这里开始)
|
|
|
+
|
|
|
+- [ ] **用户确认阶段 A 效果**(G-D1 目视确认)
|
|
|
+- [ ] 准备 Android 设备(真机 USB 调试 或 同意创建 AVD)
|
|
|
+- [ ] 设置 `ANDROID_HOME=E:\coding-environment\AndroidSDK`
|
|
|
+- [ ] 阶段 B1:接入 Capacitor 三件套 + `capacitor.config.ts`
|
|
|
+- [ ] 阶段 B2:构建链路 + 出 debug APK
|
|
|
+- [ ] 阶段 B3:更正 CORS 过时注释(`attachment-fetch.ts:61`、`parse-api.ts:90`)
|
|
|
+- [ ] 阶段 B4:真机全链路验证
|
|
|
+- [ ] 阶段 C1:App scheme + deep link
|
|
|
+- [ ] 阶段 C2:应用内通知整合
|
|
|
+- [ ] 阶段 C3:外部分享接收(单独立项评估)
|
|
|
+- [ ] 阶段 C4:JPush 接入时机评估
|
|
|
+- [ ] 阶段 A 遗留高优项:`m-dock` visualViewport 适配、长按菜单
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 七、相关文档索引
|
|
|
+
|
|
|
+| 文档 | 用途 |
|
|
|
+|---|---|
|
|
|
+| `docs/04-quality/review/2026-11-14-手机端UX方案评审.md` | 外部方案逐条真伪判定与代码依据 |
|
|
|
+| `docs/00-tracking/操作追踪.md`(续十三 / 续十四) | 操作留痕 |
|
|
|
+| `docs/02-design/design-system/设计令牌.md` | UI 改动必须遵循的令牌 |
|
|
|
+| `docs/02-design/design-system/双端布局规范.md` | 移动端布局规范(安全区、触控尺寸) |
|
|
|
+| `docs/00-tracking/2026-11-13-真机预览问题-PDF崩溃与HTML白屏.md` | 旧 WebView 兼容前车之鉴 |
|
|
|
+| `docs/05-operations/部署发布手册.md` | Web 侧发布链路(Android 发布待补) |
|