• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות

    דוח נתוני האזנה

    מתוזמן נעוץ נעול הועבר הסברים מסודרים ממשתמשים
    1 פוסטים 1 כותבים 52 צפיות 1 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • ע מנותק
      ע.ג.
      נערך לאחרונה על ידי ע.ג.

      מצורף קוד משוכלל למעקב אחר נתוני האזנה של התלמידים במרחב הקולי
      המערכת משקללת את רצף ההאזנה האמיתי ומסננת כפילויות האזנה או דילוגים, כך שהתוצאה משקפת את זמן האזנה לקובץ בפועל, ולא את משך הזמן שבו הקובץ היה בהשמעה
      לדוגמה, אם בחיוג הראשון האזין מהתחלה עד דקה 10, ובחיוג השני האזין מדקה 5 עד דקה 15, או דילג 5 דקות מהשיעור והגיע לדקה 20, לא יהיה רשום שהאזין 20 דקות, אלא יהיה רשום שהאזין 15 דקות, כי בסה"כ מכל הקובץ הוא שמע רק 15 דקות, וזה גם מסונכרן מכמה ימים, כלומר אם מגדירים שיציג מכמה ימים הוא מסנכרן על כל קובץ כמה בסה"כ התלמיד שמע מהקובץ הזה
      מומלץ מאד עבור מוסדות המשתמשים במרחב הקולי
      עריכה: במידה והכניסה למערכת מתבצעת באמצעות מספר ת"ז של התלמיד, יופיע שם ות"ז. במידה ולא מתבצעת כניסה לפי ת"ז, יופיע מספר טלפון
      שימו לב! המערכת מיועדת להצגת נתוני האזנה במערכות בהם מוגדר שמירת קובץ דוח יומי (יש להגדיר בקובץ ivr.ini את ההגדרה: log_playback_play_stop=yes ).
      הקוד בספוילר
      יש להעתיק את הקוד, ולהדביק ב"פנקס רשימות", ולשמור בשם ניתוח_נתוני_האזנה.html

      <!DOCTYPE html>
      <html lang="he" dir="rtl">
      <head>
          <meta charset="UTF-8">
          <title>ניתוח נתוני האזנה מתקדם</title>
          <style>
              :root {
                  --primary-color: #1a73e8;
                  --primary-hover: #1557b0;
                  --success-color: #28a745;
                  --bg-color: #f0f2f5;
                  --card-bg: #ffffff;
                  --border-color: #e4e6eb;
                  --text-main: #1c1e21;
                  --text-secondary: #65676b;
              }
       
              body { 
                  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; 
                  background-color: var(--bg-color); 
                  margin: 20px; 
                  color: var(--text-main);
                  line-height: 1.5;
              }
       
              .container { 
                  max-width: 1400px; 
                  margin: auto; 
                  background: var(--card-bg); 
                  padding: 30px; 
                  border-radius: 12px; 
                  box-shadow: 0 8px 24px rgba(0,0,0,0.08); 
              }
       
              h2 { 
                  color: var(--primary-color); 
                  text-align: center; 
                  margin-bottom: 10px; 
                  font-weight: 600;
                  font-size: 1.8rem;
              }
       
              .instructions {
                  text-align: center;
                  color: var(--text-secondary);
                  font-size: 14px;
                  margin-bottom: 30px;
                  line-height: 1.6;
              }
              
              .setup-panel { 
                  background: #f8f9fa; 
                  padding: 20px; 
                  border-radius: 10px; 
                  border: 1px solid var(--border-color); 
                  margin-bottom: 25px; 
                  display: flex; 
                  gap: 20px; 
                  align-items: flex-end; 
                  flex-wrap: wrap; 
              }
       
              .form-group { 
                  display: flex; 
                  flex-direction: column; 
                  gap: 8px; 
                  flex: 1; 
                  min-width: 160px; 
              }
       
              .token-input-wrapper {
                  display: flex;
                  border: 1px solid #dddfe2;
                  border-radius: 6px;
                  overflow: hidden;
                  background: white;
                  transition: focus-within 0.2s;
              }
              
              .token-input-wrapper:focus-within {
                  border-color: var(--primary-color); 
                  box-shadow: 0 0 0 2px rgba(26,115,232,0.15); 
              }
       
              .token-input-wrapper input {
                  border: none !important;
                  box-shadow: none !important;
                  flex-grow: 1;
                  padding: 10px 14px;
              }
       
              #clear-token-btn {
                  background-color: #f8f9fa;
                  color: #65676b;
                  border: none;
                  border-right: 1px solid #dddfe2;
                  min-width: 40px;
                  cursor: pointer;
                  font-size: 16px;
                  display: flex;
                  align-items: center;
                  justify-content: center;
              }
       
              #clear-token-btn:hover {
                  background-color: #fee2e2;
                  color: #dc3545;
              }
       
              label { font-weight: 600; font-size: 0.9rem; color: var(--text-secondary); }
       
              input, select, button { 
                  padding: 10px 14px; 
                  border: 1px solid #dddfe2; 
                  border-radius: 6px; 
                  font-size: 14px; 
                  outline: none; 
                  transition: all 0.2s;
              }
              
              button { 
                  background-color: var(--primary-color); 
                  color: white; 
                  border: none; 
                  cursor: pointer; 
                  font-weight: 600; 
                  min-width: 130px; 
              }
       
              button:hover { 
                  background-color: var(--primary-hover); 
                  transform: translateY(-1px); 
              }
       
              #export-btn { background-color: var(--success-color); }
              #export-btn:hover { background-color: #218838; }
       
              .table-wrapper { 
                  overflow-x: auto; 
                  margin-top: 20px; 
                  border-radius: 8px; 
                  border: 1px solid var(--border-color); 
              }
       
              table { 
                  width: 100%; 
                  border-collapse: collapse; 
                  background: white; 
                  min-width: 1100px; 
              }
       
              th { 
                  background-color: #f8f9fa; 
                  color: var(--text-secondary); 
                  padding: 15px 12px; 
                  text-align: right; 
                  position: sticky; 
                  top: 0; 
                  z-index: 10; 
                  border-bottom: 2px solid #dee2e6;
                  cursor: pointer;
                  user-select: none;
              }
       
              td { 
                  padding: 12px; 
                  border-bottom: 1px solid #eff2f5; 
                  font-size: 14px; 
                  vertical-align: middle; 
              }
       
              tr:hover { background-color: #f8faff; }
       
              .filter-row { background-color: #ffffff; }
              .filter-row input, .filter-row select { 
                  width: 100%; 
                  padding: 6px; 
                  font-size: 13px; 
                  border: 1px solid #e1e4e8; 
                  background: #fafafa; 
                  box-sizing: border-box;
              }
       
              .progress-container { 
                  display: flex; 
                  align-items: center; 
                  gap: 10px; 
                  min-width: 140px; 
              }
       
              .progress-bar { 
                  background: #e9ecef; 
                  border-radius: 20px; 
                  flex-grow: 1; 
                  height: 10px; 
                  overflow: hidden; 
              }
       
              .progress-fill { 
                  height: 100%; 
                  border-radius: 20px; 
                  transition: width 0.8s cubic-bezier(0.4, 0, 0.2, 1); 
              }
       
              .bg-green { background: linear-gradient(90deg, #28a745, #34ce57); }
              .bg-orange { background: linear-gradient(90deg, #ffc107, #ffca2c); }
              .bg-red { background: linear-gradient(90deg, #dc3545, #ea4335); }
       
              #status-msg { 
                  margin: 15px 0; 
                  font-weight: 500; 
                  text-align: center; 
                  padding: 12px; 
                  border-radius: 6px; 
                  min-height: 20px;
              }
       
              .loading { color: var(--primary-color); background: #e8f0fe; display: block; }
              .error { color: #d93025; background: #fce8e6; display: block; }
              
              small { color: var(--text-secondary); display: block; margin-top: 2px; }
          </style>
      </head>
      <body>
       
      <div class="container">
          <h2>מערכת ניתוח האזנה מתקדמת</h2>
          
          <div class="instructions">
              נא להזין את טווח התאריכים המבוקש ואת הטוקן של המערכת. (הטוקן נשמר במטמון של הדפדפן הנוכחי (ניתן למחוק), ואינו מועבר לשום מקום אחר).<br>
              ניתן לסנן את התוצאות, ולייצא את הנתונים המצומצמים לקובץ Excel.<br>
              המערכת משקללת את רצף ההאזנה האמיתי ומסננת כפילויות האזנה או דילוגים, כך שהתוצאה משקפת את זמן האזנה לקובץ בפועל, ולא את משך הזמן שבו הקובץ היה בהשמעה.<br>
              המערכת מציגה את נתוני האזנה לקבצים מוקלטים, ולא את נתוני השתתפות בועידות ושידורים חיים.<br>
              עד 40% האזנה, יופיע צבע אדום. בין 40% ל-80%, יופיע צבע צהוב. מעל 80% האזנה, יופיע צבע ירוק.<br>
              המערכת מיועדת להצגת נתוני האזנה במערכות בהם מוגדר שמירת קובץ דוח יומי (יש להגדיר בקובץ ivr.ini את ההגדרה: log_playback_play_stop=yes ).<br>
              לתשומת ליבכם: לא מומלץ להפיק דוחות בין 4 ל-5 לפנות בוקר, בשעות אלו יתכן שהדוח לא יהיה מדוייק.<br>
          </div>
          
          <div class="setup-panel">
              <div class="form-group">
                  <label>מתאריך:</label>
                  <input type="date" id="from-date">
              </div>
              <div class="form-group">
                  <label>עד תאריך:</label>
                  <input type="date" id="to-date">
              </div>
              <div class="form-group">
                  <label>טוקן:</label>
                  <div class="token-input-wrapper">
                      <button id="clear-token-btn" title="נקה טוקן שמור">✕</button>
                      <input type="text" id="api-token" placeholder="הכנס טוקן API...">
                  </div>
              </div>
              <button id="fetch-btn">משוך נתונים</button>
              <button id="export-btn" style="display:none;">ייצא לאקסל את הנתונים המסוננים</button>
          </div>
       
          <div id="status-msg"></div>
       
          <div class="table-wrapper">
              <table id="results-table" style="display:none;">
                  <thead>
                      <tr id="header-row">
                          </tr>
                      <tr class="filter-row" id="filter-row">
                          </tr>
                  </thead>
                  <tbody id="table-body"></tbody>
              </table>
          </div>
      </div>
       
      <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
       
      <script>
          const today = new Date().toISOString().split('T')[0];
          document.getElementById('from-date').value = today;
          document.getElementById('to-date').value = today;
       
          const savedToken = localStorage.getItem('api_token_cached');
          if (savedToken) {
              document.getElementById('api-token').value = savedToken;
          }
       
          let currentData = []; 
          let sortDirections = Array(7).fill(true);
          let hasEnterId = true; // משתנה גלובלי לזיהוי סוג הקובץ
       
          const fetchBtn = document.getElementById('fetch-btn');
          const exportBtn = document.getElementById('export-btn');
          const statusMsg = document.getElementById('status-msg');
          const clearTokenBtn = document.getElementById('clear-token-btn');
       
          clearTokenBtn.onclick = function(e) {
              if (confirm("האם למחוק את הטוקן השמור?")) {
                  localStorage.removeItem('api_token_cached');
                  document.getElementById('api-token').value = '';
                  statusMsg.innerHTML = 'הטוקן נמחק מהזיכרון';
                  setTimeout(() => statusMsg.innerHTML = '', 2000);
              }
          };
       
          fetchBtn.onclick = async function() {
              const fromDate = document.getElementById('from-date').value;
              const toDate = document.getElementById('to-date').value;
              const token = document.getElementById('api-token').value;
              
              if (!fromDate || !toDate || !token) { alert("נא להזין את כל הפרטים"); return; }
              localStorage.setItem('api_token_cached', token);
       
              statusMsg.innerHTML = '<span class="loading">טוען נתונים מהשרת, אנא המתן...</span>';
              const dates = getDatesRange(new Date(fromDate), new Date(toDate));
              const dataMap = {};
              hasEnterId = true; // איפוס הנחה
      
              try {
                  const results = await Promise.all(dates.map(date => 
                      fetch(`https://www.call2all.co.il/ym/api/RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogPlaybackPlayStop/LogPlaybackPlayStop.${date}.ymgr&convertType=csv&notLoadLang=1`)
                      .then(res => res.ok ? res.text() : null)
                      .catch(err => { console.error(`Error fetching date ${date}:`, err); return null; })
                  ));
                  
                  results.forEach(csv => { if(csv) processCsvSegment(csv, dataMap); });
                  finalizeData(dataMap);
              } catch (err) {
                  statusMsg.innerHTML = `<span class="error">שגיאה כללית בשליפת הנתונים: ${err.message}</span>`;
              }
          };
       
          function processCsvSegment(text, dataMap) {
              const rows = text.replace(/^\uFEFF/, "").trim().split(/\r?\n/).map(r => r.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/));
              if (rows.length < 2) return;
              const headers = rows[0].map(h => h.replace(/"/g, '').trim());
       
              // בדיקה אם קיים שדה EnterId
              if (!headers.includes("EnterId")) hasEnterId = false;
      
              for (let i = 1; i < rows.length; i++) {
                  let row = {};
                  headers.forEach((h, idx) => row[h] = (rows[i][idx] || "").replace(/"/g, '').trim());
                  if (!row["FileLength"] || row["FileLength"] === "0:0:0") continue;
       
                  const flenSec = timeToSeconds(row["FileLength"]);
                  const identityKey = hasEnterId ? row["EnterId"] : row["Phone"];
                  const key = `${identityKey}_${row["Folder"]}_${row["Current"]}_${row["FileLength"]}`;
                  
                  if (!dataMap[key]) dataMap[key] = { info: row, intervals: [], flenSec: flenSec };
       
                  let start = (parseInt(row["PositionPlay"]) || 0) / 1000;
                  let stop = (isNaN(parseInt(row["PositionStop"])) || parseInt(row["PositionStop"]) === -1) ? flenSec : parseInt(row["PositionStop"]) / 1000;
                  dataMap[key].intervals.push([start, stop]);
              }
          }
       
          function finalizeData(dataMap) {
              currentData = Object.values(dataMap).map(item => {
                  const netSec = mergeIntervals(item.intervals);
                  return {
                      ...item,
                      netSec: netSec,
                      percent: item.flenSec > 0 ? Math.min(100, Math.round((netSec / item.flenSec) * 100)) : 0
                  };
              });
              
              setupTableStructure(); // יצירת מבנה העמודות לפי סוג הקובץ
              populateSchoolDropdown();
              renderTable(currentData);
              
              if (currentData.length > 0) {
                  exportBtn.style.display = 'inline-block';
                  document.getElementById('results-table').style.display = 'table';
              } else {
                  statusMsg.innerHTML = '<span class="error">לא נמצאו נתונים לטווח התאריכים הנבחר.</span>';
              }
          }
      
          function setupTableStructure() {
              const headerRow = document.getElementById('header-row');
              const filterRow = document.getElementById('filter-row');
              
              if (hasEnterId) {
                  headerRow.innerHTML = `
                      <th onclick="sortTable(0)">כיתה ↕</th>
                      <th onclick="sortTable(1)">שם ות"ז ↕</th>
                      <th onclick="sortTable(2)">שלוחה ↕</th>
                      <th onclick="sortTable(3)">שם הקובץ ↕</th>
                      <th onclick="sortTable(4)">אורך קובץ ↕</th>
                      <th onclick="sortTable(5)">האזנה נטו ↕</th>
                      <th onclick="sortTable(6)">אחוז האזנה ↕</th>
                  `;
                  filterRow.innerHTML = `
                      <th><select id="filter-school" class="col-filter-action"><option value="">הכל</option></select></th>
                      <th><input type="text" id="filter-name" class="col-filter-action" placeholder="חיפוש..."></th>
                      <th><input type="text" id="filter-folder" class="col-filter-action" placeholder="סנן שלוחה..."></th>
                      <th><input type="text" id="filter-file" class="col-filter-action" placeholder="סנן קובץ..."></th>
                      <th></th><th></th>
                      <th>
                          <div class="filter-group" style="display:flex; gap:5px; align-items:center;">
                              <span style="font-size:11px">מעל</span>
                              <input type="number" id="filter-percent" class="col-filter-action" min="0" max="100" placeholder="0" style="width:50px">
                              <span style="font-size:11px">%</span>
                          </div>
                      </th>
                  `;
              } else {
                  headerRow.innerHTML = `
                      <th onclick="sortTable(1)">טלפון ↕</th>
                      <th onclick="sortTable(2)">שלוחה ↕</th>
                      <th onclick="sortTable(3)">שם הקובץ ↕</th>
                      <th onclick="sortTable(4)">אורך קובץ ↕</th>
                      <th onclick="sortTable(5)">האזנה נטו ↕</th>
                      <th onclick="sortTable(6)">אחוז האזנה ↕</th>
                  `;
                  filterRow.innerHTML = `
                      <th><input type="text" id="filter-name" class="col-filter-action" placeholder="חיפוש טלפון..."></th>
                      <th><input type="text" id="filter-folder" class="col-filter-action" placeholder="סנן שלוחה..."></th>
                      <th><input type="text" id="filter-file" class="col-filter-action" placeholder="סנן קובץ..."></th>
                      <th></th><th></th>
                      <th>
                          <div class="filter-group" style="display:flex; gap:5px; align-items:center;">
                              <span style="font-size:11px">מעל</span>
                              <input type="number" id="filter-percent" class="col-filter-action" min="0" max="100" placeholder="0" style="width:50px">
                              <span style="font-size:11px">%</span>
                          </div>
                      </th>
                  `;
              }
              document.querySelectorAll('.col-filter-action').forEach(el => { el.oninput = applyMultiFilter; });
          }
       
          function populateSchoolDropdown() {
              if (!hasEnterId) return;
              const schools = [...new Set(currentData.map(item => item.info.School || "-"))].sort();
              const select = document.getElementById('filter-school');
              if (select) {
                  select.innerHTML = '<option value="">הכל</option>';
                  schools.forEach(s => {
                      const opt = document.createElement('option');
                      opt.value = s; opt.textContent = s;
                      select.appendChild(opt);
                  });
              }
          }
       
          function renderTable(data) {
              const tbody = document.getElementById('table-body');
              let html = '';
              data.forEach(item => {
                  const color = item.percent > 80 ? 'bg-green' : (item.percent > 40 ? 'bg-orange' : 'bg-red');
                  
                  let identityCell = '';
                  if (hasEnterId) {
                      identityCell = `<td>${item.info.School || '-'}</td><td><strong>${item.info.ValName}</strong><small>${item.info.EnterId}</small></td>`;
                  } else {
                      identityCell = `<td><strong>${item.info.Phone}</strong></td>`;
                  }
      
                  html += `<tr>
                      ${identityCell}
                      <td>${item.info.Folder.replace(/\//g, '>')}</td>
                      <td>${item.info.Current}</td>
                      <td>${formatSeconds(item.flenSec)}</td>
                      <td>${formatSeconds(item.netSec)}</td>
                      <td>
                          <div class="progress-container">
                              <div class="progress-bar"><div class="progress-fill ${color}" style="width: ${item.percent}%"></div></div>
                              <span style="font-weight:bold; min-width:35px">${item.percent}%</span>
                          </div>
                      </td>
                  </tr>`;
              });
              tbody.innerHTML = html;
              applyMultiFilter();
          }
       
          function applyMultiFilter() {
              const fSchool = hasEnterId ? document.getElementById('filter-school').value.toLowerCase() : "";
              const fName = document.getElementById('filter-name').value.toLowerCase();
              const fFolder = document.getElementById('filter-folder').value.toLowerCase();
              const fFile = document.getElementById('filter-file').value.toLowerCase();
              const fMinPercent = parseInt(document.getElementById('filter-percent').value) || 0;
              const rows = document.querySelectorAll('#table-body tr');
              
              let count = 0;
              rows.forEach(row => {
                  let tSchool = "", tName = "", tFolder = "", tFile = "", tPercent = 0;
                  
                  if (hasEnterId) {
                      tSchool = row.cells[0].innerText.toLowerCase();
                      tName = row.cells[1].innerText.toLowerCase();
                      tFolder = row.cells[2].innerText.toLowerCase();
                      tFile = row.cells[3].innerText.toLowerCase();
                      tPercent = parseInt(row.cells[6].innerText);
                  } else {
                      tName = row.cells[0].innerText.toLowerCase();
                      tFolder = row.cells[1].innerText.toLowerCase();
                      tFile = row.cells[2].innerText.toLowerCase();
                      tPercent = parseInt(row.cells[5].innerText);
                  }
      
                  const match = (fSchool === "" || tSchool === fSchool) && (tName.includes(fName)) && (tFolder.includes(fFolder)) && (tFile.includes(fFile)) && (tPercent >= fMinPercent);
                  row.style.display = match ? '' : 'none';
                  if (match) count++;
              });
              statusMsg.innerHTML = `נמצאו: ${currentData.length} רשומות | לאחר סינון: ${count} רשומות`;
          }
       
          function sortTable(idx) {
              sortDirections[idx] = !sortDirections[idx];
              const dir = sortDirections[idx] ? 1 : -1;
              currentData.sort((a, b) => {
                  let v1, v2;
                  switch(idx) {
                      case 0: v1 = (a.info.School || "").toLowerCase(); v2 = (b.info.School || "").toLowerCase(); break;
                      case 1: v1 = (hasEnterId ? (a.info.ValName || "") : a.info.Phone).toLowerCase(); v2 = (hasEnterId ? (b.info.ValName || "") : b.info.Phone).toLowerCase(); break;
                      case 2: v1 = a.info.Folder.toLowerCase(); v2 = b.info.Folder.toLowerCase(); break;
                      case 3: v1 = a.info.Current.toLowerCase(); v2 = b.info.Current.toLowerCase(); break;
                      case 4: v1 = a.flenSec; v2 = b.flenSec; break;
                      case 5: v1 = a.netSec; v2 = b.netSec; break;
                      case 6: v1 = a.percent; v2 = b.percent; break;
                  }
                  return v1 < v2 ? -1 * dir : (v1 > v2 ? 1 * dir : 0);
              });
              renderTable(currentData);
          }
       
          function timeToSeconds(t){
              const p = t.trim().split(':').map(Number);
              return p.length === 3 ? p[0]*3600 + p[1]*60 + p[2] : (p.length === 2 ? p[0]*60 + p[1] : 0);
          }
          function formatSeconds(s){
              let h=Math.floor(s/3600), m=Math.floor((s%3600)/60), sec=Math.floor(s%60);
              return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}:${sec.toString().padStart(2,'0')}`;
          }
          function mergeIntervals(arr){
              if(!arr.length) return 0;
              arr.sort((a,b) => a[0]-b[0]);
              let total = 0, [start, end] = arr[0];
              for(let i=1; i<arr.length; i++){
                  if(arr[i][0] <= end) end = Math.max(end, arr[i][1]);
                  else { total += (end - start); [start, end] = arr[i]; }
              }
              return total + (end - start);
          }
          function getDatesRange(s,e){
              const d=[]; let c=new Date(s);
              while(c<=e){ d.push(c.toISOString().split('T')[0]); c.setDate(c.getDate()+1); }
              return d;
          }
       
          exportBtn.onclick = function() {
              const rows = document.querySelectorAll('#table-body tr');
              const exportedData = [];
              rows.forEach(row => {
                  if (row.style.display !== 'none') {
                      let obj = {};
                      if (hasEnterId) {
                          obj["כיתה"] = row.cells[0].innerText;
                          obj["שם תלמיד"] = row.cells[1].querySelector('strong').innerText;
                          obj["תעודת זהות"] = row.cells[1].querySelector('small').innerText;
                          obj["שלוחה"] = row.cells[2].innerText;
                          obj["שם הקובץ"] = row.cells[3].innerText;
                          obj["אורך קובץ"] = row.cells[4].innerText;
                          obj["האזנה נטו"] = row.cells[5].innerText;
                          obj["אחוז האזנה"] = row.cells[6].innerText.replace('%', '');
                      } else {
                          obj["טלפון"] = row.cells[0].innerText;
                          obj["שלוחה"] = row.cells[1].innerText;
                          obj["שם הקובץ"] = row.cells[2].innerText;
                          obj["אורך קובץ"] = row.cells[3].innerText;
                          obj["האזנה נטו"] = row.cells[4].innerText;
                          obj["אחוז האזנה"] = row.cells[5].innerText.replace('%', '');
                      }
                      exportedData.push(obj);
                  }
              });
              const ws = XLSX.utils.json_to_sheet(exportedData);
              const wb = XLSX.utils.book_new();
              XLSX.utils.book_append_sheet(wb, ws, "דוח האזנה");
              const ts = new Date().toISOString().replace('T', '_').replace(/[:.]/g, '-').slice(0, 19);
              XLSX.writeFile(wb, `דוח_האזנה_${ts}.xlsx`);
          };
      </script>
       
      </body>
      </html>
      

      תגובה 1 תגובה אחרונה תגובה ציטוט 3
      • ע על אוטומט התייחס לנושא זה
      • פוסט ראשון
        פוסט אחרון