index.blade.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. @extends('layouts.app')
  2. @section('content')
  3. <div class="container-fluid">
  4. <div class="row">
  5. <div class="col-12">
  6. <h2>{{ $title }}</h2>
  7. {{-- Вкладки --}}
  8. <ul class="nav nav-tabs mb-3">
  9. <li class="nav-item">
  10. <a class="nav-link {{ ($tab ?? 'catalog') === 'catalog' ? 'active' : '' }}"
  11. href="{{ route('spare_parts.index') }}">
  12. Каталог
  13. </a>
  14. </li>
  15. <li class="nav-item">
  16. <a class="nav-link {{ ($tab ?? '') === 'orders' ? 'active' : '' }}"
  17. href="{{ route('spare_part_orders.index') }}">
  18. Заказы деталей
  19. </a>
  20. </li>
  21. <li class="nav-item">
  22. <a class="nav-link {{ ($tab ?? '') === 'inventory' ? 'active' : '' }}"
  23. href="{{ route('spare_part_inventory.index') }}">
  24. Контроль наличия
  25. </a>
  26. </li>
  27. @if(hasRole('admin'))
  28. <li class="nav-item">
  29. <a class="nav-link" href="{{ route('pricing_codes.index') }}">
  30. Справочник расшифровок
  31. </a>
  32. </li>
  33. @endif
  34. </ul>
  35. @if(($tab ?? 'catalog') === 'catalog')
  36. {{-- Кнопки управления --}}
  37. <div class="mb-3">
  38. @if(hasRole('admin'))
  39. <a href="{{ route('spare_parts.create') }}" class="btn btn-primary">Добавить запчасть</a>
  40. <form action="{{ route('spare_parts.export') }}" method="POST" class="d-inline">
  41. @csrf
  42. <button type="submit" class="btn btn-success">Экспорт</button>
  43. </form>
  44. <button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#importModal">
  45. Импорт
  46. </button>
  47. @endif
  48. </div>
  49. {{-- Таблица каталога --}}
  50. @if(isset($spare_parts) && isset($strings))
  51. @include('partials.table', [
  52. 'id' => $id,
  53. 'header' => $header,
  54. 'strings' => $strings,
  55. 'filters' => $filters ?? [],
  56. 'ranges' => $ranges ?? [],
  57. 'dates' => $dates ?? [],
  58. 'searchFields' => $searchFields ?? [],
  59. 'sortBy' => $sortBy ?? 'article',
  60. 'orderBy' => $orderBy ?? 'asc',
  61. 'routeName' => $routeName ?? null,
  62. ])
  63. {{ $spare_parts->links() }}
  64. @endif
  65. @elseif($tab === 'orders')
  66. {{-- Таблица заказов --}}
  67. @if(isset($spare_part_orders))
  68. <div class="mb-3">
  69. @if(hasRole('admin,manager'))
  70. <a href="{{ route('spare_part_orders.create') }}" class="btn btn-primary">Создать заказ</a>
  71. @endif
  72. </div>
  73. @include('partials.table', [
  74. 'id' => $id,
  75. 'header' => $header,
  76. 'strings' => $strings,
  77. 'filters' => $filters ?? [],
  78. 'ranges' => $ranges ?? [],
  79. 'dates' => $dates ?? [],
  80. 'searchFields' => $searchFields ?? [],
  81. 'sortBy' => $sortBy ?? 'id',
  82. 'orderBy' => $orderBy ?? 'desc',
  83. 'routeName' => $routeName ?? null,
  84. ])
  85. {{ $spare_part_orders->links() }}
  86. @endif
  87. @elseif($tab === 'inventory')
  88. {{-- Контроль наличия --}}
  89. <h4 class="text-danger">Критический недостаток</h4>
  90. @if(isset($critical_shortages) && $critical_shortages->count() > 0)
  91. <div class="table-responsive">
  92. <table class="table table-danger table-striped">
  93. <thead>
  94. <tr>
  95. <th>Картинка</th>
  96. <th>Артикул</th>
  97. <th>Кол-во без док</th>
  98. <th>Кол-во с док</th>
  99. <th>Примечание</th>
  100. </tr>
  101. </thead>
  102. <tbody>
  103. @foreach($critical_shortages as $sp)
  104. <tr>
  105. <td>
  106. @if($sp->image)
  107. <img src="{{ $sp->image }}" alt="{{ $sp->article }}" style="max-width: 50px;">
  108. @endif
  109. </td>
  110. <td><a href="{{ route('spare_parts.show', $sp->id) }}">{{ $sp->article }}</a></td>
  111. <td>{{ $sp->quantity_without_docs }}</td>
  112. <td>{{ $sp->quantity_with_docs }}</td>
  113. <td>Отсутствие детали</td>
  114. </tr>
  115. @endforeach
  116. </tbody>
  117. </table>
  118. </div>
  119. @else
  120. <p class="text-muted">Нет запчастей с критическим недостатком</p>
  121. @endif
  122. <h4 class="text-warning mt-4">Ниже минимального остатка</h4>
  123. @if(isset($below_min_stock) && $below_min_stock->count() > 0)
  124. <div class="table-responsive">
  125. <table class="table table-warning table-striped">
  126. <thead>
  127. <tr>
  128. <th>Картинка</th>
  129. <th>Артикул</th>
  130. <th>Текущий остаток</th>
  131. <th>Минимальный остаток</th>
  132. <th>Примечание</th>
  133. </tr>
  134. </thead>
  135. <tbody>
  136. @foreach($below_min_stock as $sp)
  137. <tr>
  138. <td>
  139. @if($sp->image)
  140. <img src="{{ $sp->image }}" alt="{{ $sp->article }}" style="max-width: 50px;">
  141. @endif
  142. </td>
  143. <td><a href="{{ route('spare_parts.show', $sp->id) }}">{{ $sp->article }}</a></td>
  144. <td>{{ $sp->total_quantity }}</td>
  145. <td>{{ $sp->min_stock }}</td>
  146. <td>Достигнут лимит минимального остатка ({{ $sp->min_stock }} шт)</td>
  147. </tr>
  148. @endforeach
  149. </tbody>
  150. </table>
  151. </div>
  152. @else
  153. <p class="text-muted">Нет запчастей ниже минимального остатка</p>
  154. @endif
  155. @endif
  156. </div>
  157. </div>
  158. </div>
  159. {{-- Модальное окно импорта --}}
  160. @if(hasRole('admin'))
  161. <div class="modal fade" id="importModal" tabindex="-1">
  162. <div class="modal-dialog">
  163. <div class="modal-content">
  164. <div class="modal-header">
  165. <h5 class="modal-title">Импорт каталога запчастей и справочника расшифровок</h5>
  166. <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
  167. </div>
  168. <form action="{{ route('spare_parts.import') }}" method="POST" enctype="multipart/form-data">
  169. @csrf
  170. <div class="modal-body">
  171. <div class="mb-3">
  172. <label for="import_file" class="form-label">Выберите файл Excel</label>
  173. <input type="file" class="form-control" id="import_file" name="file" accept=".xlsx,.xls" required>
  174. <div class="form-text">
  175. Файл должен содержать две вкладки:<br>
  176. 1. Каталог запчастей (колонки: ID, Артикул, Где используется, Кол-во без док, Кол-во с док, Кол-во общее, Примечание, Цена закупки, Цена для заказчика, Цена экспертизы, № по ТСН, Шифр расценки, Минимальный остаток)<br>
  177. 2. Справочник расшифровок (колонки: ID, Тип, Код, Расшифровка)
  178. </div>
  179. </div>
  180. </div>
  181. <div class="modal-footer">
  182. <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
  183. <button type="submit" class="btn btn-primary">Импортировать</button>
  184. </div>
  185. </form>
  186. </div>
  187. </div>
  188. </div>
  189. @endif
  190. @push('scripts')
  191. <script type="module">
  192. function waitForJQuery(callback) {
  193. if (typeof window.$ !== 'undefined') {
  194. callback();
  195. } else {
  196. setTimeout(() => waitForJQuery(callback), 50);
  197. }
  198. }
  199. waitForJQuery(function() {
  200. $(document).on('click', '.clickable-quantity', function(e) {
  201. e.preventDefault();
  202. const sparePartId = $(this).data('spare-part-id');
  203. const withDocs = $(this).data('with-docs');
  204. let url = "{{ route('spare_part_orders.index') }}" +
  205. "?spare_part_id=" + sparePartId +
  206. "&status=in_stock&remaining_quantity_min=1";
  207. if (withDocs !== 'all') {
  208. url += "&with_documents=" + withDocs;
  209. }
  210. window.location.href = url;
  211. });
  212. });
  213. </script>
  214. @endpush
  215. @endsection