cqp 1 Minggu lalu
induk
melakukan
c0e958cd51

+ 67 - 4
app/Exports/SingleSheetExport.php

@@ -2,12 +2,19 @@
 
 namespace App\Exports;
 
-
+use Illuminate\Support\Collection;
 use Maatwebsite\Excel\Concerns\FromCollection;
 use Maatwebsite\Excel\Concerns\WithTitle;
-use Illuminate\Support\Collection;
+use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
+use Maatwebsite\Excel\Concerns\WithStyles;
+use PhpOffice\PhpSpreadsheet\Cell\Cell;
+use PhpOffice\PhpSpreadsheet\Cell\DataType;
+use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Border;
 
-class SingleSheetExport implements FromCollection,WithTitle
+class SingleSheetExport extends DefaultValueBinder implements FromCollection, WithTitle, WithCustomValueBinder, WithStyles
 {
     protected $data;
     protected $sheetName;
@@ -18,13 +25,69 @@ class SingleSheetExport implements FromCollection,WithTitle
         $this->sheetName = $sheetName;
     }
 
+    /**
+     * 数据集合
+     */
     public function collection()
     {
         return new Collection($this->data);
     }
 
+    /**
+     * Sheet 名称
+     */
     public function title(): string
     {
         return $this->sheetName;
     }
-}
+
+    /**
+     * 自定义单元格绑定(防止数字丢失前导零 / 科学计数法)
+     */
+    public function bindValue(Cell $cell, $value)
+    {
+        // 如果是纯数字,则以字符串形式写入
+        if (is_numeric($value)) {
+            $cell->setValueExplicit($value, DataType::TYPE_STRING);
+            return true;
+        }
+
+        return parent::bindValue($cell, $value);
+    }
+
+    /**
+     * 每页 Sheet 的样式
+     */
+    public function styles(Worksheet $sheet)
+    {
+        $highestRow = $sheet->getHighestRow();
+        $highestColumn = $sheet->getHighestColumn();
+
+        // 1. 表头加粗、居中
+        $sheet->getStyle('A1:' . $highestColumn . '1')->applyFromArray([
+            'font' => [
+                'bold' => true,
+                'size' => 11,
+            ],
+            'alignment' => [
+                'horizontal' => Alignment::HORIZONTAL_CENTER,
+                'vertical' => Alignment::VERTICAL_CENTER,
+            ],
+            'borders' => [
+                'bottom' => ['borderStyle' => Border::BORDER_THIN],
+            ],
+        ]);
+
+        // 2. 内容垂直居中
+        $sheet->getStyle('A2:' . $highestColumn . $highestRow)
+            ->getAlignment()
+            ->setVertical(Alignment::VERTICAL_CENTER);
+
+        // 3. 自动列宽
+        foreach (range('A', $highestColumn) as $col) {
+            $sheet->getColumnDimension($col)->setAutoSize(true);
+        }
+
+        return [];
+    }
+}

+ 33 - 1
app/Service/ExportFileService.php

@@ -3,6 +3,7 @@
 namespace App\Service;
 
 use App\Exports\ExportOrder;
+use App\Exports\MultiSheetExport;
 use App\Model\RevenueCost;
 use Maatwebsite\Excel\Facades\Excel;
 
@@ -308,7 +309,7 @@ class ExportFileService extends Service
         return [true, $this->saveExportData($return,$header)];
     }
 
-    public function ten($ergs,$user){
+    public function ten11($ergs,$user){
         $return = [];
         $header_default = $user['e_header_default'];
         $column = array_column($header_default, 'key');
@@ -336,10 +337,41 @@ class ExportFileService extends Service
         return [true, $this->saveExportData($return,$header)];
     }
 
+    public function ten($ergs,$user){
+        $return = [];
+        $header_default = $user['e_header_default'];
+        $column = array_column($header_default, 'key');
+        $header = array_column($header_default, 'value');
+
+        $service = new StatisticsService();
+        list($status,$model) = $service->statisticsFreightFeeCommon($ergs, $user);
+        if(! $status) return [false, $model];
+
+        $model->chunk(10, function ($data) use (&$return, $column, $service,$user, $ergs) {
+            $data = $data->toArray();
+
+            $order_time = array_column($data,'order_time');
+            $ergs = array_merge($ergs, ['order_time' => $order_time]);
+
+            $list = $service->statisticsFreightFeeDetailsForExport($ergs, $user);
+            $return = array_merge_recursive($return, $list);
+        });
+
+        return [true, $this->saveExportData2($return)];
+    }
+
     public function saveExportData($data, $headers, $type = 'default',$file_name = ''){
         if(empty($file_name)) $file_name = self::$filename . "_". date("Y-m-d") . "_". rand(1000,9999);
         $filename =  $file_name . '.' . 'xlsx';
         $bool = Excel::store(new ExportOrder($data,$type,$headers),"/public/export/{$filename}", null, 'Xlsx', []);
         return $filename;
     }
+
+    public function saveExportData2($data,$file_name = ''){
+        if(empty($file_name)) $file_name = self::$filename . "_". date("Y-m-d") . "_". rand(1000,9999);
+        $filename =  $file_name . '.' . 'xlsx';
+        \Maatwebsite\Excel\Facades\Excel::store(new MultiSheetExport($data),"/public/export/{$filename}", null, 'Xlsx', []);
+
+        return $filename;
+    }
 }

