_field_pickers.blade.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. {{--
  2. Partial: picker-поля — cars_picker, makes_picker, reviews_picker, services_picker
  3. Переменные из родителя: $field, $prefix, $values
  4. --}}
  5. {{-- ── cars_picker — мультиселект авто из каталога ────────────────── --}}
  6. @if($field['type'] === 'cars_picker')
  7. @php
  8. // Площадки из справочника — строго оттуда, не из car.platform
  9. $cpSection = \App\Models\DictSection::where('code', 'platforms')->with('values')->first();
  10. $cpPlatforms = $cpSection ? $cpSection->values->pluck('value') : collect();
  11. $allCars = \App\Models\Car::select('id', 'make', 'model', 'year', 'price_rub', 'price_usd', 'platform')
  12. ->where('status', 'active')
  13. ->orderBy('make')->orderBy('model')->get();
  14. $selectedIds = array_map('intval', $values[$field['name']] ?? []);
  15. $cpUid = 'cp-' . Str::random(6); // уникальный id для изоляции JS на странице с несколькими picker-ами
  16. @endphp
  17. <div class="form-group">
  18. <label>{{ $field['label'] }}</label>
  19. {{-- Кнопки-фильтры по площадкам (данные из справочника) --}}
  20. @if($cpPlatforms->isNotEmpty())
  21. <div class="mb-2 d-flex flex-wrap" style="gap:4px">
  22. <button type="button"
  23. class="btn btn-xs btn-primary cp-filter-btn"
  24. data-picker="{{ $cpUid }}" data-platform="">
  25. Все
  26. </button>
  27. @foreach($cpPlatforms as $cpPl)
  28. <button type="button"
  29. class="btn btn-xs btn-outline-secondary cp-filter-btn"
  30. data-picker="{{ $cpUid }}" data-platform="{{ $cpPl }}">
  31. {{ $cpPl }}
  32. </button>
  33. @endforeach
  34. </div>
  35. @endif
  36. {{-- Список авто с data-platform для JS-фильтрации --}}
  37. <div class="border rounded p-2" style="max-height:280px;overflow-y:auto;background:#f8f9fa"
  38. id="{{ $cpUid }}-list">
  39. @forelse($allCars as $car)
  40. <div class="form-check cp-car-row"
  41. data-picker="{{ $cpUid }}"
  42. data-platform="{{ $car->platform }}">
  43. <input class="form-check-input" type="checkbox"
  44. name="{{ $prefix }}[{{ $field['name'] }}][]"
  45. value="{{ $car->id }}"
  46. id="car-{{ $car->id }}"
  47. @checked(in_array($car->id, $selectedIds))>
  48. <label class="form-check-label" for="car-{{ $car->id }}">
  49. {{ $car->make }} {{ $car->model }} ({{ $car->year }})
  50. @if($car->price_rub)
  51. — {{ number_format($car->price_rub, 0, '.', ' ') }} ₽
  52. @elseif($car->price_usd)
  53. — {{ number_format($car->price_usd, 0, '.', ' ') }} $
  54. @endif
  55. @if($car->platform)
  56. <span class="text-muted" style="font-size:11px">[{{ $car->platform }}]</span>
  57. @endif
  58. </label>
  59. </div>
  60. @empty
  61. <p class="text-muted small mb-0">В каталоге пока нет автомобилей.</p>
  62. @endforelse
  63. </div>
  64. <small class="text-muted">Порядок на странице — в том порядке, в каком выбраны.</small>
  65. </div>
  66. {{-- JS: фильтрация строк по площадке, изолирована по data-picker --}}
  67. <script>
  68. (function () {
  69. document.querySelectorAll('.cp-filter-btn[data-picker="{{ $cpUid }}"]').forEach(function (btn) {
  70. btn.addEventListener('click', function () {
  71. var picker = this.dataset.picker;
  72. var platform = this.dataset.platform;
  73. // Переключаем активную кнопку
  74. document.querySelectorAll('.cp-filter-btn[data-picker="' + picker + '"]').forEach(function (b) {
  75. b.classList.toggle('btn-primary', b === btn);
  76. b.classList.toggle('btn-outline-secondary', b !== btn);
  77. });
  78. // Показываем/скрываем строки
  79. document.querySelectorAll('.cp-car-row[data-picker="' + picker + '"]').forEach(function (row) {
  80. row.style.display = (!platform || row.dataset.platform === platform) ? '' : 'none';
  81. });
  82. });
  83. });
  84. })();
  85. </script>
  86. {{-- ── makes_picker — чекбоксы марок из справочника dict_values ──── --}}
  87. @elseif($field['type'] === 'makes_picker')
  88. @php
  89. $makesSection = \App\Models\DictSection::where('code', 'makes')->first();
  90. $allMakeObjs = $makesSection
  91. ? \App\Models\DictValue::where('section_id', $makesSection->id)
  92. ->whereNull('parent_id')
  93. ->orderBy('sort_order')
  94. ->get(['id', 'value', 'logo'])
  95. : collect();
  96. $selectedMakes = $values[$field['name']] ?? [];
  97. @endphp
  98. <div class="form-group">
  99. <label>{{ $field['label'] }}</label>
  100. <div class="border rounded p-2" style="background:#f8f9fa">
  101. <div class="row">
  102. @forelse($allMakeObjs as $makeObj)
  103. <div class="col-6 col-md-4">
  104. <div class="form-check d-flex align-items-center">
  105. <input class="form-check-input flex-shrink-0" type="checkbox"
  106. name="{{ $prefix }}[{{ $field['name'] }}][]"
  107. value="{{ $makeObj->value }}"
  108. id="make-{{ Str::slug($makeObj->value) }}"
  109. @checked(in_array($makeObj->value, $selectedMakes))>
  110. <label class="form-check-label d-flex align-items-center ml-1"
  111. for="make-{{ Str::slug($makeObj->value) }}">
  112. @if($makeObj->logo)
  113. <img src="{{ asset('storage/' . $makeObj->logo) }}"
  114. alt="{{ $makeObj->value }}"
  115. style="width:24px;height:24px;object-fit:contain;margin-right:5px">
  116. @endif
  117. {{ $makeObj->value }}
  118. </label>
  119. </div>
  120. </div>
  121. @empty
  122. <p class="text-muted small mb-0 col-12">Добавьте марки в справочник «Марки и модели».</p>
  123. @endforelse
  124. </div>
  125. </div>
  126. <small class="text-muted">Выбранные марки выводятся в алфавитном порядке в блоке.</small>
  127. </div>
  128. {{-- ── reviews_picker — выбор отзывов из таблицы reviews ─────────── --}}
  129. @elseif($field['type'] === 'reviews_picker')
  130. @php
  131. $allReviews = \App\Models\Review::orderBy('sort_order')->orderByDesc('created_at')->get();
  132. $selectedIds = array_map('intval', $values[$field['name']] ?? []);
  133. @endphp
  134. <div class="form-group">
  135. <label>{{ $field['label'] }}</label>
  136. @if($allReviews->isEmpty())
  137. <div class="alert alert-warning py-2">
  138. Отзывов пока нет. <a href="{{ route('admin.reviews.create') }}" target="_blank">Добавить отзыв</a>
  139. </div>
  140. @else
  141. <div class="border rounded p-2" style="max-height:300px;overflow-y:auto;background:#f8f9fa">
  142. @foreach($allReviews as $rev)
  143. <div class="form-check">
  144. <input class="form-check-input" type="checkbox"
  145. name="{{ $prefix }}[{{ $field['name'] }}][]"
  146. value="{{ $rev->id }}"
  147. id="rev-{{ $rev->id }}"
  148. @checked(in_array($rev->id, $selectedIds))>
  149. <label class="form-check-label" for="rev-{{ $rev->id }}">
  150. <strong>{{ $rev->author }}</strong>
  151. @if($rev->car_name) — {{ $rev->car_name }}@endif
  152. <span style="color:#f39c12">
  153. {{ str_repeat('★', $rev->rating) }}{{ str_repeat('☆', 5 - $rev->rating) }}
  154. </span>
  155. @if(!$rev->is_active)
  156. <span class="badge badge-secondary ml-1">скрыт</span>
  157. @endif
  158. </label>
  159. </div>
  160. @endforeach
  161. </div>
  162. <small class="text-muted">
  163. Выбранные отзывы выводятся в порядке их sort_order.
  164. <a href="{{ route('admin.reviews.index') }}" target="_blank">Управление отзывами</a>
  165. </small>
  166. @endif
  167. </div>
  168. {{-- ── services_picker — чекбоксы услуг из таблицы services ─────── --}}
  169. @elseif($field['type'] === 'services_picker')
  170. @php
  171. $allServices = \App\Models\Service::orderBy('sort_order')->orderBy('title')->get();
  172. $selectedIds = array_map('intval', $values[$field['name']] ?? []);
  173. @endphp
  174. <div class="form-group">
  175. <label>{{ $field['label'] }}</label>
  176. @if($allServices->isEmpty())
  177. <div class="alert alert-warning py-2">
  178. Услуг пока нет. <a href="{{ route('admin.services.create') }}" target="_blank">Добавить</a>
  179. </div>
  180. @else
  181. <div class="border rounded p-2" style="max-height:280px;overflow-y:auto;background:#f8f9fa">
  182. @foreach($allServices as $svc)
  183. <div class="form-check">
  184. <input class="form-check-input" type="checkbox"
  185. name="{{ $prefix }}[{{ $field['name'] }}][]"
  186. value="{{ $svc->id }}"
  187. id="svc-{{ $svc->id }}"
  188. @checked(in_array($svc->id, $selectedIds))>
  189. <label class="form-check-label" for="svc-{{ $svc->id }}">
  190. @if($svc->icon) {{ $svc->icon }} @endif
  191. <strong>{{ $svc->title }}</strong>
  192. @if(!$svc->is_active)
  193. <span class="badge badge-secondary ml-1">скрыта</span>
  194. @endif
  195. </label>
  196. </div>
  197. @endforeach
  198. </div>
  199. <small class="text-muted">
  200. Оставьте пустым — будут показаны последние N активных услуг.
  201. <a href="{{ route('admin.services.index') }}" target="_blank">Управление услугами</a>
  202. </small>
  203. @endif
  204. </div>
  205. @endif