php
复制代码
public function export()
{
list($page, $limit, $where) = $this->buildTableParames();
if(!$where){
$this->error('搜索条件不能为空');
}
$count = $this->model
->withJoin(['customer','bills'],'left')
->where($where)
->count();
if($count <= 0){
$this->error('没有检测到有效的数据');
}
// 定义转换数组
$bill_statusArr = [0=>'未生成',1=>'已生成'];
// 定义表头
$header = [
['订单日期', 'order_time'],
....
['账单状态', 'bill_status'],
];
// 设置每批处理的数据量
$batchSize = 1000;
// 设置单个Excel文件最大行数3000行数据+1行表头, 避免生成过大的文件
$maxRowsPerFile = 3001;
// 创建一个临时目录来存放生成的Excel文件
$tempDir = runtime_path() . 'export_temp_yswuliumingxi_' . time() . '/';
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$excelFiles = []; // 用于记录生成的所有Excel文件路径
// 初始化当前Excel写入对象
$fileNamePrefix = '物流配送费_应收款明细_';
try {
// 计算总批次数
$totalPages = ceil($count / $batchSize);
$spreadsheet = null;
$writer = null;
$fileIndex = 1;
$rowCounterInCurrentFile = 0;
for ($pageNum = 1; $pageNum <= $totalPages; $pageNum++) {
// 1. 分页查询数据(逻辑不变)
$list = $this->model
->alias('cw_ys_wuliu')
->join('cw_ys_wuliu_bills bills','cw_ys_wuliu.bills_id = bills.id','left')
->where($where)
->order(['cw_ys_wuliu.id'=>'desc'])
->field('cw_ys_wuliu.id,order_time,kb_code,bills.ordersn as bills_ordersn,old_code,good_name,delivery_people,pricetype,cw_ys_wuliu.settlement_style,start_provice,start_city,start_area,cw_ys_wuliu.provice,cw_ys_wuliu.city,cw_ys_wuliu.area,cw_ys_wuliu.good_jian,cw_ys_wuliu.good_volumn,cw_ys_wuliu.good_weight,cw_ys_wuliu.ps_price,cw_ys_wuliu.sh_price,cw_ys_wuliu.other_price,cw_ys_wuliu.total_price,cw_ys_wuliu.service_deduct_price,cw_ys_wuliu.bill_status')
->page($pageNum, $batchSize)
->select()
->each(function($item, $key) use($bill_statusArr){
$item['order_time'] = date('Y-m-d H:i:s', $item['order_time']);
$item['bill_status'] = $bill_statusArr[$item['bill_status']] ?? $item['bill_status'];
return $item;
})->toArray();
// 2. 检查是否需要创建新的Excel对象和文件
if ($spreadsheet === null || $rowCounterInCurrentFile + count($list) > $maxRowsPerFile) {
// 如果已有上一个文件,先保存
if ($writer !== null) {
$currentFilePath = $tempDir . $fileNamePrefix . 'Part' . ($fileIndex-1) . '.xlsx';
$writer->save($currentFilePath);
$excelFiles[] = $currentFilePath;
}
// 创建新的PhpSpreadsheet对象和工作表
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 写入表头
$colIndex = 1;
foreach ($header as $head) {
$sheet->setCellValueByColumnAndRow($colIndex, 1, $head[0]);
$colIndex++;
}
$rowCounterInCurrentFile = 1; // 表头占第1行
$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
$fileIndex++;
}
// 3. 将这一批数据写入当前工作表
foreach ($list as $dataRow) {
$rowCounterInCurrentFile++;
$colIndex = 1;
foreach ($header as $head) {
$fieldName = $head[1];
$cellValue = $dataRow[$fieldName] ?? '';
$sheet->setCellValueByColumnAndRow($colIndex, $rowCounterInCurrentFile, $cellValue);
$colIndex++;
}
}
// 释放本批数据内存
unset($list);
}
// 循环结束后,保存最后一个Excel文件
if ($writer !== null) {
$currentFilePath = $tempDir . $fileNamePrefix . 'Part' . ($fileIndex-1) . '.xlsx';
$writer->save($currentFilePath);
$excelFiles[] = $currentFilePath;
}
// --- 生成ZIP压缩包并提供下载 ---
if (count($excelFiles) === 1) {
// 如果只有一个文件,直接提供下载
$downloadFilePath = $excelFiles[0];
$downloadFileName = $fileNamePrefix . date('YmdHis') . '.xlsx';
} else {
// 如果有多个文件,打包成ZIP
$zipFileName = $fileNamePrefix . '打包_' . date('YmdHis') . '.zip';
$zipFilePath = $tempDir . $zipFileName;
$zip = new \ZipArchive();
if ($zip->open($zipFilePath, \ZipArchive::CREATE) === TRUE) {
foreach ($excelFiles as $file) {
$zip->addFile($file, basename($file));
}
$zip->close();
}
$downloadFilePath = $zipFilePath;
$downloadFileName = $zipFileName;
}
// 输出文件到浏览器
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . urlencode($downloadFileName) . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($downloadFilePath));
readfile($downloadFilePath);
// 清理临时文件(可选)
$this->deleteDir($tempDir);
exit; // 结束执行,避免框架输出额外内容
} catch (\Exception $e) {
// 清理临时文件
if (is_dir($tempDir)) {
$this->deleteDir($tempDir);
}
$this->error('导出过程发生错误:' . $e->getMessage());
}
}
/**
* 辅助函数:删除目录及其下所有文件
*/
private function deleteDir($dirPath) {
if (!is_dir($dirPath)) return;
$files = array_diff(scandir($dirPath), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dirPath/$file")) ? $this->deleteDir("$dirPath/$file") : unlink("$dirPath/$file");
}
return rmdir($dirPath);
}