文章目录
一、下拉刷新
需求
实现下拉刷新小程序

分析
scroll-view 开启
- refresher-enabled
- refresher-triggered="{{refresherTriggered}}"
- bindrefresherrefresh="onRefresh"
javascript
data: {
orders: [],
// 视角
cameraAngles: ['无人机视角', '地面全景', '飞达池特写'],
progressSteps: [
{ step:0, label: '已下单', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic1.jpg' },
{ step:2, label: '已封装', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic2.jpg' },
{ step:3, label: '绕飞中', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic3.jpg' },
{ step:4, label: '投放完成', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic4.jpg' },
],
// 分页与刷新
pageNo: 1,
pageSize: 10,
hasMore: true,
loading: false,
refresherTriggered: false,
},
onRefresh() {
if (this.data.loading) return
this.setData({ pageNo: 1, hasMore: true, refresherTriggered: true })
this.getTradeOrderList({ append: false })
},
二、上拉加载更多
需求
实现上拉加载更多数据的功能
分析
scroll-view 开启
- refresher-enabled
- refresher-triggered="{{refresherTriggered}}"
- bindrefresherrefresh="onRefresh"
javascript
data: {
orders: [],
// 视角
cameraAngles: ['无人机视角', '地面全景', '飞达池特写'],
progressSteps: [
{ step:0, label: '已下单', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic1.jpg' },
{ step:2, label: '已封装', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic2.jpg' },
{ step:3, label: '绕飞中', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic3.jpg' },
{ step:4, label: '投放完成', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic4.jpg' },
],
// 分页与刷新
pageNo: 1,
pageSize: 10,
hasMore: true,
loading: false,
refresherTriggered: false,
},
onLoadMore() {
if (this.data.loading || !this.data.hasMore) return
console.log('触底加载更多,当前页码:', this.data.pageNo);
this.setData({
pageNo: this.data.pageNo + 1,
loading: true
});
this.loadMoreOrders();
},
// 加载更多订单
async loadMoreOrders() {
try {
const res = await fetchTradeOrderListApi({
pageNo: this.data.pageNo,
pageSize: this.data.pageSize,
});
if (res.code === 0 && res.data.list.length > 0) {
// 为新订单计算飞行状态
const newOrders = res.data.list.map(order => {
let flightState = -1;
if (order.flightInfo && typeof order.flightInfo.state === 'number') {
flightState = order.flightInfo.state;
} else if (order.state === 3) {
flightState = 0; // 已下单
}
return {
...order,
flightState: flightState
};
});
// 判断是否还有更多数据
const hasMore = newOrders.length >= this.data.pageSize;
this.setData({
orders: [...this.data.orders, ...newOrders],
hasMore: hasMore,
loading: false
});
console.log('加载更多完成,新增订单数:', newOrders.length, '是否还有更多:', hasMore);
} else {
// 没有更多数据
this.setData({
hasMore: false,
loading: false
});
console.log('没有更多数据了');
}
} catch (err) {
console.error('加载更多订单失败:', err);
this.setData({ loading: false });
wx.showToast({
title: '加载失败',
icon: 'none'
});
}
},
总
wxml
javascript
<!--pages/blessing-archive/archive.wxml-->
<navigation-bar title="档案" back="{{true}}" color="#FFF5D0" background="transparent" opacity="0" transparent="true"></navigation-bar>
<image class="bg-image" src="/assets/feiyuan/bg-home.jpg" mode="aspectFill"></image>
<scroll-view
class="page-scroll"
scroll-y="true"
enhanced="true"
show-scrollbar="false"
bindscrolltolower="onLoadMore"
refresher-enabled
refresher-triggered="{{refresherTriggered}}"
bindrefresherrefresh="onRefresh"
>
<view class="page-container" wx:if="{{orders.length > 0}}">
<!-- 展开的订单 -->
<block wx:for="{{orders}}" wx:key="id" wx:for-index="parentIndex">
<view class="order-item">
<!-- 订单头部 -->
<view class="order-header" bindtap="toggleOrder" data-id="{{item.id}}">
<view class="order-id">
<view class="order-id-text">{{item.tradeOrderNo}}</view>
<view class="order-service-text">飞达进度</view>
</view>
<view style="display: flex; align-items: center;">
<view wx:if="{{item.state === 4}}" class="order-status completed" bindtap="onViewCertificate" data-id="{{item.id}}">
飞达证书
</view>
<view wx:else class="order-status processing">
<block wx:if="{{item.state == 0}}">待支付</block>
<block wx:elif="{{item.state == 1}}">待审核</block>
<block wx:elif="{{item.state == 2}}">审核未通过</block>
<block wx:elif="{{item.state == 3}}">飞达中</block>
<block wx:elif="{{item.state == 4}}">已完成</block>
<block wx:else>已取消</block>
</view>
</view>
</view>
<!-- 订单详情 -->
<view wx:if="{{item.state === 4}}" class="order-detail">
<!-- 视频区域 -->
<view class="video-area" bindtap="onPlayVideo" data-parent-index="{{parentIndex}}">
<image
class="video-cover"
src="https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/home-3.jpg"
mode="aspectFill"
/>
<view class="video-overlay"></view>
<!-- <view class="video-play-btn">
<view class="video-play-icon"></view>
</view> -->
</view>
<!-- 视角切换 -->
<view class="camera-tabs">
<view
class="camera-tab {{item.currentAngle === angleIndex ? 'active' : ''}}"
wx:for="{{cameraAngles}}"
wx:key="*this"
wx:for-item="angle"
wx:for-index="angleIndex"
data-index="{{angleIndex}}"
data-parent-index="{{parentIndex}}"
bindtap="onAngleChange"
>
<text class="camera-tab-text">{{angle}}</text>
</view>
</view>
</view>
<view wx:else class="order-detail">
<!-- 飞达进度 -->
<view class="progress-card" style="display: flex; align-items: center; justify-content: space-around;" wx:if="{{item.state === 0}}">
<view class="submit-btn submit-state1" bindtap="payNow" data-id="{{item.tradeInfo.payOrderId}}">
<text class="submit-btn-text">立即支付</text>
</view>
<view class="submit-btn submit-state2" bindtap="closeOrder" data-id="{{item.tradeOrderId}}">
<text class="submit-btn-text" style="color: #FF4D4F;">取消订单</text>
</view>
</view>
<view class="progress-card" wx:else>
<!-- <text class="progress-title">飞达进度</text> -->
<view class="progress-steps">
<view class="step-item" wx:for="{{progressSteps}}" wx:key="label" wx:for-item="feat">
<!-- 步骤编号圆 -->
<view class="step-top-row">
<view class="step-line-left {{feat.step === 0 ? 'hidden' : ''}} {{feat.step <= item.flightState ? 'done' : ''}}"></view>
<view class="step-circle {{feat.step <= item.flightState ? 'done' : ''}} {{feat.step === item.flightState ? 'active' : ''}}">
<image wx:if="{{feat.step <= item.flightState}}" class="step-icon" src="https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/status1-1.png" mode="aspectFill" />
<image wx:else class="step-icon" src="https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/status2-2.png" mode="aspectFill" />
</view>
<view class="step-line-right {{feat.step === progressSteps.length - 1 ? 'hidden' : ''}} {{feat.step < item.flightState ? 'done' : ''}}"></view>
</view>
<!-- 步骤名称 -->
<text class="step-label {{feat.step <= item.flightState ? 'done' : ''}}">{{feat.label}}</text>
<!-- 缩略图占位 -->
<view class="step-thumb {{feat.step <= item.flightState ? 'done' : ''}}">
<image wx:if="{{feat.thumb}}" class="step-thumb-img" src="{{feat.thumb}}" mode="aspectFill" />
</view>
</view>
</view>
</view>
</view>
</view>
</block>
</view>
<!-- ========== 无订单 - 缺省状态 ========== -->
<block wx:else>
<view class="no-video-container">
<!-- 缺省图片 -->
<image
class="no-video-image"
src="/assets/feiyuan/live-videono.png"
mode="aspectFit"
/>
<!-- 前往飞达页面 -->
<view class="no-video-btn" bindtap="onGoToBlessing">
<text class="no-video-btn-text">前往飞达</text>
</view>
</view>
</block>
<!-- 加载状态提示 -->
<view class="loading-status" wx:if="{{loading}}">
<text>加载中...</text>
</view>
<view class="loading-status" wx:elif="{{!hasMore && orders.length > 0}}">
<text>没有更多数据了</text>
</view>
</scroll-view>
js
javascript
// pages/blessing-archive/archive.js
import {fetchTradeOrderListApi} from '../../api/prayApi.js'
import { cancelPayOrder } from '../../api/orderListApi.js'
import { getPayOrder,getPayOrderDetail,submitPayOrder } from '../../api/packageDetailApi.js'
Page({
data: {
orders: [],
// 视角
cameraAngles: ['无人机视角', '地面全景', '飞达池特写'],
progressSteps: [
{ step:0, label: '已下单', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic1.jpg' },
{ step:2, label: '已封装', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic2.jpg' },
{ step:3, label: '绕飞中', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic3.jpg' },
{ step:4, label: '投放完成', thumb: 'https://www.aaa.com/ifly-api/admin-api/infra/file/29/get/wxMiniProDefault/feiyuan/pic4.jpg' },
],
// 分页与刷新
pageNo: 1,
pageSize: 10,
hasMore: true,
loading: false,
refresherTriggered: false,
},
onShow() {
// 页面显示
this.getTradeOrderList({ append: false }); // 获取订单列表
},
// ===== 展开/收起订单 =====
toggleOrder(e) {
const id = e.currentTarget.dataset.id;
const orders = this.data.orders;
const order = orders.find(o => o.id === id);
if (order) {
order.expanded = !order.expanded;
this.setData({ orders });
}
},
// ===== 查看证书 =====
onViewCertificate(e) {
const id = e.currentTarget.dataset.id;
wx.navigateTo({
url: `/pages/certificate-detail/detail?tradeOrderNo=${id}`
});
},
// ===== 展开折叠订单 =====
expandCollapsedOrder(e) {
const id = e.currentTarget.dataset.id;
const collapsed = this.data.collapsedOrders;
const order = collapsed.find(o => o.id === id);
if (order) {
// 模拟展开逻辑:将折叠项移到主列表
const newOrder = {
id: order.id,
tradeOrderNo: order.tradeOrderNo,
service: '基础版飞达服务',
time: '2026-02-28 20:00',
status: 'completed',
statusText: '飞达完成',
expanded: true
};
this.setData({
orders: [...this.data.orders, newOrder],
collapsedOrders: collapsed.filter(o => o.id !== id)
});
}
},
// ===== 视角切换 =====
onAngleChange(e) {
const childIndex = e.currentTarget.dataset.index; // 子循环索引
console.log(e.currentTarget.dataset);
const parentIndex = e.currentTarget.dataset.parentIndex; // 父循环索引
const orders = this.data.orders;
const order = orders[parentIndex];
if (order) {
order.currentAngle = childIndex;
this.setData({ orders });
}
},
// ===== 视频播放 =====
onPlayVideo() {
console.log('点击了视频视频播放');
wx.showToast({ title: '视频加载中...', icon: 'none' });
},
// ===== 获取订单列表 =====
async getTradeOrderList({ append }) {
if (this.data.loading || (!this.data.hasMore && append)) return
this.setData({ loading: true })
const { pageNo, pageSize } = this.data
try {
const res = await fetchTradeOrderListApi({
pageNo,
pageSize,
});
if (res.code === 0) {
// 为每个订单计算飞行状态
const ordersWithFlightState = res.data.list.map(order => {
let flightState = -1;
// 如果 flightInfo 存在,使用 flightInfo.state
if (order.flightInfo && typeof order.flightInfo.state === 'number') {
flightState = order.flightInfo.state;
} else if (order.state === 3) {
// 如果 flightInfo 为 null 但 order.state === 3,显示已下单状态
flightState = 0; // 已下单
}
return {
...order,
flightState: flightState
};
});
// 判断是否还有更多数据
const hasMore = ordersWithFlightState.length >= pageSize;
this.setData({
orders: append ? [...this.data.orders, ...ordersWithFlightState] : ordersWithFlightState,
hasMore: append ? this.data.hasMore && hasMore : hasMore,
loading: false,
refresherTriggered: false
});
console.log(`获取订单列表成功,共${append ? this.data.orders.length + ordersWithFlightState.length : ordersWithFlightState.length}条订单,是否还有更多:${hasMore}`);
} else {
this.setData({
hasMore: false,
loading: false,
refresherTriggered: false
});
}
} catch (err) {
console.error('获取订单列表失败:', err);
this.setData({ loading: false, refresherTriggered: false })
wx.showToast({
title: '获取失败',
icon: 'none'
});
}
},
// ===== 立即支付 =====
async payNow(e) {
const payOrderId = e.currentTarget?.dataset?.id
if (!payOrderId) {
wx.showToast({ title: '支付信息缺失', icon: 'none' })
return
}
try {
const openid = wx.getStorageSync('openId')
const pRes = await submitPayOrder({
id: payOrderId,
channelCode: 'wx_wish',
channelExtras: { openid },
openid,
})
if (pRes?.code !== 0) {
throw new Error(pRes?.msg || '支付失败')
}
const payData = pRes?.data || {}
const params = JSON.parse(payData.displayContent || '{}')
const payParams = {
timeStamp: params.timeStamp,
nonceStr: params.nonceStr,
package: params.packageValue,
signType: params.signType,
paySign: params.paySign,
success: async () => {
try {
// 先同步查询订单状态,后台会把订单状态改为已支付/待使用
const res = await getPayOrder(payOrderId, true)
const merchantOrderId = res?.data?.merchantOrderId
if (merchantOrderId) {
await getPayOrderDetail(merchantOrderId, true)
}
} catch (err) {
console.warn('同步支付结果失败', err)
}
wx.showToast({ title: '支付成功', icon: 'success' })
// 刷新页面列表
this.getTradeOrderList({ append: false })
},
fail: err => {
console.warn('支付失败', err)
wx.showToast({ title: '支付已取消', icon: 'none' })
},
}
wx.requestPayment(payParams)
} catch (err) {
console.error('支付失败', err)
wx.showToast({ title: err?.message || '支付失败', icon: 'none' })
}
},
// ===== 关闭订单 =====
closeOrder(e) {
const id = e?.currentTarget?.dataset?.id
if (!id) {
wx.showToast({ title: '订单ID错误', icon: 'none' })
return
}
wx.showModal({
title: '提示',
content: '确定要关闭订单吗?',
success: async res => {
if (!res.confirm) return
try {
wx.showLoading({ title: '取消中...' })
// TODO: 更换调用取消订单接口,返回结果后刷新页面列表
wx.showToast({ title: '该功能正在开发中', icon: 'success' })
wx.hideLoading()
return
const result = await cancelPayOrder({ id })
wx.hideLoading()
if (result?.code === 0) {
wx.showToast({ title: '已取消', icon: 'success' })
// 刷新页面列表
this.getTradeOrderList()
} else {
wx.showToast({
title: result?.msg || '关闭失败',
icon: 'none',
})
}
} catch (err) {
wx.hideLoading()
console.error('关闭订单失败', err)
wx.showToast({ title: '关闭失败', icon: 'none' })
}
},
})
},
// ===== 前往飞达页面 =====
onGoToBlessing() {
wx.switchTab({
url: '/pages/pray/pray'
});
},
// ===== 下拉刷新 =====
onRefresh() {
if (this.data.loading) return
this.setData({ pageNo: 1, hasMore: true, refresherTriggered: true })
this.getTradeOrderList({ append: false })
},
// 触底加载更多
onLoadMore() {
if (this.data.loading || !this.data.hasMore) return
console.log('触底加载更多,当前页码:', this.data.pageNo);
this.setData({
pageNo: this.data.pageNo + 1,
loading: true
});
this.loadMoreOrders();
},
// 加载更多订单
async loadMoreOrders() {
try {
const res = await fetchTradeOrderListApi({
pageNo: this.data.pageNo,
pageSize: this.data.pageSize,
});
if (res.code === 0 && res.data.list.length > 0) {
// 为新订单计算飞行状态
const newOrders = res.data.list.map(order => {
let flightState = -1;
if (order.flightInfo && typeof order.flightInfo.state === 'number') {
flightState = order.flightInfo.state;
} else if (order.state === 3) {
flightState = 0; // 已下单
}
return {
...order,
flightState: flightState
};
});
// 判断是否还有更多数据
const hasMore = newOrders.length >= this.data.pageSize;
this.setData({
orders: [...this.data.orders, ...newOrders],
hasMore: hasMore,
loading: false
});
console.log('加载更多完成,新增订单数:', newOrders.length, '是否还有更多:', hasMore);
} else {
// 没有更多数据
this.setData({
hasMore: false,
loading: false
});
console.log('没有更多数据了');
}
} catch (err) {
console.error('加载更多订单失败:', err);
this.setData({ loading: false });
wx.showToast({
title: '加载失败',
icon: 'none'
});
}
},
});