25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

253 satır
8.0KB

  1. <h2>Import Jurisdiction</h2>
  2. <% Flash().ShowErrorsIfPresent %>
  3. <% Flash().ShowSuccessIfPresent %>
  4. <%= HTML.FormTag("Jurisdiction", "ImportPost", Array("_P","1"), Array("enctype","multipart/form-data","id","jurisdiction-import-form")) %>
  5. <%= HTML.Hidden("nonce", HTMLSecurity.GetAntiCSRFToken("JurisdictionImportForm")) %>
  6. <hr />
  7. <div>
  8. <p>Upload the BRM permit workbook as an Excel file. Row 1 is ignored, row 2 must contain the expected headers, and jurisdictions are updated or inserted using the JCode inside the <code>Jurisdiction</code> column.</p>
  9. </div>
  10. <div class="form-group">
  11. <div class="row">
  12. <div class="col-md-5">
  13. <div class="form-group">
  14. <label for="filename">Select XLSX File</label>
  15. <input type="file" id="filename" name="filename" accept=".xlsx" required class="form-control">
  16. </div>
  17. </div>
  18. </div>
  19. <p></p>
  20. <button type="submit" id="import-submit" class="btn btn-primary"><i class="glyphicon glyphicon-upload"></i> Start Import</button>
  21. <small class="form-text text-muted">Accepted format: .xlsx | Max size: 10 MB</small>
  22. </div>
  23. </form>
  24. <div id="import-feedback" class="panel panel-default" style="display:none; margin-top:20px;">
  25. <div class="panel-heading">
  26. <strong>Import Progress</strong>
  27. </div>
  28. <div class="panel-body">
  29. <p id="import-status">Waiting to start.</p>
  30. <div class="progress">
  31. <div id="import-progress-bar" class="progress-bar progress-bar-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" style="width:0%;">
  32. 0%
  33. </div>
  34. </div>
  35. <div class="row">
  36. <div class="col-sm-2"><strong>Total</strong><div id="summary-total">0</div></div>
  37. <div class="col-sm-2"><strong>Processed</strong><div id="summary-processed">0</div></div>
  38. <div class="col-sm-2"><strong>Updated</strong><div id="summary-updated">0</div></div>
  39. <div class="col-sm-2"><strong>Inserted</strong><div id="summary-inserted">0</div></div>
  40. <div class="col-sm-2"><strong>Invalid</strong><div id="summary-invalid">0</div></div>
  41. <div class="col-sm-2"><strong>Failed</strong><div id="summary-failed">0</div></div>
  42. </div>
  43. <div class="row" style="margin-top:12px;">
  44. <div class="col-sm-2"><strong>Duplicates</strong><div id="summary-duplicates">0</div></div>
  45. </div>
  46. <div id="import-error-panel" class="alert alert-warning" style="display:none; margin-top:15px;">
  47. <strong>Row Issues</strong>
  48. <ul id="import-error-list" style="margin-top:10px; margin-bottom:0;"></ul>
  49. </div>
  50. </div>
  51. </div>
  52. <div id="import-message" class="alert" style="display:none; margin-top:20px;"></div>
  53. <script type="text/javascript">
  54. (function () {
  55. var form = document.getElementById('jurisdiction-import-form');
  56. var fileInput = document.getElementById('filename');
  57. var submitButton = document.getElementById('import-submit');
  58. var nonceField = form.querySelector('input[name="nonce"]');
  59. var feedbackPanel = document.getElementById('import-feedback');
  60. var messageBox = document.getElementById('import-message');
  61. var statusText = document.getElementById('import-status');
  62. var progressBar = document.getElementById('import-progress-bar');
  63. var pollTimer = null;
  64. var summaryFields = {
  65. totalRows: document.getElementById('summary-total'),
  66. processedRows: document.getElementById('summary-processed'),
  67. updatedCount: document.getElementById('summary-updated'),
  68. insertedCount: document.getElementById('summary-inserted'),
  69. invalidCount: document.getElementById('summary-invalid'),
  70. failedCount: document.getElementById('summary-failed'),
  71. duplicateCount: document.getElementById('summary-duplicates')
  72. };
  73. var errorPanel = document.getElementById('import-error-panel');
  74. var errorList = document.getElementById('import-error-list');
  75. var pollUrlBase = '<%= Routes.UrlTo("Jurisdiction", "ImportProgress", Array("_P","1")) %>';
  76. function setMessage(cssClass, message) {
  77. messageBox.className = 'alert ' + cssClass;
  78. messageBox.textContent = message;
  79. messageBox.style.display = 'block';
  80. }
  81. function clearMessage() {
  82. messageBox.style.display = 'none';
  83. messageBox.textContent = '';
  84. }
  85. function updateSummary(data) {
  86. summaryFields.totalRows.textContent = data.totalRows || 0;
  87. summaryFields.processedRows.textContent = data.processedRows || 0;
  88. summaryFields.updatedCount.textContent = data.updatedCount || 0;
  89. summaryFields.insertedCount.textContent = data.insertedCount || 0;
  90. summaryFields.invalidCount.textContent = data.invalidCount || 0;
  91. summaryFields.failedCount.textContent = data.failedCount || 0;
  92. summaryFields.duplicateCount.textContent = data.duplicateCount || 0;
  93. }
  94. function refreshNonce(data) {
  95. if (nonceField && data && data.nextNonce) {
  96. nonceField.value = data.nextNonce;
  97. }
  98. }
  99. function updateProgress(data) {
  100. var percent = data.percentComplete || 0;
  101. progressBar.style.width = percent + '%';
  102. progressBar.setAttribute('aria-valuenow', percent);
  103. progressBar.textContent = percent + '%';
  104. statusText.textContent = data.statusMessage || 'Processing import.';
  105. updateSummary(data);
  106. renderErrors(data.errors || []);
  107. if (data.phase === 'complete') {
  108. progressBar.className = 'progress-bar';
  109. setMessage('alert-success', 'Jurisdiction import complete.');
  110. } else if (data.phase === 'error') {
  111. progressBar.className = 'progress-bar';
  112. setMessage('alert-danger', data.statusMessage || 'Import failed.');
  113. }
  114. }
  115. function renderErrors(errors) {
  116. errorList.innerHTML = '';
  117. if (!errors.length) {
  118. errorPanel.style.display = 'none';
  119. return;
  120. }
  121. for (var i = 0; i < errors.length; i += 1) {
  122. var item = document.createElement('li');
  123. item.textContent = errors[i];
  124. errorList.appendChild(item);
  125. }
  126. errorPanel.style.display = 'block';
  127. }
  128. function stopPolling() {
  129. if (pollTimer) {
  130. window.clearTimeout(pollTimer);
  131. pollTimer = null;
  132. }
  133. submitButton.disabled = false;
  134. }
  135. function sendJsonRequest(url, options, onSuccess, onError) {
  136. var xhr = new XMLHttpRequest();
  137. xhr.open(options.method || 'GET', url, true);
  138. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  139. xhr.onreadystatechange = function () {
  140. var data;
  141. if (xhr.readyState !== 4) {
  142. return;
  143. }
  144. try {
  145. data = JSON.parse(xhr.responseText || '{}');
  146. } catch (parseError) {
  147. onError('The server returned an invalid JSON response.');
  148. return;
  149. }
  150. if (xhr.status < 200 || xhr.status >= 300 || !data.ok) {
  151. refreshNonce(data);
  152. onError((data && data.message) || 'The request failed.');
  153. return;
  154. }
  155. refreshNonce(data);
  156. onSuccess(data);
  157. };
  158. xhr.onerror = function () {
  159. onError('The request failed.');
  160. };
  161. xhr.send(options.body || null);
  162. }
  163. function pollProgress(token) {
  164. sendJsonRequest(
  165. pollUrlBase + '&token=' + encodeURIComponent(token),
  166. { method: 'GET' },
  167. function (data) {
  168. updateProgress(data);
  169. if (data.phase === 'complete' || data.phase === 'error') {
  170. stopPolling();
  171. return;
  172. }
  173. pollTimer = window.setTimeout(function () {
  174. pollProgress(token);
  175. }, 1200);
  176. },
  177. function (error) {
  178. stopPolling();
  179. setMessage('alert-danger', error || 'Import progress request failed.');
  180. }
  181. );
  182. }
  183. form.addEventListener('submit', function (event) {
  184. event.preventDefault();
  185. clearMessage();
  186. renderErrors([]);
  187. if (!fileInput.files.length) {
  188. setMessage('alert-danger', 'Select an .xlsx file before starting the import.');
  189. return;
  190. }
  191. submitButton.disabled = true;
  192. feedbackPanel.style.display = 'block';
  193. statusText.textContent = 'Uploading workbook...';
  194. progressBar.className = 'progress-bar progress-bar-striped active';
  195. updateSummary({
  196. totalRows: 0,
  197. processedRows: 0,
  198. updatedCount: 0,
  199. insertedCount: 0,
  200. invalidCount: 0,
  201. failedCount: 0,
  202. duplicateCount: 0,
  203. percentComplete: 0
  204. });
  205. updateProgress({ percentComplete: 0, statusMessage: 'Uploading workbook...', errors: [] });
  206. var formData = new FormData(form);
  207. sendJsonRequest(
  208. form.action,
  209. { method: 'POST', body: formData },
  210. function (data) {
  211. updateProgress(data);
  212. pollProgress(data.token);
  213. },
  214. function (error) {
  215. stopPolling();
  216. setMessage('alert-danger', error || 'Import request failed.');
  217. }
  218. );
  219. });
  220. })();
  221. </script>

Powered by TurnKey Linux.