Просмотр исходного кода

feat(商城订单): 对接后端API并优化UI布局

- 将订单列表、详情、搜索等组件从模拟数据改为调用后端接口
- 调整表格列宽布局,使用固定宽度替代弹性布局提高一致性
- 更新搜索表单字段以匹配后端参数命名规范
- 添加数据加载状态和空数据提示
- 统一订单状态、支付方式等字段的显示映射
ylong 1 месяц назад
Родитель
Сommit
fac330d24f

+ 71 - 85
src/views/mallOrder/all/components/order-base-info.vue

@@ -10,15 +10,15 @@
                     </div>
                     <div class="info-item">
                         <span class="label">订单来源:</span>
-                        <span class="value">{{ detail.source }}</span>
+                        <span class="value">商城小程序</span>
                     </div>
                     <div class="info-item">
                         <span class="label">支付渠道:</span>
-                        <span class="value">{{ detail.payChannel }}</span>
+                        <span class="value">{{ getPayType(detail.payType) }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">交易状态:</span>
-                        <span class="value">{{ detail.status }}</span>
+                        <span class="value">{{ getStatusText(detail.status) }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">平台备注:</span>
@@ -30,24 +30,24 @@
                 <div class="info-column">
                     <div class="info-item">
                         <span class="label">用户名:</span>
-                        <span class="value">{{ detail.buyer?.name }}</span>
+                        <span class="value">{{ detail.userNick }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">收 件 人:</span>
-                        <span class="value">{{ detail.receiver?.name }}</span>
+                        <span class="value">{{ detail.receiverName }}</span>
                         <el-button link type="success" class="ml-2" @click="$emit('edit-receiver')">修改</el-button>
                     </div>
                     <div class="info-item">
                         <span class="label">电 话:</span>
-                        <span class="value">{{ detail.receiver?.phone }}</span>
+                        <span class="value">{{ detail.receiverMobile }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">地 址:</span>
-                        <span class="value">{{ detail.receiver?.address }}</span>
+                        <span class="value">{{ detail.receiverAddress }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">用户备注:</span>
-                        <span class="value">{{ detail.buyerNote || '无' }}</span>
+                        <span class="value">{{ detail.remark || '无' }}</span>
                     </div>
                     <div class="info-item warning-text" v-if="detail.shortageNote">
                         <span class="label" style="color: #f56c6c;">如遇缺货:</span>
@@ -59,15 +59,15 @@
                 <div class="info-column">
                     <div class="info-item">
                         <span class="label">发货物流:</span>
-                        <span class="value">{{ detail.logistics?.company || '-' }}</span>
+                        <span class="value">{{ detail.expressName || '-' }}</span>
                     </div>
                     <div class="info-item">
                         <span class="label">发货单号:</span>
-                        <span class="value">{{ detail.logistics?.no || '-' }}</span>
+                        <span class="value">{{ detail.waybillCode || '-' }}</span>
 
                         <el-popover placement="bottom" title="物流动态" :width="300" trigger="hover">
                             <template #reference>
-                                <el-button link type="success" class="ml-2" v-if="detail.logistics?.no"
+                                <el-button link type="success" class="ml-2" v-if="detail.waybillCode"
                                     @click="viewLogistics">查看</el-button>
                             </template>
                             <el-timeline>
@@ -86,11 +86,11 @@
                     </div>
 
                     <div class="status-tags mt-2">
-                        <el-tag :type="detail.isShipped ? 'success' : 'warning'" effect="dark" class="mr-2">
-                            {{ detail.isShipped ? '已发货' : '未发货' }}
+                        <el-tag :type="detail.status >= 3 ? 'success' : 'warning'" effect="dark" class="mr-2">
+                            {{ detail.status >= 3 ? '已发货' : '未发货' }}
                         </el-tag>
-                        <el-tag :type="detail.isCompleted ? 'success' : 'warning'" effect="dark">
-                            {{ detail.isCompleted ? '已完成' : '未完成' }}
+                        <el-tag :type="detail.status == 4 ? 'success' : 'warning'" effect="dark">
+                            {{ detail.status == 4 ? '已完成' : '未完成' }}
                         </el-tag>
                     </div>
                 </div>
@@ -100,101 +100,87 @@
 </template>
 
 <script setup>
-import { ref } from 'vue';
 import { Lightning } from '@element-plus/icons-vue';
+import { EleMessage } from 'ele-admin-plus/es';
+import { ref } from 'vue';
 
 const props = defineProps({
     detail: {
         type: Object,
+        required: true,
         default: () => ({})
     }
 });
 
-const emit = defineEmits(['add-package', 'edit-receiver']);
-
-const activities = [
-    {
-        content: '已签收,签收人是拍照签收',
-        timestamp: '2024-04-12 20:46',
-    },
-    {
-        content: '派送中',
-        timestamp: '2024-04-12 20:46',
-    },
-    {
-        content: '已发货',
-        timestamp: '2024-04-11 20:46',
-    },
-];
+defineEmits(['add-package', 'edit-receiver']);
+
+const activities = ref([]);
 
 const viewLogistics = () => {
-    // Logic to view full logistics
+    EleMessage.info('物流详情功能开发中');
+};
+
+const getStatusText = (status) => {
+    const statusMap = {
+        '1': '等待买家付款',
+        '2': '等待卖家发货',
+        '3': '等待买家确认收货',
+        '4': '已完成',
+        '5': '退款成功',
+        '6': '退款中',
+        '7': '已取消'
+    };
+    return statusMap[status] || status;
+};
+
+const getPayType = (type) => {
+    if (!type) {
+        return '-';
+    }
+    const map = {
+        '1': '余额',
+        '2': '微信',
+        '3': '支付宝'
+    };
+    return map[type] || type;
 };
 </script>
 
-<style lang="scss" scoped>
+<style scoped>
+.order-base-info {
+    font-size: 13px;
+}
+
 .info-layout {
     display: flex;
-    justify-content: space-between;
     gap: 20px;
+}
 
-    .info-column {
-        flex: 1;
-
-        .info-item {
-            margin-bottom: 12px;
-            font-size: 14px;
-            display: flex;
-
-            .label {
-                color: #606266;
-                width: 80px;
-                flex-shrink: 0;
-            }
-
-            .value {
-                color: #303133;
-                font-weight: 500;
-                flex: 1;
-            }
-        }
-
-        .warning-text {
-            color: #f56c6c;
-            font-weight: bold;
-        }
-    }
+.info-column {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
 }
 
-.status-box {
-    background-color: #fdf6ec;
-    border: 1px solid #faecd8;
-    color: #e6a23c;
-    padding: 10px;
-    border-radius: 4px;
-    font-size: 12px;
-    cursor: pointer;
-    margin-top: 10px;
-
-    .status-dot {
-        display: inline-block;
-        width: 6px;
-        height: 6px;
-        background-color: #e6a23c;
-        border-radius: 50%;
-        margin-right: 5px;
-    }
+.info-item {
+    display: flex;
+    align-items: flex-start;
+    line-height: 1.4;
 }
 
-.ml-2 {
-    margin-left: 8px;
+.label {
+    color: #909399;
+    width: 70px;
+    flex-shrink: 0;
 }
 
-.mr-2 {
-    margin-right: 8px;
+.value {
+    color: #303133;
+    word-break: break-all;
 }
 
-.mt-2 {
-    margin-top: 8px;
+.action-area {
+    margin-top: auto;
 }
 </style>

+ 56 - 135
src/views/mallOrder/all/components/order-detail.vue

@@ -3,7 +3,7 @@
         :width="1200"
         v-model="visible"
         title="订单详情"
-        @open="handleOpen"
+        @open="onOpen"
         :body-style="{
             maxHeight: '80vh',
             overflow: 'auto',
@@ -12,31 +12,32 @@
         }"
         top="5vh"
     >
-        <!-- Status Steps -->
-        <ele-card class="mb-4">
-            <el-steps :active="activeStep" align-center finish-status="success">
-                <el-step title="提交订单" :description="detail.createTime" />
-                <el-step title="支付订单" :description="detail.payTime" />
-                <el-step title="平台发货" :description="detail.deliveryTime" />
-                <el-step title="确认收货" :description="detail.receiveTime" />
-                <el-step title="完成评价" :description="detail.finishTime" />
-            </el-steps>
-        </ele-card>
+        <div v-loading="loading">
+            <!-- Status Steps -->
+            <ele-card class="mb-4">
+                <el-steps :active="activeStep" align-center finish-status="success">
+                    <el-step title="提交订单" :description="detail.createTime" />
+                    <el-step title="支付订单" :description="detail.payTime" />
+                    <el-step title="平台发货" :description="detail.deliveryTime" />
+                    <el-step title="确认收货" :description="detail.receiptTime" />
+                    <el-step title="完成评价" :description="detail.finishTime" />
+                </el-steps>
+            </ele-card>
 
-        <!-- Order Base Info Component -->
-        <order-base-info 
-            :detail="detail" 
-            @add-package="openAddPackage"
-            @edit-receiver="handleEditReceiver"
-            class="mb-4"
-        />
+            <!-- Order Base Info Component -->
+            <order-base-info 
+                :detail="detail" 
+                @add-package="openAddPackage"
+                @edit-receiver="handleEditReceiver"
+                class="mb-4"
+            />
 
-        <!-- Product List Component -->
-        <order-product-list 
-            :products="detail.products"
-            :payment="detail.payment"
-            class="mb-4"
-        />
+            <!-- Product List Component -->
+            <order-product-list 
+                :detail="detail"
+                class="mb-4"
+            />
+        </div>
 
         <!-- Action Buttons Footer -->
         <template #footer>
@@ -62,141 +63,61 @@ import PushSmsDialog from './push-sms-dialog.vue';
 import RefundDialog from './refund-dialog.vue';
 import OrderBaseInfo from './order-base-info.vue';
 import OrderProductList from './order-product-list.vue';
+import request from '@/utils/request';
 
 const visible = defineModel({ type: Boolean });
 const detail = ref({});
+const loading = ref(false);
 const packageRef = ref(null);
 const smsRef = ref(null);
 const refundRef = ref(null);
 
 const activeStep = computed(() => {
     const status = detail.value.status;
-    if (status === '等待买家付款') return 0;
-    if (status === '等待卖家发货') return 1;
-    if (status === '等待买家确认收货') return 2;
-    if (status === '交易成功') return 4;
+    if (status === '1') return 1; // 等待买家付款
+    if (status === '2') return 2; // 等待卖家发货
+    if (status === '3') return 3; // 等待买家确认收货
+    if (status === '4') return 5; // 已完成
     return 1; // Default
 });
 
-const handleOpen = (data) => {
-    // Enhanced Mock Data logic
-    // In a real app, this would fetch from API using data.orderId
-    
-    // Base Mock Data
-    const baseData = {
-        orderId: '4066879393210936038',
-        createTime: '2024-10-04 12:01:09',
-        payTime: '2024-10-04 12:05:00',
-        deliveryTime: '2024-10-05 09:30:00',
-        receiveTime: '',
-        finishTime: '',
-        source: '微信',
-        payChannel: '微信支付',
-        status: '等待买家确认收货',
-        remark: '正常发货',
-        buyer: {
-            name: '书嗨565652323',
-            id: 'u123456'
-        },
-        receiver: {
-            name: '书嗨',
-            phone: '17512688011',
-            address: '河南省/鹤壁市/浚县/黄河路街道'
-        },
-        buyerNote: '发新一点的',
-        shortageNote: '缺货时与我电话沟通',
-        logistics: {
-            company: '韵达快递',
-            no: '463855119742',
-            status: '已发货'
-        },
-        isShipped: true,
-        isCompleted: false,
-        
-        // Payment Info
-        payment: {
-            total: 2.9,
-            shipping: 2.9,
-            discountTotal: 2.9,
-            redPacket: 2.9,
-            shareDiscount: 2.9
-        },
-        
-        // Products
-        products: [
-            {
-                image: 'https://img14.360buyimg.com/n0/jfs/t1/157997/3/36676/122176/65e975a0F98822998/5023348143493720.jpg',
-                title: '毛泽东思想和中国特色社会主义理论体系概论(2023年版)',
-                isbn: '9787040599039',
-                condition: '中等',
-                discount: 1,
-                recycleStatus: '正在回收',
-                refundStatus: '未确认收货',
-                qty: 1,
-                price: 2.9,
-                discountAmount: 0.9,
-                actualPayment: 2,
-                weight: 0.5
-            },
-            {
-                image: 'https://img14.360buyimg.com/n0/jfs/t1/157997/3/36676/122176/65e975a0F98822998/5023348143493720.jpg',
-                title: '毛泽东思想和中国特色社会主义理论体系概论(2023年版)',
-                isbn: '9787040599039',
-                condition: '中等',
-                discount: 1,
-                recycleStatus: '正在回收',
-                refundStatus: '未确认收货',
-                qty: 1,
-                price: 2.9,
-                discountAmount: 0,
-                actualPayment: 2.9,
-                weight: 0.5
-            }
-        ]
-    };
+const handleOpen = (row) => {
+    visible.value = true;
+    loading.value = true;
+    request.get(`/shop/shopOrder/getInfo/${row.orderId}`)
+        .then(res => {
+            const data = res.data.data || res.data;
+            detail.value = data;
+        })
+        .finally(() => {
+            loading.value = false;
+        });
+};
 
-    // If passed data has specific overrides, merge them (simple merge)
-    if (data && data.orderId) {
-        detail.value = { ...baseData, ...data };
-        // Ensure complex objects are not lost if not present in passed data
-        if (!data.products) detail.value.products = baseData.products;
-        if (!data.payment) detail.value.payment = baseData.payment;
-        if (!data.receiver) detail.value.receiver = baseData.receiver;
-    } else {
-        detail.value = baseData;
-    }
+// Exposed method for parent to call
+const onOpen = () => {
+    // This is called by ele-modal @open, but we need data passed.
+    // However, handleOpen is called by parent ref.
+    // We can rely on handleOpen being called explicitly.
 };
 
 const openAddPackage = () => {
-    packageRef.value?.handleOpen();
+    packageRef.value?.open(detail.value);
 };
 
-const openPushSms = () => {
-    smsRef.value?.handleOpen(detail.value);
+const handleEditReceiver = () => {
+    EleMessage.info('功能开发中');
 };
 
-const openRefund = () => {
-    refundRef.value?.handleOpen(detail.value);
+const openPushSms = () => {
+    smsRef.value?.open(detail.value);
 };
 
-const handleEditReceiver = () => {
-    EleMessage.info('修改收货人信息功能待开发');
+const openRefund = () => {
+    refundRef.value?.open(detail.value);
 };
 
 defineExpose({
-    handleOpen: (data) => {
-        visible.value = true;
-        handleOpen(data);
-    }
+    handleOpen
 });
 </script>
-
-<style scoped>
-.mb-4 {
-    margin-bottom: 16px;
-}
-.dialog-footer {
-    display: flex;
-    justify-content: flex-end;
-}
-</style>

+ 214 - 158
src/views/mallOrder/all/components/order-item.vue

@@ -6,8 +6,8 @@
             <span class="mr-4">订单编号: {{ order.orderId }} <el-button link type="primary" size="small"
                     @click="handleCopy(order.orderId)">复制</el-button></span>
             <span class="mr-4">创建时间: {{ order.createTime }}</span>
-            <span class="mr-4">支付渠道: {{ order.payChannel }}</span>
-            <span class="mr-4">订单来源: {{ order.source }}</span>
+            <span class="mr-4">支付渠道: {{ getPayType(order.payType) }}</span>
+            <span class="mr-4">订单来源: 商城小程序</span>
             <span class="flag-icon" v-if="order.flag"><el-icon>
                     <Flag />
                 </el-icon></span>
@@ -18,28 +18,29 @@
         <div class="order-body">
             <!-- Products Column -->
             <div class="col-products-wrapper">
-                <div v-for="(product, idx) in order.products" :key="idx" class="product-row">
+                <div v-for="(product, idx) in order.detailList" :key="idx" class="product-row">
                     <div class="col-product product-info mr-2">
-                        <el-image :src="product.image" class="product-img" fit="cover" />
+                        <el-image :src="product.cover" class="product-img" fit="cover" />
                         <div class="product-detail">
-                            <div class="product-title">{{ product.title }}</div>
+                            <div class="product-title">{{ product.bookName }}</div>
                             <div class="product-isbn">ISBN: <span class="link">{{ product.isbn }}</span>
                                 <el-icon class="cursor-pointer" @click="handleCopy(product.isbn)">
                                     <CopyDocument />
-                                </el-icon> (品相: {{ product.condition }})
+                                </el-icon> (品相: {{ getConditionText(product.conditionType) }})
                             </div>
                             <div class="product-tags">
-                                <span class="tag">回收折扣: {{ product.discount }}折</span>
-                                <span class="tag success">(回收状态: {{ product.recycleStatus }})</span>
+                                <span class="tag">回收折扣: {{ product.discount || 1 }}折</span>
+                                <span class="tag success">(回收状态: {{ getRecycleStatusText(product.recycleStatus) }})</span>
                             </div>
                         </div>
                     </div>
                     <div class="col-price">¥ {{ product.price }}</div>
-                    <div class="col-qty">x{{ product.qty }}</div>
+                    <div class="col-qty">x1</div>
                     <div class="col-aftersales">
                         <span
-                            :class="{ 'text-blue': product.refundStatus === '退款成功', 'text-red': product.refundStatus === '退款取消' }">{{
-                                product.refundStatus }}</span>
+                            :class="{ 'text-blue': product.status === '3', 'text-red': product.status === '2' }">
+                            {{ getDetailStatusText(product.status) }}
+                        </span>
                     </div>
                 </div>
             </div>
@@ -47,21 +48,21 @@
             <!-- Merged Columns -->
             <div class="col-merged col-buyer">
                 <div class="buyer-info">
-                    <el-avatar :size="30" :src="order.buyer.avatar" />
-                    <div class="buyer-name">{{ order.buyer.name }}</div>
-                    <div class="buyer-phone">{{ order.buyer.phone }}</div>
+                    <el-avatar :size="30" :src="order.avatar" />
+                    <div class="buyer-name">{{ order.userNick }}</div>
+                    <div class="buyer-phone">{{ order.receiverMobile }}</div>
                 </div>
             </div>
             <div class="col-merged col-payment">
-                <div class="payment-amount">¥ {{ order.payment.total }}</div>
-                <div class="shipping-fee">(含邮费: ¥ {{ order.payment.shipping }})</div>
+                <div class="payment-amount">¥ {{ order.totalMoney }}</div>
+                <div class="shipping-fee">(含邮费: ¥ {{ order.expressMoney }})</div>
             </div>
             <div class="col-merged col-logistics">
-                <div>{{ order.logistics.company }}</div>
-                <div>{{ order.logistics.no }}</div>
+                <div>{{ order.expressName }}</div>
+                <div>{{ order.waybillCode }}</div>
             </div>
             <div class="col-merged col-status">
-                <div :class="getStatusColor(order.status)">{{ order.status }}</div>
+                <div :class="getStatusColor(order.status)">{{ getStatusText(order.status) }}</div>
                 <el-button link type="primary" @click="$emit('view-detail', order)">[查看详情]</el-button>
             </div>
             <div class="col-merged col-action">
@@ -71,9 +72,9 @@
         </div>
 
         <!-- Buyer Note -->
-        <div class="buyer-note" v-if="order.buyerNote">
+        <div class="buyer-note" v-if="order.remark">
             <span class="note-label">买家备注:</span>
-            <span class="note-content">{{ order.buyerNote }}</span>
+            <span class="note-content">{{ order.remark }}</span>
         </div>
     </div>
 </template>
@@ -103,186 +104,241 @@ const handleCopy = async (text) => {
     }
 };
 
+const getStatusText = (status) => {
+    const statusMap = {
+        '1': '等待买家付款',
+        '2': '等待卖家发货',
+        '3': '等待买家确认收货',
+        '4': '已完成',
+        '5': '退款成功',
+        '6': '退款中',
+        '7': '已取消'
+    };
+    return statusMap[status] || status;
+};
+
 const getStatusColor = (status) => {
-    if (status === '退款成功') return 'text-red';
-    if (status === '等待买家确认收货') return 'text-red';
+    // Implement color logic if needed, e.g. return 'text-red'
     return '';
 };
+
+const getDetailStatusText = (status) => {
+    const map = {
+        '1': '正常',
+        '2': '退款中',
+        '3': '已退款'
+    };
+    return map[status] || '';
+};
+
+const getConditionText = (type) => {
+    const map = {
+        '1': '良好',
+        '2': '中等',
+        '3': '次品',
+        '4': '全新'
+    };
+    return map[type] || '-';
+};
+
+const getRecycleStatusText = (status) => {
+    const map = {
+        '1': '正在回收',
+        '2': '暂停回收',
+        '3': '未加入回收书单',
+        '4': '黑名单',
+        '5': '手动暂停'
+    };
+    return map[status] || '-';
+};
+
+const getPayType = (type) => {
+    if (!type) {
+        return '-';
+    }
+    const map = {
+        '1': '余额',
+        '2': '微信',
+        '3': '支付宝'
+    };
+    return map[type] || type;
+};
 </script>
 
-<style lang="scss" scoped>
+<style scoped>
 .order-item {
-    border: 1px solid #ebeef5;
-    margin-bottom: 15px;
-
-    .order-header {
-        background-color: #f0f9eb; // Light blue/greenish background like screenshot
-        padding: 8px 15px;
-        font-size: 13px;
-        color: #606266;
-        display: flex;
-        align-items: center;
-
-        .urge-tag {
-            background-color: #f56c6c;
-            color: #fff;
-            padding: 1px 5px;
-            border-radius: 2px;
-            font-size: 12px;
-            margin-left: 10px;
-        }
-    }
+    border: 1px solid #e4e7ed;
+    margin-bottom: 20px;
+    font-size: 13px;
+}
 
-    .order-body {
-        display: flex;
-        border-top: 1px solid #ebeef5;
-
-        .col-products-wrapper {
-            flex: 4; // Takes up 4 columns worth of space (Product, Price, Qty, Aftersales)
-            display: flex;
-            flex-direction: column;
-        }
-
-        .product-row {
-            display: flex;
-            border-bottom: 1px solid #ebeef5;
-
-            &:last-child {
-                border-bottom: none;
-            }
-
-            padding: 10px 0;
-
-            .col-product {
-                flex: 1.5;
-            }
-
-            .col-price {
-                flex: 0.5;
-            }
-
-            .col-qty {
-                flex: 0.5;
-            }
-
-            .col-aftersales {
-                flex: 0.5;
-            }
-        }
-
-        .col-merged {
-            border-left: 1px solid #ebeef5;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            align-items: center;
-            padding: 10px;
-            text-align: center;
-            font-size: 13px;
-        }
-    }
+.order-header {
+    background-color: #f5f7fa;
+    padding: 10px 20px;
+    display: flex;
+    align-items: center;
+    border-bottom: 1px solid #e4e7ed;
+}
 
-    .buyer-note {
-        background-color: #fff0f0;
-        padding: 8px 15px;
-        font-size: 12px;
-        color: #f56c6c;
-        border-top: 1px solid #ebeef5;
-
-        .note-label {
-            font-weight: bold;
-            margin-right: 5px;
-        }
-    }
+.order-body {
+    display: flex;
+    align-items: stretch;
+}
+
+.col-products-wrapper {
+    flex: 1;
+    min-width: 0;
+    display: flex;
+    flex-direction: column;
+    border-right: 1px solid #e4e7ed;
+}
+
+.product-row {
+    display: flex;
+    align-items: center;
+    padding: 15px 0;
+    border-bottom: 1px solid #ebeef5;
+}
+
+.product-row:last-child {
+    border-bottom: none;
 }
 
-// Column Widths
 .col-product {
-    flex: 1.5;
-    text-align: left !important;
-    padding-left: 15px !important;
+    flex: 1;
+    min-width: 200px;
+    padding-left: 20px;
+    display: flex;
+}
+
+.product-img {
+    width: 60px;
+    height: 60px;
+    border-radius: 4px;
+    margin-right: 10px;
+}
+
+.product-detail {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+}
+
+.product-title {
+    font-weight: 500;
+    margin-bottom: 4px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
 }
 
 .col-price {
-    flex: 0.5;
+    width: 100px;
+    flex: none;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 }
 
 .col-qty {
-    flex: 0.5;
+    width: 80px;
+    flex: none;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 }
 
 .col-aftersales {
-    flex: 0.5;
+    width: 100px;
+    flex: none;
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.col-merged {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    border-right: 1px solid #e4e7ed;
+    padding: 10px;
+    text-align: center;
+}
+
+.col-merged:last-child {
+    border-right: none;
 }
 
 .col-buyer {
-    flex: 0.8;
+    width: 150px;
+    flex: none;
 }
 
 .col-payment {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 
 .col-logistics {
-    flex: 1;
+    width: 150px;
+    flex: none;
 }
 
 .col-status {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 
 .col-action {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 
-// Product Styles
-.product-info {
-    display: flex;
-    align-items: flex-start;
-
-    .product-img {
-        width: 60px;
-        height: 60px;
-        margin-right: 10px;
-        border-radius: 2px;
-    }
+.buyer-note {
+    background-color: #fff8e6;
+    padding: 8px 20px;
+    color: #e6a23c;
+    border-top: 1px solid #faecd8;
+}
 
-    .product-detail {
-        font-size: 13px;
-
-        .product-title {
-            color: #303133;
-            margin-bottom: 4px;
-        }
-
-        .product-isbn {
-            color: #909399;
-            margin-bottom: 4px;
-
-            .link {
-                color: #409eff;
-                cursor: pointer;
-            }
-        }
-
-        .product-tags {
-            .tag {
-                color: #67c23a;
-                margin-right: 5px;
-
-                &.success {
-                    color: #67c23a;
-                }
-            }
-        }
-    }
+.text-blue {
+    color: #409eff;
 }
 
 .text-red {
     color: #f56c6c;
 }
 
-.text-blue {
-    color: #409eff;
+.flag-icon {
+    color: #f56c6c;
+    margin-left: 10px;
+}
+
+.urge-tag {
+    background-color: #f56c6c;
+    color: #fff;
+    padding: 2px 6px;
+    border-radius: 4px;
+    font-size: 12px;
+    margin-left: 10px;
+}
+
+.tag {
+    background-color: #f0f2f5;
+    padding: 2px 6px;
+    border-radius: 4px;
+    margin-right: 5px;
+    font-size: 12px;
+}
+
+.tag.success {
+    background-color: #f0f9eb;
+    color: #67c23a;
 }
 </style>

+ 123 - 90
src/views/mallOrder/all/components/order-product-list.vue

@@ -1,15 +1,15 @@
 <template>
     <div class="order-product-list">
         <ele-card header="商品详情">
-            <el-table :data="products" border style="width: 100%">
+            <el-table :data="detail.detailList" border style="width: 100%">
                 <!-- Image -->
-                <el-table-column label="图片" width="80" align="center">
+                <el-table-column label="图片" width="90" align="center">
                     <template #default="{ row }">
                         <el-image 
-                            :src="row.image" 
+                            :src="row.cover" 
                             style="width: 60px; height: 60px" 
                             fit="cover" 
-                            :preview-src-list="[row.image]"
+                            :preview-src-list="[row.cover]"
                             preview-teleported
                         />
                     </template>
@@ -19,11 +19,11 @@
                 <el-table-column label="商品信息" min-width="250">
                     <template #default="{ row }">
                         <div class="product-info">
-                            <div class="title">{{ row.title }}</div>
+                            <div class="title">{{ row.bookName }}</div>
                             <div class="meta">ISBN: {{ row.isbn }}</div>
                             <div class="tags">
-                                <span class="discount-tag">回收折扣: {{ row.discount }}折</span>
-                                <span class="status-tag">(回收状态: {{ row.recycleStatus }})</span>
+                                <span class="discount-tag">回收折扣: {{ row.discount || 1 }}折</span>
+                                <span class="status-tag">(回收状态: {{ getRecycleStatusText(row.recycleStatus) }})</span>
                             </div>
                         </div>
                     </template>
@@ -32,21 +32,21 @@
                 <!-- Specs -->
                 <el-table-column label="规格" width="100" align="center">
                     <template #default="{ row }">
-                        <span>({{ row.condition }})</span>
+                        <span>({{ getConditionText(row.conditionType) }})</span>
                     </template>
                 </el-table-column>
 
                 <!-- Status -->
                 <el-table-column label="状态" width="120" align="center">
                     <template #default="{ row }">
-                        <span :class="getStatusColor(row.refundStatus)">{{ row.refundStatus || '未确认收货' }}</span>
+                        <span :class="getStatusColor(row.status)">{{ getDetailStatusText(row.status) }}</span>
                     </template>
                 </el-table-column>
 
                 <!-- Quantity -->
                 <el-table-column label="数量" width="80" align="center">
                     <template #default="{ row }">
-                        <span>x{{ row.qty }}</span>
+                        <span>x1</span>
                     </template>
                 </el-table-column>
 
@@ -71,39 +71,35 @@
                 <!-- Actual Payment -->
                 <el-table-column label="实收款" width="100" align="center">
                     <template #default="{ row }">
-                        <span>¥ {{ row.actualPayment }}</span>
+                        <span>¥ {{ row.price }}</span>
                     </template>
                 </el-table-column>
 
                 <!-- Weight -->
                 <el-table-column label="重量" width="80" align="center">
                     <template #default="{ row }">
-                        <span>{{ row.weight }}kg</span>
+                        <span>0kg</span>
                     </template>
                 </el-table-column>
             </el-table>
 
             <!-- Summary Footer -->
             <div class="summary-footer">
-                <div class="summary-row" v-if="payment.discountTotal > 0">
+                <div class="summary-row" v-if="detail.discountMoney > 0">
                     <span>余额优惠:</span>
-                    <span class="amount red">¥ {{ payment.discountTotal }}</span>
-                </div>
-                <div class="summary-row" v-if="payment.redPacket > 0">
-                    <span>惊喜红包:</span>
-                    <span class="amount red">¥ {{ payment.redPacket }}</span>
+                    <span class="amount red">¥ {{ detail.discountMoney }}</span>
                 </div>
-                <div class="summary-row" v-if="payment.shareDiscount > 0">
+                <div class="summary-row" v-if="detail.reduceMoney > 0">
                     <span>分享降价:</span>
-                    <span class="amount red">¥ {{ payment.shareDiscount }}</span>
+                    <span class="amount red">¥ {{ detail.reduceMoney }}</span>
                 </div>
                 <div class="summary-row">
                     <span>运费:</span>
-                    <span class="amount red">¥ {{ payment.shipping }}</span>
+                    <span class="amount">¥ {{ detail.expressMoney }}</span>
                 </div>
                 <div class="summary-row total">
-                    <span>订单实付金额:</span>
-                    <span class="amount red large">¥ {{ payment.total }}</span>
+                    <span>实收款:</span>
+                    <span class="amount red large">¥ {{ detail.payMoney }}</span>
                 </div>
             </div>
         </ele-card>
@@ -112,91 +108,128 @@
 
 <script setup>
 const props = defineProps({
-    products: {
-        type: Array,
-        default: () => []
-    },
-    payment: {
+    detail: {
         type: Object,
+        required: true,
         default: () => ({
-            total: 0,
-            shipping: 0,
-            discountTotal: 0,
-            redPacket: 0,
-            shareDiscount: 0
+            detailList: []
         })
     }
 });
 
+const getDetailStatusText = (status) => {
+    const map = {
+        '1': '正常',
+        '2': '退款中',
+        '3': '已退款'
+    };
+    return map[status] || '';
+};
+
+const getConditionText = (type) => {
+    const map = {
+        '1': '良好',
+        '2': '中等',
+        '3': '次品',
+        '4': '全新'
+    };
+    return map[type] || '良好';
+};
+
+const getRecycleStatusText = (status) => {
+    const map = {
+        '1': '正在回收',
+        '2': '暂停回收',
+        '3': '未加入回收书单',
+        '4': '黑名单',
+        '5': '手动暂停'
+    };
+    return map[status] || '-';
+};
+
 const getStatusColor = (status) => {
-    if (status === '退款成功') return 'text-green'; // Or red based on design
-    if (status === '未确认收货') return 'text-green';
+    if (status === '2' || status === '3') return 'text-red';
     return '';
 };
 </script>
 
-<style lang="scss" scoped>
+<style scoped>
 .product-info {
-    font-size: 13px;
-    .title {
-        color: #333;
-        margin-bottom: 4px;
-        line-height: 1.4;
-    }
-    .meta {
-        color: #999;
-        margin-bottom: 4px;
-    }
-    .tags {
-        font-size: 12px;
-        .discount-tag {
-            color: #67c23a;
-            margin-right: 5px;
-        }
-        .status-tag {
-            color: #67c23a;
-        }
-    }
+    display: flex;
+    flex-direction: column;
+    gap: 4px;
+}
+
+.title {
+    font-weight: 500;
+    color: #303133;
 }
 
-.text-green { color: #67c23a; }
-.text-red { color: #f56c6c; }
+.meta {
+    font-size: 12px;
+    color: #909399;
+}
+
+.tags {
+    display: flex;
+    gap: 8px;
+    font-size: 12px;
+}
+
+.discount-tag {
+    color: #e6a23c;
+    background-color: #fdf6ec;
+    padding: 2px 4px;
+    border-radius: 4px;
+}
+
+.status-tag {
+    color: #67c23a;
+    background-color: #f0f9eb;
+    padding: 2px 4px;
+    border-radius: 4px;
+}
+
+.text-red {
+    color: #f56c6c;
+}
 
 .summary-footer {
-    margin-top: 15px;
-    padding: 15px;
-    background-color: #f8fcfb; // Light greenish tint matching the screenshot bottom area
+    margin-top: 20px;
     display: flex;
     flex-direction: column;
     align-items: flex-end;
-    
-    .summary-row {
-        margin-bottom: 5px;
-        font-size: 14px;
-        color: #606266;
-        
-        .amount {
-            margin-left: 10px;
-            font-weight: 500;
-            width: 80px;
-            text-align: right;
-            display: inline-block;
-            
-            &.red {
-                color: #f56c6c;
-            }
-            
-            &.large {
-                font-size: 16px;
-                font-weight: bold;
-            }
-        }
-        
-        &.total {
-            margin-top: 5px;
-            padding-top: 5px;
-            border-top: 1px dashed #e4e7ed;
-        }
-    }
+    gap: 8px;
+    padding-right: 20px;
+}
+
+.summary-row {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    font-size: 14px;
+    color: #606266;
+}
+
+.amount {
+    font-weight: 500;
+    color: #303133;
+    min-width: 80px;
+    text-align: right;
+}
+
+.amount.red {
+    color: #f56c6c;
+}
+
+.amount.large {
+    font-size: 18px;
+    font-weight: bold;
+}
+
+.total {
+    margin-top: 8px;
+    padding-top: 12px;
+    border-top: 1px solid #ebeef5;
 }
 </style>

+ 18 - 9
src/views/mallOrder/all/components/order-table-header.vue

@@ -35,40 +35,49 @@
 
 // Column Widths - Keep consistent with OrderItem
 .col-product {
-    flex: 1.5;
+    flex: 1;
+    min-width: 200px;
     text-align: left !important;
     padding-left: 15px !important;
 }
 
 .col-price {
-    flex: 0.5;
+    width: 100px;
+    flex: none;
 }
 
 .col-qty {
-    flex: 0.5;
+    width: 80px;
+    flex: none;
 }
 
 .col-aftersales {
-    flex: 0.5;
+    width: 100px;
+    flex: none;
 }
 
 .col-buyer {
-    flex: 0.8;
+    width: 150px;
+    flex: none;
 }
 
 .col-payment {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 
 .col-logistics {
-    flex: 1;
+    width: 150px;
+    flex: none;
 }
 
 .col-status {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 
 .col-action {
-    flex: 0.8;
+    width: 120px;
+    flex: none;
 }
 </style>

+ 19 - 17
src/views/mallOrder/all/components/page-search.vue

@@ -19,36 +19,38 @@ const searchRef = ref(null);
 const formItems = reactive([
     { type: 'input', label: '订单编号', prop: 'orderId' },
     { type: 'input', label: '收件人姓名', prop: 'receiverName' },
-    { type: 'input', label: '收件人手机号', prop: 'receiverPhone' },
-    { type: 'input', label: '发货物流单号', prop: 'logisticsNo' },
-    { type: 'input', label: '退货物流单号', prop: 'returnLogisticsNo' },
+    { type: 'input', label: '收件人手机号', prop: 'receiverMobile' },
+    { type: 'input', label: '发货物流单号', prop: 'waybillCode' },
+    { type: 'input', label: '退货物流单号', prop: 'refundWaybillCode' },
     { 
         type: 'dictSelect', 
         label: '全部订单状态', 
         prop: 'status', 
         props: { code: 'order_status' } 
     },
-    { type: 'input', label: '搜索备注关键字', prop: 'keyword' },
+    { type: 'input', label: '搜索备注关键字', prop: 'remark' },
     {
         type: 'select',
-        label: '催发货订单',
-        prop: 'urgeStatus',
+        label: '支付方式',
+        prop: 'payType',
         options: [
-            { label: '催发货', value: '1' }
+            { label: '余额', value: '1' },
+            { label: '微信', value: '2' },
+            { label: '支付宝', value: '3' }
         ]
     },
     {
         type: 'daterange',
         label: '下单时间',
         prop: 'dateRange',
-        keys: ['startTime', 'endTime'],
+        keys: ['createTimeStart', 'createTimeEnd'],
         props: {
             format: 'YYYY-MM-DD',
             valueFormat: 'YYYY-MM-DD',
             onChange: (val) => {
                 searchRef.value?.setData({
-                    startTime: val && val.length > 0 ? val[0] : '',
-                    endTime: val && val.length > 0 ? val[1] : ''
+                    createTimeStart: val && val.length > 0 ? val[0] : '',
+                    createTimeEnd: val && val.length > 0 ? val[1] : ''
                 });
             }
         }
@@ -58,14 +60,14 @@ const formItems = reactive([
 const initKeys = reactive({
     orderId: '',
     receiverName: '',
-    receiverPhone: '',
-    logisticsNo: '',
-    returnLogisticsNo: '',
+    receiverMobile: '',
+    waybillCode: '',
+    refundWaybillCode: '',
     status: '',
-    keyword: '',
-    urgeStatus: '',
-    startTime: '',
-    endTime: ''
+    remark: '',
+    payType: '',
+    createTimeStart: '',
+    createTimeEnd: ''
 });
 
 const search = (data) => {

+ 105 - 151
src/views/mallOrder/all/index.vue

@@ -21,6 +21,7 @@
 
             <!-- Order List -->
             <div class="order-list" v-loading="loading">
+                <div v-if="list.length === 0" class="empty-text">暂无数据</div>
                 <order-item v-for="order in list" :key="order.orderId" :order="order" @view-detail="openDetail"
                     @push-sms="openSms" @refund="openRefund" />
             </div>
@@ -42,157 +43,110 @@
 </template>
 
 <script setup>
-import { ref, reactive } from 'vue';
-import PageSearch from './components/page-search.vue';
-import OrderDetail from './components/order-detail.vue';
-import PushSmsDialog from './components/push-sms-dialog.vue';
-import RefundDialog from './components/refund-dialog.vue';
-import AddPackageDialog from './components/add-package-dialog.vue';
-import OrderTableHeader from './components/order-table-header.vue';
-import OrderItem from './components/order-item.vue';
-
-const activeTab = ref('all');
-const loading = ref(false);
-const total = ref(10);
-const pageParams = reactive({
-    page: 1,
-    limit: 10
-});
-
-const list = ref([
-    {
-        orderId: '4066879393210936038',
-        createTime: '2024-10-04 12:01:09',
-        payChannel: '微信支付',
-        source: '微信',
-        flag: true,
-        isUrge: false,
-        checked: false,
-        buyer: {
-            avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
-            name: '用户44541',
-            phone: '1894984dsaddq'
-        },
-        payment: {
-            total: 2.9,
-            shipping: 0
-        },
-        logistics: {
-            company: '韵达快递',
-            no: '46382090456249',
-            status: '已发货'
-        },
-        status: '退款成功',
-        buyerNote: '',
-        products: [
-            {
-                image: 'https://img14.360buyimg.com/n0/jfs/t1/157997/3/36676/122176/65e975a0F98822998/5023348143493720.jpg',
-                title: '毛泽东思想和中国特色社会主义理论体系概论(2023年版)',
-                isbn: '9787040599012',
-                condition: '中等',
-                price: 2.9,
-                qty: 1,
-                discount: 1,
-                recycleStatus: '正在回收',
-                refundStatus: '退款成功'
-            }
-        ]
-    },
-    {
-        orderId: '4066879393210936039',
-        createTime: '2024-10-04 12:06:09',
-        payChannel: '微信支付',
-        source: '微信',
-        flag: false,
-        isUrge: true,
-        checked: false,
-        buyer: {
-            avatar: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
-            name: '用户44541',
-            phone: '1894984dsaddq'
-        },
-        payment: {
-            total: 5.8,
-            shipping: 0
-        },
-        logistics: {
-            company: '韵达快递',
-            no: '46382090456248',
-            status: '已发货'
-        },
-        status: '等待买家确认收货',
-        buyerNote: '您好,请确保书籍正版,且无破损、不缺页。请不要随书夹带任何票据,有问题留言不要打电话。请尽快发货,谢谢啦~',
-        products: [
-            {
-                image: 'https://img14.360buyimg.com/n0/jfs/t1/157997/3/36676/122176/65e975a0F98822998/5023348143493720.jpg',
-                title: '毛泽东思想和中国特色社会主义理论体系概论(2023年版)',
-                isbn: '9787040599012',
-                condition: '中等',
-                price: 2.9,
-                qty: 1,
-                discount: 1,
-                recycleStatus: '正在回收',
-                refundStatus: ''
-            },
-            {
-                image: 'https://img14.360buyimg.com/n0/jfs/t1/157997/3/36676/122176/65e975a0F98822998/5023348143493720.jpg',
-                title: '毛泽东思想和中国特色社会主义理论体系概论(2023年版)',
-                isbn: '9787040599012',
-                condition: '中等',
-                price: 2.9,
-                qty: 2,
-                discount: 1,
-                recycleStatus: '正在回收',
-                refundStatus: '退款取消'
-            }
-        ]
-    }
-]);
-
-const detailRef = ref(null);
-const smsRef = ref(null);
-const refundRef = ref(null);
-const packageRef = ref(null);
-
-const handleSearch = (params) => {
-    console.log('Search:', params);
-    // Mock reload
-    loading.value = true;
-    setTimeout(() => { loading.value = false; }, 500);
-};
-
-const handleTabClick = (tab) => {
-    console.log('Tab:', tab.props.name);
-    handleSearch({});
-};
-
-const handleSizeChange = (val) => {
-    pageParams.limit = val;
-    handleSearch({});
-};
-
-const handlePageChange = (val) => {
-    pageParams.page = val;
-    handleSearch({});
-};
-
-const openDetail = (row) => {
-    detailRef.value?.handleOpen(row);
-};
-
-const openSms = (row) => {
-    smsRef.value?.handleOpen(row);
-};
-
-const openRefund = (row) => {
-    refundRef.value?.handleOpen(row);
-};
+    import { ref, reactive, onMounted } from 'vue';
+    import PageSearch from './components/page-search.vue';
+    import OrderDetail from './components/order-detail.vue';
+    import PushSmsDialog from './components/push-sms-dialog.vue';
+    import RefundDialog from './components/refund-dialog.vue';
+    import AddPackageDialog from './components/add-package-dialog.vue';
+    import OrderTableHeader from './components/order-table-header.vue';
+    import OrderItem from './components/order-item.vue';
+    import request from '@/utils/request';
+
+    defineOptions({ name: 'MallOrderAll' });
+
+    const activeTab = ref('all');
+    const loading = ref(false);
+    const total = ref(0);
+    const pageParams = reactive({
+        page: 1,
+        limit: 10
+    });
+    const searchParams = ref({});
+
+    const list = ref([]);
+    const detailRef = ref(null);
+    const smsRef = ref(null);
+    const refundRef = ref(null);
+    const packageRef = ref(null);
+
+    const fetchData = () => {
+        loading.value = true;
+        const params = {
+            ...pageParams,
+            ...searchParams.value
+        };
+
+        // Handle Tab Filter
+        if (activeTab.value !== 'all' && activeTab.value !== 'warning') {
+            params.status = activeTab.value;
+        }
+        // Handle Warning/Urge Tab logic if needed
+        // if (activeTab.value === 'warning') { ... }
+
+        request.get('/shop/shopOrder/pagelist', { params })
+            .then(res => {
+                const data = res.data; // Adjust based on response structure
+                total.value = data.total || 0;
+                list.value = data.rows || [];
+            })
+            .finally(() => {
+                loading.value = false;
+            });
+    };
+
+    const handleSearch = (data) => {
+        pageParams.page = 1;
+        searchParams.value = data;
+        fetchData();
+    };
+
+    const handleTabClick = () => {
+        pageParams.page = 1;
+        fetchData();
+    };
+
+    const handleSizeChange = (val) => {
+        pageParams.limit = val;
+        fetchData();
+    };
+
+    const handlePageChange = (val) => {
+        pageParams.page = val;
+        fetchData();
+    };
+
+    const openDetail = (row) => {
+        detailRef.value?.handleOpen(row);
+    };
+
+    const openSms = (row) => {
+        smsRef.value?.open(row);
+    };
+
+    const openRefund = (row) => {
+        refundRef.value?.open(row);
+    };
+
+    onMounted(() => {
+        fetchData();
+    });
 </script>
 
-<style lang="scss" scoped>
-.pagination-wrapper {
-    margin-top: 15px;
-    display: flex;
-    justify-content: flex-end;
-}
+<style scoped>
+    .order-list {
+        min-height: 200px;
+    }
+
+    .empty-text {
+        text-align: center;
+        padding: 40px;
+        color: #909399;
+    }
+
+    .pagination-wrapper {
+        margin-top: 16px;
+        display: flex;
+        justify-content: flex-end;
+    }
 </style>