Преглед на файлове

完善订单导出功能

罗永浩 преди 1 месец
родител
ревизия
67419470da

+ 26 - 15
addons/admin/src/views/order/order.vue

@@ -595,23 +595,34 @@ export default {
 			}).then(() => {
 				const loading = this.$loading({ lock: true, text: '正在导出...' });
 				// 构建导出参数
-				const params = { ...this.table.where, export: 1 };
-				const queryString = Object.keys(params)
-					.map(key => `${key}=${encodeURIComponent(params[key])}`)
-					.join('&');
-
-				// 创建隐藏的下载链接
-				const link = document.createElement('a');
-				link.href = `/order/export?${queryString}`;
-				link.download = `订单列表_${new Date().getTime()}.xlsx`;
-				document.body.appendChild(link);
-				link.click();
-				document.body.removeChild(link);
-
-				setTimeout(() => {
+				const params = { ...this.table.where };
+				// 过滤空值
+				Object.keys(params).forEach(key => {
+					if (params[key] === undefined || params[key] === null || params[key] === '') {
+						delete params[key];
+					}
+				});
+
+				// 使用axios下载文件
+				this.$http.get('/order/export', {
+					params: params,
+					responseType: 'blob'
+				}).then(res => {
 					loading.close();
+					// 创建下载链接
+					const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+					const link = document.createElement('a');
+					link.href = window.URL.createObjectURL(blob);
+					link.download = `订单列表_${new Date().getTime()}.xlsx`;
+					document.body.appendChild(link);
+					link.click();
+					document.body.removeChild(link);
+					window.URL.revokeObjectURL(link.href);
 					this.$message.success('导出成功');
-				}, 1000);
+				}).catch(e => {
+					loading.close();
+					this.$message.error(e.message || '导出失败');
+				});
 			}).catch(() => { });
 		},
 		// 完成支付

+ 41 - 6
addons/admin/src/views/orders/afterType.vue

@@ -123,7 +123,9 @@
 						<span style="font-weight: bold;">
 							<i class="el-icon-warning-outline"></i> 售后申请信息
 						</span>
-						<el-tag :type="orderInfo.refund_status == 3 ? 'warning' : orderInfo.refund_status == 1 ? 'success' : 'danger'" size="small">
+						<el-tag
+							:type="orderInfo.refund_status == 3 ? 'warning' : orderInfo.refund_status == 1 ? 'success' : 'danger'"
+							size="small">
 							{{ orderInfo.refund_status == 3 ? '待审核' : orderInfo.refund_status == 1 ? '已处理' : '已驳回' }}
 						</el-tag>
 					</div>
@@ -196,7 +198,8 @@
 						<el-col :span="8">
 							<div class="info-item">
 								<span class="info-label">订单金额:</span>
-								<span class="info-value" style="color: #F56C6C; font-weight: bold;">¥{{ orderInfo.pay_total || '0.00' }}</span>
+								<span class="info-value" style="color: #F56C6C; font-weight: bold;">¥{{ orderInfo.pay_total || '0.00'
+									}}</span>
 							</div>
 						</el-col>
 						<el-col :span="8">
@@ -220,16 +223,19 @@
 						<i class="el-icon-goods"></i> 商品信息
 					</div>
 					<div style="display: flex; align-items: center; padding: 10px; background: #f5f7fa; border-radius: 4px;">
-						<el-image :src="orderInfo.goods.thumb" style="width: 80px; height: 80px; margin-right: 20px; border-radius: 4px;" fit="cover" />
+						<el-image :src="orderInfo.goods.thumb"
+							style="width: 80px; height: 80px; margin-right: 20px; border-radius: 4px;" fit="cover" />
 						<div style="flex: 1;">
-							<div style="font-size: 16px; font-weight: bold; margin-bottom: 8px;">{{ orderInfo.goods.goods_name }}</div>
+							<div style="font-size: 16px; font-weight: bold; margin-bottom: 8px;">{{ orderInfo.goods.goods_name }}
+							</div>
 							<div style="color: #909399; font-size: 14px;">
 								<span>规格:{{ orderInfo.goods.spec_name || '默认' }}</span>
 								<span style="margin-left: 20px;">数量:{{ orderInfo.goods_num || 1 }}</span>
 							</div>
 						</div>
 						<div style="text-align: right;">
-							<div style="color: #F56C6C; font-size: 18px; font-weight: bold;">¥{{ orderInfo.goods.price || '0.00' }}</div>
+							<div style="color: #F56C6C; font-size: 18px; font-weight: bold;">¥{{ orderInfo.goods.price || '0.00' }}
+							</div>
 						</div>
 					</div>
 				</el-card>
