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 让截图看起来正确。体验示例见交互演示。