Bläddra i källkod

Fix spare parts catalog filters and sorting

Alexander Musikhin 3 dagar sedan
förälder
incheckning
766148be55

+ 24 - 0
app/Http/Controllers/Controller.php

@@ -213,6 +213,30 @@ class Controller extends BaseController
                     continue;
                 }
 
+                if (($this->data['id'] ?? null) === 'spare_parts' && $filterName === 'pricing_codes_list') {
+                    $values = explode('||', $filterValue);
+                    $nonEmptyValues = array_values(array_filter($values, static fn ($value) => $value !== '-пусто-'));
+                    $includeEmpty = in_array('-пусто-', $values, true);
+
+                    $query->where(function (Builder $q) use ($nonEmptyValues, $includeEmpty) {
+                        if (!empty($nonEmptyValues)) {
+                            $q->whereHas('pricingCodes', function (Builder $pricingCodesQuery) use ($nonEmptyValues) {
+                                $pricingCodesQuery->whereIn('code', $nonEmptyValues);
+                            });
+                        }
+
+                        if ($includeEmpty) {
+                            if (!empty($nonEmptyValues)) {
+                                $q->orWhereDoesntHave('pricingCodes');
+                            } else {
+                                $q->whereDoesntHave('pricingCodes');
+                            }
+                        }
+                    });
+
+                    continue;
+                }
+
                 // Резолвим виртуальные столбцы и значения
                 [$dbColumn, $dbValue] = $this->resolveFilterColumn($filterName, $filterValue);
 

+ 22 - 1
app/Http/Controllers/FilterController.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers;
 
+use App\Models\SparePartsView;
 use App\Http\Requests\FilterRequest;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Schema;
@@ -110,6 +111,26 @@ class FilterController extends Controller
         }
         $gp = session('gp_' . $table);
 
+        if ($table === 'spare_parts' && $column === 'pricing_codes_list') {
+            $result = DB::table('pricing_codes as pc')
+                ->join('spare_part_pricing_code as sppc', 'sppc.pricing_code_id', '=', 'pc.id')
+                ->select('pc.code')
+                ->distinct()
+                ->orderBy('pc.code')
+                ->pluck('pc.code')
+                ->toArray();
+
+            $hasEmptyValue = SparePartsView::query()
+                ->doesntHave('pricingCodes')
+                ->exists();
+
+            if ($hasEmptyValue) {
+                array_unshift($result, '-пусто-');
+            }
+
+            return response()->json($result, 200, [], JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT);
+        }
+
         $dbTable = self::DB_TABLES[$table];
 
         // Определяем реальный столбец БД
