浏览代码

update exporter

jqh 5 年之前
父节点
当前提交
2f64f0eb74

+ 6 - 6
src/Grid.php

@@ -161,17 +161,17 @@ class Grid
         'show_bordered'          => false,
         'show_toolbar'           => true,
 
-        'row_selector_style'      => 'primary',
-        'row_selector_circle'     => true,
-        'row_selector_clicktr'    => false,
+        'row_selector_style'     => 'primary',
+        'row_selector_circle'    => true,
+        'row_selector_clicktr'   => false,
         'row_selector_label_key' => null,
-        'row_selector_bg'         => 'var(--20)',
+        'row_selector_bg'        => 'var(--20)',
 
         'show_exporter'             => false,
         'show_export_all'           => true,
         'show_export_current_page'  => true,
         'show_export_selected_rows' => true,
-        'export_limit'              => 50000,
+        'export_chunk_size'         => 5000,
 
         'dialog_form_area'   => ['700px', '670px'],
         'table_header_style' => 'table-header-gray',
@@ -895,7 +895,7 @@ HTML;
      */
     public function render()
     {
-        $this->handleExportRequest(true);
+        $this->handleExportRequest();
 
         try {
             $this->callComposing();

+ 14 - 19
src/Grid/Concerns/HasExporter.php

@@ -44,27 +44,22 @@ trait HasExporter
      */
     protected function handleExportRequest($forceExport = false)
     {
-        if (
-            ! $this->allowExportBtn()
-            || ! $scope = request($this->getExporter()->getQueryName())
-        ) {
+        if (! $scope = request($this->getExporter()->getQueryName())) {
             return;
         }
 
-        // clear output buffer.
-        if (ob_get_length()) {
-            ob_end_clean();
-        }
-
-        $this->model()->usePaginate(false);
-
         if ($this->builder) {
             call_user_func($this->builder, $this);
 
-            return $this->resolveExportDriver($scope)->export();
+            $this->builder = null;
+        }
+
+        // clear output buffer.
+        if (ob_get_length()) {
+            ob_end_clean();
         }
 
-        if ($forceExport) {
+        if ($forceExport || $this->allowExporter()) {
             return $this->resolveExportDriver($scope)->export();
         }
     }
@@ -82,7 +77,7 @@ trait HasExporter
      */
     protected function setExporterQueryName($gridName)
     {
-        if (! $this->allowExportBtn()) {
+        if (! $this->allowExporter()) {
             return;
         }
 
@@ -123,10 +118,10 @@ trait HasExporter
      * @param array $options
      * @return $this
      */
-    public function setExportOptions(array $options)
+    public function setExporterOptions(array $options)
     {
-        if (isset($options['limit'])) {
-            $this->options['export_limit'] = $options['limit'];
+        if (isset($options['chunk_size'])) {
+            $this->options['export_chunk_size'] = (int) $options['chunk_size'];
         }
 
         if (isset($options['all'])) {
@@ -151,7 +146,7 @@ trait HasExporter
      */
     public function renderExportButton()
     {
-        if (! $this->allowExportBtn()) {
+        if (! $this->allowExporter()) {
             return '';
         }
         
@@ -183,7 +178,7 @@ trait HasExporter
      *
      * @return bool
      */
-    public function allowExportBtn()
+    public function allowExporter()
     {
         return $this->options['show_exporter'];
     }

+ 1 - 1
src/Grid/Concerns/HasTools.php

@@ -174,7 +174,7 @@ trait HasTools
             $this->option('show_toolbar')
             && (
                 $this->getTools()->has() ||
-                $this->allowExportBtn() ||
+                $this->allowExporter() ||
                 $this->allowCreateBtn() ||
                 $this->allowQuickCreateBtn() ||
                 $this->allowResponsive() ||

+ 3 - 3
src/Grid/Exporter.php

@@ -99,7 +99,7 @@ class Exporter
      *
      * @param string $driver
      *
-     * @return CsvExporter
+     * @return Grid\Exporters\AbstractExporter
      */
     protected function getExporter($driver)
     {
@@ -113,11 +113,11 @@ class Exporter
     /**
      * Get default exporter.
      *
-     * @return CsvExporter
+     * @return Grid\Exporters\AbstractExporter
      */
     public function getDefaultExporter()
     {
-        return (new CsvExporter())->setGrid($this->grid);
+        return (new Grid\Exporters\XlsxExporter())->setGrid($this->grid);
     }
 
     /**

+ 29 - 19
src/Grid/Exporters/AbstractExporter.php

@@ -20,7 +20,7 @@ abstract class AbstractExporter implements ExporterInterface
     /**
      * @var array
      */
-    public $titles;
+    public $titles = [];
 
     /**
      * @var array
@@ -32,6 +32,11 @@ abstract class AbstractExporter implements ExporterInterface
      */
     public $filename;
 
+    /**
+     * @var string
+     */
+    protected $scope;
+
     /**
      * Create a new exporter instance.
      *
@@ -74,10 +79,25 @@ abstract class AbstractExporter implements ExporterInterface
     /**
      * Get data with export query.
      *
-     * @return array
+     * @param int $page
+     * @param int $perPage
+     * @return array|\Illuminate\Support\Collection|mixed
      */
-    public function getData()
+    public function buildData(?int $page = null, ?int $perPage = null)
     {
+        $model = $this->grid->model();
+
+        $model->usePaginate(false);
+        $model->reset();
+
+        if ($this->scope !== Grid\Exporter::SCOPE_SELECTED_ROWS) {
+            if ($page) {
+                $perPage = $perPage ?: $this->grid->option('export_chunk_size');
+
+                $model->forPage($page, $perPage);
+            }
+        }
+
         return $this->data ?? $this->grid->getFilter()->execute(true);
     }
 
@@ -90,27 +110,17 @@ abstract class AbstractExporter implements ExporterInterface
      */
     public function withScope($scope)
     {
-        $model = $this->grid->model();
+        $data = explode(':', $scope);
 
-        $model->usePaginate(false);
+        $scope = $data[0] ?? '';
+        $args  = $data[1] ?? '';
 
-        if ($scope == Grid\Exporter::SCOPE_ALL) {
-            $model->usePaginate(true);
-            $model->setPerPage($this->grid->option('export_limit'));
-            $model->setCurrentPage(1);
-
-            return $this;
-        }
-
-        list($scope, $args) = explode(':', $scope);
-
-        if ($scope == Grid\Exporter::SCOPE_CURRENT_PAGE) {
-            $model->usePaginate(true);
-        }
+        $this->scope = $scope;
 
         if ($scope == Grid\Exporter::SCOPE_SELECTED_ROWS) {
             $selected = explode(',', $args);
-            $model->whereIn($this->grid->getKeyName(), $selected);
+
+            $this->grid->model()->whereIn($this->grid->getKeyName(), $selected);
         }
 
         return $this;

+ 20 - 73
src/Grid/Exporters/CsvExporter.php

@@ -2,93 +2,40 @@
 
 namespace Dcat\Admin\Grid\Exporters;
 
-use Illuminate\Contracts\Support\Arrayable;
-use Illuminate\Support\Arr;
-use Illuminate\Support\Str;
+use Dcat\EasyExcel\Excel;
+use Dcat\Admin\Grid;
 
 class CsvExporter extends AbstractExporter
 {
+    /**
+     * @var string
+     */
+    protected $extension = 'csv';
+
     /**
      * {@inheritdoc}
      */
     public function export()
     {
-        $filename = $this->getFilename().'.csv';
-
-        $headers = [
-            'Content-Encoding'    => 'UTF-8',
-            'Content-Type'        => 'text/csv;charset=UTF-8',
-            'Content-Disposition' => "attachment; filename=\"$filename\"",
-        ];
-
-        response()->stream(function () {
-            $handle = fopen('php://output', 'w');
-
-            $titles = $this->titles;
-
-            if ($titles) {
-                // Add CSV headers
-                fputcsv($handle, $titles);
-            }
-
-            $records = $this->getData();
-
-            if ($this->builder) {
-                $records = $this->builder->call($records);
-            }
+        if (! class_exists(Excel::class)) {
+            throw new \Exception('To use exporter, please install [dcat/easy-excel] first.');
+        }
 
-            if (empty($titles)) {
-                $titles = $this->getHeaderRowFromRecords($records);
+        $filename = $this->getFilename().'.'.$this->extension;
 
-                // Add CSV headers
-                fputcsv($handle, $titles);
-            }
+        $exporter = Excel::export();
 
-            foreach ($records as $record) {
-                fputcsv($handle, $this->getFormattedRecord($titles, $record));
-            }
+        if ($this->scope === Grid\Exporter::SCOPE_ALL) {
+            $exporter->chunk(function (int $times) {
+                return $this->buildData($times);
+            });
+        } else {
+            $exporter->data($this->buildData());
+        }
 
-            // Close the output stream
-            fclose($handle);
-        }, 200, $headers)->send();
+        $exporter->headings($this->titles)->download($filename);
 
         exit;
     }
 
-    /**
-     * @param array $records
-     *
-     * @return array
-     */
-    public function getHeaderRowFromRecords(array $records): array
-    {
-        $titles = [];
-
-        collect(Arr::dot($records[0] ?? []))->keys()->map(
-            function ($key) use(&$titles) {
-                if (Str::contains($key, '.')) return;
-
-                $titles[$key] = Str::ucfirst($key);
-            }
-        );
-
-        return $titles;
-    }
-
-    /**
-     * @param $titles
-     * @param $record
-     * @return array
-     */
-    public function getFormattedRecord($titles, $record)
-    {
-        $result = [];
-
-        $record = Arr::dot($record);
-        foreach ($titles as $k => $label) {
-            $result[] = $record[$k] ?? '';
-        }
-
-        return $result;
-    }
 }

+ 11 - 0
src/Grid/Exporters/XlsxExporter.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace Dcat\Admin\Grid\Exporters;
+
+class XlsxExporter extends CsvExporter
+{
+    /**
+     * @var string
+     */
+    protected $extension = 'xlsx';
+}

+ 16 - 1
src/Grid/Model.php

@@ -429,7 +429,11 @@ class Model
      */
     protected function handleInvalidPage(LengthAwarePaginator $paginator)
     {
-        if ($paginator->lastPage() && $paginator->currentPage() > $paginator->lastPage()) {
+        if (
+            $this->usePaginate
+            && $paginator->lastPage()
+            && $paginator->currentPage() > $paginator->lastPage()
+        ) {
             $lastPageUrl = Request::fullUrlWithQuery([
                 $paginator->getPageName() => $paginator->lastPage(),
             ]);
@@ -686,4 +690,15 @@ class Model
             return $data[$key];
         }
     }
+
+    /**
+     * @return $this
+     */
+    public function reset()
+    {
+        $this->data  = null;
+        $this->model = null;
+
+        return $this;
+    }
 }

+ 3 - 7
src/Repositories/Proxy.php

@@ -13,8 +13,8 @@ class Proxy implements \Dcat\Admin\Contracts\Repository
     protected $__listeners = [];
 
     protected $__caches = [
-        'edit' => [],
-        'detail' => [],
+        'edit'     => [],
+        'detail'   => [],
         'updating' => [],
     ];
 
@@ -52,11 +52,7 @@ class Proxy implements \Dcat\Admin\Contracts\Repository
 
     public function get(Grid\Model $model)
     {
-        if (array_key_exists('get', $this->__caches)) {
-            return $this->__caches['get'];
-        }
-
-        return $this->__caches['get'] = $this->repository->get($model);
+        return $this->repository->get($model);
     }
 
     public function edit(Form $form): array