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

    קבצים ותוכנות לשימוש במערכות ימות המשיח

    מתוזמן נעוץ נעול הועבר עזרה הדדית למשתמשים מתקדמים
    91 פוסטים 15 כותבים 2.2k צפיות 10 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • א מנותק
      אA @ezerphone
      נערך לאחרונה על ידי אA

      @ezerphone
      אתה עורך את הקודים מחדש או מעלה כמו שהם (בPHP כמובן)?

      תגובה 1 תגובה אחרונה תגובה ציטוט 0
      • א מנותק
        אA
        נערך לאחרונה על ידי

        קובץ לשינוי פרטי הקובץ בהשמעת קבצים

        הקובץ בzip
        שינוי-פרטי-קובץ.zip

        קרדיט: @cubase התותח!

        תגובה 1 תגובה אחרונה תגובה ציטוט 0
        • א מנותק
          אA
          נערך לאחרונה על ידי

          קובץ לפתיחת שלוחת טרוויה

          הקוד

          <!DOCTYPE html>
          <html lang="he" dir="rtl">
          <head>
              <meta charset="UTF-8">
              <title>מנהל טריוויה IVR2 - שליטה מלאה</title>
              <link href="https://fonts.googleapis.com/css2?family=Assistant:wght@400;700&family=Courier+Prime&display=swap" rel="stylesheet">
              <style>
                  :root { --primary: #1a73e8; --bg: #f8f9fa; --border: #dadce0; --log-bg: #1e1e1e; }
                  body { font-family: 'Assistant', sans-serif; background: var(--bg); margin: 0; padding: 10px; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
                  .app-wrapper { max-width: 1000px; margin: auto; background: white; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.1); display: flex; flex-direction: column; max-height: 95vh; width: 100%; }
                  .header { padding: 15px 25px; border-bottom: 2px solid #eee; display: flex; justify-content: space-between; align-items: center; }
                  .scroll-area { padding: 20px; overflow-y: auto; flex-grow: 1; }
                  .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 15px; }
                  .full { grid-column: span 3; }
                  .half { grid-column: span 1.5; }
                  .field { display: flex; flex-direction: column; }
                  label { font-weight: 700; font-size: 12px; margin-bottom: 4px; color: #555; }
                  input, select { padding: 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 13px; background: #fff; }
                  .btn { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; }
                  .btn-primary { background: var(--primary); color: white; }
                  .btn-success { background: #1e8e3e; color: white; width: 100%; margin-top: 15px; }
                  #log-area { background: var(--log-bg); color: #00ff00; font-family: 'Courier Prime', monospace; padding: 12px; height: 120px; overflow-y: auto; font-size: 12px; border-top: 4px solid #333; direction: ltr; text-align: left; }
                  .modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: 1000; justify-content: center; align-items: center; }
                  .modal-content { background: white; width: 90%; max-width: 800px; border-radius: 12px; padding: 25px; overflow-y: auto; max-height: 90vh; }
                  .section-title { grid-column: span 3; margin-top: 15px; padding: 6px 12px; background: #e8f0fe; color: #1a73e8; font-weight: bold; border-radius: 6px; font-size: 13px; border-right: 4px solid var(--primary); }
                  .hidden { display: none; }
              </style>
          </head>
          <body>
          
          <div class="app-wrapper">
              <div class="header">
                  <h2 style="margin:0; font-size: 1.2rem;">מנהל טריוויה IVR2 - הגדרות מלאות</h2>
                  <button id="add-btn" class="btn btn-primary hidden" onclick="openModal()">+ הוספת שאלה</button>
              </div>
          
              <div id="login-screen" class="scroll-area">
                  <div class="grid" style="grid-template-columns: 1fr 1fr;">
                      <div class="field"><label>מספר מערכת</label><input type="text" id="user"></div>
                      <div class="field"><label>סיסמה</label><input type="password" id="pass"></div>
                      <div class="field full"><label>נתיב שלוחה</label><input type="text" id="path" value="/1"></div>
                      <button class="btn btn-primary full" onclick="doLogin()">התחבר</button>
                  </div>
              </div>
          
              <div id="manage-screen" class="scroll-area hidden">
                  <div class="grid">
                      <div class="section-title">הגדרות ניקוד ונסיונות</div>
                      <div class="field"><label>ניקוד ניסיון 1 (points_1)</label><input type="text" id="trivia_questions_points_1" value="2"></div>
                      <div class="field"><label>ניקוד ניסיון 2 (points_2)</label><input type="text" id="trivia_questions_points_2" value="1"></div>
                      <div class="field"><label>ניסיון אחד בלבד?</label>
                          <select id="trivia_questions_only_once"><option value="no">לא</option><option value="yes">כן (yes)</option></select>
                      </div>
          
                      <div class="section-title">הגדרות השמעה וחשיפה</div>
                      <div class="field"><label>ללא חשיפת תשובה?</label>
                          <select id="trivia_questions_without_reveals_answer"><option value="no">לא</option><option value="yes">כן (yes)</option></select>
                      </div>
                      <div class="field"><label>סדר אקראי?</label>
                          <select id="trivia_questions_random"><option value="no">לא</option><option value="yes">כן (yes)</option></select>
                      </div>
                      <div class="field"><label>דילוג על הסבר?</label>
                          <select id="trivia_questions_no_explanation"><option value="no">לא</option><option value="yes">כן (yes)</option></select>
                      </div>
          
                      <div class="section-title">ניהול זמנים וסיום</div>
                      <div class="field"><label>זמן למענה (שניות)</label><input type="number" id="trivia_questions_time_to_answer" value="15"></div>
                      <div class="field"><label>כמות שאלות למשחק</label><input type="number" id="trivia_questions_total_questions" value="0"></div>
                      <div class="field"><label>סגירת השלוחה בסיום?</label>
                          <select id="trivia_questions_hangup_at_end"><option value="no">לא</option><option value="yes">כן (yes)</option></select>
                      </div>
          
                      <div class="section-title">הגדרות מתקדמות</div>
                      <div class="field"><label>השמעת ניקוד בסיום?</label>
                          <select id="trivia_questions_play_points_at_end"><option value="yes">כן</option><option value="no">לא</option></select>
                      </div>
                      <div class="field"><label>מניעת כפל משחקים?</label>
                          <select id="trivia_questions_once_a_day"><option value="no">לא</option><option value="yes">כן (פעם ביום)</option></select>
                      </div>
                      <div class="field"><label>הקלטת שם מאזין?</label>
                          <select id="trivia_questions_record_name"><option value="no">לא</option><option value="yes">כן</option></select>
                      </div>
                  </div>
              </div>
          
              <div id="log-area"><div style="color:#aaa">> המערכת מוכנה לסנכרון.</div></div>
          </div>
          
          <div id="qModal" class="modal">
              <div class="modal-content">
                  <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:15px; border-bottom:1px solid #eee; padding-bottom:10px;">
                      <h3 style="margin:0">הוספת שאלה (תיקייה)</h3>
                      <button class="btn" style="background:#eee" onclick="closeModal()">X</button>
                  </div>
                 
                  <div class="grid" style="grid-template-columns: 1fr 1fr;">
                      <div class="field full"><label>מספר תיקייה</label><input type="text" id="q_folder" placeholder="001"></div>
                      <div class="field full"><label>סוג השאלה</label>
                          <select id="ui_mode" onchange="updateUI()">
                              <option value="american">אמריקאי (Q, A, B, C, D)</option>
                              <option value="yes_no">נכון / לא נכון (q_yes / q_no)</option>
                          </select>
                      </div>
          
                      <div id="box-american" class="full grid" style="grid-template-columns: 1fr 1fr;">
                          <div class="field full"><label>שאלה (Q.wav)</label><input type="file" id="f_q"></div>
                          <div class="field"><label>נכונה (A.wav)</label><input type="file" id="f_a"></div>
                          <div class="field"><label>שגויה B</label><input type="file" id="f_b"></div>
                          <div class="field"><label>שגויה C</label><input type="file" id="f_c"></div>
                          <div class="field"><label>שגויה D</label><input type="file" id="f_d"></div>
                      </div>
          
                      <div id="box-yesno" class="full hidden grid" style="grid-template-columns: 1fr;">
                          <div class="field"><label>קובץ הקלטה</label><input type="file" id="f_yn"></div>
                          <div class="field"><label>התשובה הנכונה</label>
                              <select id="yn_val">
                                  <option value="q_yes">נכון (1)</option>
                                  <option value="q_no">לא נכון (0)</option>
                              </select>
                          </div>
                      </div>
                     
                      <button class="btn btn-success full" onclick="startUpload()">בצע סנכרון שלוחה ושאלה</button>
                  </div>
              </div>
          </div>
          
          <script>
              let token = '';
              const API = 'https://www.call2all.co.il/ym/api/';
          
              function addLog(m, e=false) {
                  const div = document.createElement('div');
                  if(e) div.style.color = '#ff5555';
                  div.innerText = `[${new Date().toLocaleTimeString()}] ${m}`;
                  document.getElementById('log-area').appendChild(div);
                  document.getElementById('log-area').scrollTop = document.getElementById('log-area').scrollHeight;
              }
          
              async function doLogin() {
                  const u = document.getElementById('user').value, p = document.getElementById('pass').value;
                  try {
                      const r = await fetch(`${API}Login?username=${u}&password=${p}`);
                      const d = await r.json();
                      if (d.responseStatus === 'OK') {
                          token = d.token;
                          addLog("חיבור הצליח.");
                          document.getElementById('login-screen').classList.add('hidden');
                          document.getElementById('manage-screen').classList.remove('hidden');
                          document.getElementById('add-btn').classList.remove('hidden');
                      } else { addLog(d.message, true); }
                  } catch (e) { addLog("שגיאת תקשורת/CORS", true); }
              }
          
              function updateUI() {
                  const mode = document.getElementById('ui_mode').value;
                  document.getElementById('box-american').className = (mode === 'american' ? 'full grid' : 'hidden');
                  document.getElementById('box-yesno').className = (mode === 'yes_no' ? 'full grid' : 'hidden');
              }
          
              async function startUpload() {
                  const folder = document.getElementById('q_folder').value, root = document.getElementById('path').value, mode = document.getElementById('ui_mode').value;
                  if(!folder) return alert("הזן תיקייה");
          
                  addLog(`בונה ext.ini עם כל ההגדרות...`);
          
                  // יצירת קובץ ה-ext.ini המלא עם כל מה שמופיע ב-Dashboard
                  let ini = `type=trivia_questions\n`;
                  const settings = [
                      'trivia_questions_points_1', 'trivia_questions_points_2', 'trivia_questions_only_once',
                      'trivia_questions_without_reveals_answer', 'trivia_questions_random', 'trivia_questions_no_explanation',
                      'trivia_questions_time_to_answer', 'trivia_questions_total_questions', 'trivia_questions_hangup_at_end',
                      'trivia_questions_play_points_at_end', 'trivia_questions_once_a_day', 'trivia_questions_record_name'
                  ];
          
                  settings.forEach(s => {
                      const val = document.getElementById(s).value;
                      if(val !== 'no' && val !== '0') ini += `${s}=${val}\n`;
                      else if(val === 'no' || val === '0') { /* אפשר להשאיר ריק או לכתוב no לפי הצורך */ }
                  });
          
                  await uploadFile(new Blob([ini], {type:'text/plain'}), root + "/ext.ini");
          
                  // העלאת קבצים
                  if(mode === 'american') {
                      const map = {'Q.wav': 'f_q', 'A.wav': 'f_a', 'B.wav': 'f_b', 'C.wav': 'f_c', 'D.wav': 'f_d'};
                      for(let [file, id] of Object.entries(map)) {
                          const b = document.getElementById(id).files[0];
                          if(b) await uploadFile(b, `${root}/${folder}/${file}`);
                      }
                  } else {
                      const b = document.getElementById('f_yn').files[0];
                      if(b) await uploadFile(b, `${root}/${folder}/${document.getElementById('yn_val').value}.wav`);
                  }
                  addLog(`סיום פעולה בתיקייה ${folder}.`);
                  closeModal();
              }
          
              async function uploadFile(blob, rawPath) {
                  const path = 'ivr2:' + (rawPath.startsWith('/') ? rawPath : '/' + rawPath);
                  const fd = new FormData();
                  fd.append('token', token); fd.append('path', path); fd.append('file', blob, path.split('/').pop());
                  try {
                      const r = await fetch(`${API}UploadFile`, {method: 'POST', body: fd});
                      const d = await r.json();
                      if(d.responseStatus === 'OK') addLog(`הועלה בהצלחה: ${path}`);
                  } catch(e) { addLog("שגיאת העלאה", true); }
              }
          
              function openModal() { document.getElementById('qModal').style.display = 'flex'; updateUI(); }
              function closeModal() { document.getElementById('qModal').style.display = 'none'; }
          </script>
          </body>
          </html>
          

          קרדיט:@אa

          תגובה 1 תגובה אחרונה תגובה ציטוט 0
          • א מנותק
            אA
            נערך לאחרונה על ידי

            קובץ לניתוח נתוני המערכת

            הקוד

            <!DOCTYPE html>
            <html lang="he" dir="rtl">
            <head>
                <meta charset="UTF-8">
                <title>ניתוח נתוני מערכות | v26.3</title>
                <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
                <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
                <style>
                    :root { --bg: #0f172a; --card: #1e293b; --primary: #38bdf8; --accent: #22c55e; --text: #f1f5f9; --border: #334155; --danger: #ef4444; --warning: #f59e0b; }
                    body { font-family: 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); margin: 0; display: flex; flex-direction: column; height: 100vh; }
                    header { background: #1e293b; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
                    .logo-box { display: flex; align-items: center; gap: 12px; }
                    .logo-icon { background: linear-gradient(135deg, var(--primary), #0ea5e9); color: #0f172a; width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; }
                    .logo-text { font-size: 1.4rem; font-weight: 800; color: var(--text); }
                    .config-box { display: flex; gap: 12px; align-items: center; }
                    input, select { background: #0f172a; border: 1px solid var(--border); color: white; padding: 10px; border-radius: 8px; outline: none; }
                    .btn-run { background: var(--primary); color: #0f172a; border: none; padding: 10px 25px; border-radius: 8px; font-weight: bold; cursor: pointer; transition: 0.3s; }
                    .nav-tabs { background: #1e293b; display: flex; padding: 0 20px; border-bottom: 1px solid var(--border); }
                    .tab { padding: 15px 25px; cursor: pointer; color: #94a3b8; border-bottom: 3px solid transparent; transition: 0.3s; }
                    .tab.active { color: var(--primary); border-bottom-color: var(--primary); background: rgba(56, 189, 248, 0.07); }
                    .main-content { flex: 1; padding: 25px; overflow-y: auto; background: #0f172a; }
                    .card { background: var(--card); padding: 25px; border-radius: 16px; border: 1px solid var(--border); margin-bottom: 25px; }
                    .stat-num { font-size: 2.5rem; font-weight: 800; color: var(--primary); }
                    .control-bar { display: flex; gap: 20px; align-items: center; background: #334155; padding: 15px 25px; border-radius: 12px 12px 0 0; }
                    .search-input { background: #0f172a; border: 1px solid var(--border); color: white; padding: 8px 15px; border-radius: 8px; width: 250px; }
                    table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 0 0 12px 12px; overflow: hidden; }
                    th { text-align: right; padding: 15px; background: #475569; color: white; font-size: 0.85rem; }
                    td { padding: 15px; border-bottom: 1px solid var(--border); font-size: 0.95rem; }
                    tr.clickable { cursor: pointer; }
                    tr.clickable:hover { background: rgba(56, 189, 248, 0.1); }
                    .bar-container { width: 100px; background: #0f172a; height: 10px; border-radius: 10px; display: inline-block; overflow: hidden; vertical-align: middle; margin-left: 8px; }
                    .bar-fill { height: 100%; background: var(--accent); }
                    .modal-overlay { position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.85); display: none; justify-content: center; align-items: center; z-index: 1000; }
                    .modal-content { background: var(--card); width: 85%; max-height: 85%; border-radius: 20px; border: 1px solid var(--primary); overflow-y: auto; padding: 30px; position: relative; }
                    .close-modal { position: absolute; top: 20px; left: 20px; color: white; font-size: 2rem; cursor: pointer; }
                    .progress-container { width: 100%; background: #1e293b; height: 6px; display: none; }
                    #progress-fill { height: 100%; background: var(--primary); width: 0%; transition: 0.4s; }
                    .hidden { display: none; }
                    .live-status { display: flex; align-items: center; gap: 6px; font-size: 0.75rem; padding: 4px 10px; border-radius: 20px; background: #334155; }
                    .dot { width: 8px; height: 8px; border-radius: 50%; background: #666; }
                    .dot.active { background: var(--accent); animation: pulse 2s infinite; }
                    @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
                </style>
            </head>
            <body>
            
            <header>
                <div class="logo-box">
                    <div class="logo-icon"><i class="fas fa-chart-pie"></i></div>
                    <div class="logo-text">ניתוח נתוני מערכות</div>
                    <div class="live-status"><div id="live-dot" class="dot"></div> <span id="live-text">OFFLINE</span></div>
                </div>
                <div class="config-box">
                    <input type="password" id="apiToken" placeholder="טוקן API">
                    <input type="date" id="startDate">
                    <input type="date" id="endDate">
                    <button class="btn-run" onclick="manualStart()">הפעל ניתוח</button>
                </div>
            </header>
            
            <div class="progress-container" id="progBar"><div id="progress-fill"></div></div>
            
            <div class="nav-tabs">
                <div class="tab active" onclick="switchTab(event, 'dash-tab')">דאשבורד</div>
                <div class="tab" onclick="switchTab(event, 'ext-tab')">שלוחות</div>
                <div class="tab" onclick="switchTab(event, 'play-tab')">השמעות</div>
                <div class="tab" onclick="switchTab(event, 'users-tab')">מאזינים</div>
                <div class="tab" style="color: var(--warning)" onclick="switchTab(event, 'debug-tab')">לוג</div>
            </div>
            
            <div class="main-content">
                <div id="dash-tab" class="tab-content">
                    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 25px; margin-bottom: 25px;">
                        <div class="card"><span style="color: #94a3b8">מאזינים ייחודיים</span><br><span id="stat-users" class="stat-num">0</span></div>
                        <div class="card"><span style="color: #94a3b8">סה"כ דקות האזנה</span><br><span id="stat-min" class="stat-num">0</span></div>
                        <div class="card"><span style="color: #94a3b8">שיחות שהושלמו (סוף קובץ)</span><br><span id="stat-comp" class="stat-num">0</span></div>
                    </div>
                    <div class="card"><h3>גרף פעילות יומי</h3><canvas id="dailyChart" height="100"></canvas></div>
                </div>
            
                <div id="ext-tab" class="tab-content hidden">
                    <div class="control-bar">
                        <select id="extSort" onchange="renderExts()"><option value="count">כמות כניסות</option><option value="sec">זמן שהייה</option></select>
                        <input type="text" id="extSearch" class="search-input" placeholder="חפש שלוחה..." onkeyup="renderExts()">
                    </div>
                    <table id="extTable"><thead><tr><th>שם השלוחה</th><th>כניסות</th><th>דקות שהייה</th><th>ממוצע</th></tr></thead><tbody></tbody></table>
                </div>
            
                <div id="play-tab" class="tab-content hidden">
                    <div class="control-bar">
                        <select id="playSort" onchange="renderPlays()"><option value="count">פופולריות</option><option value="pct">אחוז השלמה</option></select>
                        <input type="text" id="playSearch" class="search-input" placeholder="חפש קובץ..." onkeyup="renderPlays()">
                    </div>
                    <table id="playTable"><thead><tr><th>שם קובץ / שלוחה</th><th>השמעות</th><th>סה"כ דקות</th><th>אחוז השלמה</th><th>נטישה</th></tr></thead><tbody></tbody></table>
                </div>
            
                <div id="users-tab" class="tab-content hidden">
                    <div class="control-bar">
                        <select id="userSort" onchange="renderUsers()"><option value="sec">זמן האזנה כולל</option><option value="calls">מספר שיחות</option></select>
                        <input type="text" id="userSearch" class="search-input" placeholder="חפש טלפון..." onkeyup="renderUsers()">
                    </div>
                    <table id="usersTable"><thead><tr><th>מספר טלפון</th><th>דקות האזנה</th><th>מספר שיחות</th><th>סטטוס</th></tr></thead><tbody></tbody></table>
                </div>
            
                <div id="debug-tab" class="tab-content hidden"><div class="card"><div id="debug-console" style="background:#000; color:#22c55e; padding:20px; height:400px; overflow-y:auto; font-family:monospace;"></div></div></div>
            </div>
            
            <div id="userModal" class="modal-overlay" onclick="closeModal()">
                <div class="modal-content" onclick="event.stopPropagation()">
                    <span class="close-modal" onclick="closeModal()">&times;</span>
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                        <h2 id="modalTitle" style="color: var(--primary); margin:0;"></h2>
                        <select id="modalFilter" onchange="filterModalContent()" style="background: var(--bg); border: 1px solid var(--primary); padding: 5px 15px;">
                            <option value="all">הכל</option>
                            <option value="שלוחה">שלוחות בלבד</option>
                            <option value="השמעה">השמעות בלבד</option>
                        </select>
                    </div>
                    <table id="modalTable">
                        <thead>
                            <tr>
                                <th>סוג פעילות</th>
                                <th>שלוחה/קובץ</th>
                                <th>זמן שהייה</th>
                                <th>תאריך</th>
                            </tr>
                        </thead>
                        <tbody></tbody>
                    </table>
                </div>
            </div>
            
            <script>
                const API = "https://www.call2all.co.il/ym/api/";
                let dataStore = { exts: {}, plays: {}, users: {}, daily: {}, rawActivity: [], totalSec: 0, completed: 0 };
                let currentModalPhone = "";
                let dailyChart = null;
                let autoRefreshTimer = null;
            
                function addLog(msg, color = '#22c55e') {
                    const console = document.getElementById('debug-console');
                    if(!console) return;
                    const div = document.createElement('div');
                    div.style.color = color;
                    div.innerText = `[${new Date().toLocaleTimeString()}] ${msg}`;
                    console.appendChild(div);
                }
            
                function cleanExt(val) {
                    if (!val) return "ראשית";
                    let s = val.toString().trim().replace(/^\ufeff/, "");
                    if (s === "" || s === "/" || s === "." || s.toLowerCase() === "root" || s.toLowerCase() === "main") return "ראשית";
                    return s;
                }
            
                function parseSec(t) {
                    if (!t) return 0;
                    if (t.toString().includes(':')) {
                        const p = t.split(':').map(Number);
                        return p.length === 3 ? (p[0]*3600)+(p[1]*60)+p[2] : (p[0]*60)+p[1];
                    }
                    return parseInt(t) || 0;
                }
            
                async function manualStart() {
                    if(autoRefreshTimer) clearInterval(autoRefreshTimer);
                    await startFullAnalysis();
                    document.getElementById('live-dot').classList.add('active');
                    document.getElementById('live-text').innerText = "LIVE (עדכון אוטומטי)";
                    autoRefreshTimer = setInterval(startFullAnalysis, 60000); 
                }
            
                async function startFullAnalysis() {
                    const token = document.getElementById('apiToken').value;
                    const start = document.getElementById('startDate').value;
                    const end = document.getElementById('endDate').value;
                    if (!token) return alert("נא להזין טוקן API");
            
                    addLog("מתחיל סנכרון נתונים...");
                    dataStore = { exts: {}, plays: {}, users: {}, daily: {}, rawActivity: [], totalSec: 0, completed: 0 };
                    document.getElementById('progBar').style.display = 'block';
            
                    const monthStr = start.substring(0, 7); 
                    
                    try {
                        const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogFolderEnterExit-${monthStr}.ymgr&convertType=json`);
                        const json = await res.json();
                        if (json.data) {
                            json.data.forEach(row => {
                                const extName = cleanExt(row["שלוחה"]);
                                const phone = row["טלפון"] || "חסוי";
                                const sec = parseInt(row["סה\"כ שניות"]) || 0;
                                const date = row["תאריך"] || "";
                                const time = row["התחלה שעה"] || "";
                                
                                if (!dataStore.exts[extName]) dataStore.exts[extName] = { count: 0, sec: 0 };
                                dataStore.exts[extName].count++;
                                dataStore.exts[extName].sec += sec;
                                
                                dataStore.totalSec += sec;
                                if (!dataStore.users[phone]) dataStore.users[phone] = { sec: 0, calls: 0 };
                                dataStore.users[phone].sec += sec;
            
                                dataStore.rawActivity.push({ 
                                    phone, 
                                    type: 'שלוחה', 
                                    name: extName, 
                                    sec: sec + " ש'", 
                                    date: date + " " + time
                                });
                            });
                        }
                    } catch(e) { addLog("שגיאה בגישה לקובץ LogFolderEnterExit", "red"); }
            
                    let dates = [];
                    for(let d=new Date(start); d<=new Date(end); d.setDate(d.getDate()+1)) dates.push(new Date(d).toISOString().split('T')[0]);
            
                    for (let day of dates) {
                        updateProgress(dates.indexOf(day)+1, dates.length);
                        try {
                            const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogPlaybackPlayStop/LogPlaybackPlayStop.${day}.ymgr&convertType=json`);
                            const json = await res.json();
                            if (json.data) {
                                if (!dataStore.daily[day]) dataStore.daily[day] = 0;
                                json.data.forEach(row => {
                                    const file = row["השמעה"] || "לא ידוע";
                                    const phone = row["טלפון"] || "חסוי";
                                    const sec = parseInt(row["סה\"כ שניות"]) || 0;
                                    const len = parseSec(row["אורך הקובץ"]);
                                    const isEnd = row["נקודת יציאה"] === "סוף";
                                    
                                    dataStore.daily[day]++;
                                    dataStore.totalSec += sec;
                                    if (isEnd) dataStore.completed++;
            
                                    if (!dataStore.users[phone]) dataStore.users[phone] = { sec: 0, calls: 0 };
                                    dataStore.users[phone].sec += sec;
                                    dataStore.users[phone].calls++;
            
                                    if (!dataStore.plays[file]) dataStore.plays[file] = { count: 0, sec: 0, drops: 0, pcts: [] };
                                    dataStore.plays[file].count++;
                                    dataStore.plays[file].sec += sec;
                                    dataStore.plays[file].pcts.push(len > 0 ? Math.min(100, Math.round((sec/len)*100)) : 0);
                                    if (!isEnd) dataStore.plays[file].drops++;
            
                                    dataStore.rawActivity.push({ 
                                        phone, 
                                        type: 'השמעה', 
                                        name: file, 
                                        sec: sec + " ש'", 
                                        date: day + " " + (row["שעה"] || "") 
                                    });
                                });
                            }
                        } catch(e) {}
                    }
                    renderUI();
                }
            
                function renderUI() {
                    document.getElementById('progBar').style.display = 'none';
                    document.getElementById('stat-users').innerText = Object.keys(dataStore.users).length.toLocaleString();
                    document.getElementById('stat-min').innerText = Math.floor(dataStore.totalSec / 60).toLocaleString();
                    document.getElementById('stat-comp').innerText = dataStore.completed.toLocaleString();
                    renderExts(); renderPlays(); renderUsers(); updateChart();
                    addLog("הנתונים מעודכנים.");
                }
            
                function renderExts() {
                    const sort = document.getElementById('extSort').value;
                    const q = document.getElementById('extSearch').value.toLowerCase();
                    let items = Object.entries(dataStore.exts).map(([name, d]) => ({name, ...d})).filter(i => i.name.toLowerCase().includes(q));
                    items.sort((a,b) => b[sort] - a[sort]);
                    document.querySelector('#extTable tbody').innerHTML = items.map(i => `
                        <tr><td style="color:var(--primary); font-weight:600">${i.name}</td><td>${i.count}</td><td>${(i.sec/60).toFixed(1)}</td><td>${i.count ? Math.round(i.sec/i.count) : 0} ש'</td></tr>
                    `).join('');
                }
            
                function renderPlays() {
                    const sort = document.getElementById('playSort').value;
                    const q = document.getElementById('playSearch').value.toLowerCase();
                    let items = Object.entries(dataStore.plays).map(([name, d]) => {
                        const avg = d.pcts.length ? Math.round(d.pcts.reduce((a,b)=>a+b,0)/d.pcts.length) : 0;
                        const drop = Math.round((d.drops/d.count)*100);
                        return {name, avg, drop, ...d};
                    }).filter(i => i.name.toLowerCase().includes(q));
                    items.sort((a,b) => sort === 'count' ? b.count - a.count : b.avg - a.avg);
                    document.querySelector('#playTable tbody').innerHTML = items.map(i => `
                        <tr><td>${i.name}</td><td>${i.count}</td><td>${(i.sec/60).toFixed(1)}</td>
                        <td><div class="bar-container"><div class="bar-fill" style="width:${i.avg}%"></div></div> ${i.avg}%</td>
                        <td style="color:${i.drop > 50 ? 'var(--danger)' : 'var(--accent)'}">${i.drop}%</td></tr>
                    `).join('');
                }
            
                function renderUsers() {
                    const sortKey = document.getElementById('userSort').value;
                    const q = document.getElementById('userSearch').value;
                    let items = Object.entries(dataStore.users).map(([phone, d]) => ({phone, ...d})).filter(i => i.phone.includes(q));
                    items.sort((a,b) => b[sortKey] - a[sortKey]);
                    document.querySelector('#usersTable tbody').innerHTML = items.map((i, idx) => `
                        <tr class="clickable" onclick="openUserDetail('${i.phone}')">
                            <td style="font-weight:bold">${i.phone}</td>
                            <td style="color:var(--primary); font-weight:bold">${(i.sec/60).toFixed(1)}</td>
                            <td>${i.calls}</td>
                            <td>${idx < 3 ? '🏆 מוביל' : 'מאזין'}</td>
                        </tr>
                    `).join('');
                }
            
                function openUserDetail(phone) {
                    currentModalPhone = phone;
                    document.getElementById('modalTitle').innerText = `פירוט מאזין: ${phone}`;
                    document.getElementById('modalFilter').value = 'all';
                    filterModalContent();
                    document.getElementById('userModal').style.display = 'flex';
                }
            
                function filterModalContent() {
                    const filter = document.getElementById('modalFilter').value;
                    const activity = dataStore.rawActivity.filter(a => a.phone === currentModalPhone);
                    const filtered = filter === 'all' ? activity : activity.filter(a => a.type === filter);
            
                    document.querySelector('#modalTable tbody').innerHTML = filtered.map(a => `
                        <tr>
                            <td style="color:${a.type==='השמעה'?'var(--primary)':'var(--accent)'}; font-weight:bold">${a.type}</td>
                            <td>${a.name}</td>
                            <td>${a.sec}</td>
                            <td>${a.date}</td>
                        </tr>
                    `).join('');
                }
            
                function closeModal() { document.getElementById('userModal').style.display = 'none'; }
                function updateProgress(c, t) { document.getElementById('progress-fill').style.width = (c/t*100) + '%'; }
                function switchTab(e, id) {
                    document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden'));
                    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                    document.getElementById(id).classList.remove('hidden');
                    e.currentTarget.classList.add('active');
                }
                function updateChart() {
                    if (dailyChart) dailyChart.destroy();
                    const ctx = document.getElementById('dailyChart').getContext('2d');
                    dailyChart = new Chart(ctx, {
                        type: 'line',
                        data: { labels: Object.keys(dataStore.daily), datasets: [{ label: 'שיחות', data: Object.values(dataStore.daily), borderColor: '#38bdf8', tension: 0.4, fill: true, backgroundColor: 'rgba(56, 189, 248, 0.1)' }] },
                        options: { plugins: { legend: { display: false } } }
                    });
                }
                document.getElementById('startDate').value = document.getElementById('endDate').value = new Date().toISOString().split('T')[0];
            </script>
            </body>
            </html>
            

            קרדיט: @אa

            ב תגובה 1 תגובה אחרונה תגובה ציטוט 0
            • א מנותק
              אA
              נערך לאחרונה על ידי

              עידכון:
              השרשור עודכן בקבצים חדשים.
              כל הקבצים בפוסט הראשון.

              תגובה 1 תגובה אחרונה תגובה ציטוט 0
              • ב מנותק
                בוס @אA
                נערך לאחרונה על ידי

                @אA אולי כדאי שתפתח פוסט חדש במדריכים עם כל הקבצים, זה קצת איבד כאן את הרצף...
                תודה רבה על כל הפעילות.

                א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                • א מנותק
                  אA @בוס
                  נערך לאחרונה על ידי

                  @בוס
                  קיבלתי.

                  ב תגובה 1 תגובה אחרונה תגובה ציטוט 1
                  • ב מנותק
                    בוס @אA
                    נערך לאחרונה על ידי בוס

                    @אA את הקודים עצמם תשים בספוילר למניאת גלילה ארוכה ומיותרת, ואם יש שני גרסאות שימושיות של תוכנה כל שהיא אפשר להביא את שניהם ולציין זאת.

                    א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                    • א מנותק
                      אA @בוס
                      נערך לאחרונה על ידי

                      @בוס
                      לא עדיף בקוד להעתקה קלה?

                      ב תגובה 1 תגובה אחרונה תגובה ציטוט 0
                      • ב מנותק
                        בוס @אA
                        נערך לאחרונה על ידי בוס

                        @אA כן אבל בתוך סופוילר

                        ככה:

                        <!DOCTYPE html>
                        <html lang="he" dir="rtl">
                        <head>
                            <meta charset="UTF-8">
                            <title>ניתוח נתוני מערכות | v26.3</title>
                            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
                            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
                            <style>
                                :root { --bg: #0f172a; --card: #1e293b; --primary: #38bdf8; --accent: #22c55e; --text: #f1f5f9; --border: #334155; --danger: #ef4444; --warning: #f59e0b; }
                                body { font-family: 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); margin: 0; display: flex; flex-direction: column; height: 100vh; }
                                header { background: #1e293b; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
                                .logo-box { display: flex; align-items: center; gap: 12px; }
                                .logo-icon { background: linear-gradient(135deg, var(--primary), #0ea5e9); color: #0f172a; width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; }
                                .logo-text { font-size: 1.4rem; font-weight: 800; color: var(--text); }
                                .config-box { display: flex; gap: 12px; align-items: center; }
                                input, select { background: #0f172a; border: 1px solid var(--border); color: white; padding: 10px; border-radius: 8px; outline: none; }
                                .btn-run { background: var(--primary); color: #0f172a; border: none; padding: 10px 25px; border-radius: 8px; font-weight: bold; cursor: pointer; transition: 0.3s; }
                                .nav-tabs { background: #1e293b; display: flex; padding: 0 20px; border-bottom: 1px solid var(--border); }
                                .tab { padding: 15px 25px; cursor: pointer; color: #94a3b8; border-bottom: 3px solid transparent; transition: 0.3s; }
                                .tab.active { color: var(--primary); border-bottom-color: var(--primary); background: rgba(56, 189, 248, 0.07); }
                                .main-content { flex: 1; padding: 25px; overflow-y: auto; background: #0f172a; }
                                .card { background: var(--card); padding: 25px; border-radius: 16px; border: 1px solid var(--border); margin-bottom: 25px; }
                                .stat-num { font-size: 2.5rem; font-weight: 800; color: var(--primary); }
                                .control-bar { display: flex; gap: 20px; align-items: center; background: #334155; padding: 15px 25px; border-radius: 12px 12px 0 0; }
                                .search-input { background: #0f172a; border: 1px solid var(--border); color: white; padding: 8px 15px; border-radius: 8px; width: 250px; }
                                table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 0 0 12px 12px; overflow: hidden; }
                                th { text-align: right; padding: 15px; background: #475569; color: white; font-size: 0.85rem; }
                                td { padding: 15px; border-bottom: 1px solid var(--border); font-size: 0.95rem; }
                                tr.clickable { cursor: pointer; }
                                tr.clickable:hover { background: rgba(56, 189, 248, 0.1); }
                                .bar-container { width: 100px; background: #0f172a; height: 10px; border-radius: 10px; display: inline-block; overflow: hidden; vertical-align: middle; margin-left: 8px; }
                                .bar-fill { height: 100%; background: var(--accent); }
                                .modal-overlay { position: fixed; top:0; left:0; width:100%; height:100%; background: rgba(0,0,0,0.85); display: none; justify-content: center; align-items: center; z-index: 1000; }
                                .modal-content { background: var(--card); width: 85%; max-height: 85%; border-radius: 20px; border: 1px solid var(--primary); overflow-y: auto; padding: 30px; position: relative; }
                                .close-modal { position: absolute; top: 20px; left: 20px; color: white; font-size: 2rem; cursor: pointer; }
                                .progress-container { width: 100%; background: #1e293b; height: 6px; display: none; }
                                #progress-fill { height: 100%; background: var(--primary); width: 0%; transition: 0.4s; }
                                .hidden { display: none; }
                                .live-status { display: flex; align-items: center; gap: 6px; font-size: 0.75rem; padding: 4px 10px; border-radius: 20px; background: #334155; }
                                .dot { width: 8px; height: 8px; border-radius: 50%; background: #666; }
                                .dot.active { background: var(--accent); animation: pulse 2s infinite; }
                                @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
                            </style>
                        </head>
                        <body>
                         
                        <header>
                            <div class="logo-box">
                                <div class="logo-icon"><i class="fas fa-chart-pie"></i></div>
                                <div class="logo-text">ניתוח נתוני מערכות</div>
                                <div class="live-status"><div id="live-dot" class="dot"></div> <span id="live-text">OFFLINE</span></div>
                            </div>
                            <div class="config-box">
                                <input type="password" id="apiToken" placeholder="טוקן API">
                                <input type="date" id="startDate">
                                <input type="date" id="endDate">
                                <button class="btn-run" onclick="manualStart()">הפעל ניתוח</button>
                            </div>
                        </header>
                         
                        <div class="progress-container" id="progBar"><div id="progress-fill"></div></div>
                         
                        <div class="nav-tabs">
                            <div class="tab active" onclick="switchTab(event, 'dash-tab')">דאשבורד</div>
                            <div class="tab" onclick="switchTab(event, 'ext-tab')">שלוחות</div>
                            <div class="tab" onclick="switchTab(event, 'play-tab')">השמעות</div>
                            <div class="tab" onclick="switchTab(event, 'users-tab')">מאזינים</div>
                            <div class="tab" style="color: var(--warning)" onclick="switchTab(event, 'debug-tab')">לוג</div>
                        </div>
                         
                        <div class="main-content">
                            <div id="dash-tab" class="tab-content">
                                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 25px; margin-bottom: 25px;">
                                    <div class="card"><span style="color: #94a3b8">מאזינים ייחודיים</span><br><span id="stat-users" class="stat-num">0</span></div>
                                    <div class="card"><span style="color: #94a3b8">סה"כ דקות האזנה</span><br><span id="stat-min" class="stat-num">0</span></div>
                                    <div class="card"><span style="color: #94a3b8">שיחות שהושלמו (סוף קובץ)</span><br><span id="stat-comp" class="stat-num">0</span></div>
                                </div>
                                <div class="card"><h3>גרף פעילות יומי</h3><canvas id="dailyChart" height="100"></canvas></div>
                            </div>
                         
                            <div id="ext-tab" class="tab-content hidden">
                                <div class="control-bar">
                                    <select id="extSort" onchange="renderExts()"><option value="count">כמות כניסות</option><option value="sec">זמן שהייה</option></select>
                                    <input type="text" id="extSearch" class="search-input" placeholder="חפש שלוחה..." onkeyup="renderExts()">
                                </div>
                                <table id="extTable"><thead><tr><th>שם השלוחה</th><th>כניסות</th><th>דקות שהייה</th><th>ממוצע</th></tr></thead><tbody></tbody></table>
                            </div>
                         
                            <div id="play-tab" class="tab-content hidden">
                                <div class="control-bar">
                                    <select id="playSort" onchange="renderPlays()"><option value="count">פופולריות</option><option value="pct">אחוז השלמה</option></select>
                                    <input type="text" id="playSearch" class="search-input" placeholder="חפש קובץ..." onkeyup="renderPlays()">
                                </div>
                                <table id="playTable"><thead><tr><th>שם קובץ / שלוחה</th><th>השמעות</th><th>סה"כ דקות</th><th>אחוז השלמה</th><th>נטישה</th></tr></thead><tbody></tbody></table>
                            </div>
                         
                            <div id="users-tab" class="tab-content hidden">
                                <div class="control-bar">
                                    <select id="userSort" onchange="renderUsers()"><option value="sec">זמן האזנה כולל</option><option value="calls">מספר שיחות</option></select>
                                    <input type="text" id="userSearch" class="search-input" placeholder="חפש טלפון..." onkeyup="renderUsers()">
                                </div>
                                <table id="usersTable"><thead><tr><th>מספר טלפון</th><th>דקות האזנה</th><th>מספר שיחות</th><th>סטטוס</th></tr></thead><tbody></tbody></table>
                            </div>
                         
                            <div id="debug-tab" class="tab-content hidden"><div class="card"><div id="debug-console" style="background:#000; color:#22c55e; padding:20px; height:400px; overflow-y:auto; font-family:monospace;"></div></div></div>
                        </div>
                         
                        <div id="userModal" class="modal-overlay" onclick="closeModal()">
                            <div class="modal-content" onclick="event.stopPropagation()">
                                <span class="close-modal" onclick="closeModal()">&times;</span>
                                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
                                    <h2 id="modalTitle" style="color: var(--primary); margin:0;"></h2>
                                    <select id="modalFilter" onchange="filterModalContent()" style="background: var(--bg); border: 1px solid var(--primary); padding: 5px 15px;">
                                        <option value="all">הכל</option>
                                        <option value="שלוחה">שלוחות בלבד</option>
                                        <option value="השמעה">השמעות בלבד</option>
                                    </select>
                                </div>
                                <table id="modalTable">
                                    <thead>
                                        <tr>
                                            <th>סוג פעילות</th>
                                            <th>שלוחה/קובץ</th>
                                            <th>זמן שהייה</th>
                                            <th>תאריך</th>
                                        </tr>
                                    </thead>
                                    <tbody></tbody>
                                </table>
                            </div>
                        </div>
                         
                        <script>
                            const API = "https://www.call2all.co.il/ym/api/";
                            let dataStore = { exts: {}, plays: {}, users: {}, daily: {}, rawActivity: [], totalSec: 0, completed: 0 };
                            let currentModalPhone = "";
                            let dailyChart = null;
                            let autoRefreshTimer = null;
                         
                            function addLog(msg, color = '#22c55e') {
                                const console = document.getElementById('debug-console');
                                if(!console) return;
                                const div = document.createElement('div');
                                div.style.color = color;
                                div.innerText = `[${new Date().toLocaleTimeString()}] ${msg}`;
                                console.appendChild(div);
                            }
                         
                            function cleanExt(val) {
                                if (!val) return "ראשית";
                                let s = val.toString().trim().replace(/^\ufeff/, "");
                                if (s === "" || s === "/" || s === "." || s.toLowerCase() === "root" || s.toLowerCase() === "main") return "ראשית";
                                return s;
                            }
                         
                            function parseSec(t) {
                                if (!t) return 0;
                                if (t.toString().includes(':')) {
                                    const p = t.split(':').map(Number);
                                    return p.length === 3 ? (p[0]*3600)+(p[1]*60)+p[2] : (p[0]*60)+p[1];
                                }
                                return parseInt(t) || 0;
                            }
                         
                            async function manualStart() {
                                if(autoRefreshTimer) clearInterval(autoRefreshTimer);
                                await startFullAnalysis();
                                document.getElementById('live-dot').classList.add('active');
                                document.getElementById('live-text').innerText = "LIVE (עדכון אוטומטי)";
                                autoRefreshTimer = setInterval(startFullAnalysis, 60000); 
                            }
                         
                            async function startFullAnalysis() {
                                const token = document.getElementById('apiToken').value;
                                const start = document.getElementById('startDate').value;
                                const end = document.getElementById('endDate').value;
                                if (!token) return alert("נא להזין טוקן API");
                         
                                addLog("מתחיל סנכרון נתונים...");
                                dataStore = { exts: {}, plays: {}, users: {}, daily: {}, rawActivity: [], totalSec: 0, completed: 0 };
                                document.getElementById('progBar').style.display = 'block';
                         
                                const monthStr = start.substring(0, 7); 
                                
                                try {
                                    const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogFolderEnterExit-${monthStr}.ymgr&convertType=json`);
                                    const json = await res.json();
                                    if (json.data) {
                                        json.data.forEach(row => {
                                            const extName = cleanExt(row["שלוחה"]);
                                            const phone = row["טלפון"] || "חסוי";
                                            const sec = parseInt(row["סה\"כ שניות"]) || 0;
                                            const date = row["תאריך"] || "";
                                            const time = row["התחלה שעה"] || "";
                                            
                                            if (!dataStore.exts[extName]) dataStore.exts[extName] = { count: 0, sec: 0 };
                                            dataStore.exts[extName].count++;
                                            dataStore.exts[extName].sec += sec;
                                            
                                            dataStore.totalSec += sec;
                                            if (!dataStore.users[phone]) dataStore.users[phone] = { sec: 0, calls: 0 };
                                            dataStore.users[phone].sec += sec;
                         
                                            dataStore.rawActivity.push({ 
                                                phone, 
                                                type: 'שלוחה', 
                                                name: extName, 
                                                sec: sec + " ש'", 
                                                date: date + " " + time
                                            });
                                        });
                                    }
                                } catch(e) { addLog("שגיאה בגישה לקובץ LogFolderEnterExit", "red"); }
                         
                                let dates = [];
                                for(let d=new Date(start); d<=new Date(end); d.setDate(d.getDate()+1)) dates.push(new Date(d).toISOString().split('T')[0]);
                         
                                for (let day of dates) {
                                    updateProgress(dates.indexOf(day)+1, dates.length);
                                    try {
                                        const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogPlaybackPlayStop/LogPlaybackPlayStop.${day}.ymgr&convertType=json`);
                                        const json = await res.json();
                                        if (json.data) {
                                            if (!dataStore.daily[day]) dataStore.daily[day] = 0;
                                            json.data.forEach(row => {
                                                const file = row["השמעה"] || "לא ידוע";
                                                const phone = row["טלפון"] || "חסוי";
                                                const sec = parseInt(row["סה\"כ שניות"]) || 0;
                                                const len = parseSec(row["אורך הקובץ"]);
                                                const isEnd = row["נקודת יציאה"] === "סוף";
                                                
                                                dataStore.daily[day]++;
                                                dataStore.totalSec += sec;
                                                if (isEnd) dataStore.completed++;
                         
                                                if (!dataStore.users[phone]) dataStore.users[phone] = { sec: 0, calls: 0 };
                                                dataStore.users[phone].sec += sec;
                                                dataStore.users[phone].calls++;
                         
                                                if (!dataStore.plays[file]) dataStore.plays[file] = { count: 0, sec: 0, drops: 0, pcts: [] };
                                                dataStore.plays[file].count++;
                                                dataStore.plays[file].sec += sec;
                                                dataStore.plays[file].pcts.push(len > 0 ? Math.min(100, Math.round((sec/len)*100)) : 0);
                                                if (!isEnd) dataStore.plays[file].drops++;
                         
                                                dataStore.rawActivity.push({ 
                                                    phone, 
                                                    type: 'השמעה', 
                                                    name: file, 
                                                    sec: sec + " ש'", 
                                                    date: day + " " + (row["שעה"] || "") 
                                                });
                                            });
                                        }
                                    } catch(e) {}
                                }
                                renderUI();
                            }
                         
                            function renderUI() {
                                document.getElementById('progBar').style.display = 'none';
                                document.getElementById('stat-users').innerText = Object.keys(dataStore.users).length.toLocaleString();
                                document.getElementById('stat-min').innerText = Math.floor(dataStore.totalSec / 60).toLocaleString();
                                document.getElementById('stat-comp').innerText = dataStore.completed.toLocaleString();
                                renderExts(); renderPlays(); renderUsers(); updateChart();
                                addLog("הנתונים מעודכנים.");
                            }
                         
                            function renderExts() {
                                const sort = document.getElementById('extSort').value;
                                const q = document.getElementById('extSearch').value.toLowerCase();
                                let items = Object.entries(dataStore.exts).map(([name, d]) => ({name, ...d})).filter(i => i.name.toLowerCase().includes(q));
                                items.sort((a,b) => b[sort] - a[sort]);
                                document.querySelector('#extTable tbody').innerHTML = items.map(i => `
                                    <tr><td style="color:var(--primary); font-weight:600">${i.name}</td><td>${i.count}</td><td>${(i.sec/60).toFixed(1)}</td><td>${i.count ? Math.round(i.sec/i.count) : 0} ש'</td></tr>
                                `).join('');
                            }
                         
                            function renderPlays() {
                                const sort = document.getElementById('playSort').value;
                                const q = document.getElementById('playSearch').value.toLowerCase();
                                let items = Object.entries(dataStore.plays).map(([name, d]) => {
                                    const avg = d.pcts.length ? Math.round(d.pcts.reduce((a,b)=>a+b,0)/d.pcts.length) : 0;
                                    const drop = Math.round((d.drops/d.count)*100);
                                    return {name, avg, drop, ...d};
                                }).filter(i => i.name.toLowerCase().includes(q));
                                items.sort((a,b) => sort === 'count' ? b.count - a.count : b.avg - a.avg);
                                document.querySelector('#playTable tbody').innerHTML = items.map(i => `
                                    <tr><td>${i.name}</td><td>${i.count}</td><td>${(i.sec/60).toFixed(1)}</td>
                                    <td><div class="bar-container"><div class="bar-fill" style="width:${i.avg}%"></div></div> ${i.avg}%</td>
                                    <td style="color:${i.drop > 50 ? 'var(--danger)' : 'var(--accent)'}">${i.drop}%</td></tr>
                                `).join('');
                            }
                         
                            function renderUsers() {
                                const sortKey = document.getElementById('userSort').value;
                                const q = document.getElementById('userSearch').value;
                                let items = Object.entries(dataStore.users).map(([phone, d]) => ({phone, ...d})).filter(i => i.phone.includes(q));
                                items.sort((a,b) => b[sortKey] - a[sortKey]);
                                document.querySelector('#usersTable tbody').innerHTML = items.map((i, idx) => `
                                    <tr class="clickable" onclick="openUserDetail('${i.phone}')">
                                        <td style="font-weight:bold">${i.phone}</td>
                                        <td style="color:var(--primary); font-weight:bold">${(i.sec/60).toFixed(1)}</td>
                                        <td>${i.calls}</td>
                                        <td>${idx < 3 ? '🏆 מוביל' : 'מאזין'}</td>
                                    </tr>
                                `).join('');
                            }
                         
                            function openUserDetail(phone) {
                                currentModalPhone = phone;
                                document.getElementById('modalTitle').innerText = `פירוט מאזין: ${phone}`;
                                document.getElementById('modalFilter').value = 'all';
                                filterModalContent();
                                document.getElementById('userModal').style.display = 'flex';
                            }
                         
                            function filterModalContent() {
                                const filter = document.getElementById('modalFilter').value;
                                const activity = dataStore.rawActivity.filter(a => a.phone === currentModalPhone);
                                const filtered = filter === 'all' ? activity : activity.filter(a => a.type === filter);
                         
                                document.querySelector('#modalTable tbody').innerHTML = filtered.map(a => `
                                    <tr>
                                        <td style="color:${a.type==='השמעה'?'var(--primary)':'var(--accent)'}; font-weight:bold">${a.type}</td>
                                        <td>${a.name}</td>
                                        <td>${a.sec}</td>
                                        <td>${a.date}</td>
                                    </tr>
                                `).join('');
                            }
                         
                            function closeModal() { document.getElementById('userModal').style.display = 'none'; }
                            function updateProgress(c, t) { document.getElementById('progress-fill').style.width = (c/t*100) + '%'; }
                            function switchTab(e, id) {
                                document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden'));
                                document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                                document.getElementById(id).classList.remove('hidden');
                                e.currentTarget.classList.add('active');
                            }
                            function updateChart() {
                                if (dailyChart) dailyChart.destroy();
                                const ctx = document.getElementById('dailyChart').getContext('2d');
                                dailyChart = new Chart(ctx, {
                                    type: 'line',
                                    data: { labels: Object.keys(dataStore.daily), datasets: [{ label: 'שיחות', data: Object.values(dataStore.daily), borderColor: '#38bdf8', tension: 0.4, fill: true, backgroundColor: 'rgba(56, 189, 248, 0.1)' }] },
                                    options: { plugins: { legend: { display: false } } }
                                });
                            }
                            document.getElementById('startDate').value = document.getElementById('endDate').value = new Date().toISOString().split('T')[0];
                        </script>
                        </body>
                        </html>
                        

                        ובשרשור הזה תשנה את הכותרת ל"תגובות על..."

                        א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                        • א מנותק
                          אA @בוס
                          נערך לאחרונה על ידי

                          @בוס

                          גם לך קופץ כל הזמ שהפורום התעדכן לגירסא האחרונה?

                          ב תגובה 1 תגובה אחרונה תגובה ציטוט 0
                          • ב מנותק
                            בוס @אA
                            נערך לאחרונה על ידי

                            @אA

                            קפץ פעם אחת, בפועל לא התשנה משהו הנראה לעין.

                            א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                            • א מנותק
                              אA @בוס
                              נערך לאחרונה על ידי

                              @בוס

                              לי כבר קפץ פעמיים, אבל גם בלי שינוי נראה...

                              ב תגובה 1 תגובה אחרונה תגובה ציטוט 0
                              • ב מנותק
                                בוס @אA
                                נערך לאחרונה על ידי בוס

                                @אA

                                תיכף אחד מ"חכמי" הפורום יפתח ע"ז שרשור שלם...

                                רק לי קפץ התראה על שינוי הפורום...

                                וכמובן איך אפשק לשכוח, תמונה.

                                267358c1-7e2f-43b6-a8b7-caba2e9b6a8e-image.png

                                תגובה 1 תגובה אחרונה תגובה ציטוט 0
                                • פוסט ראשון
                                  פוסט אחרון