05 · 页面状态、异常与恢复
适用:所有依赖数据、权限、网络和异步任务的页面。状态设计从业务事实出发,不能用一个 isLoading 覆盖所有情况。
ST-01 · 分开描述内容、请求与访问状态
内容:unknown / empty / ready
请求:idle / pending / success / error / outcome-unknown
访问:anonymous / allowed / forbidden / expired
编辑:clean / dirty / saving / conflict
环境:online / offline / degraded
这些维度可以组合:旧内容仍为 ready,刷新请求却 error。页面应保留旧内容并提示刷新失败,不能突然变成全页报错。若用单一枚举,也应明确哪些组合被合并、为什么。
ST-02 · 常见状态的处理矩阵
| 状态 | 用户看到什么 | 操作与恢复 |
|---|---|---|
| 首次加载 | 结构匹配的骨架或等待信息 | 可离开;超时后有下一步 |
| 后台刷新 | 保留已有内容,局部更新 | 刷新失败可重试,不清空内容 |
| 首次使用 | 产品价值、一个开始入口 | 创建、导入或体验示例 |
| 真正零数据 | 当前范围为空的事实 | 根据任务提供创建入口 |
| 搜索无结果 | 当前条件没有匹配 | 清除或修改条件 |
| 部分内容成功 | 成功区域继续显示 | 对失败区域单独重试 |
| 临时网络失败 | 当前操作未完成 | 重试、返回;保留输入 |
| 离线且有缓存 | 缓存内容及必要的更新时间 | 查询、草稿;写操作策略明确 |
| 离线且无缓存 | 当前内容不可取得 | 重连、返回其他可用页面 |
| 未登录 | 当前任务为何需要登录 | 登录后恢复可恢复的任务 |
| 登录过期 | 需要重新验证 | 保存草稿;完成验证后继续 |
| 无权限 | 当前无法查看或修改 | 申请权限或离开,不展示敏感细节 |
| 对象不存在 | 无法找到对象 | 返回列表或搜索 |
| 已删除或已归档 | 对象当前事实 | 合理情况下恢复、查看归档 |
| 字段校验失败 | 字段问题与修正方式 | 聚焦或链接到错误字段 |
| 保存失败 | 未能保存,输入保持 | 重试、复制、存草稿或离开 |
| 冲突 | 本地与远端版本差异 | 比较、合并、另存,避免静默覆盖 |
| 超时且结果未知 | 尚不能确认是否执行 | 查结果或核对记录,再决定重试 |
| 限流 | 当前请求暂时受限 | 有依据时显示等待时间;避免循环重试 |
| 配额不足 | 当前额度和受限动作 | 管理用量、调整任务或按产品规则扩容 |
| 长任务排队 | 所处阶段,可查任务状态 | 允许离开后回来、取消可取消阶段 |
| 用户取消 | 哪些部分已经生效 | 回到稳定状态,清理临时工作 |
| 部分批量失败 | 成功和失败项分别列出 | 只重试失败项、导出结果 |
| 上传中断 | 已传输部分与剩余工作 | 有能力时续传,否则明确重新选择 |
| 空间或存储不足 | 无法继续写入 | 清理、另存、导出,保护已有工作 |
| 外部依赖不可用 | 受影响功能范围 | 使用替代方式,其他区域继续可用 |
这张表是检查目录。每个页面只实例化适用状态,并给出进入方式与不适用理由。
ST-03 · 状态切换应保护用户已经做的事
搜索只显示最新条件对应的响应;离开页面后不把旧请求结果写回新页面;保存失败保留输入;返回列表恢复合理位置;刷新失败不把现有数值替换成假的 0。
使用请求序号、取消信号或查询库管理竞态。取消客户端请求不代表服务端没有执行,尤其不能据此断言写操作失败。
ST-04 · “失败”与“结果未知”是两种状态
扣款、发布、创建资源请求超时,服务端可能已经执行。不要立即显示“失败,请再点一次”。应使用操作标识查询结果,或向用户提供订单、任务记录的入口。幂等与权限校验需要服务端参与。
普通只读查询通常可直接重试;写操作应按业务语义决定能否重试。演示中的模拟保存不证明真实后端具备这些能力。
ST-05 · 每个异常状态都有出口
每个状态规格写四件事:触发条件、可见表达、可做操作、离开路径。尽可能使用一个明确主操作和必要的次操作,避免让失败页成为满屏技术细节。
错误详情和日志标识可提供给需要排障的用户,但不要把堆栈、原始请求体或内部服务名放进普通用户的主要提示。
页面规格示例
| 页面·状态 | 进入方式 | 内容与操作 | 出口 |
|---|---|---|---|
| projects.first-use | 新账号且无项目 | 价值说明、创建项目 | 全局导航 |
| projects.no-match | 搜索一个不存在名称 | 无匹配、清除搜索 | 清除或返回列表 |
| projects.refresh-error | 已有数据,刷新响应失败 | 旧列表、刷新提示、重试 | 正常导航 |
| editor.save-error | 模拟服务端拒绝保存 | 保留表单、原位重试 | 取消、草稿或返回 |
验证必须经过真实控制器或测试服务提供状态,不能只改 DOM 让截图看起来正确。体验示例见交互演示。