01现状诊断
P1

功能不可发现

置顶与删除完全藏在左滑手势之后,界面没有任何提示。新用户在手机上几乎不可能自己找到这两个操作,功能等于不存在。

MobileSessionCard.vue — 无 hint 元素
P2

长按语义被低频操作占用

450ms 长按被绑定到「复制会话 ID」,与 iOS / Android「长按呼出菜单」的系统惯例相悖。复制 ID 是低频动作,却占据了移动端最高频的长按入口。

copySessionId() — setTimeout 500ms
P3

展开态不互斥

每张卡片独立维护 actionsRevealed,连续滑动多张卡片时界面上会同时残留多个展开的操作区,进入会话前需要先逐个收起。

actionsRevealed = ref(false) — 卡片局部状态
P4

删除确认可达性差

删除确认使用居中 alertdialog,「删除」按钮落在单手拇指热区之外;5.5 英寸屏上误触「取消」与「删除」相邻的风险也高。

mobile-delete-overlay — 居中 dialog
P5

置顶缺少结果反馈

点击「置顶」后列表瞬间重排,卡片去向没有任何动画或说明,用户无法确认操作是否生效、卡片去了哪里。

togglePin() — 仅收起操作区 + emit
02交互总纲 · 手势地图

一张卡片上的四种手势

半滑 · 露出
水平拖拽 0 → 64px 卡片跟手左移,右侧渐显快捷操作(置顶 / 删除)。松手时位移 ≥ 40px 驻留展开,否则回弹。驻留态全局互斥:滑开新卡片自动收起上一张。
全滑 · 置顶
拖拽超过 150px 或快速甩动(速度 > 0.5px/ms)后松手,不再驻留,直接执行置顶 / 取消置顶:卡片弹回原位并以 FLIP 动画飞向置顶分组。高频操作一势完成。
长按 · 菜单
按住 450ms(位移 < 8px)呼出底部上下文菜单:置顶、复制会话 ID、删除(仅终态会话)。替代现有「长按复制 ID」,对齐桌面端 SessionActions 的能力集。
删除 · 确认
菜单或快捷区中的「删除」均先弹出底部确认 sheet:会话标题 + 影响说明 + 取消 / 删除按钮,全部落在拇指热区内。确认后卡片原地收合消失。
boundary ╴ touch-action: pan-y → 垂直滚动始终优先 ╴ 距屏幕左缘 ≤ 20px 不启动手势 → 留给 iOS 系统返回 ╴ navigator.vibrate(10/15) → 驻留 / 菜单弹出触觉反馈 ╴ prefers-reduced-motion → 关闭 FLIP、回弹、脉冲动画

触控分区(375pt 视口)

≤20px 系统返回保留区(手势不启动)
卡片主体 · 水平拖拽 = 快捷操作
操作露出区 72 / 144px
右缘 · 一次性滑动提示(首次)
删除按钮热区 ≥ 44 × 44pt(放大到整高)
左缘列表卡片(垂直滚动优先)右缘
03可交互原型
9:41●●● Wi-Fi

muwenbin 的主机

原型 A · 滑动操作与置顶 — 在卡片上向左拖拽:半滑露出操作区(注意驻留互斥),继续拉满或快速甩动直接置顶 / 取消置顶,卡片以 FLIP 动画换组。首卡片右缘的滑动提示在首次成功滑动后消失。

9:41●●● Wi-Fi

muwenbin 的主机

会话操作
取消
删除会话
会话消息与文件变更将从 daemon 删除,且无法恢复。

原型 B · 长按菜单与删除确认 — 长按任意卡片 450ms(卡片按压高亮)呼出底部菜单;点击「删除会话」弹出确认 sheet,确认后卡片原地收合消失。终态(已退出 / 完成)会话才有删除项。

04交互规格
参数取值说明
操作按钮热区≥ 44 × 44ptiOS HIG 44pt / Material 48dp 下限;露出区按钮放大到卡片整高,宽 72px。
驻留阈值40px(≈62% 操作区宽)松手位移超过即驻留展开,否则回弹;与现有 36px 阈值接近,肌肉记忆兼容。
全滑阈值150px ∥ 速度 > 0.5px/ms满足其一即判定全滑,松手直接执行置顶 / 取消置顶,不经驻留态。
长按判定450ms · 容差 8px与系统长按节奏一致;触发时卡片 scale(.98) 高亮 + 触觉反馈。
sheet 动效260ms ease-out · 遮罩 62%底部滑入;遮罩点击 / 下拉关闭;进入后焦点锁定首个可操作项。
FLIP 换组350ms · translateY置顶后卡片从原位置飞向置顶分组;取消置顶飞回全部分组按时间序位置。
删除收合280ms height→0确认后卡片高度收合 + 相邻卡片上移填补,列表无跳变。
触觉反馈vibrate(10) / (15)驻留展开 10ms、菜单弹出 15ms;不支持 vibrate 的浏览器静默降级。
滑动提示一次性 · localStorage首次进入列表时首卡片右缘显示「‹‹ 左滑操作」微动提示,首次成功滑动后永久隐藏。
状态矩阵见下running / busy / retry / idle:仅置顶;exited / completed / killed / error:置顶 + 删除。与现有 isTerminal 判定一致。
05落地要点

MobileSessionCard.vue 改造

  • actionsRevealed 提升为父级管理(provide / inject 或 props + emit),实现全局 single-open 互斥。
  • onPointerUp 增加速度判定(记录最近两次 move 的时间差),命中全滑直接 emit('toggle-pin')
  • 长按分支从「复制 ID」改为 emit('long-press'),复制 ID 移入菜单;保留 copySessionId 供菜单调用。
  • 操作露出区高度由 73px 改为卡片整高(inset: 0),满足 44pt 热区。

SessionList.vue 改造

  • 新增底部 sheet 组件(菜单 + 删除确认两个实例),替代现有 mobile-delete-overlay 居中弹窗。
  • 置顶分组标签「置顶 · N」;toggleMobilePin 后触发 FLIP 动画(记录 first rect → 重排 → 反演 transform)。
  • 滑动提示状态:localStorage['m.swipe-hint.done'],首卡渲染时未标记则显示。
  • 删除确认后走现有 confirmMobileDelete,补充卡片收合动画与列表空态兜底。

边界与无障碍

  • 保留 touch-action: pan-y;pointerdown 时 setPointerCapture,pointercancel 全量复位。
  • 卡片左缘 20px 内不启动水平拖拽,让位 iOS 边缘返回。
  • sheet:role="dialog" + aria-modal,焦点圈定;菜单项 role="menuitem"
  • prefers-reduced-motion 下 FLIP / 回弹 / 脉冲全部禁用,操作瞬时完成。
  • 键盘与桌面端不受影响:桌面继续走 SessionActions「···」菜单。