Bladeren bron

feat: 添加订单操作功能并优化红包组件

- 在订单列表和详情页添加“延长收货”和“确认收货”功能
- 红包列表页接入真实API,移除模拟数据
- 红包组件适配新接口字段并优化显示逻辑
- 通用滚动组件支持POST请求方法
ylong 2 weken geleden
bovenliggende
commit
cef952a535

+ 9 - 0
api/modules/mall.js

@@ -100,5 +100,14 @@ export const useMallApi = (Vue, vm) => {
 
         // 订单一键加购
         orderAddToCartAjax: (data) => vm.$u.post('/token/shop/order/orderAddToCart', data),
+
+        // 延长收货
+        orderAddDeadlineAjax: (orderId) => vm.$u.post('/token/shop/order/orderAddDeadline?orderId=' + orderId),
+
+        // 我的红包列表
+        getMyCouponListAjax: (params) => vm.$u.post('/token/shop/order/myCouponList', params),
+
+        // 确认收货
+        confirmReceiveAjax: (data) => vm.$u.post('/token/shop/order/confirmReceive', data),
 	}
 }

+ 134 - 134
components/pageScroll/index.vue

@@ -1,20 +1,14 @@
 <template>
     <!-- 列表 -->
-    <scroll-view
-        class="scroll-view"
-        scroll-y
-        refresher-enabled
-        :refresher-triggered="isRefreshing"
-        @refresherrefresh="onRefresh"
-        @scrolltolower="onLoadMore"
-        :style="{ height: height }"
-    >
+    <scroll-view class="scroll-view" scroll-y refresher-enabled :refresher-triggered="isRefreshing"
+        @refresherrefresh="onRefresh" @scrolltolower="onLoadMore" :style="{ height: height }">
         <!-- 空状态 -->
         <slot></slot>
-		
+
         <view v-if="!loading && !dataList.length" class="empty-state">
             <view class="flex-d flex-a-c" style="padding-top: 25vh" v-if="slotEmpty">
-                <image src="https://shuhi.oss-cn-qingdao.aliyuncs.com/mini/no-data.png" style="width: 100%; height: 260rpx" mode="heightFix"></image>
+                <image src="https://shuhi.oss-cn-qingdao.aliyuncs.com/mini/no-data.png"
+                    style="width: 100%; height: 260rpx" mode="heightFix"></image>
                 <view class="common-title" style="padding: 33rpx 0 20rpx 0">暂无内容</view>
                 <view class="common-text" v-if="emptyText">{{ emptyText }}</view>
             </view>
@@ -30,151 +24,157 @@
 </template>
 
 <script>
