状态驱动的前端页面设计:让按钮、标签和流程保持一致

759 字
4 分钟
状态驱动的前端页面设计:让按钮、标签和流程保持一致

订单和异常模块有一个共同特点:同一条数据在不同状态下,颜色、文案、按钮和下一步都不同。若把规则散在几十个 v-if 中,页面迟早会出现“显示待调度,却还能再次审核”的矛盾。

1. 原始状态与展示状态分开#

服务端状态是业务事实,页面标签是面向用户的分组。小程序把多个后台终态归入“已完成”标签,但卡片仍显示“已取消”“已驳回”等具体状态。

const historyStates = new Set([
'COMPLETED', 'CANCELED', 'REJECTED', 'DELIVERY_FAILED'
])

分组用于筛选,原始状态用于解释,二者不能互相覆盖。

2. 状态元数据表#

const ORDER_STATUS_META = {
UNPAID: { label: '待支付', tone: 'danger' },
PENDING_AUDIT: { label: '待审核', tone: 'warning' },
WAIT_DISPATCH: { label: '待调度', tone: 'success' },
DELIVERING: { label: '配送中', tone: 'primary' },
COMPLETED: { label: '已完成', tone: 'info' }
}

列表、详情和消息卡片从同一份元数据读取文案与色彩。未知状态必须有安全回退,而不是渲染空白。

3. 操作白名单#

按钮应从“当前状态允许什么”推导:

const ACTIONS_BY_STATUS = {
PENDING_AUDIT: ['approve', 'reject'],
WAIT_DISPATCH: ['cancel', 'startFlight'],
DELIVERING: ['markDelivered', 'markFailed']
}
const can = action => (ACTIONS_BY_STATUS[status.value] || []).includes(action)

前端白名单改善体验,后端仍要再次校验状态,防止重复请求或越权调用。

4. 派生状态不要重复保存#

“是否历史订单”“是否可以支付”“异常处于登记还是跟踪阶段”都可以由原始数据计算:

const stage = computed(() => ticket.value?.resultOrderId
? 'tracking'
: 'registration')

如果同时保存 stage 和 resultOrderId,其中一个更新失败就会产生矛盾。能计算出来的状态尽量用 computed。

5. 操作后重新获取事实#

审核、支付、取消或完成配送后,不只修改本地 status,而是重新读取详情。一次后端动作可能同时生成流程日志、任务和通知,本地只改一个字段无法覆盖全部副作用。

6. 终态与中间态#

终态通常只读,中间态允许继续操作。异常流程还存在派生订单,使“原订单终态”不等于“异常处理结束”。状态设计要围绕业务对象分别判断,不能拿订单状态替代工单状态。

7. 状态文案也属于规则#

同一个值在用户端与管理端可以有不同表达,例如后台“待审核”对用户可解释为“订单已提交,等待平台确认”。枚举值保持一致,展示文案根据角色转换。

8. 本篇小结#

状态驱动并不是把 if 换成对象,而是承认页面行为来自业务状态。规则集中以后,按钮不再各有各的想法,整个页面终于像同一个团队开发的——哪怕这个团队其实就是昨天和今天的我。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
状态驱动的前端页面设计:让按钮、标签和流程保持一致
https://firefly.cuteleaf.cn/posts/state-driven-frontend-ui/
作者
Yore
发布于
2026-08-18
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Yore
Hello, I'm Yore.
公告
欢迎来到Yore的博客!本站基于原创作者夏叶的博客网站模版创作。
分类
标签
最新动态
站点统计
文章
51
分类
2
标签
124
总字数
94,115
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
EdgeOne Pages
博客版本
Firefly v6.15.0
文章许可
CC BY-NC-SA 4.0