This commit is contained in:
2023-02-03 13:11:10 +08:00
parent 4a6d2f08e8
commit e379da02c7

View File

@@ -0,0 +1,288 @@
<?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];
}
}