index.blade.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. @extends('layouts.app')
  2. @section('content')
  3. <div class="row mb-3">
  4. <div class="col-12">
  5. <h3>Экспорт и импорт данных за год</h3>
  6. </div>
  7. </div>
  8. <div class="row">
  9. <!-- Экспорт -->
  10. <div class="col-md-6 mb-4">
  11. <div class="card">
  12. <div class="card-header bg-primary text-white">
  13. <i class="bi bi-download me-2"></i>Экспорт данных
  14. </div>
  15. <div class="card-body">
  16. @if(count($years) > 0)
  17. <p class="text-muted">Экспортирует все данные за выбранный год в ZIP-архив, включая файлы (фото, документы, сертификаты, паспорта).</p>
  18. <div class="mb-3">
  19. <label for="exportYear" class="form-label">Год для экспорта</label>
  20. <select class="form-select" id="exportYear" name="year">
  21. <option value="">-- Выберите год --</option>
  22. @foreach($years as $year)
  23. <option value="{{ $year }}">{{ $year }}</option>
  24. @endforeach
  25. </select>
  26. </div>
  27. <button type="button" class="btn btn-outline-primary" id="btnGetExportStats" disabled>
  28. Показать статистику
  29. </button>
  30. <div id="exportStatsBlock" class="mt-3" style="display: none;">
  31. <h6>Данные для экспорта за <span id="exportStatsYear"></span> год:</h6>
  32. <table class="table table-sm table-striped" id="exportStatsTable">
  33. <thead>
  34. <tr>
  35. <th>Сущность</th>
  36. <th class="text-end">Количество</th>
  37. </tr>
  38. </thead>
  39. <tbody></tbody>
  40. <tfoot>
  41. <tr class="table-dark">
  42. <th>Итого</th>
  43. <th class="text-end" id="exportStatsTotal"></th>
  44. </tr>
  45. </tfoot>
  46. </table>
  47. <form action="{{ route('year-data.export') }}" method="post">
  48. @csrf
  49. <input type="hidden" name="year" id="exportYearInput">
  50. <button type="submit" class="btn btn-primary">
  51. <i class="bi bi-download me-2"></i>Начать экспорт
  52. </button>
  53. </form>
  54. </div>
  55. @else
  56. <div class="alert alert-info mb-0">
  57. Нет данных для экспорта
  58. </div>
  59. @endif
  60. </div>
  61. </div>
  62. </div>
  63. <!-- Импорт -->
  64. <div class="col-md-6 mb-4">
  65. <div class="card">
  66. <div class="card-header bg-success text-white">
  67. <i class="bi bi-upload me-2"></i>Импорт данных
  68. </div>
  69. <div class="card-body">
  70. <p class="text-muted">Импортирует данные из ранее созданного ZIP-архива экспорта.</p>
  71. <form action="{{ route('year-data.import') }}" method="post" enctype="multipart/form-data">
  72. @csrf
  73. <div class="mb-3">
  74. <label for="importYear" class="form-label">Год для импорта</label>
  75. <input type="number" class="form-control" id="importYear" name="year"
  76. min="2020" max="2100" value="{{ date('Y') }}" required>
  77. <div class="form-text">Год, в который будут импортированы данные</div>
  78. </div>
  79. <div class="mb-3">
  80. <label for="importFile" class="form-label">ZIP-архив с данными</label>
  81. <input type="file" class="form-control" id="importFile" name="import_file"
  82. accept=".zip" required>
  83. </div>
  84. <div class="mb-3 form-check">
  85. <input type="checkbox" class="form-check-input" id="clearExisting" name="clear_existing" value="1">
  86. <label class="form-check-label text-danger" for="clearExisting">
  87. <strong>Очистить существующие данные</strong> за этот год перед импортом
  88. </label>
  89. </div>
  90. <div class="alert alert-warning">
  91. <i class="bi bi-exclamation-triangle me-2"></i>
  92. <strong>Внимание!</strong> При включенной опции очистки все существующие данные за указанный год будут удалены перед импортом.
  93. </div>
  94. <button type="submit" class="btn btn-success" id="btnImport">
  95. <i class="bi bi-upload me-2"></i>Начать импорт
  96. </button>
  97. </form>
  98. </div>
  99. </div>
  100. </div>
  101. </div>
  102. <!-- Недавние экспорты -->
  103. @if($exports->count() > 0)
  104. <div class="row">
  105. <div class="col-12">
  106. <div class="card">
  107. <div class="card-header">
  108. <i class="bi bi-clock-history me-2"></i>Недавние экспорты
  109. </div>
  110. <div class="card-body">
  111. <table class="table table-striped table-hover">
  112. <thead>
  113. <tr>
  114. <th>Файл</th>
  115. <th>Дата создания</th>
  116. <th>Действия</th>
  117. </tr>
  118. </thead>
  119. <tbody>
  120. @foreach($exports as $export)
  121. <tr>
  122. <td>{{ $export->original_name }}</td>
  123. <td>{{ $export->created_at->format('d.m.Y H:i') }}</td>
  124. <td>
  125. <a href="{{ $export->link }}" class="btn btn-sm btn-outline-primary" target="_blank">
  126. <i class="bi bi-download"></i> Скачать
  127. </a>
  128. </td>
  129. </tr>
  130. @endforeach
  131. </tbody>
  132. </table>
  133. </div>
  134. </div>
  135. </div>
  136. </div>
  137. @endif
  138. @endsection
  139. @push('scripts')
  140. <script type="module">
  141. $(document).ready(function() {
  142. let selectedExportYear = null;
  143. $('#exportYear').on('change', function() {
  144. selectedExportYear = $(this).val();
  145. $('#btnGetExportStats').prop('disabled', !selectedExportYear);
  146. $('#exportStatsBlock').hide();
  147. });
  148. $('#btnGetExportStats').on('click', function() {
  149. if (!selectedExportYear) return;
  150. const btn = $(this);
  151. btn.prop('disabled', true).text('Загрузка...');
  152. $.ajax({
  153. url: '{{ route('year-data.stats') }}',
  154. method: 'GET',
  155. data: { year: selectedExportYear },
  156. success: function(response) {
  157. $('#exportStatsYear').text(response.year);
  158. $('#exportStatsTotal').text(response.total);
  159. $('#exportYearInput').val(response.year);
  160. const tbody = $('#exportStatsTable tbody');
  161. tbody.empty();
  162. for (const [entity, count] of Object.entries(response.stats)) {
  163. tbody.append(`<tr><td>${entity}</td><td class="text-end">${count}</td></tr>`);
  164. }
  165. $('#exportStatsBlock').show();
  166. },
  167. error: function(xhr) {
  168. alert('Ошибка получения статистики: ' + (xhr.responseJSON?.error || 'Неизвестная ошибка'));
  169. },
  170. complete: function() {
  171. btn.prop('disabled', false).text('Показать статистику');
  172. }
  173. });
  174. });
  175. // Валидация формы импорта
  176. $('form[action="{{ route('year-data.import') }}"]').on('submit', function(e) {
  177. const file = $('#importFile').val();
  178. const clearExisting = $('#clearExisting').is(':checked');
  179. if (!file) {
  180. e.preventDefault();
  181. alert('Пожалуйста, выберите ZIP-архив для импорта');
  182. return false;
  183. }
  184. if (clearExisting) {
  185. if (!confirm('Вы уверены, что хотите очистить существующие данные за этот год? Это действие необратимо!')) {
  186. e.preventDefault();
  187. return false;
  188. }
  189. }
  190. $('#btnImport').prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-2"></span>Загрузка...');
  191. });
  192. });
  193. </script>
  194. @endpush