@@ -147,7 +168,7 @@ class FilterController extends Controller
             // Конвертация цен из копеек в рубли для отображения
             if (str_ends_with($dbColumn, '_price')) {
                 $result = array_map(function ($val) {
-                    if ($val === null) {
+                    if ($val === null || $val === '-пусто-') {
                         return $val;
                     }
                     return $val / 100;

+ 31 - 41
app/Http/Controllers/SparePartController.php

@@ -10,6 +10,7 @@ use App\Models\SparePart;
 use App\Models\SparePartsView;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\File;
 use Illuminate\Support\Facades\Log;
@@ -63,13 +64,24 @@ class SparePartController extends Controller
 
         // Фильтры
         $this->createFilters($model, 'used_in_maf');
-
-        // Для range фильтров нужно использовать реальные поля БД (без _txt)
-        // но заголовки брать из header с _txt
-//        $this->createRangeFiltersForPrices($model, 'customer_price', 'expertise_price', 'min_stock');
-//        if (hasRole('admin')) {
-//            $this->createRangeFiltersForPrices($model, 'purchase_price');
-//        }
+        $this->data['filters']['customer_price_txt'] = [
+            'title' => $this->data['header']['customer_price_txt'],
+            'values' => [],
+        ];
+        $this->data['filters']['expertise_price_txt'] = [
+            'title' => $this->data['header']['expertise_price_txt'],
+            'values' => [],
+        ];
+        $this->data['filters']['pricing_codes_list'] = [
+            'title' => $this->data['header']['pricing_codes_list'],
+            'values' => [],
+        ];
+        if (hasRole('admin')) {
+            $this->data['filters']['purchase_price_txt'] = [
+                'title' => $this->data['header']['purchase_price_txt'],
+                'values' => [],
+            ];
+        }
 
         // Запрос
         $q = $model::query()->with('pricingCodes');
@@ -78,7 +90,18 @@ class SparePartController extends Controller
         $this->acceptSearch($q, $request);
 
         $this->setSortAndOrderBy($model, $request);
-        $this->applyStableSorting($q);
+        if ($request->get('sortBy') === 'pricing_codes_list') {
+            $this->data['sortBy'] = 'pricing_codes_list';
+            $q->orderBy(
+                DB::table('spare_part_pricing_code as sppc')
+                    ->join('pricing_codes as pc', 'pc.id', '=', 'sppc.pricing_code_id')
+                    ->selectRaw('MIN(pc.code)')
+                    ->whereColumn('sppc.spare_part_id', 'spare_parts_view.id'),
+                $this->data['orderBy'] ?? 'asc'
+            )->orderBy('id', $this->data['orderBy'] ?? 'asc');
+        } else {
+            $this->applyStableSorting($q);
+        }
 
         $this->data['spare_parts'] = $q->paginate($this->data['per_page'])->withQueryString();
         $this->data['strings'] = $this->data['spare_parts'];
@@ -303,37 +326,4 @@ class SparePartController extends Controller
         return response()->json($spareParts);
     }
 
-    /**
-     * Создание range фильтров для полей с ценами
-     * Использует правильные заголовки из header (_txt версии)
-     */
-    protected function createRangeFiltersForPrices(SparePart $model, string ...$columnNames): void
-    {
-        foreach ($columnNames as $columnName) {
-            // Определяем ключ заголовка
-            $headerKey = str_ends_with($columnName, '_price') ? $columnName . '_txt' : $columnName;
-
-            // Проверяем, есть ли заголовок
-            if (!isset($this->data['header'][$headerKey])) {
-                continue;
-            }
-
-            if (str_ends_with($columnName, '_price')) {
-                $min = $model::query()->min($columnName);
-                $max = $model::query()->max($columnName);
-
-                $this->data['ranges'][$columnName] = [
-                    'title' => $this->data['header'][$headerKey],
-                    'min' => $min ? $min / 100 : 0,
-                    'max' => $max ? $max / 100 : 0,
-                ];
-            } else {
-                $this->data['ranges'][$columnName] = [
-                    'title' => $this->data['header'][$headerKey],
-                    'min' => $model::query()->min($columnName) ?? 0,
-                    'max' => $model::query()->max($columnName) ?? 0,
-                ];
-            }
-        }
-    }
 }

+ 6 - 2
resources/views/partials/table.blade.php

@@ -21,6 +21,10 @@
         <thead class="table-head-shadow">
         <tr>
             @foreach($header as $headerName => $headerTitle)
+                @php
+                    $normalizedHeaderName = str_replace('_txt', '', $headerName);
+                    $isCurrentSortColumn = $headerName === $sortBy || $normalizedHeaderName === $sortBy;
+                @endphp
                 <th scope="col" class="bg-primary-subtle column_{{ $headerName }}">
                     <div class="d-flex align-items-center justify-content-between">
 
@@ -28,7 +32,7 @@
                             {{ $headerTitle }}
                         </div>
                         <div class="text-center mx-1 @if($headerName !== 'actions') cursor-pointer @endif" data-name="{{ $headerName }}">
-                            @if($headerName !== 'actions' && ($headerName== $sortBy))
+                            @if($headerName !== 'actions' && $isCurrentSortColumn)
                                 @if($orderBy === 'asc')
                                     <i class="bi bi-arrow-down-square-fill text-primary"></i>
                                 @else
@@ -68,7 +72,7 @@
                                     bi-funnel
                                 @endif
                                 " id="{{$headerName}}"></i>
-                                @include('partials.newFilterElement', ['id' => $headerName, 'data' => $data, 'type' => $type, 'table' => $id, 'isSort' => $headerName == $sortBy, '$orderBy' => $orderBy])
+                                @include('partials.newFilterElement', ['id' => $headerName, 'data' => $data, 'type' => $type, 'table' => $id, 'isSort' => $isCurrentSortColumn, '$orderBy' => $orderBy])
                             </div>
                         @endif
                     </div>