HarmonyOS7 订单状态时间线:ArkUI/ArkTS 实战拆解
前言
订单状态时间线看起来只是几条记录,实际承担的是用户对订单进度的信任感。我做这类页面时,会先盯住三个问题:当前走到哪一步、有没有异常、用户下一步能做什么。
这篇单独聊 物流详情 这个场景。重点不是堆 API,而是把订单节点、异常提示和刷新反馈放进一个真实页面里,看 ArkUI 布局怎么和 ArkTS 状态配合。
为什么这个问题经常被写乱
订单状态时间线 这类内容很容易被写成“代码能跑就算讲完了”,但对初学者来说,这恰恰是最不够的地方。真正让人卡住的,往往不是某个组件名记不住,而是不知道这段代码为什么要这样拆、状态为什么要这样放、以后需求变化时应该从哪里改。
所以这篇文章不只想给你一个能跑的例子,更想把背后的判断过程讲清楚。你只要把这个判断过程吃透,后面自己改页面、补需求、查问题时,心里会稳很多。
我会这样落到真实订单页
订单时间线不要只显示两行文案,真实业务里至少要处理 当前节点、异常节点、客服电话入口、刷新状态。我的做法是先把状态定义清楚,再让 UI 根据状态决定颜色和操作。
实操步骤
- 先和后端约定节点字段:
status、time、operator、remark,不要让前端从一段描述里拆信息。 - 把节点状态收敛成
done/current/warn/wait四类,UI 不直接认识后端枚举。 - 当前节点放在第一屏可见位置,异常节点给出可点击的处理建议。
- 刷新按钮只改加载态和节点列表,不要顺手改订单基础信息。
| 节点状态 | 视觉处理 | 用户动作 |
|---|---|---|
| done | 深色标题、浅色说明 | 只读 |
| current | 品牌色圆点、展开备注 | 查看详情 |
| warn | 红色提示、显示处理按钮 | 联系客服 |
| wait | 灰色弱化 | 无操作 |
时间线页面最怕“所有节点长得一样”。用户真正关心的是:现在到哪了、哪里卡住了、下一步要做什么。
interface OrderStep {
id: number
title: string
time: string
remark: string
state: string
}
@Entry
@Component
struct OrderTimelinePage {
@State refreshing: boolean = false
@State steps: OrderStep[] = [
{ id: 1, title: '已签收', time: '07-11 16:20', remark: '本人签收,服务已完成', state: 'current' },
{ id: 2, title: '派送中', time: '07-11 09:15', remark: '骑手正在前往收货地址', state: 'done' },
{ id: 3, title: '运输异常', time: '07-10 21:40', remark: '中转站延迟,已重新分拣', state: 'warn' },
{ id: 4, title: '商家已发货', time: '07-10 18:05', remark: '包裹离开发货仓', state: 'done' }
]
private stepColor(state: string): string {
if (state === 'current') {
return '#0A59F7'
}
if (state === 'warn') {
return '#D92D20'
}
return '#8A8F99'
}
build() {
Column({ space: 14 }) {
Row() {
Text('订单跟踪').fontSize(22).fontWeight(FontWeight.Bold)
Blank()
Button(this.refreshing ? '刷新中' : '刷新')
.enabled(!this.refreshing)
.onClick(() => {
this.refreshing = true
this.steps[0].remark = '刚刚同步,物流状态无变化'
this.refreshing = false
})
}.width('100%')
List({ space: 0 }) {
ForEach(this.steps, (step: OrderStep, index: number) => {
ListItem() {
Row({ space: 12 }) {
Column() {
Circle({ width: 12, height: 12 }).fill(this.stepColor(step.state))
if (index < this.steps.length - 1) {
Divider().vertical(true).height(58).color('#DADDE3')
}
}.width(20)
Column({ space: 6 }) {
Text(step.title).fontSize(16).fontWeight(step.state === 'current' ? FontWeight.Bold : FontWeight.Medium)
Text(step.time).fontSize(12).fontColor('#8A8F99')
Text(step.remark).fontSize(13).fontColor(this.stepColor(step.state))
if (step.state === 'warn') {
Button('联系客服处理').height(30).fontSize(12)
}
}.alignItems(HorizontalAlign.Start).layoutWeight(1)
}.padding({ top: 10, bottom: 10 })
}
}, (step: OrderStep) => step.id.toString())
}.width('100%')
}.padding(16).backgroundColor('#F6F7FB').height('100%')
}
}
把关键代码一段段拆开
OrderStep.state是前端视图状态,避免 UI 直接绑定复杂后端码值。stepColor()把颜色规则集中起来,后面改主题时不用翻每个Text。ForEach的 key 使用id,物流节点刷新或插入时不容易出现状态复用问题。- 刷新按钮用
refreshing控制禁用态,能挡住连续点击造成的重复请求。
时间线真正要讲清楚什么
订单时间线不是把节点倒序排出来就结束了。用户打开这个页面,是想确认订单有没有正常推进,所以当前节点要最醒目,异常节点要给出解释和下一步动作,已经完成的节点只需要稳定记录。
示例里的 state 是一个前端视图状态,它把后端各种物流码收敛成页面能理解的几类。这样 UI 不需要到处判断复杂码值,只要根据 current、warn、done 去决定颜色、按钮和说明文案。
写在最后
如果后续接真实接口,刷新时建议整体替换 steps 数组,而不是只修改数组里某个对象字段。时间线经常会插入新节点或调整顺序,稳定的业务 id 和明确的数组更新,会让页面刷新更可靠。
更多推荐



所有评论(0)