hookehuyr

feat(订单支付): 优化支付成功后订单状态更新逻辑

修改支付组件和订单页面,使用事件驱动方式更新订单状态
移除页面重新加载方式,提升用户体验和性能
添加支付成功事件处理函数,实现订单状态本地更新
更新相关文档说明优化方案和效果
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) => {
......