feat(订单支付): 优化支付成功后订单状态更新逻辑
修改支付组件和订单页面,使用事件驱动方式更新订单状态 移除页面重新加载方式,提升用户体验和性能 添加支付成功事件处理函数,实现订单状态本地更新 更新相关文档说明优化方案和效果
Showing
5 changed files
with
188 additions
and
19 deletions
payment-status-update-guide.md
0 → 100644
| 1 | +# 支付成功后订单状态更新优化 | ||
| 2 | + | ||
| 3 | +## 问题描述 | ||
| 4 | + | ||
| 5 | +原来的实现中,在我的订单页面支付成功后,使用 `Taro.reLaunch()` 重新加载整个页面来刷新订单状态。这种方式存在以下问题: | ||
| 6 | + | ||
| 7 | +1. **用户体验差**:页面重新加载会导致闪烁,用户体验不佳 | ||
| 8 | +2. **性能问题**:重新加载整个页面消耗更多资源 | ||
| 9 | +3. **状态丢失**:页面重新加载会丢失当前的筛选状态、滚动位置等 | ||
| 10 | +4. **不必要的网络请求**:重新加载会触发不必要的数据请求 | ||
| 11 | + | ||
| 12 | +## 解决方案 | ||
| 13 | + | ||
| 14 | +### 1. 修改支付组件 (payCard.vue) | ||
| 15 | + | ||
| 16 | +#### 添加支付成功事件 | ||
| 17 | +```javascript | ||
| 18 | +// 添加 paySuccess 事件到 emit 声明 | ||
| 19 | +const emit = defineEmits(['close', 'paySuccess']); | ||
| 20 | +``` | ||
| 21 | + | ||
| 22 | +#### 修改支付成功处理逻辑 | ||
| 23 | +```javascript | ||
| 24 | +// 原来的实现:重新加载页面 | ||
| 25 | +if (current_page === 'pages/myOrders/index') { | ||
| 26 | + Taro.reLaunch({ | ||
| 27 | + url: '/pages/myOrders/index' | ||
| 28 | + }); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +// 新的实现:发出事件通知父组件 | ||
| 32 | +if (current_page === 'pages/myOrders/index') { | ||
| 33 | + // 发出支付成功事件,通知父组件更新订单状态 | ||
| 34 | + emit('paySuccess', { orderId: id.value }); | ||
| 35 | +} | ||
| 36 | +``` | ||
| 37 | + | ||
| 38 | +### 2. 修改订单页面 (myOrders/index.vue) | ||
| 39 | + | ||
| 40 | +#### 监听支付成功事件 | ||
| 41 | +```vue | ||
| 42 | +<!-- 在模板中添加事件监听 --> | ||
| 43 | +<payCard | ||
| 44 | + :visible="show_pay" | ||
| 45 | + :data="payData" | ||
| 46 | + @close="onPayClose" | ||
| 47 | + @paySuccess="onPaySuccess" | ||
| 48 | +/> | ||
| 49 | +``` | ||
| 50 | + | ||
| 51 | +#### 添加支付成功处理函数 | ||
| 52 | +```javascript | ||
| 53 | +/** | ||
| 54 | + * 处理支付成功事件 | ||
| 55 | + * @param {Object} data - 支付成功数据 | ||
| 56 | + * @param {string} data.orderId - 订单ID | ||
| 57 | + */ | ||
| 58 | +const onPaySuccess = ({ orderId }) => { | ||
| 59 | + // 找到对应的订单并更新状态 | ||
| 60 | + const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value | ||
| 61 | + const order = orders.find(o => o.id === orderId) | ||
| 62 | + | ||
| 63 | + if (order) { | ||
| 64 | + // 更新订单状态为已完成 | ||
| 65 | + order.status = 'completed' | ||
| 66 | + | ||
| 67 | + Taro.showToast({ | ||
| 68 | + title: '支付成功,订单已更新', | ||
| 69 | + icon: 'success', | ||
| 70 | + duration: 2000 | ||
| 71 | + }) | ||
| 72 | + } | ||
| 73 | +} | ||
| 74 | +``` | ||
| 75 | + | ||
| 76 | +## 优化效果 | ||
| 77 | + | ||
| 78 | +### 1. 用户体验提升 | ||
| 79 | +- ✅ **无页面闪烁**:订单状态实时更新,无需重新加载页面 | ||
| 80 | +- ✅ **保持状态**:筛选条件、滚动位置等状态得以保持 | ||
| 81 | +- ✅ **响应迅速**:状态更新即时生效,用户感知更好 | ||
| 82 | + | ||
| 83 | +### 2. 性能优化 | ||
| 84 | +- ✅ **减少资源消耗**:避免重新加载整个页面 | ||
| 85 | +- ✅ **减少网络请求**:无需重新获取订单列表数据 | ||
| 86 | +- ✅ **内存效率**:复用现有组件实例 | ||
| 87 | + | ||
| 88 | +### 3. 代码维护性 | ||
| 89 | +- ✅ **事件驱动**:使用标准的 Vue 事件机制 | ||
| 90 | +- ✅ **组件解耦**:支付组件与页面逻辑分离 | ||
| 91 | +- ✅ **易于扩展**:可以轻松添加更多支付相关事件 | ||
| 92 | + | ||
| 93 | +## 技术实现细节 | ||
| 94 | + | ||
| 95 | +### 事件流程 | ||
| 96 | +1. 用户在订单页面点击"去支付"按钮 | ||
| 97 | +2. 打开支付弹窗组件 (payCard) | ||
| 98 | +3. 用户完成支付操作 | ||
| 99 | +4. 支付组件调用支付检查API确认支付成功 | ||
| 100 | +5. 支付组件发出 `paySuccess` 事件,传递订单ID | ||
| 101 | +6. 订单页面监听到事件,根据订单ID更新对应订单状态 | ||
| 102 | +7. 页面UI自动响应状态变化,显示最新状态 | ||
| 103 | + | ||
| 104 | +### 数据流向 | ||
| 105 | +``` | ||
| 106 | +订单页面 → 支付组件 → 微信支付 → 支付成功 → 事件通知 → 订单页面 → 状态更新 | ||
| 107 | +``` | ||
| 108 | + | ||
| 109 | +## 测试建议 | ||
| 110 | + | ||
| 111 | +1. **功能测试** | ||
| 112 | + - 在订单页面选择待支付订单进行支付 | ||
| 113 | + - 验证支付成功后订单状态是否正确更新为"已完成" | ||
| 114 | + - 确认页面无重新加载现象 | ||
| 115 | + | ||
| 116 | +2. **状态保持测试** | ||
| 117 | + - 切换到特定筛选标签(如"待支付") | ||
| 118 | + - 滚动到页面中间位置 | ||
| 119 | + - 进行支付操作 | ||
| 120 | + - 验证支付成功后筛选状态和滚动位置是否保持 | ||
| 121 | + | ||
| 122 | +3. **边界情况测试** | ||
| 123 | + - 支付失败时的处理 | ||
| 124 | + - 网络异常时的处理 | ||
| 125 | + - 多个订单同时支付的情况 | ||
| 126 | + | ||
| 127 | +## 相关文件 | ||
| 128 | + | ||
| 129 | +- `/src/components/payCard.vue` - 支付组件 | ||
| 130 | +- `/src/pages/myOrders/index.vue` - 订单管理页面 | ||
| 131 | + | ||
| 132 | +## 注意事项 | ||
| 133 | + | ||
| 134 | +1. 确保支付成功后的状态更新逻辑与后端API保持一致 | ||
| 135 | +2. 考虑添加错误处理机制,处理支付过程中的异常情况 | ||
| 136 | +3. 如果有其他页面也使用了支付组件,需要相应地添加事件监听 | ||
| 137 | +4. 建议在真实环境中测试支付流程的完整性 | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -23,7 +23,7 @@ const App = createApp({ | ... | @@ -23,7 +23,7 @@ const App = createApp({ |
| 23 | // if (path !== 'pages/index/index' && !wx.getStorageSync("sessionid")) { | 23 | // if (path !== 'pages/index/index' && !wx.getStorageSync("sessionid")) { |
| 24 | if (!wx.getStorageSync("sessionid")) { | 24 | if (!wx.getStorageSync("sessionid")) { |
| 25 | console.warn("没有权限"); | 25 | console.warn("没有权限"); |
| 26 | - if (path === 'pages/detail/index') { | 26 | + if (path === 'pages/productDetail/index') { |
| 27 | Taro.navigateTo({ | 27 | Taro.navigateTo({ |
| 28 | url: `./pages/auth/index?url=${path}&id=${query.id}`, | 28 | url: `./pages/auth/index?url=${path}&id=${query.id}`, |
| 29 | }) | 29 | }) | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2023-12-20 14:11:11 | 2 | * @Date: 2023-12-20 14:11:11 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-08 20:22:50 | 4 | + * @LastEditTime: 2025-07-09 12:16:16 |
| 5 | * @FilePath: /jgdl/src/components/payCard.vue | 5 | * @FilePath: /jgdl/src/components/payCard.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| 9 | <div class="pay-card"> | 9 | <div class="pay-card"> |
| 10 | - <nut-action-sheet v-model:visible="props.visible" title="" @close="onClose"> | 10 | + <nut-action-sheet v-model:visible="visible" title="" @close="onClose"> |
| 11 | <view style="padding: 2rem 1rem; text-align: center;"> | 11 | <view style="padding: 2rem 1rem; text-align: center;"> |
| 12 | <view style="font-size: 32rpx;">实付金额</view> | 12 | <view style="font-size: 32rpx;">实付金额</view> |
| 13 | <view style="color: red; margin: 10rpx 0;"><text style="font-size: 50rpx;">¥</text><text style="font-size: 80rpx;">{{ price }}</text></view> | 13 | <view style="color: red; margin: 10rpx 0;"><text style="font-size: 50rpx;">¥</text><text style="font-size: 80rpx;">{{ price }}</text></view> |
| ... | @@ -47,14 +47,16 @@ const props = defineProps({ | ... | @@ -47,14 +47,16 @@ const props = defineProps({ |
| 47 | }, | 47 | }, |
| 48 | data: { | 48 | data: { |
| 49 | type: Object, | 49 | type: Object, |
| 50 | - default: {}, | 50 | + default: () => ({}), |
| 51 | }, | 51 | }, |
| 52 | }); | 52 | }); |
| 53 | 53 | ||
| 54 | -const emit = defineEmits(['close']); | 54 | +const emit = defineEmits(['close', 'paySuccess']); |
| 55 | + | ||
| 56 | +const visible = ref(false); | ||
| 55 | 57 | ||
| 56 | const onClose = () => { | 58 | const onClose = () => { |
| 57 | - emit('close'); | 59 | + visible.value = false; |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | const id = ref(''); | 62 | const id = ref(''); |
| ... | @@ -66,6 +68,7 @@ let timeId = null; | ... | @@ -66,6 +68,7 @@ let timeId = null; |
| 66 | watch( | 68 | watch( |
| 67 | () => props.visible, | 69 | () => props.visible, |
| 68 | (val) => { | 70 | (val) => { |
| 71 | + visible.value = val; | ||
| 69 | if (val) { | 72 | if (val) { |
| 70 | id.value = props.data.id; | 73 | id.value = props.data.id; |
| 71 | price.value = props.data.price; | 74 | price.value = props.data.price; |
| ... | @@ -74,13 +77,22 @@ watch( | ... | @@ -74,13 +77,22 @@ watch( |
| 74 | } | 77 | } |
| 75 | ) | 78 | ) |
| 76 | 79 | ||
| 80 | +watch( | ||
| 81 | + () => visible.value, | ||
| 82 | + (val) => { | ||
| 83 | + if (!val) { | ||
| 84 | + emit('close'); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | +) | ||
| 88 | + | ||
| 77 | onMounted(() => { | 89 | onMounted(() => { |
| 78 | // 进入页面后,开始倒计时 | 90 | // 进入页面后,开始倒计时 |
| 79 | timeId = setInterval(() => { | 91 | timeId = setInterval(() => { |
| 80 | remain_time.value ? remain_time.value -= 1 : 0; | 92 | remain_time.value ? remain_time.value -= 1 : 0; |
| 81 | if (remain_time.value === 0) { // 倒计时结束 | 93 | if (remain_time.value === 0) { // 倒计时结束 |
| 82 | clearInterval(timeId); | 94 | clearInterval(timeId); |
| 83 | - emit('close'); | 95 | + visible.value = false; |
| 84 | } | 96 | } |
| 85 | }, 1000); | 97 | }, 1000); |
| 86 | }) | 98 | }) |
| ... | @@ -102,8 +114,8 @@ const goToPay = async () => { | ... | @@ -102,8 +114,8 @@ const goToPay = async () => { |
| 102 | package: pay.package, | 114 | package: pay.package, |
| 103 | signType: pay.signType, | 115 | signType: pay.signType, |
| 104 | paySign: pay.paySign, | 116 | paySign: pay.paySign, |
| 105 | - success: async (result) => { | 117 | + success: async () => { |
| 106 | - emit('close'); // 关闭支付弹框 | 118 | + visible.value = false; // 关闭支付弹框 |
| 107 | Taro.showToast({ | 119 | Taro.showToast({ |
| 108 | title: '支付成功', | 120 | title: '支付成功', |
| 109 | icon: 'success', | 121 | icon: 'success', |
| ... | @@ -113,16 +125,14 @@ const goToPay = async () => { | ... | @@ -113,16 +125,14 @@ const goToPay = async () => { |
| 113 | const pay_success = await payCheckAPI({ order_id: id.value }); | 125 | const pay_success = await payCheckAPI({ order_id: id.value }); |
| 114 | if (pay_success.code) { | 126 | if (pay_success.code) { |
| 115 | let current_page = getCurrentPageUrl(); | 127 | let current_page = getCurrentPageUrl(); |
| 116 | - if (current_page === 'pages/my/index') { // 我的页面打开 | 128 | + if (current_page === 'pages/myOrders/index') { // 我的订单打开 |
| 117 | - // 刷新当前页面 | 129 | + // 发出支付成功事件,通知父组件更新订单状态 |
| 118 | - Taro.reLaunch({ | 130 | + emit('paySuccess', { orderId: id.value }); |
| 119 | - url: '/pages/my/index?tab_index=5' | ||
| 120 | - }); | ||
| 121 | } | 131 | } |
| 122 | - if (current_page === 'pages/detail/index') { // 订房确认页打开 | 132 | + if (current_page === 'pages/productDetail/index') { // 详情页打开 |
| 123 | // 跳转订单成功页 | 133 | // 跳转订单成功页 |
| 124 | Taro.navigateTo({ | 134 | Taro.navigateTo({ |
| 125 | - url: '/pages/payInfo/index', | 135 | + url: '/pages/myOrders/index', |
| 126 | }); | 136 | }); |
| 127 | } | 137 | } |
| 128 | } | 138 | } | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-09 11:36:52 | 4 | + * @LastEditTime: 2025-07-09 11:47:21 |
| 5 | * @FilePath: /jgdl/src/pages/auth/index.vue | 5 | * @FilePath: /jgdl/src/pages/auth/index.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -60,7 +60,7 @@ export default { | ... | @@ -60,7 +60,7 @@ export default { |
| 60 | // } | 60 | // } |
| 61 | // TAG:处理分享跳转问题 | 61 | // TAG:处理分享跳转问题 |
| 62 | const params = getCurrentPageParam(); | 62 | const params = getCurrentPageParam(); |
| 63 | - if (getCurrentPageParam().url === 'pages/detail/index') { // 详情页的分享跳转处理 | 63 | + if (getCurrentPageParam().url === 'pages/productDetail/index') { // 详情页的分享跳转处理 |
| 64 | Taro.reLaunch({ | 64 | Taro.reLaunch({ |
| 65 | url: `../../${params.url}?id=${params.id}` | 65 | url: `../../${params.url}?id=${params.id}` |
| 66 | }) | 66 | }) | ... | ... |
| ... | @@ -120,7 +120,7 @@ | ... | @@ -120,7 +120,7 @@ |
| 120 | </view> | 120 | </view> |
| 121 | 121 | ||
| 122 | <!-- 支付组件 --> | 122 | <!-- 支付组件 --> |
| 123 | - <payCard :visible="show_pay" :data="payData" @close="onPayClose" /> | 123 | + <payCard :visible="show_pay" :data="payData" @close="onPayClose" @paySuccess="onPaySuccess" /> |
| 124 | 124 | ||
| 125 | <!-- 评价弹窗 --> | 125 | <!-- 评价弹窗 --> |
| 126 | <nut-popup v-model:visible="showRatePopup" position="right" :style="{ width: '100%', height: '100%' }" closeable | 126 | <nut-popup v-model:visible="showRatePopup" position="right" :style="{ width: '100%', height: '100%' }" closeable |
| ... | @@ -784,6 +784,28 @@ const onPayClose = () => { | ... | @@ -784,6 +784,28 @@ const onPayClose = () => { |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | /** | 786 | /** |
| 787 | + * 处理支付成功事件 | ||
| 788 | + * @param {Object} data - 支付成功数据 | ||
| 789 | + * @param {string} data.orderId - 订单ID | ||
| 790 | + */ | ||
| 791 | +const onPaySuccess = ({ orderId }) => { | ||
| 792 | + // 找到对应的订单并更新状态 | ||
| 793 | + const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value | ||
| 794 | + const order = orders.find(o => o.id === orderId) | ||
| 795 | + | ||
| 796 | + if (order) { | ||
| 797 | + // 更新订单状态为已完成 | ||
| 798 | + order.status = 'completed' | ||
| 799 | + | ||
| 800 | + Taro.showToast({ | ||
| 801 | + title: '支付成功,订单已更新', | ||
| 802 | + icon: 'success', | ||
| 803 | + duration: 2000 | ||
| 804 | + }) | ||
| 805 | + } | ||
| 806 | +} | ||
| 807 | + | ||
| 808 | +/** | ||
| 787 | * 查看订单详情 | 809 | * 查看订单详情 |
| 788 | */ | 810 | */ |
| 789 | const viewOrderDetail = (orderId) => { | 811 | const viewOrderDetail = (orderId) => { | ... | ... |
-
Please register or login to post a comment