Alexander Musikhin vor 10 Monaten
Ursprung
Commit
4f6afb972e

+ 34 - 0
app/Console/Commands/ExportMaf.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Services\ExportService;
+use Exception;
+use Illuminate\Console\Command;
+
+class ExportMaf extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'app:export-maf';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Экспорт каталога МАФ';
+
+    /**
+     * Execute the console command.
+     * @throws Exception
+     */
+    public function handle(): void
+    {
+        // run service command
+        $this->info((new ExportService)->handle());
+    }
+}

+ 10 - 1
app/Http/Controllers/ProductController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers;
 
 use App\Helpers\DateHelper;
+use App\Jobs\Export\ExportCatalog;
 use App\Jobs\Import\ImportCatalog;
 use App\Models\Product;
 use Illuminate\Http\RedirectResponse;
@@ -186,9 +187,17 @@ class ProductController extends Controller
 
     public function export(Request $request)
     {
+        $request->validate([
+            'withFilter' => 'nullable',
+        ]);
 
+        // load and save file
 
+        // dispatch job
+        ExportCatalog::dispatch([], $request->user()->id);
+        Log::info('ImportCatalog job created!');
 
-        return redirect()->route('catalog.index')->with(['success' => 'Задача импорта успешно создана!']);
+
+        return redirect()->route('catalog.index')->with(['success' => 'Задача экспорта успешно создана!']);
     }
 }

+ 2 - 2
app/Jobs/Export/ExportCatalog.php

@@ -16,7 +16,7 @@ class ExportCatalog implements ShouldQueue
     /**
      * Create a new job instance.
      */
-    public function __construct(private readonly int $userId)
+    public function __construct(private readonly array $filters, private readonly int $userId)
     {
         // can add where clauses
     }
@@ -27,7 +27,7 @@ class ExportCatalog implements ShouldQueue
     public function handle(): void
     {
         try {
-            $file = (new ExportService())->handle();
+            $file = (new ExportService())->handle($this->filters);
             Log::info('ExportCatalog job done!');
             event(new SendWebSocketMessageEvent('Экспорт завершён!', $this->userId, ['download' => $file]));
         } catch (Exception $e) {

+ 36 - 3
app/Services/ExportService.php

@@ -3,19 +3,52 @@
 namespace App\Services;
 
 use App\Models\Product;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 
 class ExportService
 {
 
 
-    public function handle(): string
+    public function handle(array $filters = []): string
     {
         $products = Product::cursor();
+        $inputFileType = 'Xlsx'; // Xlsx - Xml - Ods - Slk - Gnumeric - Csv
+        $inputFileName = './templates/ExportCatalogTemplate.xlsx';
+
+        $reader = IOFactory::createReader($inputFileType);
+        $spreadsheet = $reader->load($inputFileName);
+        $sheet = $spreadsheet->getActiveSheet();
+
+        $i = 2;
+        $sum_format = '#,##0.00\ "₽";[Red]\-#,##0.00\ "₽"';
 
         foreach ($products as $product) {
-            dump($product->id);
+            $sheet->setCellValue('B' . $i, $product->name_tz);
+            $sheet->setCellValue('C' . $i, $product->type_tz);
+            $sheet->setCellValue('D' . $i, $product->nomenclature_number);
+            $sheet->setCellValue('E' . $i, $product->sizes);
+            $sheet->setCellValue('F' . $i, $product->manufacturer);
+            $sheet->setCellValue('G' . $i, $product->unit);
+            $sheet->setCellValue('H' . $i, $product->type);
+            $sheet->setCellValue('I' . $i, $product->price_status);
+            $sheet->setCellValue('J' . $i, $product->product_price);
+            $sheet->setCellValue('K' . $i, $product->installation_price);
+            $sheet->setCellValue('L' . $i, $product->service_price);
+            $sheet->setCellValue('M' . $i, $product->total_price);
+            $sheet->setCellValue('N' . $i, $product->manufacturer_name);
+            $sheet->setCellValue('O' . $i, $product->article);
+            $sheet->setCellValue('P' . $i, $product->note);
+
+            $sheet->getStyle("J{$i}:M{$i}")->getNumberFormat()->setFormatCode($sum_format);
+
+            $i++;
         }
 
-        return 'path';
+        $fileName = 'product_export_' . date('Y-m-d_H-i-s') . '.xlsx';
+        $writer = new Xlsx($spreadsheet);
+        $writer->save(storage_path('app/public/export') . '/' . $fileName);
+
+        return $fileName;
     }
 }

+ 3 - 0
resources/js/custom.js

@@ -19,6 +19,9 @@ $(document).ready(function () {
             if (parseInt(received.data.user_id) === parseInt(user)) {
                 console.log(received);
                 console.log(`[WS] Received data action: ${received.data.action}. Message: ${received.data.message}`);
+                if(received.data.payload.download) {
+                   document.location.href = '/storage/export/' + received.data.payload.download;
+                }
                 setTimeout(function () {
                         if (received.data.payload.error) {
                             $('.alerts').append('<div class="main-alert2 alert alert-danger" role="alert">' + received.data.message + '</div>');

+ 23 - 0
resources/views/catalog/index.blade.php

@@ -10,6 +10,10 @@
             <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#importModal">
                 Импорт
             </button>
+            <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exportModal">
+                Экспорт
+            </button>
+
         </div>
     </div>
 
@@ -47,6 +51,25 @@
         </div>
     </div>
 
+    <!-- Модальное окно импорта-->
+    <div class="modal fade" id="exportModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
+        <div class="modal-dialog modal-fullscreen-sm-down modal-lg">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h1 class="modal-title fs-5" id="exampleModalLabel">Экспорт</h1>
+                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
+                </div>
+                <div class="modal-body">
+                    <form action="{{ route('catalog.export') }}" method="post" enctype="multipart/form-data">
+                        @csrf
+                        @include('partials.checkbox', ['title' => 'С учётом текущего фильтра и поиска', 'name' => 'withFilter', 'type' => 'checkbox', 'value' => 'yes', 'checked' => false])
+                        @include('partials.submit', ['name' => 'Экспорт'])
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+
     @if($errors->count())
         @dump($errors)
     @endif

+ 1 - 0
routes/web.php

@@ -35,6 +35,7 @@ Route::middleware('auth:web')->group(function () {
     Route::get('catalog', [ProductController::class, 'index'])->name('catalog.index');
     Route::get('catalog/{product}', [ProductController::class, 'show'])->name('catalog.show');
     Route::post('catalog/import', [ProductController::class, 'import'])->name('catalog.import');
+    Route::post('catalog/export', [ProductController::class, 'export'])->name('catalog.export');
 
 
 

BIN
templates/ExportCatalogTemplate.xlsx


+ 2 - 2
todo.md

@@ -2,8 +2,8 @@
 - [x] управление пользователями (CRUD)
 - [x] каталог товаров
 - [x] настраиваемые таблицы
-- [ ] каталог товаров: +фильтры, поиск, +сортировка
-- [ ] каталог товаров: экспорт
+- [x] каталог товаров: фильтры, поиск, сортировка
+- [x] каталог товаров: экспорт
 - [x] каталог товаров: импорт
 - [ ] складские остатки товаров
 - [ ] заказы (площадки) (сюда же входят клиенты, если нужна отдельная сущность)