工程与设计规范
teleMail 原型中心用于个人管理 Web、Mobile、组件规范、机制说明与流程图。所有新页面必须使用生成器创建,并遵循这里的底座。
本文件保存技术与已确认业务规则;协作节奏、按需读取和分级检查以根目录 AGENTS.md 为准。业务章节中的历史交付说明不要求每轮重读或重复执行,日常迭代也不要求每轮全量构建、双路径构建和 QA 报告。
首页固定保留移动端、桌面端、组件目录和文章四个主入口。移动端与桌面端各提供一个统一入口,具体业务页面通过原型内部导航访问。页面台账用于登记与校验,不作为首页入口列表;以后新增页面也不得自动加入首页,不恢复搜索、筛选或完成状态。用户已明确批准在四个主入口下方提供旧版 Axure 原型 teleMailClient 的 CoDesign 外部参考链接,在新标签页打开。
技术真源
- Next 16.3.8 / React 19.2.8 / TypeScript 6.0.3 / Tailwind 4.1.18。
- Node 24.18.0 / npm 11.16.0,所有依赖精确锁定。
- App Router 路由只负责装配;静态组件默认服务端,交互只进入必要的客户端叶子组件。
- 使用纯静态导出。部署子路径通过 NEXT_PUBLIC_BASE_PATH 在构建时设置。
设计令牌
- shadcn new-york、Neutral、黑色主色、仅浅色、Lucide 图标。
- 思源黑体统一中英文字体。正文 14px / 28px,辅助信息 12px / 20px,页面标题 24–36px。
- 间距采用 4px 基础步长;常用 8、12、16、24、32、40px。
- 圆角沿用 shadcn 语义半径,阴影只允许组件基线里的 shadow-sm。
- 所有可操作控件最小 44px,保留可见键盘焦点,文本对比度满足 WCAG 2.2 AA。
- Web 1280–1920px,以 1440px 验收。Mobile 360–430px,以 390×844 验收。
组件与目录边界
- components/ui 存放批准的 shadcn 原始组件,业务代码通过这里调用,禁止直接导入 Radix。
- components/system 存放页面壳层、共享状态与通用组合组件。
- 从业务重复结构提取的组合登记在 src/registry/compositions.json,并同步组件目录示例。SearchInput 属于共享输入结构;MailResponseActions 属于邮件域,仅通过 mail/index.ts 对外公开。
- features 按功能域组织模型、repository、fixtures、查询、视图。跨功能域引用只允许显式公开入口。
- 页面只能通过 repository 查询数据,不得直接引用 fixtures。
- 禁止 CSS Modules、CSS-in-JS、页面裸 CSS、硬编码颜色、任意圆角和未经批准的任意值类。
- 业务文案必须进入 next-intl 消息文件;邮件正文保留原文,时区固定 Asia/Singapore。
创建页面
npm run generate:page -- --surface web --module mail --screen settings --title-zh "邮件设置" --title-en "Mail settings"
npm run generate:page -- --surface mobile --module mail --screen settings --title-zh "邮件设置" --title-en "Mail settings" --with-doc
npm run generate:doc -- --module mail --screen rules --title "邮件机制说明"
生成的页面默认为未完成。完成已确认范围并通过 AGENTS.md 中适用级别的代码检查后,再将台账状态改成 complete;该状态不代表用户视觉验收已完成。文档完全按需,不强制每个页面编写说明。
检查与交付
检查按 AGENTS.md 的风险级别执行:文档仅检查格式与一致性,局部 UI 检查受影响文件,业务交互补类型/规范及相关最小回归;新路由、共享基础组件或构建配置等高风险改动,在批次收尾执行一次 npm run check。该命令已经包含格式、lint、类型、规范和根路径构建,不叠加重复执行同套检查。
初次底座验收、部署准备,以及新路由、链接/资源路径或 basePath/导出配置变化时验证 root 与 /telemail,不为每个按钮调整重复双路径构建。新增翻译、组件、样式和台账仍须满足规范;不通过减少检查绕过约束。
代码、类型或静态构建通过不代表运行时、视觉或无障碍验收通过。用户已明确不要求代理操作浏览器,实际页面交互、键盘、焦点、AA 对比度与目标视口由用户验收;除非用户明确要求,不执行浏览器验收或每轮生成 QA 报告。
桌面企业协同容器
Web 邮箱嵌入企业协同工作台,不采用独立邮箱站点结构。外层为工作台标题栏和 68px 全局应用轨道;内层为 260px TeleMail 邮箱导航、顶部选项卡及操作栏、360–440px 邮件列表和自适应阅读区。
邮箱侧栏按“产品标题与写信入口 → 搜索 → 收藏夹 → 账户 → 账户目录树 → 底部添加账户”排列。目录顺序固定为收件箱、草稿、发件箱、已发送、垃圾箱、垃圾邮件、稍后处理、会话历史、归档。账户支持折叠;其他未实现入口保持禁用,不创建虚假跳转。列表数量来自模拟数据,不照抄截图中的真实计数。
参考实际客户端仅复用信息架构和布局关系,不复制品牌标识、绿色配色、原生窗口控制或高保真视觉。继续使用 Neutral shadcn 组件和语义令牌;移动端保持原有独立画布。
桌面邮件详情操作
阅读区“更多”菜单按客户端参考排列回复、回复全部、转发、转发到聊天、删除、归档、已读/未读、标记/取消标记、打印、下载、查看,并保留智能翻译开关。已接入删除、归档、已读/未读、标记和既有翻译;同阅读区上方删除/归档按钮共用操作。桌面写信与聊天转发流程未接入,打印缺少邮件专用预览,下载格式/附件范围与查看子菜单未确认,保持禁用并提供原因,不模拟成功。顶部全局 ribbon 与底部回复按钮不在本轮启用。
桌面侧栏仅启用收件箱、垃圾箱、归档,文件夹和邮件 ID 经受控 folder/message 参数保留;其他目录不新增演示数据。删除移入垃圾箱,归档移入归档,无永久删除;已在目标文件夹时禁用对应动作。列表、详情、文件夹数量与标记图标同步更新;空文件夹显示空态。已读/未读和标记可反向切换,不自动覆盖用户手动标未读。
桌面状态经本域 webMailRepository 与 TanStack Query 独立会话覆盖层管理,底层 mailRepository、移动端、IM 邮箱助手及日历回复镜像的数据不被桌面操作改写,刷新恢复。归档与删除成功气泡保留 5 秒撤销,最近一次移动替换前一入口;撤销恢复原文件夹和原状态。重复撤销或被后续操作修改的邮件不覆盖新状态,显示失败;不在切换文件夹后强制跳回。缓存直接同步本地状态,不新增后端、持久化、路由或真实邮箱服务。
桌面日历浏览
日历复用企业协同外壳与全局应用导航。左侧为迷你月历、我的日历列表和底部设置;右侧为周切换工具栏和全天时间网格,周从星期日开始。侧栏固定 336px,确保七列日期按钮满足 44px 最小触控尺寸;时间列 64px,每小时 96px、半小时 48px。
日历实现日期选择、月份切换、上周、下周和今天。今天按 Asia/Singapore 计算;日期运算使用 UTC 表示民用日期,避免浏览器本地时区造成偏移。网格展示已接受或待定的模拟邮件邀请;新建、立即开会、日历设置与日历订阅开关仍禁用,不提供持久化。
日历日期工具栏保持单行:左侧依次为今天、上一周期、下一周期、紧凑日期范围;右侧为日/周/月分段切换,选中项明确标记。日视图仅禁用占位,周、月维持原有功能。新建、立即开会和更多操作独立放在上方,不混入日期导航。
周、月视图通过客户端链接切换,保留选中日期与内存状态。月视图为星期日起始的六行七列网格;日程按钮复用 EventPopover,周视图也使用相同回复弹卡。弹卡支持可选留言(最多 1000 字)与“向组织者发送电子邮件”勾选项,默认勾选。勾选时在本地收件箱生成一封回复通知镜像,用于模拟查看组织者收到的通知,不发送真实邮件;未勾选仅更新日历。通知保留当次状态和留言快照,后续改状态不会改写历史通知。所有通知与日历一样仅存在内存中,刷新重置。
邮件联系人名片
阅读区发件人(头像、名称、邮箱)和收件人地址可点击,MailContactTrigger 组合批准的 Popover、Avatar、Button 与 Dropdown Menu。匹配由 mail repository 查询,不在视图读取 fixtures;使用 TanStack Query 按邮箱缓存并处理加载与错误。
模拟目录中林语(linyu@example.com)和原型用户(you@telemail.example)各有一个 IM 账号,邮箱与 IM ID 均唯一,按明确地址匹配,不模糊认领或推断别名。Alex Morgan(alex@example.com)等其他地址展示未匹配邮箱名片。匹配后可点击名片头部展开 IM 资料卡;空间不足时 Popover 避让,不强制遮出视口。资料均为虚构样本,不连接真实 IM。
IM 详情卡宽度为 320px,依次展示右上更多入口、居中圆形头像与姓名、昵称/teleConnect+ ID/电话号码/邮箱/部门、备注行、底部消息/语音/视频三列操作。使用现有 shadcn 与 Neutral 令牌,仅还原参考图结构;没有头像资源时使用 UserRound 图标,不复制参考人物照片或性别标识。昵称与电话号码是可选字段,缺失显示“未提供”,ID 使用 repository 返回的模拟 IM ID。长字段单行截断并保留完整 title,邮箱点击仍复制完整地址。备注、更多、消息、语音、视频保持禁用,不接入真实服务。
联系人名片不规划添加星标、移入免提醒或邮件特别提醒,不展示这些入口,也不保留禁用占位。写邮件、往来邮件、添加邮件联系人、编辑、删除、备注、日程、发消息与通话保持禁用。名片、IM 资料和更多菜单可展开/关闭;名片及 IM 资料中的邮箱地址可点击复制,成功写入剪贴板后通过 Sonner 气泡提示,复制失败时明确提示检查浏览器权限。复制按钮支持键盘且不嵌套在资料展开按钮中。邮件列表原有星标展示保持原样,邀请卡片内部不嵌套联系人按钮。
移动端邮箱助手入口
通过生成器新增 mobile-im-conversations、mobile-im-mail-assistant、mobile-mail-detail;既有 mobile-mail-inbox 接入详情链接。完整链路为 IM 会话列表 → 邮箱助手 → 对应邮件详情;欢迎卡“开始使用”和固定底部“进入邮箱”均进入移动收件箱,收件箱可继续打开邮件详情。
会话列表保留个人信息、搜索、全部/未读/@我/单聊/群聊筛选、会话行及五列底栏。搜索和筛选可交互;只有邮箱助手会话可打开,其余会话禁用。底栏消息与应用可切换,其余禁用,不建设 IM 聊天。邮箱助手按时间展示欢迎卡与两条邮件通知,通知包含发件人、主题、正文摘要和真实对应的演示附件数量。未读数为固定演示数据,不因打开页面而改变,不模拟真实消息推送。
IM 数据经过本域 repository,跨域只通过 mail/index 公开入口读取邮件;摘要、附件数量和详情共用同一邮件 ID。新增两封虚构邮件 assistant-planning(1 个附件)及 assistant-contract(4 个附件),不替换原有邮件。附件只展示名称和数量,不下载真实文件。移动详情的回复进入模拟写信页,转发未实现;不扩展桌面的邀请回应、联系人名片或翻译功能。
返回来源仅识别受控参数:通知详情 from=assistant 返回助手;收件箱详情 from=inbox 返回收件箱,via=assistant 保留“收件箱 → 助手”的返回路径。缺失/无效邮件 ID 显示标准空状态,查询失败显示错误与重试,不随意打开第一封邮件。客户端 Link 与统一路径工具保证中文/英文及 basePath 下导航一致。
继续复用 MobileFrame,桌面为 390×844 画布,360–430px 真实移动视口全屏;内容区独立滚动,头栏与底部入口固定在画布内,保留安全区。截图仅还原结构,不复制蓝绿配色、真实头像、手机系统状态栏或批注。使用统一 shadcn Neutral、Lucide 图标及已有字体;不新增原始 UI 组件、依赖、后端、持久化或真实收发邮件能力。
邮件标题与正文翻译
Web 阅读区提供英语、阿姆哈拉语、中文的预置译文演示,翻译仅替换阅读区标题与正文,不修改原邮件、列表主题、联系人资料、附件或 ICS 卡片。原文与译文可切换;切换邮件或目标语言时取消未完成任务,不把旧语言结果混入新内容。动态回复等没有预置译文的邮件显示明确错误,并保留原文入口,不伪造译文。
翻译默认关闭,通过阅读区右上角“更多 → 智能翻译”勾选项开启/关闭,不再常驻显示启动与查看原文按钮。开启后展示目标语言与译文演示区域,其工具栏右侧下拉菜单另提供“退出翻译”,与更多菜单中的勾选状态联动,不新增反馈入口;更换语言自动加载该语言,长文沿用分段停止/继续。取消勾选或退出翻译均立即恢复原始标题、正文并取消未完成请求;再次开启可复用已完成缓存。切换邮件回到默认关闭状态,不扩展截图中的其他菜单功能。
翻译工具栏采用紧凑单行布局,保留语言选择、译文标识与右侧退出菜单,取消独立卡片外框、大内边距和“原型演示”提示。普通邮件工具栏仅一行,特别长文仍保留原有进度与停止/继续区域;不改变预置译文演示的服务边界。
长文阈值为原始正文去除空白后超过 10000 个 Unicode 码点(不按英文词数、UTF-16 长度或译文长度判断),恰好 10000 不进入长文模式。普通邮件一次显示完整预置译文,不显示分段进度。长文按预置译文分块渐进呈现,显示已完成/总段数、停止与继续;未完成区明确说明不是全文译文,不混排尚未翻译的原文。标题随首块显示。超长单段按码点切分,不切断 Unicode 代理对。缓存按邮件 ID 与目标语言隔离,TanStack Query 管理分块请求、异常及会话内缓存,取消后保留已完成块;不提供持久化或真实翻译服务。
收件箱末尾附加“长邮件翻译演示 · 产品评审记录”虚构样本,供数万字场景验收;原有默认邮件顺序与选中逻辑不变。仅渲染已完成译文块,避免一次等待整封长邮件。本次不新增业务路由、原始组件、依赖或后端。
邮件接收 ICS 邀请
邮件域的 InvitationCard 复用批准的 Sheet、Button、Badge 组件,负责邀请摘要与右侧详情,不新增原始组件或独立路由。邀请来自 repository 对模拟 text/calendar 附件的解析;日期显示固定 Asia/Singapore,内容仅以文本渲染,不执行 HTML 或跳转到真实会议。
收件邀请卡片宽度不超过 max-w-lg(512px),窄阅读区按容器宽度收缩。摘要的 UTC+08:00 时区紧随日期时间,不另设时区行。摘要与组织者、参与人、地点信息整体作为详情入口,不再展示独立的“查看日程详情”按钮;底部回应按钮保持独立,不触发详情。
当前解析器仅服务此原型样本:单个 METHOD:REQUEST 的 VEVENT、UTC 起止时间、组织者与参与人、描述和分钟提醒。折行与文本转义可解码,不支持完整 ICS 导入、重复事件、全天事件或 TZID 时区。无法识别时退回普通附件展示,不生成日程。聊天、纪要、转发与加入会议仍禁用。移动邮件列表可进入只读详情,不扩展 ICS 回应控件。
接受与待定将邀请按 UID 幂等写入浏览器内存日历,拒绝删除同 UID 日程,允许重新选择。状态查询和变更由日历 repository 与 TanStack Query 统一管理,邮件域仅通过 calendar/index 公开入口调用。卡片与详情显示同一状态;“在日历中查看”传入日期并定位日程所在周。Mail 与 Calendar 使用客户端导航保留内存;刷新、整页跳转或关闭页面会重置,不使用本地存储,也不发送真实回信。当前网格只标注邀请开始的半小时位置,不实现拖动、调整时长或重叠排布。
移动端群聊聊天页
mobile-im-group-chat 通过生成器创建。会话列表将预置 Esignature Work Group 群聊项接入聊天页,ID/名称与演示数据一致;入口范围见下文单聊与会话列表章节,不增加首页入口。返回目标固定为会话列表,不接受任意 URL。进出沿用右侧滑入/向右退出动画,支持 reduced motion。
页面按参考图分为固定群信息头栏、独立滚动消息区、固定输入栏及底部键盘/更多功能区。群名、14 位成员/7 位在线、历史英文文本、时间、点赞计数和文件卡片均为预置演示数据,经 IM 域模型、repository 与 Query 访问。头像沿用 Neutral 现有头像组件,不复制截图照片或品牌配色。收到消息左侧带头像及发送人,自发消息右对齐;长文本支持展开/收起,点赞只读,文件仅显示预置名称和大小,不创建下载或预览能力。时间按 Asia/Singapore 展示,勾选只代表演示消息,不声称真实送达或已读。
仅确认文字消息的会话内模拟发送:拒绝纯空白内容,成功后追加到右侧并清空输入、滚动至最新,失败保留输入并可重试,提交期间防重复。刷新恢复预置历史;不写持久化、不接真实 IM、不自动回复、不改变会话列表、未读数或邮件数据。输入复用 MobileKeyboard,支持真实键盘输入;键盘与“+”面板互斥。会议图标展开快速会议/预约会议/全部会议菜单,“+”展开相册、相机、群通话、文件、名片、投票、发送 DMS 文件七项;这些业务操作以及语音通话、表情、AI、语音消息、更多均未确认,明确禁用,不模拟系统权限、上传或真实服务。
移动端会话列表与单聊
列表按参考图调整为较大头像和账号栏、胶囊搜索/筛选、头像与两行摘要、独立时间/未读角标及固定底栏。仍使用 Neutral、Lucide 与现有字体,不复制个人照片、品牌绿或系统状态栏。保留邮箱助手及原有过滤和应用邮箱链路;按用户要求移除离线联系人、DMS Assistant、产品同步。剩余六项均可进入对应会话,不能将其他群或联系人导向错误的演示会话。
Esignature Work Group、TMS、周会纪要、项目沟通共用现有群聊路由,以 room 参数分别选择 esignature、tms、weekly-meeting、project-chat;无参数默认 Esignature,未知 ID 显示错误而不回退到其他群。四个会话各有独立名称、预置历史、会话内存与按 ID 隔离的 Query 缓存,切换会话重置输入区局部状态。支持各自模拟文字发送及返回列表,不增加会议业务功能,不联动列表摘要或未读数。路由使用 Suspense 支持静态导出,保留根路径与子路径导航。
mobile-im-direct-chat 经生成器创建。Kirubel Aynalem 的 ID、名称、历史图片摘要与列表一致,在线为预置演示状态。单聊与群聊复用 IM 域 ChatRoom 视图及 MobileKeyboard,但使用独立 repository 会话对象和 Query key,模拟消息不能串到其他会话或邮箱;不自动联动列表摘要、排序或未读数。文字发送规则与群聊相同,仅会话内存,刷新恢复。日期分隔、时间统一按 Asia/Singapore;历史邀请正文保留原文中的 Nairobi 时区描述,不将其当作实际预约数据。
单聊中会议邀请仅为纯文本,不接真实链接、不加入日历、不提供加入会议;历史图片为内置图像工具生成的中性文档表格演示素材,保存在 public/images/im/document-approvals-demo.png,经 staticPath 支持子路径导出。图片仅展示,无预览、下载或转发;通话、表情、AI、语音及更多附件仍未确认,禁用。ChatRoom 已登记组合目录,并提供群聊与单聊原型示例入口;既有页面数据层继续复用 IM model/repository/queries,不为每页复制一套。
移动端应用菜单入口
mobile-im-apps 通过生成器创建,位于会话列表底栏第四项“应用”。保留常用应用四列网格(11 项)、邀你体验四列网格(6 项)和固定协同底栏;仅邮箱可用,其余应用禁用。继续沿用 Neutral 与 Lucide,不复制截图蓝绿配色或系统状态栏。应用清单通过 IM repository 和 TanStack Query 获取。
应用邮箱入口传入 from=apps;邮件详情保留 via=apps,返回收件箱后继续保留来源,收件箱返回应用。原有助手链路不变,未知来源退回默认入口。不新增首页入口、持久化或真实服务。MobileCollaborationNav 统一底栏并登记组合组件目录。
移动端收件箱、阅读与模拟写信
mobile-mail-compose 经页面生成器创建。移动收件箱使用账号头栏、收件箱与筛选入口、日期分组、头像/发件人/主题/摘要行及悬浮写信入口,不再显示原单列邮件底栏。搜索匹配发件人、邮箱、主题和摘要;筛选支持全部、未读、附件、已标记和已置顶。日期按 Asia/Singapore 和当前日期分组为今天、昨天、本周、上周、更早,周从星期日开始;日期与邮件正文沿用现有演示数据,不照抄参考图真实账号或伪造实时消息。
移动展示数据通过 mobileMailRepository 获取:个人邮箱为 you@telemail.example,工作邮箱为 you@work.example,均为预置演示账号;置顶、旗标与已读状态支持移动端会话内修改,不改 Web 邮件的顺序和状态。会话数为独立只读演示元数据,不表示已有完整会话展开功能。列表详情链接和回复链接保留 assistant / apps 返回来源以及 account / folder 上下文,未知来源不接受任意跳转地址。
移动列表支持全部/未读/已标记/已置顶/带附件五类筛选。打开邮件自动标已读(含助手直达详情);长按 500ms 进入多选并选中当前邮件,也可用顶部多选入口或键盘空格进入。多选顶部显示已选数量、全选/取消全选,头像切换勾选,底部悬浮工具栏仅提供标记、已读/未读、置顶、删除四类批量操作,不展示移动、归档或更多占位。全选作用于当前搜索与筛选结果;混合状态时统一设为标记/已读/置顶,全部已设置时显示相反操作;成功后退出多选,失败保留选择。返回按钮及 Escape 退出,不进入邮件详情。
列表支持左右滑动,具体动作采用下文的全局滑动配置,不再将左滑固定为删除。短滑显示当前方向操作按钮,滑动距离超过 100px 后松手执行;纵向滚动不触发操作或长按,多选模式不响应滑动。选择删除及批量删除仍移入同账号“已删除”,不进行永久删除;已删除中的删除动作不生效。列表的归档、删除成功气泡提供 5 秒“撤销”,不增加二次确认;批量删除一次恢复整批,恢复操作前的文件夹、已读、旗标、置顶状态并同步缓存,不重新拉取列表。只保留最近一次归档/删除的撤销入口;邮件被后续操作修改时不覆盖新状态,提示无法撤销;其他动作(包括已读并归档)不提供撤销。本轮不扩展详情页操作。置顶邮件单独在列表最上方分组,其余按日期分组,已发送按发送时间、草稿按修改时间倒序。账号、文件夹、未读数与详情缓存同步更新;刷新后恢复模拟样本,不写本地存储或真实邮箱。
首次进入列表、切换账号/文件夹、顶部刷新按钮及列表顶端下拉松手均触发模拟加载。加载期间顶部显示加载图标、列表显示标准骨架,屏蔽邮件操作;请求由 Query 管理并支持取消,避免旧账号响应覆盖新账号。断网时显示明确网络提示,其他加载失败使用 AsyncState 错误及重试;不会用旧缓存伪装本次刷新成功。不新增真实网络服务或分页。
详情结构为顶部返回、浅色主题条、发件人及时间/收件人、附件卡片、正文、固定底部浮动工具栏。底栏为回复主按钮与独立下拉、标为未读、删除、更多;回复下拉与更多使用手机画布内的底部 Sheet,保持模态焦点、遮罩及关闭能力。回复显示原发件人地址并进入现有写信页;多收件人时增加全部回复,转发与编辑收件人按参考图排列,但这三项用户明确暂不联动,展示禁用状态及待写信页调整的说明。收件人数量仅按当前 repository 返回地址计算,不编造参与人。
更多菜单依次展示标为未读、标记/取消标记、置顶/取消置顶、回复、全部回复(仅多收件人)、转发、删除;已发送/草稿不开放回复,已删除不展示删除入口。全部回复与转发仍禁用,不展示用户本轮明确排除的“从服务器删除备份”和“标记为垃圾邮件”,也不扩展归档、移动或分类。
附件使用现有 repository 返回的名称,单附件显示一张卡片;两个及以上时在主题下显示数量、卡片横向滚动,并提供附件总数及保存入口。卡片/更多按钮打开该附件操作;批量保存先全选进入附件选择 Sheet,可取消勾选,零选中禁用保存,再选择保存到设备/保存到 DMS/发送到聊天。用户确认三项都只做本地结果提示,明确不实际下载、上传、连接 DMS 或发送聊天消息,不产生文件、网络请求或持久化。当前模拟数据未提供文件大小,显示“大小未提供”,不伪造单个或合计容量;关闭弹层恢复原触发器焦点,单附件与多附件共用画布内 Sheet 容器。
标为未读与删除复用 mobile repository/Query 会话操作,成功后沿原来源向右滑出返回列表或助手,列表不重新同步;标为未读期间禁止自动已读逻辑覆盖结果。删除仍移入同账号已删除,保留退出过程中的正文快照,避免源查询变空时闪屏。标记与置顶更新本地缓存、关闭弹层并留在详情;重复点击锁定,失败提示且保留页面。长正文只让内容区滚动,不挤出底部操作。桌面 MailResponseActions 保持禁用,不启用桌面写信,也不扩展移动 ICS 回应、联系人或翻译。
写信页提供账号头栏、收件人、可展开抄送/密送、主题、正文及固定工具栏。React Hook Form 和 Zod 验证至少一个有效收件人,抄送/密送可空;多地址支持中英文逗号、分号和换行分隔。主题与正文可空,不擅自定义真实邮件发送规则。回复预填原发件人地址和 Re: 主题,不复制数万字原邮件正文进编辑器。找不到原邮件时显示明确空状态,禁止降级成空白回复。
提交通过 TanStack Mutation 调用 mobileMailRepository.simulateSend,短暂模拟后展示完成说明,明确没有发送真实邮件、没有写入已发送或收件箱。发送期间禁止重复提交和关闭,失败保留输入供重试;编辑已有草稿并模拟发送成功后移除该草稿。附件、拍照、富文本、插入内容、发送选项和清除格式仅为禁用占位;不绘制或模拟操作系统键盘。
2026-10-16 用户确认移动写信关闭改为自动保存内存草稿,替代放弃确认。详情向左滑入,写信/回复向上滑入;点击叉号先保存,再用 300ms 向下滑出并返回原来源。收件人、抄送、密送、主题、正文任一字段有非空白内容即保存,允许未完成或无效地址,不使用发送校验阻止保存;全空直接关闭,已存在草稿清空后关闭则删除。保存失败留在编辑页并提示;保存及退出期间锁定操作,减少动态效果设置下不播放动画。
返回后使用 Sonner 气泡提示“已保存草稿”,提供删除刚保存草稿的操作。草稿按账号隔离,通过 repository 与 TanStack Query 更新草稿列表和数量;从草稿箱点击进入现有写信页继续编辑,URL 以 draft 参数识别,重复关闭更新同一草稿,不新增副本。保存完整 To/Cc/Bcc/主题/正文,原有预置草稿也支持编辑;未知或跨账号草稿不得降级为空白新信。所有增改删除仅在当前会话内存中,刷新后恢复预置样本、清空用户草稿,不使用本地存储、不发送真实邮件。
结构参考用户三张旧原型,仍使用浅色 Neutral shadcn、既有语义令牌、Lucide 和 MobileFrame;不新增原始组件或依赖。用户已明确不要求代理操作浏览器,本轮仅执行代码、规则、数据和静态构建检查,实际视觉、键盘、视口和交互由用户验收。
从邮件详情或写信页返回列表时,直接复用当前账号/文件夹的会话缓存,不因页面重新挂载、缓存时间或网络重连而自动同步,也不重播列表加载骨架。已读、批量操作及草稿增改删除直接更新本地列表缓存与文件夹数量;首次无缓存访问、主动切换账号/文件夹和手动刷新仍触发加载。缓存只保留在当前页面会话内,刷新浏览器后清空。
收发件人信息盒子除右侧更多按钮外,头像、名称、收件人、日期与留白区域统一展开/收起内联地址详情,支持键盘 Enter/Space。收起时展示发件人、收件人摘要与简短日期;展开时显示发件人邮箱、完整收件人及 Asia/Singapore 完整日期时间。右侧更多按钮是独立的兄弟按钮,不嵌套在展开按钮中,不改变展开状态;关闭更多菜单或完成标记/置顶后返回原触发器焦点。
邮件详情点击顶部返回时向右滑出,时长 300ms,动画结束后返回原列表或邮箱助手;退出期间屏蔽重复操作,卸载时清理计时器。开启减少动态效果时直接返回,不播放动画;返回列表仍使用缓存,不重新同步。
取消最后一封勾选或取消全选后,立即退出多选并恢复普通列表。普通列表顶部勾选入口明确为“全选”,一次选中当前可见结果;空列表不可点击,不进入“已选取 0 封”的状态。
移动端邮箱设置首页
mobile-mail-settings 通过生成器创建,由邮箱抽屉左下设置入口打开;仅在原型内部导航,不增加首页入口。设置页从右侧滑入,顶部返回向右滑出,时长 300ms,支持减少动态效果。URL 保留 from=apps|assistant、account 与 folder,返回原邮箱/文件夹,复用列表缓存,不额外同步。
设置首页快捷设置为显示与外观、签名、自动回复、通知;通用为账号、邮件、日历、联系人、语言。当前“邮件”入口进入已确认的滑动操作配置页,其他二级入口仍禁用,不新建空二级路由。搜索匹配当前语言的分组、名称及摘要,支持清除,保留匹配分组,无结果使用 AsyncState。外观摘要沿用浅色/Neutral/舒适底座,不复制参考图蓝色或引入主题切换;自动回复关闭仅为演示摘要,语言显示当前原型语言,不连接系统设置或真实邮箱。
移动端邮件搜索
移动列表的搜索入口打开覆盖当前画布的搜索界面,不新增路由;保留当前邮箱与文件夹范围,搜索发件人、邮箱、收件人、主题及正文。仅实现邮件,不扩展联系人、文件、日程。未提交时展示当前文件夹邮件中的去重发件人快捷查询,非通讯录;提交后显示数量、结果和无结果状态,点击结果沿用自动已读及详情/草稿入口。关闭搜索保留列表筛选、滚动和缓存,不重新同步。
搜索输入聚焦后显示页面内模拟键盘,支持 QWERTY 字母、大小写、数字、符号、空格、按光标插入/替换选区、退格、收起及提交。结果区独立滚动,模拟键盘位于画布底部,不遮挡结果;返回后将焦点交还搜索入口。
共享移动端模拟键盘
MobileKeyboard 与 useMobileKeyboard 位于 components/system,属于批准组件的共享组合,不新增或修改 primitive。组合已登记 compositions.json,组件目录提供单行/多行切换示例。邮件搜索、写邮件、邮箱设置搜索及 IM 会话搜索共用实现;后续移动端文本输入复用该组合,不再复制页面内键盘。
宿主通过 keyboard.bind(change, kind) 给 Input/Textarea 连接聚焦与点击事件、inputMode=none;已有 onChange、ref 和表单注册保持不变。change 由受控状态 setter 或表单 setValue 负责,键盘不直接改 DOM 值、不伪造输入事件、不拥有业务数据。kind 为 text、email 或 multiline;邮箱模式提供 @ 和点号,单行“完成”只收起、多行“换行”插入换行,搜索可显式覆盖为提交搜索。键盘的完成键不得隐式发送邮件。
写邮件的收件人、抄送、密送、主题及正文全部接入;模拟输入与真实键盘输入使用同一表单数据,原校验、模拟发送和非空草稿保存规则不变。禁用或已卸载的输入不接受模拟编辑,切换字段不丢内容;键盘收起保留值,点击输入可再次展开。键盘作为页面 flex 底部区域压缩滚动内容区,不覆盖工具栏或正文。模拟键盘不冒充系统键盘,不提供中文拼音、语音、表情或剪贴板能力;inputMode=none 避免真机重复弹出软键盘,仍支持真实键盘和输入法输入。
移动端滑动操作配置
mobile-mail-swipe-options 经生成器创建。按用户文字而非截图里的相反方向,初始右滑归档,左滑进入滑动操作设置。可从设置首页的邮件入口进入,也可由左滑设置动作直达;受控 return=inbox|settings 保留来源,返回时不重新同步邮件列表。页面从右侧滑入、向右滑出,减少动态效果时禁用动画;选择操作属于页面内状态,不额外创建路由。
所有邮箱账号共用一套配置,经类型化 mobileSwipeRepository 与 TanStack Query 会话缓存访问,修改后立即生效,刷新恢复默认。每个方向可选删除、归档、标为已读、标记、置顶、已读并归档、无操作七种;不展示移动文件夹、稍后处理、举报或分类。标为已读固定设为已读,标记/置顶复用已有切换语义;无操作不显示按钮、不触发动作。归档移入当前账号归档文件夹,保持原已读状态;已读并归档一次性设置已读并移动,避免中间状态和重复归档。已在归档中的单纯归档不生效,删除仍不支持永久删除。所有操作只更新本地列表、详情及数量缓存,不接入真实邮箱、不写持久化。
移动端账号与文件夹抽屉
用户选择仅预置两个已登录邮箱,不做添加或登录流程。列表头栏的文件夹图标打开 MobileMailboxDrawer,组合批准的 Sheet、Button、Avatar、Badge。左栏为禁用的汇总邮箱入口、个人/工作邮箱、禁用的添加入口和底部设置;右侧展示当前邮箱与收件箱、已发送、已删除、草稿、垃圾邮件、归档六个文件夹。默认 Sheet 支持遮罩、Escape、关闭按钮、焦点约束与关闭后返回触发器;不引入新原始组件。Sheet 的 asChild 兼容修复已单独获得用户批准,记录见下文。
原型宿主传入手机画布的 container;利用 SheetContent 的 asChild 和 React Portal 将内容根节点挂入画布,保留 Sheet 的引用、事件及无障碍属性,定位只用 Tailwind。面板宽为画布的 5/6,随真实移动视口变化;遮罩保留现有 Sheet 的全局模态行为。组件目录不传 container 时使用标准视口定位。关闭入口组合 SheetClose 与批准 Button,不为定位增加 primitive 接口。
2026-10-16 用户明确批准 Sheet 插槽兼容修复:SheetContent 通过官方 Slot.Slottable 标记业务子元素,避免可选关闭按钮形成的数组(包括 false 项)破坏 asChild 的单元素契约。默认非 asChild 模式保持原布局和多个子元素能力;asChild 仍必须传入单个合法元素,并保留 ref/属性透传,不绕过 Slot 验证。只有 sheet 源码摘要经此次批准更新,其他原始组件和依赖不变。组件目录补充默认模式及 asChild 默认/自定义关闭示例;非浏览器回归使用真实 SheetContent 的子元素输出与已安装 Slot 运行时验证,旧模式能复现错误、新模式通过。构建通过不替代浏览器交互验收。
点击账号进入该账号收件箱,保持抽屉打开,便于继续选择文件夹;点击文件夹关闭抽屉并更新列表。当前账号使用 aria-pressed 与勾选图标,当前文件夹使用 aria-current。切换清空搜索、重置筛选,列表滚动回顶部。已发送和草稿列表展示收件人,详情展示真实对应的模拟发/收件地址。草稿从列表直接进入写信页继续编辑;已发送详情不开放回复,不扩展邮件恢复、永久删除或文件夹管理。
账号、文件夹、详情查询缓存均以账号 ID 与文件夹 ID 隔离,详情必须从所属账号和文件夹读取,不能凭邮件 ID 跨账号命中。文件夹数量来自 repository:收件箱/垃圾邮件显示未读数,草稿显示总数,已发送/已删除不额外显示计数;不抄参考图数字。工作邮箱的已删除初始为空,用标准空状态展示。日历产生的原有模拟通知仍归属个人收件箱,桌面原始数据与排序不变。
通过受控 URL 参数 account=personal|work、folder=inbox|sent|trash|drafts|junk 保留列表 → 详情 → 回复/写信 → 返回链路,与 from/via 的 apps/assistant 来源并存。参数缺失或非法时规范化为个人收件箱;刷新带参数的链接保留定位,但不建立登录会话、数据库、cookie 或本地存储。回复和模拟发送使用当前账号的发件地址,模拟完成仍不写入已发送文件夹,也不改变任何数量。
新增账号、汇总邮箱、账号设置保持禁用,不提供密码输入、OAuth、真实邮箱连接、退出账号或登录状态变更。组件已登记组合清单和目录示例,示例只修改自身状态,不改变原型 URL。仅做代码/类型/规范/数据及 root、basePath 构建检查,浏览器与视觉验收仍由用户完成。