index.blade.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. @extends('layouts.app')
  2. @section('content')
  3. <div class="row mb-2 page-header-row">
  4. <div class="col-12 col-md-4 page-header-title">
  5. <h3>Заказы МАФ</h3>
  6. </div>
  7. <div class="col-auto col-md-4 text-md-center page-header-year">
  8. @include('partials.year-switcher')
  9. </div>
  10. <div class="col-auto col-md-4 text-md-end page-header-actions">
  11. @if(hasRole('admin,assistant_head'))
  12. <button type="button" class="btn btn-sm btn-outline-primary page-action-btn" data-bs-toggle="modal" data-bs-target="#setOrderInStockModal" aria-label="Весь заказ на складе">
  13. <i class="bi bi-box-seam page-action-btn__icon"></i>
  14. <span class="page-action-btn__label">Весь заказ на складе</span>
  15. </button>
  16. @endif
  17. <button type="button" class="btn btn-sm btn-primary page-action-btn" data-bs-toggle="modal" data-bs-target="#addModal" aria-label="Добавить">
  18. <i class="bi bi-plus-lg page-action-btn__icon"></i>
  19. <span class="page-action-btn__label">Добавить</span>
  20. </button>
  21. </div>
  22. </div>
  23. @include('partials.table', [
  24. 'id' => $id,
  25. 'header' => $header,
  26. 'strings' => $maf_orders,
  27. 'routeName' => 'maf_order.show',
  28. ])
  29. @include('partials.pagination', ['items' => $maf_orders])
  30. <!-- Модальное окно добавления-->
  31. <div class="modal fade" id="addModal" tabindex="-1" aria-labelledby="addModalLabel" aria-hidden="true">
  32. <div class="modal-dialog modal-fullscreen-sm-down modal-lg">
  33. <div class="modal-content">
  34. <div class="modal-header">
  35. <h1 class="modal-title fs-5" id="addModalLabel">Добавить заказ МАФ</h1>
  36. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
  37. </div>
  38. <div class="modal-body">
  39. <form action="{{ route('maf_order.store') }}" method="post">
  40. @csrf
  41. <div id="select_maf_form">
  42. <input type="text" class="form-control mb-2" placeholder="Поиск номенклатуры" id="search_maf">
  43. <select id="select_maf" class="form-select mb-3" multiple></select>
  44. </div>
  45. <div class="is-hidden" id="sku_form">
  46. <a href="#" onclick="$('#sku_form').slideUp(); $('#select_maf_form').slideDown()">назад</a>
  47. <input type="hidden" id="product_id" name="product_id" value="">
  48. @include('partials.input', ['name' => 'product_name', 'title' => 'МАФ', 'disabled' => true])
  49. @include('partials.input', ['name' => 'order_number', 'title' => 'Номер заказа', 'required' => false])
  50. @include('partials.input', ['name' => 'quantity', 'title' => 'Количество', 'required' => true, 'min' => 1])
  51. @include('partials.submit', ['name' => 'Добавить'])
  52. </div>
  53. </form>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. @if(hasRole('admin,assistant_head'))
  59. <div class="modal fade" id="setOrderInStockModal" tabindex="-1" aria-labelledby="setOrderInStockModalLabel" aria-hidden="true">
  60. <div class="modal-dialog">
  61. <div class="modal-content">
  62. <form action="{{ route('maf_order.set_order_in_stock') }}" method="post">
  63. @csrf
  64. <div class="modal-header">
  65. <h1 class="modal-title fs-5" id="setOrderInStockModalLabel">Отметить заказ как "На складе"</h1>
  66. <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
  67. </div>
  68. <div class="modal-body">
  69. <label for="bulk_order_number" class="form-label">Номер заказа</label>
  70. <div class="position-relative">
  71. <input type="text"
  72. class="form-control @error('bulk_order_number') is-invalid @enderror"
  73. id="bulk_order_number"
  74. name="bulk_order_number"
  75. value="{{ old('bulk_order_number') }}"
  76. placeholder="Начните вводить номер заказа"
  77. autocomplete="off"
  78. required>
  79. <div class="autocomplete-dropdown autocomplete-dropdown--order" id="bulk_order_number_dropdown"></div>
  80. </div>
  81. <div class="form-text">Доступны только заказы со статусом «Заказан».</div>
  82. @error('bulk_order_number')
  83. <div class="invalid-feedback d-block">{{ $message }}</div>
  84. @enderror
  85. </div>
  86. <div class="modal-footer">
  87. <button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Отмена</button>
  88. <button type="submit" class="btn btn-primary btn-sm">Сменить статус на складе</button>
  89. </div>
  90. </form>
  91. </div>
  92. </div>
  93. </div>
  94. @endif
  95. @endsection
  96. @push('scripts')
  97. <script type="module">
  98. $('#select_maf').on('change', function () {
  99. $('#product_id').val($(this).val());
  100. $('#product_name').val($('#select_maf option:selected').text()).slideDown();
  101. $('#select_maf_form').slideUp();
  102. $('#sku_form').slideDown();
  103. });
  104. waitForJQuery(function () {
  105. const $modal = $('#setOrderInStockModal');
  106. const $input = $modal.find('#bulk_order_number');
  107. const $dropdown = $modal.find('#bulk_order_number_dropdown');
  108. const orderNumbers = @json(($orderedOrderNumbers ?? collect())->values());
  109. let currentFocus = -1;
  110. function escapeHtml(text) {
  111. return String(text)
  112. .replace(/&/g, '&amp;')
  113. .replace(/</g, '&lt;')
  114. .replace(/>/g, '&gt;')
  115. .replace(/"/g, '&quot;')
  116. .replace(/'/g, '&#039;');
  117. }
  118. function escapeRegex(str) {
  119. return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  120. }
  121. function highlightMatch(text, query) {
  122. if (!text || !query) {
  123. return escapeHtml(text || '');
  124. }
  125. const safeText = escapeHtml(text);
  126. const regex = new RegExp('(' + escapeRegex(query) + ')', 'gi');
  127. return safeText.replace(regex, '<strong>$1</strong>');
  128. }
  129. function hideDropdown() {
  130. $dropdown.hide();
  131. currentFocus = -1;
  132. }
  133. function showDropdown(items, query) {
  134. $dropdown.empty();
  135. currentFocus = -1;
  136. if (!items.length) {
  137. $dropdown.html('<div class="autocomplete-item text-muted">Ничего не найдено</div>');
  138. $dropdown.show();
  139. return;
  140. }
  141. items.forEach(function (item) {
  142. $dropdown.append(
  143. '<div class="autocomplete-item" data-value="' + escapeHtml(item) + '">' +
  144. '<div class="article">' + highlightMatch(item, query) + '</div>' +
  145. '</div>'
  146. );
  147. });
  148. $dropdown.show();
  149. }
  150. function selectValue(value) {
  151. $input.val(value).removeClass('is-invalid');
  152. hideDropdown();
  153. }
  154. function setActive($items) {
  155. $items.removeClass('active');
  156. if (currentFocus >= 0 && currentFocus < $items.length) {
  157. const $active = $items.eq(currentFocus);
  158. $active.addClass('active');
  159. $active[0].scrollIntoView({block: 'nearest'});
  160. }
  161. }
  162. function searchOrderNumbers(query) {
  163. const normalized = String(query || '').trim().toLowerCase();
  164. if (normalized.length < 1) {
  165. showDropdown(orderNumbers.slice(0, 50), '');
  166. return;
  167. }
  168. const filtered = orderNumbers.filter(function (item) {
  169. return String(item).toLowerCase().includes(normalized);
  170. });
  171. showDropdown(filtered.slice(0, 50), normalized);
  172. }
  173. $input.on('input focus', function () {
  174. searchOrderNumbers($(this).val());
  175. });
  176. $input.on('keydown', function (e) {
  177. const $items = $dropdown.find('.autocomplete-item:not(.text-muted)');
  178. if (e.key === 'ArrowDown') {
  179. e.preventDefault();
  180. currentFocus++;
  181. if (currentFocus >= $items.length) {
  182. currentFocus = 0;
  183. }
  184. setActive($items);
  185. } else if (e.key === 'ArrowUp') {
  186. e.preventDefault();
  187. currentFocus--;
  188. if (currentFocus < 0) {
  189. currentFocus = $items.length - 1;
  190. }
  191. setActive($items);
  192. } else if (e.key === 'Enter') {
  193. if ($items.length > 0 && currentFocus > -1) {
  194. e.preventDefault();
  195. selectValue(String($items.eq(currentFocus).data('value') || ''));
  196. }
  197. } else if (e.key === 'Escape') {
  198. hideDropdown();
  199. }
  200. });
  201. $dropdown.on('click', '.autocomplete-item:not(.text-muted)', function () {
  202. selectValue(String($(this).data('value') || ''));
  203. });
  204. $(document).on('click', function (e) {
  205. if (!$(e.target).closest('#bulk_order_number, #bulk_order_number_dropdown').length) {
  206. hideDropdown();
  207. }
  208. });
  209. $modal.on('hidden.bs.modal', function () {
  210. hideDropdown();
  211. });
  212. });
  213. @if($errors->has('bulk_order_number') && hasRole('admin,assistant_head'))
  214. const setOrderInStockModalElement = document.getElementById('setOrderInStockModal');
  215. if (setOrderInStockModalElement) {
  216. const setOrderInStockModal = new bootstrap.Modal(setOrderInStockModalElement);
  217. setOrderInStockModal.show();
  218. }
  219. @endif
  220. </script>
  221. @endpush