@@ -378,7 +384,36 @@ export default {
 			this.detailVisible = false;
 		},
 		handleExport() {
-			this.$message.info('导出功能开发中...');
+			this.$confirm('确定要导出当前筛选条件下的售后订单数据吗?', '提示', {
+				type: 'warning'
+			}).then(() => {
+				const loading = this.$loading({ lock: true, text: '正在导出...' });
+				const params = { ...this.table.where };
+				Object.keys(params).forEach(key => {
+					if (params[key] === undefined || params[key] === null || params[key] === '') {
+						delete params[key];
+					}
+				});
+
+				this.$http.get('/order/export', {
+					params: params,
+					responseType: 'blob'
+				}).then(res => {
+					loading.close();
+					const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+					const link = document.createElement('a');
+					link.href = window.URL.createObjectURL(blob);
+					link.download = `售后订单_${new Date().getTime()}.xlsx`;
+					document.body.appendChild(link);
+					link.click();
+					document.body.removeChild(link);
+					window.URL.revokeObjectURL(link.href);
+					this.$message.success('导出成功');
+				}).catch(e => {
+					loading.close();
+					this.$message.error(e.message || '导出失败');
+				});
+			}).catch(() => { });
 		},
 		getStatusText(status) {
 			const map = { 1: '待付款', 2: '已付款', 3: '已发货', 4: '已完成' };

+ 30 - 1
addons/admin/src/views/orders/refundOrder.vue

@@ -328,7 +328,36 @@ export default {
 			this.handleConfirmRefund(this.orderInfo);
 		},
 		handleExport() {
-			this.$message.info('导出功能开发中...');
+			this.$confirm('确定要导出当前筛选条件下的退款订单数据吗?', '提示', {
+				type: 'warning'
+			}).then(() => {
+				const loading = this.$loading({ lock: true, text: '正在导出...' });
+				const params = { ...this.table.where };
+				Object.keys(params).forEach(key => {
+					if (params[key] === undefined || params[key] === null || params[key] === '') {
+						delete params[key];
+					}
+				});
+
+				this.$http.get('/order/export', {
+					params: params,
+					responseType: 'blob'
+				}).then(res => {
+					loading.close();
+					const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+					const link = document.createElement('a');
+					link.href = window.URL.createObjectURL(blob);
+					link.download = `退款订单_${new Date().getTime()}.xlsx`;
+					document.body.appendChild(link);
+					link.click();
+					document.body.removeChild(link);
+					window.URL.revokeObjectURL(link.href);
+					this.$message.success('导出成功');
+				}).catch(e => {
+					loading.close();
+					this.$message.error(e.message || '导出失败');
+				});
+			}).catch(() => { });
 		},
 		getStatusText(status) {
 			const map = { 1: '待付款', 2: '已付款', 3: '已发货', 4: '已完成' };

+ 10 - 0
app/Http/Controllers/Admin/OrderController.php

@@ -122,4 +122,14 @@ class OrderController extends Backend
     {
         return $this->service->getStatistics($this->storeId);
     }
+
+    /**
+     * 导出订单
+     */
+    public function export()
+    {
+        $params = request()->all();
+        $params['store_id'] = $this->storeId ?: 0;
+        return $this->service->exportData($params);
+    }
 }

+ 6 - 6
app/Http/Middleware/EnableCrossRequestMiddleware.php

@@ -37,17 +37,17 @@ class EnableCrossRequestMiddleware
         $allow_origin = [];
         if (empty($allow_origin) || in_array($origin, $allow_origin)) {
             //允许所有资源跨域
-            $response->header('Access-Control-Allow-Origin', $origin);
+            $response->headers->set('Access-Control-Allow-Origin', $origin);
             // 允许通过的响应报头
-            $response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, X-CSRF-TOKEN, Accept, Authorization, X-XSRF-TOKEN');
+            $response->headers->set('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, X-CSRF-TOKEN, Accept, Authorization, X-XSRF-TOKEN');
             // 允许axios获取响应头中的Authorization
-            $response->header('Access-Control-Expose-Headers', 'Authorization, authenticated');
+            $response->headers->set('Access-Control-Expose-Headers', 'Authorization, authenticated');
             // 允许的请求方法
-            $response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS, DELETE');
+            $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS, DELETE');
             //允许的请求方法
-            $response->header('Allow', 'GET, POST, PATCH, PUT, OPTIONS, delete');
+            $response->headers->set('Allow', 'GET, POST, PATCH, PUT, OPTIONS, delete');
             // 运行客户端携带证书式访问
-            $response->header('Access-Control-Allow-Credentials', 'true');
+            $response->headers->set('Access-Control-Allow-Credentials', 'true');
         }
         return $response;
     }

+ 0 - 1
app/Http/Middleware/UserLogin.php

@@ -34,7 +34,6 @@ class UserLogin extends Middleware
             // JWT解密token
             $jwt = new Jwt();
             $userId = $jwt->verifyToken($token);
-
         } else {
             $userId = 0;
         }

+ 5 - 5
app/Models/StoreModel.php

