chartManD commited on
Commit
a0fd4e3
·
1 Parent(s): 9d6dd50

Descarga de datos para sesion con PF

Browse files
tecnicas/static/js/download-table-zip.js ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener("DOMContentLoaded", function () {
2
+ const btn = document.getElementById("download-csv-btn");
3
+ if (!btn) return;
4
+
5
+ btn.addEventListener("click", async function () {
6
+ if (typeof JSZip === "undefined" || typeof saveAs === "undefined") {
7
+ alert(
8
+ "Librerías JSZip o FileSaver no están cargadas. Asegúrate de incluir los CDN de JSZip y FileSaver."
9
+ );
10
+ return;
11
+ }
12
+
13
+ const sections = document.querySelectorAll("section[data-tester]");
14
+ if (!sections || sections.length === 0) {
15
+ alert("No hay tablas para descargar.");
16
+ return;
17
+ }
18
+
19
+ const zip = new JSZip();
20
+
21
+ let zipName = "";
22
+
23
+ sections.forEach((sec) => {
24
+ const tester = sec.getAttribute("data-tester") || "tester";
25
+ const sessionName = sec.getAttribute("data-session-name") || "";
26
+ const sessionCode = sec.getAttribute("data-session-code") || "";
27
+
28
+ const fileName = `${tester}_${
29
+ sessionName ? sessionName.trim() : sessionCode.trim()
30
+ }`;
31
+
32
+ zipName = `datos_sesion_${
33
+ sessionName ? sessionName.trim() : sessionCode.trim()
34
+ }`;
35
+
36
+ const table = sec.querySelector("table");
37
+ if (!table) return;
38
+
39
+ // Build CSV
40
+ const rows = [];
41
+ const headerCells = Array.from(table.querySelectorAll("thead tr th"));
42
+ const headers = headerCells.map((h) => h.textContent.trim());
43
+ rows.push(headers.map(escapeCsv).join(","));
44
+
45
+ const trs = table.querySelectorAll("tbody tr");
46
+ trs.forEach((tr) => {
47
+ const tds = Array.from(tr.querySelectorAll("td"));
48
+ const values = tds.map((td) => escapeCsv(td.textContent.trim()));
49
+ rows.push(values.join(","));
50
+ });
51
+
52
+ const csvContent = rows.join("\r\n");
53
+ zip.file(`${fileName}.csv`, csvContent);
54
+ });
55
+
56
+ try {
57
+ const blob = await zip.generateAsync({ type: "blob" });
58
+ const zipNameWithExtension = zipName + ".zip";
59
+ saveAs(blob, zipNameWithExtension);
60
+ } catch (err) {
61
+ console.error(err);
62
+ alert("Error al generar el ZIP: " + err.message);
63
+ }
64
+ });
65
+
66
+ const escapeCsv = (val) => {
67
+ if (val == null) return "";
68
+ let normalVal = val.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
69
+ const needsQuotes = /[",\n,]/.test(normalVal);
70
+ let v = String(normalVal).replace(/"/g, '""');
71
+ if (needsQuotes) v = `"${v}"`;
72
+ return v;
73
+ };
74
+ });
tecnicas/templates/tecnicas/components/table_pf.html CHANGED
@@ -1,9 +1,11 @@
1
  {% load static %}
2
- <section>
 
 
3
  <h3 class="text-xl font-bold">Datos de usuario {{ data.tester }}</h3>
4
 
5
  <div class="overflow-x-auto rounded-lg border border-surface-general">
6
- <table id="convencional-table" class="min-w-max w-full text-sm text-center border-collapse">
7
  <thead class="bg-surface-sweet text-black font-semibold">
8
  <tr>
9
  <th class="py-2 px-3 border border-surface-general">Repetición</th>
@@ -15,33 +17,23 @@
15
  </thead>
16
  <tbody class="bg-surface-ligt divide-y divide-gray-200">
17
  {% for repeticion, data_product in data.ratings.items %}
18
- {% for codigo, valores in data_product.items %}
19
- <tr>
20
- <td class="py-2 px-3 border border-surface-general">{{ repeticion }}</td>
21
- <td class="py-2 px-3 border border-surface-general">{{ codigo }}</td>
22
- {% for word in data.words %}
23
- <td class="py-2 px-3 border border-surface-general">
24
- {% with match=False %}
25
- {% for valor in valores %}
26
- {% if valor.nombre_palabra == word.nombre_palabra %}
27
- {{ valor.dato_valor }}
28
- {% with match=True %}{% endwith %}
29
- {% endif %}
30
- {% endfor %}
31
- {% if match %}0{% endif %}
32
- {% endwith %}
33
- </td>
34
- {% endfor %}
35
- </tr>
36
  {% endfor %}
 
 
37
  {% endfor %}
38
  </tbody>
39
  </table>
40
  </div>
41
-
42
- <div class="flex justify-end mt-3">
43
- <button id="download-csv-btn" class="cts-btn-general cts-btn-primary btn-push">
44
- Descargar CSV
45
- </button>
46
- </div>
47
  </section>
 
1
  {% load static %}
2
+
3
+ <section data-tester="{{ data.tester }}" {% if session_name %} data-session-name="{{ session_name }}" {% endif %}
4
+ data-session-code="{{ session_code }}">
5
  <h3 class="text-xl font-bold">Datos de usuario {{ data.tester }}</h3>
6
 
7
  <div class="overflow-x-auto rounded-lg border border-surface-general">
8
+ <table class="convencional-table min-w-max w-full text-sm text-center border-collapse">
9
  <thead class="bg-surface-sweet text-black font-semibold">
10
  <tr>
11
  <th class="py-2 px-3 border border-surface-general">Repetición</th>
 
17
  </thead>
18
  <tbody class="bg-surface-ligt divide-y divide-gray-200">
19
  {% for repeticion, data_product in data.ratings.items %}
20
+ {% for codigo, valores in data_product.items %}
21
+ <tr>
22
+ <td class="py-2 px-3 border border-surface-general">{{ repeticion }}</td>
23
+ <td class="py-2 px-3 border border-surface-general">{{ codigo }}</td>
24
+ {% for word in data.words %}
25
+ <td class="py-2 px-3 border border-surface-general">
26
+ {% for valor in valores %}
27
+ {% if valor.nombre_palabra == word.nombre_palabra %}
28
+ {{ valor.dato_valor }}
29
+ {% endif %}
30
+ {% endfor %}
31
+ </td>
 
 
 
 
 
 
32
  {% endfor %}
33
+ </tr>
34
+ {% endfor %}
35
  {% endfor %}
36
  </tbody>
37
  </table>
38
  </div>
 
 
 
 
 
 
39
  </section>
tecnicas/templates/tecnicas/manage_sesions/details-session-pf.html CHANGED
@@ -218,11 +218,16 @@
218
  </article>
219
 
220
  {% if data_ratings %}
221
- <article class="overflow-x-auto py-2">
222
  {% for data_tester in data_ratings %}
223
- {% include "../components/table_pf.html" with data=data_tester %}
224
  {% endfor %}
225
  </article>
 
 
 
 
 
226
  {% else %}
227
  {% include "../components/error-message.html" with message='Sin datos por mostrar aún' %}
228
  {% endif %}
@@ -238,6 +243,9 @@
238
  {% endblock %}
239
 
240
  {% block extra_js %}
 
 
 
241
  <script src="{% static 'js/details-session.js' %}"></script>
242
  <script src="{% static 'js/showHiddenElement.js' %}"></script>
243
  {% endblock %}
 
218
  </article>
219
 
220
  {% if data_ratings %}
221
+ <article class="overflow-x-auto py-2 space-y-4">
222
  {% for data_tester in data_ratings %}
223
+ {% include "../components/table_pf.html" with data=data_tester session_name=sesion.nombre_sesion session_code=sesion.codigo_sesion %}
224
  {% endfor %}
225
  </article>
226
+ <div class="flex justify-end mt-3">
227
+ <button id="download-csv-btn" class="cts-btn-general cts-btn-primary btn-push">
228
+ Descargar datos como CSV en zip
229
+ </button>
230
+ </div>
231
  {% else %}
232
  {% include "../components/error-message.html" with message='Sin datos por mostrar aún' %}
233
  {% endif %}
 
243
  {% endblock %}
244
 
245
  {% block extra_js %}
246
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
247
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
248
+ <script src="{% static 'js/download-table-zip.js' %}"></script>
249
  <script src="{% static 'js/details-session.js' %}"></script>
250
  <script src="{% static 'js/showHiddenElement.js' %}"></script>
251
  {% endblock %}