+ 161 - 0
app/Service/StatisticsService.php

@@ -643,6 +643,167 @@ class StatisticsService extends Service
         return [true, $result];
     }
 
+    public function statisticsFreightFeeDetailsForExport($data, $user)
+    {
+        if (empty($data['order_time'])) return [];
+
+        $model = FreightFee::Clear($user, $data);
+        $orderTimes = is_array($data['order_time']) ? $data['order_time'] : [$data['order_time']];
+
+        $fee = $model->where('del_time', 0)
+            ->whereIn('order_time', $orderTimes)
+            ->get()
+            ->toArray();
+
+        // 表头定义(所有 sheet 通用)
+        $header = [
+            "仓库", "销货单备注", "业务类型", "销货单号", "销货日期", "客户",
+            "客户门店装车费单价", "业务员", "送货地址", "地区华商", "存货编码", "存货名称", "箱规",
+            "华商重量", "门店卸货费单价(华商)", "门店卸货费单价(华商)", "赠品", "货类(华商)", "运输方式",
+            "数量", "含税单价", "含税金额", "箱数", "总重量", "运价区间", "配送费单价", "配送费金额", "结算金额",
+            "门店卸货费", "上楼费", "加急费", "到货装卸费", "总金额"
+        ];
+
+        if (empty($fee)) {
+            // 返回每个请求的日期都带表头(只有表头),以便导出时每个 sheet 至少有表头
+            $resultEmpty = [];
+            foreach ($orderTimes as $ot) {
+                $dateKey = date('Y-m-d', $ot);
+                $resultEmpty[$dateKey] = [
+                    0 => $header
+                ];
+            }
+            return $resultEmpty;
+        }
+
+        // 按时间+地区聚合同一天、同地区的非退货配送费(用于 calculate 逻辑)
+        $time_amount = [];
+        foreach ($fee as $value) {
+            if ($value['business_type_id'] == FreightFee::businessTypeNormal) {
+                $key = $value['order_time'] . $value['area_hs'];
+                $time_amount[$key]['amount'] = isset($time_amount[$key]['amount'])
+                    ? bcadd($value['freight_amount'], $time_amount[$key]['amount'], 4)
+                    : $value['freight_amount'];
+                $time_amount[$key]['is_use'] = $time_amount[$key]['is_use'] ?? 0;
+            }
+        }
+
+        // 先按 order_time -> business_type_id -> (order_time|area_hs) 分组收集数据行
+        $grouped = [];
+        foreach ($fee as $value) {
+            $value = $this->calculateFreightFeeRow($value, $time_amount);
+            $key = $value['order_time'] . '|' . $value['area_hs'];
+            $grouped[$value['order_time']][$value['business_type_id']][$key][] = $value;
+        }
+
+        // 构造返回:每个日期一个 sheet(键为 YYYY-MM-DD),值为数值下标数组,0 为表头
+        $result = [];
+
+        // 需要合计的字段及小数位
+        $sumFields = ['xs','weight', 'freight_amount', 'js_amount', 'customer_store_zx_fee', 'jj_fee', 'dh_fee', 'total_amount'];
+        $sumFields_map = ['xs' => 0,'weight' => 4, 'freight_amount' => 4, 'js_amount' => 4, 'customer_store_zx_fee' => 4, 'jj_fee' => 4, 'dh_fee' => 4, 'total_amount' => 4];
+
+        // 初始化每个传入日期,确保即使某个日期无数据也有表头
+        foreach ($orderTimes as $ot) {
+            $dateKey = date('Y-m-d', $ot);
+            $result[$dateKey] = [];
+            $result[$dateKey][] = $header; // index 0 为表头
+        }
+
+        // 填充数据
+        foreach ($grouped as $order_time => $types) {
+            $dateKey = date('Y-m-d', $order_time);
+            // 若该日期未初始化(理论上不会),先初始化表头
+            if (!isset($result[$dateKey])) {
+                $result[$dateKey] = [];
+                $result[$dateKey][] = $header;
+            }
+
+            foreach ($types as $business_type_id => $group) {
+                $businessTitle = FreightFee::$business[$business_type_id] ?? '';
+                foreach ($group as $key => $rows) {
+                    // 每个 key 对应一组明细(按 area_hs 分组)
+                    $sumRow = []; // 用于该分组的合计
+
+                    foreach ($rows as $row) {
+                        $date_show = $row['order_time'] ? date('Y-m-d', $row['order_time']) : "";
+                        $is_present_show = !empty($row['is_present']) ? '是' : '否';
+                        $delivery_mode_show = FreightFee::$delivery[$row['delivery_mode']] ?? "";
+                        $area_range_show = isset($row['area_range']) && $row['area_range'] == 1 ? '1~5吨' : '5吨以上';
+
+                        // 单行数据(按你指定的字段顺序)
+                        $line = [
+                            $row['warehouse_name'] ?? '', // 仓库
+                            $row['mark'] ?? '', // 销货单备注
+                            $row['business_type_title'] ?? '', // 业务类型
+                            $row['order_number'] ?? '', // 销货单号
+                            $date_show, // 销货日期
+                            $row['customer_title'] ?? '', // 客户
+                            $row['customer_store_price'] ?? 0, // 客户门店装车费单价
+                            $row['employee_id_1_title'] ?? '', // 业务员
+                            $row['address'] ?? '', // 送货地址
+                            $row['area_hs'] ?? '', // 地区华商
+                            $row['product_code'] ?? '', // 存货编码
+                            $row['product_title'] ?? '', // 存货名称
+                            $row['product_box_size'] ?? '', // 箱规
+                            $row['product_weight'] ?? 0, // 华商重量
+                            $row['product_store_price'] ?? 0, // 门店卸货费单价(华商)
+                            $row['product_store_price2'] ?? 0, // 到货装卸费单价(华商)
+                            $is_present_show, // 赠品
+                            $row['product_category'] ?? '', // 货类(华商)
+                            $delivery_mode_show, // 运输方式
+                            $row['quantity'] ?? 0, // 数量
+                            $row['price_3'] ?? 0, // 含税单价
+                            $row['price_3_total'] ?? 0, // 含税金额
+                            number_format($row['xs'] ?? 0), // 箱数
+                            $row['weight'] ?? 0, // 总重量
+                            $area_range_show, // 运价区间
+                            $row['freight_unit_price'] ?? 0, // 配送费单价
+                            $row['freight_amount'] ?? 0, // 配送费金额
+                            $row['js_amount'] ?? 0, // 结算金额
+                            $row['customer_store_zx_fee'] ?? 0, // 门店卸货费
+                            $row['sl_fee'] ?? 0, // 上楼费
+                            number_format($row['jj_fee'] ?? 0, 2), // 加急费
+                            $row['dh_fee'] ?? 0, // 到货装卸费
+                            $row['total_amount'] ?? 0, // 总金额
+                        ];
+
+                        $result[$dateKey][] = $line;
+
+                        // 累加合计
+                        foreach ($sumFields as $field) {
+                            $decimals = $sumFields_map[$field] ?? 2;
+                            $sumRow[$field] = isset($sumRow[$field])
+                                ? bcadd($sumRow[$field], $row[$field], $decimals)
+                                : ($row[$field] ?? 0);
+                        }
+                    }
+
+                    // 添加本分组合计行(合计位置与表头列对齐,其它非合计字段留空)
+                    $totalLine = [
+                        '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
+                        $sumRow['xs'] ?? 0,
+                        $sumRow['weight'] ?? 0,
+                        '', '',
+                        $sumRow['freight_amount'] ?? 0, // 配送费金额合计
+                        $sumRow['js_amount'] ?? 0, // 结算金额合计
+                        $sumRow['customer_store_zx_fee'] ?? 0, // 门店卸货费合计
+                        $sumRow['sl_fee'] ?? 0, // 上楼费合计
+                        $sumRow['jj_fee'] ?? 0, // 加急费合计
+                        $sumRow['dh_fee'] ?? 0, // 到货装卸费合计
+                        $sumRow['total_amount'] ?? 0, // 总金额合计
+                    ];
+
+                    $result[$dateKey][] = $totalLine;
+                }
+            }
+        }
+
+        // 确保每个日期的数组是从 0 开始的连续下标(虽然我们已经按顺序 push,但为了保险)
+
+        return $result;
+    }
+
     protected function calculateFreightFeeRow(array $value, array &$time_amount)
     {
         $key = $value['order_time'] . $value['area_hs'];