@@ -59,7 +59,7 @@ class StoreModel extends BaseModel
     public function member()
     {
         return $this->hasOne(MemberModel::class, 'id', 'user_id')
-            ->select(['id', 'realname', 'nickname', 'mobile','parents', 'status']);
+            ->select(['id', 'realname', 'nickname', 'mobile', 'parents', 'status']);
     }
 
     /**
@@ -69,10 +69,10 @@ class StoreModel extends BaseModel
     {
         return $this->hasMany(GoodsModel::class, 'store_id', 'id')
             ->with(['category'])
-            ->where(['status'=>1,'mark'=>1])
-            ->select(['id','goods_name','category_id','store_id','price','thumb','sales','sku_type','unit','status'])
-            ->orderBy('sort','desc')
-            ->orderBy('id','desc');
+            ->where(['status' => 1, 'mark' => 1])
+            ->select(['id', 'goods_name', 'category_id', 'store_id', 'price', 'thumb', 'sales', 'sku_type', 'unit', 'status'])
+            ->orderBy('sort', 'desc')
+            ->orderBy('id', 'desc');
     }
 
     /**

+ 89 - 0
app/Services/Common/OrderService.php

@@ -1045,4 +1045,93 @@ class OrderService extends BaseService
             ]
         ];
     }
+
+    /**
+     * 导出订单数据
+     */
+    public function exportData($params)
+    {
+        $query = $this->model->where('mark', 1);
+
+        // 店铺筛选
+        if (isset($params['store_id']) && $params['store_id'] > 0) {
+            $query->where('store_id', $params['store_id']);
+        }
+
+        // 用户筛选
+        if (isset($params['user_id']) && $params['user_id'] > 0) {
+            $query->where('user_id', $params['user_id']);
+        }
+
+        // 状态筛选
+        if (isset($params['status']) && $params['status'] > 0) {
+            $query->where('status', $params['status']);
+        }
+
+        // 售后类型筛选
+        if (isset($params['after_type']) && $params['after_type'] > 0) {
+            $query->where('after_type', $params['after_type']);
+        }
+
+        // 退款状态筛选
+        if (isset($params['refund_status']) && $params['refund_status'] > 0) {
+            $query->where('refund_status', $params['refund_status']);
+        }
+
+        // 关键词搜索
+        if (isset($params['keyword']) && $params['keyword']) {
+            $keyword = $params['keyword'];
+            $query->where(function ($q) use ($keyword) {
+                $q->where('order_no', 'like', '%' . $keyword . '%')
+                    ->orWhere('receiver_name', 'like', '%' . $keyword . '%')
+                    ->orWhere('receiver_mobile', 'like', '%' . $keyword . '%');
+            });
+        }
+
+        $list = $query->with(['user', 'orderGoods', 'store'])
+            ->orderBy('create_time', 'desc')
+            ->limit(5000)
+            ->get();
+
+        if (!$list || $list->isEmpty()) {
+            return response()->json(['code' => 1, 'msg' => '没有可导出的数据']);
+        }
+
+        // 状态映射
+        $statusMap = [1 => '待付款', 2 => '已付款', 3 => '已发货', 4 => '已完成', 9 => '已取消'];
+        $refundStatusMap = [0 => '无', 1 => '已退款', 2 => '已审核', 3 => '待审核'];
+
+        // 构建导出数据
+        $data = [];
+        foreach ($list as $item) {
+            $goodsNames = [];
+            if ($item->orderGoods) {
+                foreach ($item->orderGoods as $goods) {
+                    $goodsNames[] = $goods->goods_name . ' x' . $goods->num;
+                }
+            }
+
+            $data[] = [
+                $item->order_no,
+                $item->user->nickname ?? '',
+                $item->user->mobile ?? '',
+                implode(';', $goodsNames),
+                $item->total ?? 0,
+                $item->pay_total ?? 0,
+                $statusMap[$item->status] ?? '未知',
+                $refundStatusMap[$item->refund_status] ?? '无',
+                $item->receiver_name ?? '',
+                $item->receiver_mobile ?? '',
+                $item->receiver_address ?? '',
+                $item->create_time ? date('Y-m-d H:i:s', strtotime($item->create_time)) : '',
+            ];
+        }
+
+        $headings = ['订单号', '用户昵称', '用户手机', '商品信息', '订单金额', '实付金额', '订单状态', '退款状态', '收货人', '收货电话', '收货地址', '下单时间'];
+
+        $export = new \App\Exports\Export($data, $headings, '订单列表');
+        $filename = '订单列表_' . date('YmdHis') . '.xlsx';
+
+        return \Maatwebsite\Excel\Facades\Excel::download($export, $filename);
+    }
 }

+ 1 - 0
routes/web.php

@@ -146,6 +146,7 @@ Route::post('/order/applyRefund', [\App\Http\Controllers\Admin\OrderController::
 Route::post('/order/agreeRefund', [\App\Http\Controllers\Admin\OrderController::class, 'agreeRefund']);
 Route::post('/order/confirmRefund', [\App\Http\Controllers\Admin\OrderController::class, 'confirmRefund']);
 Route::post('/order/rejectRefund', [\App\Http\Controllers\Admin\OrderController::class, 'rejectRefund']);
+Route::get('/order/export', [\App\Http\Controllers\Admin\OrderController::class, 'export']);
 
 // 代理管理
 Route::get('/agent/index', [\App\Http\Controllers\Admin\AgentController::class, 'index']);