✅ 阶段 4 – 订单列表 & 状态
目标
- 展示用户「我的订单」列表
- 支持状态筛选(全部 / 待处理 / 已完成)
- 支持分页加载和实时刷新
- 使用原生组件编写
✅ 1. 页面结构:文件结构
pages/orders/
├─ index.json
├─ index.wxml
├─ index.js
└─ index.wxss
✅ 2. 页面配置 index.json
{
"navigationBarTitleText": "我的订单"
}
✅ 3. 页面模板 index.wxml
<view class="tabs">
<text class="tab {{activeTab==0 ? 'active' : ''}}" data-index="0" bindtap="onTabChange">全部</text>
<text class="tab {{activeTab==1 ? 'active' : ''}}" data-index="1" bindtap="onTabChange">待处理</text>
<text class="tab {{activeTab==2 ? 'active' : ''}}" data-index="2" bindtap="onTabChange">已完成</text>
</view>
<view wx:if="{{orders.length}}">
<block wx:for="{{orders}}" wx:key="orderNo">
<view class="order-card">
<view class="order-header">
<text>订单号:{{item.orderNo}}</text>
<text class="status {{item.status}}">{{item.status == 'PENDING' ? '待处理' : '已完成'}}</text>
</view>
<view class="order-body">
<text>共 {{item.totalCount}} 件商品</text>
<text>合计:¥{{item.totalPrice}}</text>
</view>
<view class="order-time">{{item.timeStr}}</view>
</view>
</block>
</view>
<view wx:else class="empty">
<text>暂无订单</text>
</view>
✅ 4. 样式 index.wxss
.tabs {
display: flex;
border-bottom: 1px solid #eee;
background: #f8f8f8;
}
.tab {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 30rpx;
color: #888;
}
.tab.active {
color: #333;
border-bottom: 4rpx solid #07c160;
font-weight: bold;
}
.order-card {
background: #fff;
margin: 20rpx;
padding: 20rpx;
border-radius: 12rpx;
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04);
}
.order-header {
display: flex;
justify-content: space-between;
font-weight: bold;
}
.status {
font-size: 28rpx;
}
.status.PENDING {
color: #ff9900;
}
.status.DONE {
color: #07c160;
}
.order-body {
margin-top: 10rpx;
font-size: 28rpx;
display: flex;
justify-content: space-between;
}
.order-time {
font-size: 24rpx;
color: #999;
margin-top: 10rpx;
text-align: right;
}
.empty {
text-align: center;
color: #999;
font-size: 28rpx;
padding: 100rpx 0;
}
✅ 5. 页面逻辑 index.js
const db = wx.cloud.database()
const PAGE_SIZE = 10
Page({
data: {
activeTab: 0,
orders: [],
page: 0,
finished: false
},
onShow() {
this.resetAndLoad()
this.timer = setInterval(() => this.refresh(), 5000)
},
onHide() {
clearInterval(this.timer)
},
onUnload() {
clearInterval(this.timer)
},
onTabChange(e) {
this.setData({ activeTab: Number(e.currentTarget.dataset.index) })
this.resetAndLoad()
},
resetAndLoad() {
this.setData({ orders: [], page: 0, finished: false })
this.loadPage()
},
async loadPage(isRefresh = false) {
if (this.data.finished) return
const statusMap = ['', 'PENDING', 'DONE']
const filter = statusMap[this.data.activeTab]
let query = db.collection('orders')
if (filter) {
query = query.where({ status: filter })
}
const res = await query
.orderBy('createdAt', 'desc')
.skip(this.data.page * PAGE_SIZE)
.limit(PAGE_SIZE)
.get()
const list = res.data.map(o => ({
...o,
totalCount: o.items.reduce((sum, i) => sum + i.count, 0),
timeStr: this.formatTime(o.createdAt)
}))
this.setData({
orders: isRefresh ? list : this.data.orders.concat(list),
page: this.data.page + 1,
finished: list.length < PAGE_SIZE
})
},
refresh() {
this.setData({ page: 0, finished: false })
this.loadPage(true)
},
formatTime(ts) {
const date = new Date(ts)
return `${date.getMonth()+1}-${date.getDate()} ${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`
}
})
✅ 6. 自测 Checklist
- 能切换订单状态:全部 / 待处理 / 已完成
- 正确显示订单号、商品数量、金额
- 页面卡片样式清晰
- 页面首次进入加载数据
- 每 5 秒自动刷新状态(模拟店员更新)
- 无订单时显示「暂无订单」