diff --git a/app/Admin/Exporters/NewCouponExport.php b/app/Admin/Exporters/NewCouponExport.php new file mode 100644 index 0000000..106cd62 --- /dev/null +++ b/app/Admin/Exporters/NewCouponExport.php @@ -0,0 +1,288 @@ +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]; + } + + +} \ No newline at end of file