-export default {
-    data() {
-        return {
-            isRefreshing: false,
-            loading: false,
-            page: 1,
-            hasMore: true,
-            dataList: [],
-        };
-    },
-    props: {
-        height: {
-            type: String,
-            default: "calc(100vh - 88rpx)",
-        },
-        bgColor: {
-            type: String,
-            default: "#F5F5F5",
-        },
-        url: {
-            type: String,
-            required: true,
-            default: "/token/order/scanLogs",
-        },
-        pageSize: {
-            type: Number,
-            default: 10,
+    export default {
+        data() {
+            return {
+                isRefreshing: false,
+                loading: false,
+                page: 1,
+                hasMore: true,
+                dataList: [],
+            };
         },
-        slotEmpty: {
-            type: Boolean,
-            default: false,
+        props: {
+            height: {
+                type: String,
+                default: "calc(100vh - 88rpx)",
+            },
+            bgColor: {
+                type: String,
+                default: "#F5F5F5",
+            },
+            url: {
+                type: String,
+                required: true,
+                default: "/token/order/scanLogs",
+            },
+            pageSize: {
+                type: Number,
+                default: 10,
+            },
+            slotEmpty: {
+                type: Boolean,
+                default: false,
+            },
+            emptyText: {
+                type: String,
+            },
+            params: {
+                type: Object,
+                default: {},
+            },
+            method: {
+                type: String,
+                default: 'GET'
+            },
+            immediate: {
+                type: Boolean,
+                default: true,
+            },
         },
-        emptyText: {
-            type: String,
-        },
-        params: {
-            type: Object,
-            default: {},
-        },
-        immediate: {
-            type: Boolean,
-            default: true,
-        },
-    },
-    mounted() {
-        console.log(this.immediate, "immediate");
-        if (this.immediate) {
-            this.loadData(true);
-        }
-    },
-    methods: {
-        // 加载数据
-        async loadData(isRefresh = false, params = {}) {
-            if (isRefresh) {
-                this.page = 1;
-                this.hasMore = true;
+        mounted() {
+            console.log(this.immediate, "immediate");
+            if (this.immediate) {
+                this.loadData(true);
             }
-            if (!this.hasMore || this.loading) return;
-
-            this.loading = true;
-            try {
-                const res = await this.fetchBookList(params);
-
+        },
+        methods: {
+            // 加载数据
+            async loadData(isRefresh = false, params = {}) {
                 if (isRefresh) {
-                    this.dataList = res.list;
-                } else {
-                    this.dataList = [...this.dataList, ...res.list];
+                    this.page = 1;
+                    this.hasMore = true;
                 }
-                this.$emit("updateList", this.dataList);
+                if (!this.hasMore || this.loading) return;
 
-                this.hasMore = res.hasMore;
-                this.page++;
-            } catch (error) {
-                uni.showToast({
-                    title: "加载失败",
-                    icon: "none",
-                });
-            } finally {
-                this.loading = false;
-                if (isRefresh) {
-                    this.isRefreshing = false;
+                this.loading = true;
+                try {
+                    const res = await this.fetchBookList(params);
+
+                    if (isRefresh) {
+                        this.dataList = res.list;
+                    } else {
+                        this.dataList = [...this.dataList, ...res.list];
+                    }
+                    this.$emit("updateList", this.dataList);
+
+                    this.hasMore = res.hasMore;
+                    this.page++;
+                } catch (error) {
+                    uni.showToast({
+                        title: "加载失败",
+                        icon: "none",
+                    });
+                } finally {
+                    this.loading = false;
+                    if (isRefresh) {
+                        this.isRefreshing = false;
+                    }
+                    // #ifdef MP-ALIPAY
+                    my.stopPullDownRefresh()
+                    // #endif
                 }
-                // #ifdef MP-ALIPAY
-                my.stopPullDownRefresh()
-                // #endif
-            }
-        },
+            },
 
-        // 模拟获取数据
-        fetchBookList(params = {}) {
-            return new Promise((resolve) => {
-                uni.showLoading({
-                    title: "加载中...",
-                });
-                uni.$u.http
-                    .get(this.url, {
+            // 模拟获取数据
+            fetchBookList(params = {}) {
+                return new Promise((resolve) => {
+                    uni.showLoading({
+                        title: "加载中...",
+                    });
+                    const requestParams = {
                         pageSize: this.pageSize,
                         pageNum: this.page,
                         ...params,
-                    })
-                    .then((res) => {
+                    };
+                    const requestMethod = this.method.toLowerCase();
+                    const request = requestMethod === 'post' ? uni.$u.http.post(this.url, requestParams) : uni.$u.http.get(this.url, requestParams);
+
+                    request.then((res) => {
                         resolve({
                             list: res.rows,
                             hasMore: res.rows ? (this.page * this.pageSize) < res.total : false,
                         });
                     })
-                    .finally(() => {
-                        uni.hideLoading();
-                    });
-            });
-        },
+                        .finally(() => {
+                            uni.hideLoading();
+                        });
+                });
+            },
 
-        reloadData() {
-            this.page = 1;
-            this.fetchBookList();
-        },
+            reloadData() {
+                this.page = 1;
+                this.fetchBookList();
+            },
 
-        // 下拉刷新
-        async onRefresh() {
-            if (this.loading) return;
-            this.isRefreshing = true;
-            await this.loadData(true, this.params);
-        },
+            // 下拉刷新
+            async onRefresh() {
+                if (this.loading) return;
+                this.isRefreshing = true;
+                await this.loadData(true, this.params);
+            },
 
-        // 上拉加载更多
-        async onLoadMore() {
-            if (this.loading || !this.hasMore) return;
-            await this.loadData(false, this.params);
+            // 上拉加载更多
+            async onLoadMore() {
+                if (this.loading || !this.hasMore) return;
+                await this.loadData(false, this.params);
+            },
         },
-    },
-};
+    };
 </script>
 
 <style lang="scss">
-.scroll-view {
-    height: calc(100vh - 88rpx);
-}
+    .scroll-view {
+        height: calc(100vh - 88rpx);
+    }
 
-.load-more {
-    width: 100%;
-    display: flex;
-    color: #999999;
-    font-size: 24rpx;
-    padding: 30rpx 0;
-    justify-content: center;
-    padding-bottom: 40rpx;
-}
+    .load-more {
+        width: 100%;
+        display: flex;
+        color: #999999;
+        font-size: 24rpx;
+        padding: 30rpx 0;
+        justify-content: center;
+        padding-bottom: 40rpx;
+    }
 </style>

+ 19 - 0
pages-car/components/buy-order-item.vue

@@ -176,6 +176,25 @@
                     });
                     return;
                 }
+                if (type === 'confirm') {
+                    uni.showModal({
+                        title: '提示',
+                        content: '是否确认收货?',
+                        success: (res) => {
+                            if (res.confirm) {
+                                uni.showLoading({ title: '处理中' });
+                                this.$u.api.confirmReceiveAjax({ orderId: data.orderId }).then(res => {
+                                    uni.hideLoading();
+                                    if (res.code == 200) {
+                                        uni.showToast({ title: '收货成功', icon: 'success' });
+                                        this.$emit('refresh'); // 通知父组件刷新列表
+                                    }
+                                });
+                            }
+                        }
+                    });
+                    return;
+                }
                 console.log('handleAction', type, data)
                 this.$emit('action', { type, order: data })
             },

+ 20 - 7
pages-car/components/red-packet-item.vue

@@ -3,19 +3,20 @@
         <view class="left-part">
             <view class="amount-box">
                 <text class="symbol">¥</text>
-                <text class="amount">{{ info.amount || 0 }}</text>
+                <text class="amount">{{ info.faceMoney || 0 }}</text>
             </view>
-            <view class="condition">满 ¥{{ info.condition || 0 }}使用</view>
+            <view class="condition" v-if="info.thresholdMoney === 0">无门槛使用</view>
+            <view class="condition" v-else>满 ¥{{ info.thresholdMoney || 0 }} 使用</view>
         </view>
         <view class="right-part">
             <view class="info-top">
                 <view class="title-row">
-                    <view class="tag" :class="info.type === 2 ? 'surprise' : 'normal'">
-                        {{ info.typeName || (info.type === 2 ? '惊喜红包' : '普通红包') }}
+                    <view class="tag" :class="info.type == 2 ? 'surprise' : 'normal'">
+                        {{ info.type == 2 ? '惊喜红包' : '普通红包' }}
                     </view>
-                    <text class="title">{{ info.title }}</text>
+                    <text class="title">{{ info.couponName }}</text>
                 </view>
-                <view class="date">{{ info.endTime }}到期</view>
+                <view class="date">{{ formatEndTime }}到期</view>
             </view>
             
             <view class="action-box">
@@ -43,10 +44,22 @@ export default {
     computed: {
         // 0: unused, 1: used, 2: expired
         status() {
-            return this.info.status || 0;
+            if (this.info.useTime) {
+                return 1;
+            } else if (this.info.effectEndTime && new Date(this.info.effectEndTime.replace(/-/g, '/')).getTime() < new Date().getTime()) {
+                return 2;
+            }
+            return 0;
         },
         isDisabled() {
             return this.status !== 0;
+        },
+        formatEndTime() {
+            let endTime = this.info.effectEndTime || '';
+            if (endTime && endTime.length >= 10) {
+                return endTime.substring(0, 10).replace(/-/g, '.');
+            }
+            return endTime;
         }
     },
     methods: {

+ 18 - 0
pages-car/pages/my-order.vue

@@ -228,6 +228,24 @@
                     });
                 } else if (type === 'cancel') {
                     this.$refs.cancelDialog.open(order.orderId);
+                } else if (type === 'extend') {
+                    uni.showModal({
+                        title: '提示',
+                        content: '每笔订单只能延长一次收货时间,确认延长收货?',
+                        success: (res) => {
+                            if (res.confirm) {
+                                this.$u.api.orderAddDeadlineAjax(order.orderId).then(res => {
+                                    if (res.code == 200) {
+                                        uni.showToast({
+                                            title: '延长收货成功',
+                                            icon: 'success'
+                                        });
+                                        this.loadOrders(true, this.params);
+                                    }
+                                });
+                            }
+                        }
+                    });
                 } else {
                     uni.showToast({ title: '功能开发中', icon: 'none' });
                 }

+ 19 - 0
pages-car/pages/order-detail.vue

@@ -299,6 +299,25 @@
                     this.viewLogistics();
                     return;
                 }
+                if (type === 'confirm') {
+                    uni.showModal({
+                        title: '提示',
+                        content: '是否确认收货?',
+                        success: (res) => {
+                            if (res.confirm) {
+                                uni.showLoading({ title: '处理中' });
+                                this.$u.api.confirmReceiveAjax({ orderId: this.orderInfo.orderId }).then(res => {
+                                    uni.hideLoading();
+                                    if (res.code == 200) {
+                                        uni.showToast({ title: '收货成功', icon: 'success' });
+                                        this.loadOrderDetail(this.orderInfo.orderId);
+                                    }
+                                });
+                            }
+                        }
+                    });
+                    return;
+                }
                 if (type === 'addToCart') {
                     uni.showLoading({ title: '加载中' });
                     this.$u.api.orderAddToCartAjax({

+ 34 - 77
pages-car/pages/red-packet.vue

@@ -2,99 +2,56 @@
     <view class="red-packet-page">
         <!-- Navigation Bar is likely handled by pages.json configuration or custom nav -->
         <!-- Since style says navigationStyle: custom might be needed for some pages, but here we stick to default or simple -->
-        
+
         <page-scroll
             ref="pageScroll"
             emptyText="暂无红包"
+            url="/token/shop/order/myCouponList"
+            method="POST"
             @updateList="updateList"
         >
             <view class="list-container">
-                <red-packet-item 
-                    v-for="(item, index) in list" 
-                    :key="index" 
-                    :info="item"
-                    @use="handleUse"
-                />
+                <red-packet-item v-for="(item, index) in list" :key="index" :info="item" @use="handleUse" />
             </view>
         </page-scroll>
     </view>
 </template>
 
 <script>
-import PageScroll from '@/components/pageScroll/index.vue';
-import RedPacketItem from '../components/red-packet-item.vue';
+    import PageScroll from '@/components/pageScroll/index.vue';
+    import RedPacketItem from '../components/red-packet-item.vue';
 
-export default {
-    components: {
-        PageScroll,
-        RedPacketItem
-    },
-    data() {
-        return {
-            list: []
-        };
-    },
-    methods: {
-        updateList(data) {
-            // this.list = data;
-            this.list = [
-                {
-                    amount: 10,
-                    condition: 599,
-                    type: 1,
-                    typeName: '普通红包',
-                    title: '满599减10元',
-                    endTime: '2024.09.11',
-                    status: 0
-                },
-                {
-                    amount: 10,
-                    condition: 10.01,
-                    type: 2,
-                    typeName: '惊喜红包',
-                    title: '满10.01减10元',
-                    endTime: '2024.09.11',
-                    status: 0
-                },
-                {
-                    amount: 10,
-                    condition: 599,
-                    type: 1,
-                    typeName: '普通红包',
-                    title: '满599减10元',
-                    endTime: '2024.09.11',
-                    status: 1
-                },
-                {
-                    amount: 10,
-                    condition: 599,
-                    type: 1,
-                    typeName: '普通红包',
-                    title: '满599减10元',
-                    endTime: '2024.09.11',
-                    status: 2
-                }
-            ];
+    export default {
+        components: {
+            PageScroll,
+            RedPacketItem
+        },
+        data() {
+            return {
+                list: []
+            };
+        },
+        methods: {
+            updateList(data) {
+                this.list = data;
+            },
+            handleUse(item) {
+                uni.switchTab({
+                    url: '/pages/sell/index'
+                });
+            }
         },
-        handleUse(item) {
-            console.log('Use red packet', item);
-            // Handle navigation or logic
-            uni.switchTab({
-                url: '/pages/sell/index'
-            });
-        }
-    },
-}
+    }
 </script>
 
 <style lang="scss" scoped>
-.red-packet-page {
-    background-color: #f5f5f5;
-    min-height: 100vh;
-}
+    .red-packet-page {
+        background-color: #f5f5f5;
+        min-height: 100vh;
+    }
 
-.list-container {
-    padding-top: 20rpx;
-    padding-bottom: 20rpx;
-}
+    .list-container {
+        padding-top: 20rpx;
+        padding-bottom: 20rpx;
+    }
 </style>