Pārlūkot izejas kodu

Filter and search MAF order bulk stock modal

Alexander Musikhin 4 dienas atpakaļ
vecāks
revīzija
d0df5829a1

+ 8 - 4
app/Http/Controllers/MafOrderController.php

@@ -52,12 +52,14 @@ class MafOrderController extends Controller
         $this->applyStableSorting($q);
 
         $this->data['maf_orders'] = $q->paginate($this->data['per_page'])->withQueryString();
-        $this->data['order_numbers'] = MafOrder::query()
+        $this->data['orderedOrderNumbers'] = MafOrder::query()
             ->whereNotNull('order_number')
             ->where('order_number', '!=', '')
+            ->where('status', 'заказан')
             ->orderBy('order_number')
             ->distinct()
-            ->pluck('order_number');
+            ->pluck('order_number')
+            ->values();
 
         return view('maf_orders.index', $this->data);
     }
@@ -105,11 +107,13 @@ class MafOrderController extends Controller
         ]);
 
         $orderNumber = trim((string) $validated['bulk_order_number']);
-        $query = MafOrder::query()->where('order_number', $orderNumber);
+        $query = MafOrder::query()
+            ->where('order_number', $orderNumber)
+            ->where('status', 'заказан');
 
         if (!$query->exists()) {
             throw ValidationException::withMessages([
-                'bulk_order_number' => 'Заказ не найден в выбранном году.',
+                'bulk_order_number' => 'Заказ со статусом "Заказан" не найден в выбранном году.',
             ]);
         }
 

+ 143 - 6
resources/views/maf_orders/index.blade.php

@@ -72,12 +72,18 @@
                         </div>
                         <div class="modal-body">
                             <label for="bulk_order_number" class="form-label">Номер заказа</label>
-                            <select class="form-select @error('bulk_order_number') is-invalid @enderror" id="bulk_order_number" name="bulk_order_number" required>
-                                <option value="">Выберите номер заказа</option>
-                                @foreach($order_numbers as $order_number)
-                                    <option value="{{ $order_number }}" @selected(old('bulk_order_number') === $order_number)>{{ $order_number }}</option>
-                                @endforeach
-                            </select>
+                            <div class="position-relative">
+                                <input type="text"
+                                       class="form-control @error('bulk_order_number') is-invalid @enderror"
+                                       id="bulk_order_number"
+                                       name="bulk_order_number"
+                                       value="{{ old('bulk_order_number') }}"
+                                       placeholder="Начните вводить номер заказа"
+                                       autocomplete="off"
+                                       required>
+                                <div class="autocomplete-dropdown autocomplete-dropdown--order" id="bulk_order_number_dropdown"></div>
+                            </div>
+                            <div class="form-text">Доступны только заказы со статусом «Заказан».</div>
                             @error('bulk_order_number')
                             <div class="invalid-feedback d-block">{{ $message }}</div>
                             @enderror
@@ -101,6 +107,137 @@
             $('#sku_form').slideDown();
         });
 
+        waitForJQuery(function () {
+            const $modal = $('#setOrderInStockModal');
+            const $input = $modal.find('#bulk_order_number');
+            const $dropdown = $modal.find('#bulk_order_number_dropdown');
+            const orderNumbers = @json(($orderedOrderNumbers ?? collect())->values());
+            let currentFocus = -1;
+
+            function escapeHtml(text) {
+                return String(text)
+                    .replace(/&/g, '&amp;')
+                    .replace(/</g, '&lt;')
+                    .replace(/>/g, '&gt;')
+                    .replace(/"/g, '&quot;')
+                    .replace(/'/g, '&#039;');
+            }
+
+            function escapeRegex(str) {
+                return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+            }
+
+            function highlightMatch(text, query) {
+                if (!text || !query) {
+                    return escapeHtml(text || '');
+                }
+
+                const safeText = escapeHtml(text);
+                const regex = new RegExp('(' + escapeRegex(query) + ')', 'gi');
+                return safeText.replace(regex, '<strong>$1</strong>');
+            }
+
+            function hideDropdown() {
+                $dropdown.hide();
+                currentFocus = -1;
+            }
+
+            function showDropdown(items, query) {
+                $dropdown.empty();
+                currentFocus = -1;
+
+                if (!items.length) {
+                    $dropdown.html('<div class="autocomplete-item text-muted">Ничего не найдено</div>');
+                    $dropdown.show();
+                    return;
+                }
+
+                items.forEach(function (item) {
+                    $dropdown.append(
+                        '<div class="autocomplete-item" data-value="' + escapeHtml(item) + '">' +
+                        '<div class="article">' + highlightMatch(item, query) + '</div>' +
+                        '</div>'
+                    );
+                });
+
+                $dropdown.show();
+            }
+
+            function selectValue(value) {
+                $input.val(value).removeClass('is-invalid');
+                hideDropdown();
+            }
+
+            function setActive($items) {
+                $items.removeClass('active');
+                if (currentFocus >= 0 && currentFocus < $items.length) {
+                    const $active = $items.eq(currentFocus);
+                    $active.addClass('active');
+                    $active[0].scrollIntoView({block: 'nearest'});
+                }
+            }
+
+            function searchOrderNumbers(query) {
+                const normalized = String(query || '').trim().toLowerCase();
+
+                if (normalized.length < 1) {
+                    showDropdown(orderNumbers.slice(0, 50), '');
+                    return;
+                }
+
+                const filtered = orderNumbers.filter(function (item) {
+                    return String(item).toLowerCase().includes(normalized);
+                });
+
+                showDropdown(filtered.slice(0, 50), normalized);
+            }
+
+            $input.on('input focus', function () {
+                searchOrderNumbers($(this).val());
+            });
+
+            $input.on('keydown', function (e) {
+                const $items = $dropdown.find('.autocomplete-item:not(.text-muted)');
+
+                if (e.key === 'ArrowDown') {
+                    e.preventDefault();
+                    currentFocus++;
+                    if (currentFocus >= $items.length) {
+                        currentFocus = 0;
+                    }
+                    setActive($items);
+                } else if (e.key === 'ArrowUp') {
+                    e.preventDefault();
+                    currentFocus--;
+                    if (currentFocus < 0) {
+                        currentFocus = $items.length - 1;
+                    }
+                    setActive($items);
+                } else if (e.key === 'Enter') {
+                    if ($items.length > 0 && currentFocus > -1) {
+                        e.preventDefault();
+                        selectValue(String($items.eq(currentFocus).data('value') || ''));
+                    }
+                } else if (e.key === 'Escape') {
+                    hideDropdown();
+                }
+            });
+
+            $dropdown.on('click', '.autocomplete-item:not(.text-muted)', function () {
+                selectValue(String($(this).data('value') || ''));
+            });
+
+            $(document).on('click', function (e) {
+                if (!$(e.target).closest('#bulk_order_number, #bulk_order_number_dropdown').length) {
+                    hideDropdown();
+                }
+            });
+
+            $modal.on('hidden.bs.modal', function () {
+                hideDropdown();
+            });
+        });
+
         @if($errors->has('bulk_order_number') && hasRole('admin,assistant_head'))
             const setOrderInStockModalElement = document.getElementById('setOrderInStockModal');
             if (setOrderInStockModalElement) {