288 lines
8.7 KiB
PHP
288 lines
8.7 KiB
PHP
<?php
|
||
|
||
namespace App\Admin\Exporters;
|
||
|
||
use Encore\Admin\Grid\Exporters\ExcelExporter;
|
||
|
||
class NewCouponExport extends ExcelExporter
|
||
{
|
||
protected $fileName = null;
|
||
protected $debug = false;
|
||
protected $dealColumnList = [];
|
||
protected $columnCallback = null;
|
||
protected $addColumnList = [];
|
||
protected $appendColumn = [];
|
||
protected $perLimit = 1500;
|
||
|
||
/**
|
||
* 导出
|
||
*
|
||
* @return mixed|void
|
||
*/
|
||
public function export()
|
||
{
|
||
$model = $this;
|
||
$grid = $this->grid;
|
||
$columns = $this->getColumns();
|
||
$columns = $this->addingColumn($columns);
|
||
|
||
$call_back = function ($page, $limit) use ($model, $grid, $columns) {
|
||
$model->page = $page;
|
||
$grid->paginate($limit);
|
||
$model->setGrid($grid);
|
||
request()->offsetSet('per_page', $limit);
|
||
|
||
$list = $model->getQuery()->get()->toArray();
|
||
$list = $this->dealColumn($columns, $list);
|
||
if ($this->columnCallback) {
|
||
$list = call_user_func($this->columnCallback, $columns, $list);
|
||
}
|
||
return $list;
|
||
};
|
||
if ($this->debug) {
|
||
dd($columns, call_user_func($call_back, 1, 20));
|
||
}
|
||
$file_name = $this->fileName ? $this->fileName : $this->getTable().date('YmdHis');
|
||
$data_count = $this->getQuery()->count();
|
||
$perPage = request()->get('per_page', $this->perLimit);
|
||
$this->exportCsv($file_name, $columns, $call_back, $data_count, $perPage);
|
||
|
||
}
|
||
|
||
/**
|
||
* 设置文件名
|
||
*
|
||
* @param null $file_name
|
||
*/
|
||
public function setName($file_name = null)
|
||
{
|
||
if ($file_name) {
|
||
$this->fileName = $file_name;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Notes: 设置处理字段值的规则
|
||
*
|
||
* @Author: 玄尘
|
||
* @Date: 2023/2/1 15:42
|
||
* @param $column
|
||
* @param \Closure $call_back
|
||
*/
|
||
public function setColumn($column, \Closure $call_back)
|
||
{
|
||
$this->dealColumnList[$column] = $call_back;
|
||
}
|
||
|
||
/**
|
||
* 添加字段
|
||
*
|
||
* @param $column
|
||
* @param $name
|
||
* @param null|string|\Closure $after_column
|
||
* @param null|\Closure $call_back
|
||
*/
|
||
public function addColumn($column, $name, $after_column = null, $call_back = null)
|
||
{
|
||
if ($after_column instanceof \Closure) {
|
||
$this->addColumnList[$column] = $after_column;
|
||
$this->appendColumn[$column] = [$name, null];
|
||
} else {
|
||
if ($call_back instanceof \Closure) {
|
||
$this->addColumnList[$column] = $call_back;
|
||
$this->appendColumn[$column] = [$name, $after_column];
|
||
} else {
|
||
$this->appendColumn[$column] = [$name, $after_column];
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* 正式追加字段
|
||
*
|
||
* @param $columns
|
||
* @return array
|
||
*/
|
||
protected function addingColumn($columns): array
|
||
{
|
||
if (! $this->appendColumn) {
|
||
return $columns;
|
||
}
|
||
$keys = array_keys($columns);
|
||
foreach ($this->appendColumn as $column => $item) {
|
||
list ($name, $after_column) = $item;
|
||
if (! empty($after_column) && in_array($after_column, $keys)) {
|
||
$index = array_search($after_column, $keys);
|
||
array_splice($keys, $index + 1, 0, $column);
|
||
} else {
|
||
array_push($keys, $column);
|
||
}
|
||
$columns[$column] = $name;
|
||
}
|
||
$result = [];
|
||
foreach ($keys as $column) {
|
||
$result[$column] = $columns[$column] ?? $column;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* 字段值重新处理 回调函数
|
||
*
|
||
* @param \Closure $call_back
|
||
*/
|
||
public function setList(\Closure $call_back)
|
||
{
|
||
$this->columnCallback = $call_back;
|
||
}
|
||
|
||
/**
|
||
* 处理有共同特征的字段值
|
||
*
|
||
* @param $columns
|
||
* @param $list
|
||
* @return mixed
|
||
*/
|
||
protected function dealColumn($columns, $list)
|
||
{
|
||
if (! $list) {
|
||
return $list;
|
||
}
|
||
$deal = array_keys($this->dealColumnList);
|
||
$add = array_keys($this->addColumnList);
|
||
foreach ($list as $index => $data) {
|
||
foreach ($columns as $column => $name) {
|
||
switch ($column) {
|
||
case strpos($column, '.') !== false :
|
||
$keys = explode('.', $column);
|
||
$value = $data;
|
||
for ($i = 0; $i < count($keys); $i++) {
|
||
$value = $value[$keys[$i]] ?? [];
|
||
}
|
||
if (is_array($value)) {
|
||
$value = empty($value) ? '' : json_encode($value, JSON_UNESCAPED_UNICODE);
|
||
}
|
||
$data[$column] = $value;
|
||
break;
|
||
}
|
||
if ($this->dealColumnList && in_array($column, $deal)) {
|
||
$data[$column] = call_user_func_array($this->dealColumnList[$column],
|
||
[$data[$column] ?? '', $data]);
|
||
}
|
||
if ($this->addColumnList && in_array($column, $add)) {
|
||
$data[$column] = call_user_func($this->addColumnList[$column], $data);
|
||
}
|
||
}
|
||
$list[$index] = $data;
|
||
}
|
||
return $list;
|
||
}
|
||
|
||
/**
|
||
* 获取选中的导出字段
|
||
*
|
||
* @return array
|
||
*/
|
||
protected function getColumns(): array
|
||
{
|
||
$columns = [];
|
||
foreach ($this->grid->getColumns() as $column) {
|
||
$columns[$column->getName()] = $column->getLabel();
|
||
}
|
||
$column_string = request()->get('_columns_', '');
|
||
if (! $column_string) {
|
||
return $columns;
|
||
}
|
||
$column_array = explode(',', $column_string);
|
||
$column_list = [];
|
||
foreach ($columns as $column => $name) {
|
||
if (in_array($column, $column_array)) {
|
||
$column_list[$column] = $name;
|
||
}
|
||
}
|
||
return $column_list;
|
||
}
|
||
|
||
/**
|
||
* 打印
|
||
*/
|
||
public function dd()
|
||
{
|
||
$this->debug = true;
|
||
}
|
||
|
||
/**
|
||
* 导出CSV
|
||
*
|
||
* @param string $file_name 文件名
|
||
* @param array $head_list 表头
|
||
* @param int $data_count 总数
|
||
* @param int $page_limit 每页数量
|
||
* @param \Closure $call_back 获取分页数据的回调函数
|
||
*/
|
||
function exportCsv(
|
||
string $file_name,
|
||
array $head_list,
|
||
\Closure $call_back,
|
||
int $data_count,
|
||
int $page_limit = 0
|
||
) {
|
||
set_time_limit(0);
|
||
ini_set('memory_limit', -1);
|
||
header('Content-Type: application/vnd.ms-excel');
|
||
header('Content-Disposition: attachment;filename="'.$file_name.'.csv"');
|
||
header('Cache-Control: max-age=0');
|
||
//打开PHP文件句柄,php://output 表示直接输出到浏览器
|
||
$fp = fopen('php://output', 'a');
|
||
$head = [];
|
||
//输出Excel列名信息
|
||
foreach ($head_list as $name) {
|
||
//CSV的Excel支持GBK编码,一定要转换,否则乱码
|
||
$head[] = iconv('utf-8', 'gbk', $name);
|
||
}
|
||
//将数据通过fputcsv写到文件句柄
|
||
fputcsv($fp, $head);
|
||
$page_limit = $data_count > $page_limit ? $page_limit : $data_count;
|
||
$page_count = ceil($data_count / $page_limit);
|
||
for ($page = 1; $page <= $page_count; $page++) {
|
||
//逐页取出数据,不浪费内存
|
||
$data_list = call_user_func($call_back, $page, $page_limit);
|
||
if (! $data_list) {
|
||
continue;
|
||
}
|
||
foreach ($data_list as $data) {
|
||
$row = [];
|
||
foreach ($head_list as $key => $name) {
|
||
$value = $data[$key] ?? '';
|
||
$row[] = iconv('utf-8', 'gbk', $value);
|
||
}
|
||
|
||
fputcsv($fp, $row);
|
||
unset($row);
|
||
}
|
||
//刷新一下输出buffer,防止由于数据过多内存不足
|
||
ob_flush();
|
||
flush();
|
||
info($page.'/'.$page_count.' time= '.$this->getElapsedTime().' memory= '.$this->getMemoryUsage());
|
||
}
|
||
fclose($fp);
|
||
exit();
|
||
}
|
||
|
||
public function getElapsedTime(int $decimals = 2): string
|
||
{
|
||
return number_format(microtime(true) - request()->server('REQUEST_TIME_FLOAT'), $decimals).' s';
|
||
}
|
||
|
||
public function getMemoryUsage($precision = 2): string
|
||
{
|
||
$size = memory_get_usage(true);
|
||
|
||
$unit = ['b', 'kb', 'mb', 'gb', 'tb', 'pb'];
|
||
|
||
return round($size / pow(1024, ($i = floor(log($size, 1024)))), $precision).' '.$unit[$i];
|
||
}
|
||
|
||
|
||
} |