Explorar el Código

feat: 订单列表接口对接

叶静 hace 3 semanas
padre
commit
12e9cd53d7

+ 2 - 2
.env.development

@@ -4,7 +4,7 @@ SHEEP_VERSION = v1.4.0
 SHEEP_BASE_URL = /
 
 # 开发环境接口域名
- SHEEP_DEV_BASE_URL = /mall
+ SHEEP_DEV_BASE_URL = http://124.222.152.234:8501
 
 # 开发环境上传文件接口域名
  SHEEP_UPLOAD_BASE_URL = /operating
@@ -19,4 +19,4 @@ SHEEP_PREVIEW_PORT = 3002RR
 SHEEP_CACHE_PREFIX = _SHEEP_
 
 # Mock 服务配置
-SHEEP_USE_MOCK = true
+SHEEP_USE_MOCK = 

+ 0 - 1
src/app/shop/admin/goods/goods/edit.vue

@@ -466,7 +466,6 @@
   import { CircleCheck, CircleCloseFilled, Edit, Loading } from '@element-plus/icons-vue';
 
   import { api } from '../goods.service';
-  import { request } from '@/sheep/request';
 
   export default {
     name: 'GoodsEditNew',

+ 1 - 1
src/app/shop/admin/goods/goods/index.vue

@@ -26,7 +26,7 @@
             <el-tab-pane :label="`全部(${statusCounts.all})`" name="all"></el-tab-pane>
             <el-tab-pane :label="`已上架(${statusCounts.alreadyListed})`" name="up"></el-tab-pane>
             <el-tab-pane :label="`已下架(${statusCounts.removed})`" name="down"></el-tab-pane>
-            <el-tab-pane :label="`已删除(${statusCounts.recycle})`" name="isRecycle"></el-tab-pane>
+            <!-- <el-tab-pane :label="`已删除(${statusCounts.recycle})`" name="isRecycle"></el-tab-pane> -->
           </el-tabs>
           <div class="sa-title sa-flex sa-row-between">
             <div class="label sa-flex">

+ 20 - 1
src/app/shop/admin/order/order.service.js

@@ -48,7 +48,26 @@ const route = {
 
 const api = {
   order: {
-    ...CRUD('shop/admin/order/order', ['list', 'detail', 'edit']),
+    // 订单列表 - 使用POST方法
+    list: (data) =>
+      request({
+        url: '/order/list',
+        method: 'POST',
+        data,
+      }),
+    // 订单详情
+    detail: (id) =>
+      request({
+        url: `/shop/admin/order/order/detail/${id}`,
+        method: 'GET',
+      }),
+    // 编辑订单
+    edit: (id, data) =>
+      request({
+        url: `/shop/admin/order/order/edit/${id}`,
+        method: 'PUT',
+        data,
+      }),
     getType: () =>
       request({
         url: '/shop/admin/order/order/getType',

+ 237 - 95
src/app/shop/admin/order/order/index.vue

@@ -14,7 +14,7 @@
               <template #custom="{ data }">
                 <el-form-item label="下单时间">
                   <el-date-picker
-                    v-model="data.create_time"
+                    v-model="data.createTime"
                     type="datetimerange"
                     value-format="YYYY-MM-DD HH:mm:ss"
                     format="YYYY-MM-DD HH:mm:ss"
@@ -29,15 +29,15 @@
             </sa-search-simple>
           </div>
           <el-tabs class="sa-tabs" v-model="currentStatus" @tab-change="handleTabChange">
-            <el-tab-pane label="全部(100)" name="all"></el-tab-pane>
-            <el-tab-pane label="待付款(25)" name="unpaid"></el-tab-pane>
-            <el-tab-pane label="已付款(15)" name="paid"></el-tab-pane>
-            <el-tab-pane label="待发货(30)" name="nosend"></el-tab-pane>
-            <el-tab-pane label="待收货(20)" name="noget"></el-tab-pane>
-            <el-tab-pane label="已完成(20)" name="completed"></el-tab-pane>
-            <el-tab-pane label="已关闭(5)" name="closed"></el-tab-pane>
-            <el-tab-pane label="已退款(8)" name="refunded"></el-tab-pane>
-            <el-tab-pane label="已取消(12)" name="cancelled"></el-tab-pane>
+            <el-tab-pane label="全部" name="all"></el-tab-pane>
+            <el-tab-pane label="待付款" name="unpaid"></el-tab-pane>
+            <el-tab-pane label="已付款" name="paid"></el-tab-pane>
+            <el-tab-pane label="待发货" name="nosend"></el-tab-pane>
+            <el-tab-pane label="待收货" name="noget"></el-tab-pane>
+            <el-tab-pane label="已完成" name="completed"></el-tab-pane>
+            <el-tab-pane label="已关闭" name="closed"></el-tab-pane>
+            <el-tab-pane label="已退款" name="refunded"></el-tab-pane>
+            <el-tab-pane label="已取消" name="cancelled"></el-tab-pane>
           </el-tabs>
           <div class="sa-title sa-flex sa-row-between">
             <div class="label sa-flex">
@@ -73,7 +73,6 @@
               :data="table.data"
               @selection-change="changeSelection"
               @sort-change="fieldFilter"
-              @row-dblclick="detailRow"
               row-key="id"
               stripe
             >
@@ -81,86 +80,105 @@
                 <sa-empty></sa-empty>
               </template>
               <el-table-column type="selection" width="48" align="center"></el-table-column>
-              <el-table-column sortable="custom" prop="order_sn" label="订单编号" min-width="150">
+              <el-table-column sortable="custom" prop="orderId" label="订单编号" min-width="150">
                 <template #default="scope">
                   <div class="order-info">
-                    <div class="order-sn">{{ scope.row.order_sn }}</div>
+                    <div class="order-sn">{{ scope.row.orderId }}</div>
                   </div>
                 </template>
               </el-table-column>
-              <el-table-column label="商品信息" min-width="280">
+              <el-table-column label="商品信息" min-width="300">
                 <template #default="scope">
                   <div
-                    class="sa-flex sa-row-center"
-                    v-if="scope.row.items && scope.row.items.length > 0"
+                    class="sa-flex"
+                    v-if="scope.row.orderInfoVO && scope.row.orderInfoVO.length > 0"
                   >
                     <el-image
-                      :src="scope.row.items[0].goods_image"
+                      :src="scope.row.orderInfoVO[0].image"
                       style="width: 60px; height: 60px; margin-right: 12px"
                       fit="cover"
                     />
                     <div>
-                      <div class="goods-title">{{ scope.row.items[0].goods_title }}</div>
+                      <div class="goods-title">{{ scope.row.orderInfoVO[0].productName }}</div>
                     </div>
                   </div>
+                  <div v-else>-</div>
                 </template>
               </el-table-column>
               <el-table-column label="规格" min-width="120" align="center">
                 <template #default="scope">
-                  <div v-if="scope.row.items && scope.row.items.length > 0">
-                    {{ scope.row.items[0].goods_sku_text || '-' }}
+                  <div v-if="scope.row.orderInfoVO && scope.row.orderInfoVO.length > 0">
+                    {{ scope.row.orderInfoVO[0].sku || '-' }}
                   </div>
                   <div v-else>-</div>
                 </template>
               </el-table-column>
-              <el-table-column prop="goods_num" label="数量" min-width="80" align="center">
+              <el-table-column label="数量" min-width="80" align="center">
+                <template #default="scope">
+                  <div v-if="scope.row.orderInfoVO && scope.row.orderInfoVO.length > 0">
+                    {{ scope.row.orderInfoVO[0].payNum || 0 }}
+                  </div>
+                  <div v-else>0</div>
+                </template>
+              </el-table-column>
+              <el-table-column prop="realName" label="用户名" min-width="120" align="center">
+                <template #default="scope">
+                  <el-button type="text" @click="openUserDetail(scope.row.uid)">
+                    {{ scope.row.realName || '-' }}
+                  </el-button>
+                </template>
+              </el-table-column>
+              <el-table-column prop="payPrice" label="付款金额" min-width="120" align="center">
                 <template #default="scope">
-                  {{
-                    scope.row.items && scope.row.items.length > 0 ? scope.row.items[0].goods_num : 0
-                  }}
+                  <div>৳{{ scope.row.payPrice || 0 }}</div>
                 </template>
               </el-table-column>
-              <el-table-column prop="user.nickname" label="用户名" min-width="120" align="center">
+              <el-table-column label="支付状态" min-width="100" align="center">
                 <template #default="scope">
-                  <div>{{ scope.row.user ? scope.row.user.nickname : '-' }}</div>
+                  <el-tag :type="scope.row.paid === 1 ? 'success' : 'warning'">
+                    {{ scope.row.paid === 1 ? '已付款' : '待付款' }}
+                  </el-tag>
                 </template>
               </el-table-column>
-              <el-table-column prop="pay_fee" label="付款金额" min-width="120" align="center">
+              <el-table-column label="订单状态" min-width="100" align="center">
                 <template #default="scope">
-                  <div>৳{{ scope.row.pay_fee }}</div>
+                  <el-tag :type="getOrderStatusType(scope.row.status)">
+                    {{ getOrderStatusText(scope.row.status) }}
+                  </el-tag>
                 </template>
               </el-table-column>
-              <el-table-column prop="status_text" label="订单状态" min-width="100" align="center">
+              <el-table-column label="退款状态" min-width="100" align="center">
                 <template #default="scope">
-                  <el-tag :type="getStatusType(scope.row.status)">
-                    {{ scope.row.status_text }}
+                  <el-tag :type="getRefundStatusType(scope.row.refundStatus)">
+                    {{ getRefundStatusText(scope.row.refundStatus) }}
                   </el-tag>
                 </template>
               </el-table-column>
               <el-table-column label="物流信息" min-width="150" align="center">
                 <template #default="scope">
-                  <div v-if="scope.row.express_no">
-                    <div>{{ scope.row.express_company || '快递公司' }}</div>
-                    <div>{{ scope.row.express_no }}</div>
+                  <div v-if="scope.row.deliveryId">
+                    <div class="delivery-name"
+                      >{{ scope.row.deliveryName || '快递公司' }}:{{ scope.row.deliveryId }}</div
+                    >
                   </div>
-                  <div v-else>{{ scope.row.express_status || '未发货' }}</div>
+                  <div v-else>未发货</div>
                 </template>
               </el-table-column>
               <el-table-column label="下单时间" min-width="150" align="center">
                 <template #default="scope">
-                  <div>{{ scope.row.create_time }}</div>
+                  <div>{{ scope.row.createTime }}</div>
                 </template>
               </el-table-column>
               <el-table-column label="付款时间" min-width="150" align="center">
                 <template #default="scope">
-                  <div>{{ scope.row.pay_time || '-' }}</div>
+                  <div>{{ scope.row.payTime || '-' }}</div>
                 </template>
               </el-table-column>
               <el-table-column label="操作" min-width="150" fixed="right">
                 <template #default="scope">
                   <div class="sa-flex">
                     <el-button
-                      v-if="scope.row.btns?.includes('send')"
+                      v-if="scope.row.paid === 1 && scope.row.status === 0"
                       class="is-link"
                       type="primary"
                       @click="onSend(scope.row)"
@@ -170,7 +188,7 @@
                       >详情</el-button
                     >
                     <el-button
-                      v-if="scope.row.status === 'unpaid'"
+                      v-if="scope.row.paid === 0"
                       class="is-link sa-m-l-12"
                       type="danger"
                       @click="cancelOrder(scope.row.id)"
@@ -216,31 +234,25 @@
 
   // 搜索字段配置
   const searchFields = reactive({
-    order_sn: {
+    orderId: {
       type: 'input',
       label: '订单编号',
       placeholder: '请输入订单编号',
       width: 200,
     },
-    goods_info: {
+    realName: {
       type: 'input',
-      label: '商品(名称/编号)',
-      placeholder: '请输入商品名称或编号',
+      label: '用户姓名',
+      placeholder: '请输入用户姓名',
       width: 200,
     },
-    'user.nickname': {
-      type: 'input',
-      label: '用户名',
-      placeholder: '请输入用户名',
-      width: 200,
-    },
-    'user.mobile': {
+    userPhone: {
       type: 'input',
       label: '手机号',
       placeholder: '请输入手机号',
       width: 200,
     },
-    express_no: {
+    deliveryId: {
       type: 'input',
       label: '物流单号',
       placeholder: '请输入物流单号',
@@ -250,36 +262,102 @@
 
   // 默认搜索值
   const defaultSearchValues = reactive({
-    order_sn: '',
-    goods_info: '',
-    'user.nickname': '',
-    'user.mobile': '',
-    express_no: '',
-    create_time: [],
+    orderId: '',
+    realName: '',
+    userPhone: '',
+    deliveryId: '',
+    createTime: [],
   });
 
   // 当前状态标签
   const currentStatus = ref('all');
 
+  // 状态映射 - 根据后端字段定义
+  const statusMap = {
+    all: {}, // 全部 - 不传任何状态参数
+    unpaid: { paid: 0 }, // 待付款:支付状态为0
+    paid: { paid: 1 }, // 已付款:支付状态为1(不限制订单状态)
+    nosend: { paid: 1, status: 0 }, // 待发货:已付款且订单状态为0
+    noget: { paid: 1, status: 1 }, // 待收货:已付款且订单状态为1
+    completed: { paid: 1, status: 3 }, // 已完成:已付款且订单状态为3
+    closed: { status: 4 }, // 已关闭:订单状态为4
+    refunded: { refundStatus: 2 }, // 已退款:退款状态为2
+    cancelled: { status: 5 }, // 已取消:订单状态为5
+  };
+
   // 标签切换处理
   const handleTabChange = (status) => {
     currentStatus.value = status;
-    getData(1, { status: status === 'all' ? '' : status });
+    const statusParams = statusMap[status] || {};
+    getData(1, statusParams);
+  };
+
+  // 获取订单状态文本
+  const getOrderStatusText = (status) => {
+    switch (status) {
+      case 0:
+        return '待发货';
+      case 1:
+        return '待收货';
+      case 3:
+        return '已完成';
+      case 4:
+        return '已关闭';
+      case 5:
+        return '已取消';
+      default:
+        return '未知';
+    }
+  };
+
+  // 获取订单状态类型
+  const getOrderStatusType = (status) => {
+    switch (status) {
+      case 0:
+        return 'info'; // 待发货 - 蓝色
+      case 1:
+        return ''; // 待收货 - 默认色
+      case 3:
+        return 'success'; // 已完成 - 绿色
+      case 4:
+        return 'danger'; // 已关闭 - 红色
+      case 5:
+        return 'danger'; // 已取消 - 红色
+      default:
+        return '';
+    }
+  };
+
+  // 获取退款状态文本
+  const getRefundStatusText = (refundStatus) => {
+    switch (refundStatus) {
+      case 0:
+        return '未退款';
+      case 1:
+        return '申请中';
+      case 2:
+        return '已退款';
+      case 3:
+        return '退款中';
+      default:
+        return '未退款';
+    }
   };
 
-  // 获取状态类型
-  const getStatusType = (status) => {
-    const statusMap = {
-      unpaid: 'warning',
-      paid: 'info',
-      nosend: '',
-      noget: '',
-      completed: 'success',
-      closed: 'danger',
-      refunded: 'warning',
-      cancelled: 'danger',
-    };
-    return statusMap[status] || '';
+  // 获取退款状态类型
+  const getRefundStatusType = (refundStatus) => {
+    switch (refundStatus) {
+      case 0:
+        return ''; // 未退款 - 默认色
+      case 1:
+        return 'warning'; // 申请中 - 橙色
+      case 2:
+        return 'success'; // 已退款 - 绿色
+      case 3:
+        return 'info'; // 退款中 - 蓝色
+      default:
+        return '';
+    }
   };
 
   const loading = ref(true);
@@ -300,37 +378,51 @@
     try {
       if (page) pageData.page = page;
 
-      // 处理搜索参数
-      let search = {};
-      if (Object.keys(searchParams).length > 0) {
-        // 处理时间范围
-        if (searchParams.create_time && searchParams.create_time.length === 2) {
-          search.create_time = searchParams.create_time;
-        }
+      // 构建请求参数
+      const requestData = {
+        page: pageData.page,
+        limit: pageData.size,
+        ...searchParams,
+      };
 
-        // 处理其他搜索参数
-        Object.keys(searchParams).forEach((key) => {
-          if (key !== 'create_time' && searchParams[key]) {
-            search[key] = searchParams[key];
-          }
-        });
+      // 处理时间范围搜索
+      if (searchParams.createTime && searchParams.createTime.length === 2) {
+        requestData.startTime = searchParams.createTime[0];
+        requestData.endTime = searchParams.createTime[1];
+        delete requestData.createTime;
       }
 
-      const response = await api.order.list({
-        page: pageData.page,
-        size: pageData.size,
-        ...search,
-        order: table.order,
-        sort: table.sort,
-      });
+      const response = await api.order.list(requestData);
 
       console.log('API 响应:', response);
 
       if (response && response.code == '200' && response.data) {
-        table.data = response.data.orders.data || [];
-        pageData.page = response.data.orders.current_page || 1;
-        pageData.size = response.data.orders.per_page || 10;
-        pageData.total = response.data.orders.total || 0;
+        // 映射后端返回的字段到前端需要的格式
+        table.data = (response.data.list || []).map((item) => ({
+          id: item.id,
+          orderId: item.orderId, // 订单号
+          realName: item.realName, // 用户姓名
+          userPhone: item.userPhone, // 用户电话
+          uid: item.uid, // 用户ID
+          totalPrice: item.totalPrice, // 订单总价
+          payPrice: item.payPrice, // 实际支付金额
+          totalNum: item.totalNum, // 商品总数
+          paid: item.paid, // 支付状态
+          status: item.status, // 订单状态
+          refundStatus: item.refundStatus, // 退款状态
+          createTime: item.createTime, // 创建时间
+          payTime: item.payTime, // 支付时间
+          deliveryName: item.deliveryName, // 快递名称
+          deliveryId: item.deliveryId, // 快递单号
+          shippingType: item.shippingType, // 配送方式
+          userAddress: item.userAddress, // 详细地址
+          remark: item.remark, // 管理员备注
+          mark: item.mark, // 备注
+          orderInfoVO: item.orderInfoVO, // 订单商品信息
+        }));
+
+        pageData.page = response.data.current_page || pageData.page;
+        pageData.total = response.data.total || 0;
       } else {
         table.data = [];
         console.error('获取订单数据失败:', response);
@@ -417,6 +509,16 @@
     // 这里可以添加取消订单的逻辑
   }
 
+  // 打开用户详情
+  function openUserDetail(uid) {
+    if (uid) {
+      console.log('打开用户详情', uid);
+      ElMessage.info('用户详情功能待开发');
+      // TODO: 这里可以跳转到用户详情页面或打开弹窗
+      // router.push(`/user/detail/${uid}`);
+    }
+  }
+
   function onSend(row) {
     useModal(
       OrderDispatch,
@@ -504,5 +606,45 @@
         }
       }
     }
+
+    // 商品信息样式
+    .goods-title {
+      font-weight: 500;
+      color: #303133;
+      margin-bottom: 4px;
+      line-height: 1.4;
+    }
+
+    .goods-info {
+      font-size: 12px;
+      color: #909399;
+      line-height: 1.3;
+    }
+
+    // 用户名按钮样式
+    .user-name-btn {
+      color: #409eff;
+      text-decoration: none;
+      padding: 0;
+      font-size: 14px;
+
+      &:hover {
+        color: #66b1ff;
+        text-decoration: underline;
+      }
+    }
+
+    // 物流信息样式
+    .delivery-name {
+      font-size: 14px;
+      color: #303133;
+      margin-bottom: 2px;
+    }
+
+    // 订单号样式
+    .order-sn {
+      font-weight: 500;
+      color: #303133;
+    }
   }
 </style>

+ 14 - 1
src/sheep/local-data/admin.js

@@ -415,6 +415,19 @@ const menuRulesData = {
                 status_text: '显示',
                 id: 1001,
                 parent_id: 1000,
+                name: 'admin.auth.access',
+                title: '菜单权限',
+                type: 'page',
+                icon: 'sa-auth-access',
+                params: '',
+                weigh: 0,
+                status: 'show',
+              },
+              {
+                type_text: '页面',
+                status_text: '显示',
+                id: 1002,
+                parent_id: 1000,
                 name: 'admin.auth.role',
                 title: '角色管理',
                 type: 'page',
@@ -426,7 +439,7 @@ const menuRulesData = {
               {
                 type_text: '页面',
                 status_text: '显示',
-                id: 1002,
+                id: 1003,
                 parent_id: 1000,
                 name: 'admin.auth.admin',
                 title: '人员管理',

+ 0 - 51
src/test-upload.vue

@@ -1,51 +0,0 @@
-<template>
-  <div class="p-4">
-    <h2 class="text-xl font-bold mb-4">图片上传组件测试</h2>
-    
-    <div class="mb-6">
-      <h3 class="text-lg font-semibold mb-2">普通模式</h3>
-      <sa-upload-image
-        v-model="normalImages"
-        :max-count="5"
-        :max-size="5"
-        :size="120"
-        placeholder="上传商品图片"
-      />
-    </div>
-    
-    <div class="mb-6">
-      <h3 class="text-lg font-semibold mb-2">精简模式</h3>
-      <sa-upload-image
-        v-model="compactImages"
-        :max-count="3"
-        :max-size="2"
-        :size="80"
-        :compact="true"
-        :show-tip="false"
-      />
-    </div>
-    
-    <div class="mt-6">
-      <h3 class="text-lg font-semibold mb-2">数据输出</h3>
-      <div class="bg-gray-100 p-4 rounded">
-        <p><strong>普通模式图片:</strong></p>
-        <pre>{{ JSON.stringify(normalImages, null, 2) }}</pre>
-        <p class="mt-4"><strong>精简模式图片:</strong></p>
-        <pre>{{ JSON.stringify(compactImages, null, 2) }}</pre>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { ref } from 'vue';
-
-const normalImages = ref([
-  'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_200,h_200',
-  'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_300,h_300',
-]);
-
-const compactImages = ref([
-  'https://mall-oss.trust-will.com/storage/default/20250701/7bf12c56300454532244dec2aff808eb.jpg?x-oss-process=image/resize,w_100,h_100',
-]);
-</script>

+ 10 - 10
vite.config.js

@@ -45,16 +45,16 @@ export default (command, mode) => {
       hmr: {
         overlay: true,
       },
-      proxy: {
-        '/mall': {
-          target: 'http://192.168.0.101:8101/',
-          changeOrigin: true,
-        },
-        '/operating': {
-          target: 'http://192.168.0.101:8301/',
-          changeOrigin: true,
-        },
-      },
+      // proxy: {
+      //   '/mall': {
+      //     target: 'http://192.168.0.100:8101/',
+      //     changeOrigin: true,
+      //   },
+      //   '/operating': {
+      //     target: 'http://192.168.0.100:8301/',
+      //     changeOrigin: true,
+      //   },
+      // },
     },
     build: {
       chunkSizeWarningLimit: 2000,