קטגוריות

  • כל סוגי ההגדרות הניתנות להטמעה "בהגדרות מתקדמות" במערכת שלכם

    167 נושאים
    503 פוסטים
    ש
    הגדרות מקשי נציג בתור (DialKey) מערכת מקשי הנציג מאפשרת להגדיר פעולות שהנציג יכול לבצע תוך כדי שיחה עם לקוח. את ההגדרות יש לשים בקובץ ext.ini של שלוחת התור. טבלת הגדרות הגדרה ברירת מחדל תיאור dial_key_direct_press ריק (=no) yes = מקש ישיר ללא קידומת. ללא הגדרה — חייב קידומת לפני. dial_key_prefix # תו הקידומת — הנציג מקיש קודם את הקידומת ואז את הרצף. dial_key_seq ריק רצפי מקשים מותאמים. פורמט: ACTION=KEYS.ACTION=KEYS — מפריד נקודה (.). dial_key_seq_max_digits 2 מספר ספרות מקסימלי לקרוא אחרי המקש הראשון / קידומת. dial_key_return_to_call ** רצף מקשים לחזרה לשיחה מהמתנה. none = מבטל. dial_key_spy_and_talk #* רצף מקשים להאזנה + דיבור עם הלקוח. none = מבטל. dial_key_0 עד dial_key_9 ריק פעולה ישירה לספרה בודדת. dial_key_star ריק פעולה ישירה למקש *. dial_key_hash ריק פעולה ישירה למקש #. פעולות אפשריות פעולה תיאור דוגמה בהגדרה הערות hold העברת הלקוח להמתנה — הנציג עובר למצב המתנה ויכול לחזור עם dial_key_return_to_call. dial_key_5=hold return_to_call חזרה לשיחה עם הלקוח מהמתנה. dial_key_**=return_to_call spy_and_talk האזנה לשיחת הלקוח (ערוץ 3) + אפשרות דיבור (whisper/barge). dial_key_spy_and_talk=99 menu_move_client פתיחת תפריט אינטראקטיבי — הנציג בוחר שלוחה/תיקייה להעביר אליה את הלקוח. dial_key_3=menu_move_client move_client_to_folder-/FOLDER הזזת הלקוח לשלוחה/תיקייה מוגדרת מראש ללא תפריט. המערכת בודקת שהשלוחה קיימת. dial_key_seq=33=move_client_to_folder-/6 menu_routing_client פתיחת תפריט אינטראקטיבי — הנציג מקליד מספר טלפון לחייג עבור הלקוח. dial_key_4=menu_routing_client routing_client_to_number-XXXXX חיוג למספר מוגדר מראש עבור הלקוח ללא תפריט. תומך מספרים מקוצרים מקובץ DialKeyAbbreviatedDialing.ini. dial_key_seq=55=routing_client_to_number-0501234567 שימו לב! השימוש באפשרות זו כרוך בעלות יחידות כיצד זה עובד מצב קידומת (ברירת מחדל) הנציג מקיש קידומת (ברירת מחדל #) ואז את הרצף: #1 = קידומת # + מקש 1 #22 = קידומת # + רצף 22 מצב ישיר (dial_key_direct_press=yes) הנציג מקיש ישירות את הרצף בלי קידומת: 22 = הנציג מקיש 2, 2 — המערכת מזהה את הרצף *1 = הנציג מקיש *, 1 סדר עדיפויות מקש בודד — dial_key_5=hold רצף מותאם — dial_key_seq=22=hold Fallback — במידה ולא מוגדר, יתעלם מההקשה הנוספת ויתחשב במקש הראשון בלבד (כלומר מתעלם מהמקש השני וכו'). מקשים מובנים ברירת מחדל — return_to_call / spy_and_talk אחרי שנייה ללא הקשה (TIMEOUT) המערכת מסיימת לקרוא ומעבדת את מה שנאסף. אם הנציג מקיש פחות ספרות מהמקסימום — ה-TIMEOUT מסיים את הקלט. דוגמאות דוגמה 1 — מצב בסיסי: מקש בודד עם קידומת dial_key_5=hold dial_key_star=return_to_call נציג מקיש #5 ← השהיה נציג מקיש #* ← חזרה לשיחה נציג מקיש ** ← חזרה לשיחה (ברירת מחדל) דוגמה 2 — מצב ישיר + מקשים בודדים dial_key_direct_press=yes dial_key_5=hold dial_key_star=return_to_call נציג מקיש 5 ← השהיה נציג מקיש * ← חזרה לשיחה נציג מקיש ** ← חזרה לשיחה (ברירת מחדל) דוגמה 3 — רצפים קצרים עם קידומת dial_key_prefix=# dial_key_seq_max_digits=2 dial_key_seq=11=hold.22=return_to_call dial_key_return_to_call=none dial_key_spy_and_talk=none נציג מקיש #11 ← השהיה נציג מקיש #22 ← חזרה לשיחה נציג מקיש ** ← לא עובד (בוטל עם none) דוגמה 4 — רצפים ישירים עם תיקיות + חיוג dial_key_direct_press=yes dial_key_seq_max_digits=3 dial_key_seq=11=hold.22=return_to_call.33=move_client_to_folder-/6.44=menu_move_client.55=routing_client_to_number-0501234567.66=menu_routing_client dial_key_return_to_call=none dial_key_spy_and_talk=99 נציג מקיש 11 ← השהיה נציג מקיש 22 ← חזרה לשיחה נציג מקיש 33 ← הזזה לתיקייה 6 נציג מקיש 44 ← תפריט בחירת שלוחה נציג מקיש 55 ← חיוג ל-0501234567 נציג מקיש 66 ← תפריט הקלדת מספר נציג מקיש 99 ← האזנה + דיבור דוגמה 5 — רצף ארוך עם # באמצע dial_key_direct_press=yes dial_key_seq_max_digits=11 dial_key_seq=234*1*45#57=hold dial_key_return_to_call=## dial_key_spy_and_talk=none נציג מקיש 234*1*45#57 ← השהיה נציג מקיש ## ← חזרה לשיחה דוגמה 6 — קידומת * במקום # dial_key_prefix=* dial_key_seq_max_digits=2 dial_key_seq=1=hold.2=return_to_call dial_key_return_to_call=none dial_key_spy_and_talk=none נציג מקיש *1 ← השהיה נציג מקיש *2 ← חזרה לשיחה דוגמה 7 — שילוב מקשים בודדים + רצפים dial_key_direct_press=yes dial_key_5=hold dial_key_3=menu_move_client dial_key_4=menu_routing_client dial_key_seq_max_digits=3 dial_key_seq=123=move_client_to_folder-/6.456=routing_client_to_number-0501234567 dial_key_spy_and_talk=none נציג מקיש 5 ← השהיה (מקש בודד, עדיפות גבוהה) נציג מקיש 3 ← תפריט בחירת שלוחה נציג מקיש 4 ← תפריט הקלדת מספר נציג מקיש 123 ← הזזה לתיקייה 6 נציג מקיש 456 ← חיוג ל-0501234567 נציג מקיש ** ← חזרה לשיחה (ברירת מחדל) הערות חשובות מפריד בין רצפים ב-dial_key_seq — הוא נקודה (.) none מבטל ברירת מחדל — dial_key_return_to_call=none מבטל את **, ו-dial_key_spy_and_talk=none מבטל את #* dial_key_seq_max_digits — חובה להגדיר כשהרצף ארוך מ-2 תווים (למשל רצף 123 דורש לפחות 3) אפשר להשתמש בפחות מהמקסימום — אם מוגדר מקסימום 11, הנציג יכול להקיש 2 ספרות ולחכות שנייה; ה-TIMEOUT מסיים את הקלט מספרים מקוצרים — בפעולת routing_client_to_number אפשר להשתמש במספר מקוצר מתוך קובץ DialKeyAbbreviatedDialing.ini בתיקיית השלוחה או בשורש
  • 5 נושאים
    5 פוסטים
    E
    הרשאת שימוש בעיוות קול.pdf
  • 7k נושאים
    57k פוסטים
    C
    @פלפל-שחור למה בשלוחת ההקלטה כתבת type=api?
  • 10k נושאים
    87k פוסטים
    א
    @שואל-שאלה כן
  • הודעות על מודולים והודעות על נושאים חדשים

    504 נושאים
    7k פוסטים
    ש
    @שמואל-ש. אם המספר הוא לא מספר נייח / נייד ישראלי תקין, זה פשוט לא יתווסף...
  • 895 נושאים
    6k פוסטים
    K
    מצורף הקובץ מתוקן ועובד טוב מאוד עם מלא שידורגים בשביל לקבל נתוני השמעות תוסיפו במערכת בהגדרות מתקדמות בשלוחה הראשית בקובץ IVR.ini את ההגדרות הבאות log_playback_play_stop=yes log_playback_play_stop_ymgr_to_html=yes log_playback_play_stop_year_save_folder=yes log_playback_play_stop_year_save_folder_ymgr_to_html=yes log_playback_play_stop_month_save_root_log=yes log_playback_play_stop_month_save_root_log_ymgr_to_html=yes הנה הקוד: <!DOCTYPE html> <html lang="he" dir="rtl"> <head> <meta charset="UTF-8"> <title>ניתוח נתוני מערכות | v36.0 - גרסה מאובטחת</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); } .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.2s; } .btn-run:hover { opacity: 0.9; transform: scale(1.02); } .btn-reset-date { background: transparent; color: #94a3b8; border: 1px solid var(--border); padding: 8px; border-radius: 8px; cursor: pointer; } .btn-export { background: #475569; color: white; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem; display: flex; align-items: center; gap: 5px; } .nav-tabs { background: #1e293b; display: flex; padding: 0 20px; border-bottom: 1px solid var(--border); overflow-x: auto; } .tab { padding: 15px 25px; cursor: pointer; color: #94a3b8; border-bottom: 3px solid transparent; transition: 0.3s; white-space: nowrap; } .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: 20px; border-radius: 16px; border: 1px solid var(--border); margin-bottom: 25px; } .stat-num { font-size: 2.2rem; font-weight: 800; color: var(--primary); } .control-bar { display: flex; gap: 20px; align-items: center; background: #334155; padding: 12px 20px; border-radius: 12px 12px 0 0; justify-content: space-between; flex-wrap: wrap; } .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; min-width: 600px; } th { text-align: right; padding: 12px; background: #475569; color: white; font-size: 0.85rem; cursor: pointer; user-select: none; transition: 0.2s; position: relative; } th:hover { background: #64748b; } th i { margin-right: 8px; font-size: 0.7rem; opacity: 0.5; } th.sort-asc i, th.sort-desc i { opacity: 1; color: var(--primary); } td { padding: 12px; border-bottom: 1px solid var(--border); font-size: 0.9rem; } .progress-container { width: 100%; background: #1e293b; height: 6px; display: none; position: relative; } #progress-fill { height: 100%; background: var(--primary); width: 0%; transition: 0.4s; } .hidden { display: none; } .btn-play { color: var(--primary); cursor: pointer; background: transparent; border: 1px solid var(--primary); padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; } .btn-play:hover { background: var(--primary); color: #0f172a; } </style> </head> <body> <header> <div class="logo-box"> <div class="logo-icon"><i class="fas fa-headphones"></i></div> <div class="logo-text">ניתוח נתוני מערכות</div> </div> <div class="config-box"> <!-- השדה ריק כעת לצורך אבטחה --> <input type="password" id="apiToken" placeholder="הכנס טוקן API כאן" value=""> <button class="btn-reset-date" title="חזור לתחילת חודש" onclick="setDefaultDates()"><i class="fas fa-calendar-alt"></i></button> <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(250px, 1fr)); gap: 20px; 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"> <input type="text" id="extSearch" class="search-input" placeholder="חפש שלוחה..." onkeyup="renderExts()"> <button class="btn-export" onclick="exportTableToCSV('extTable', 'שלוחות')"><i class="fas fa-file-excel"></i> ייצוא</button> </div> <table id="extTable"> <thead> <tr> <th onclick="sortTable('extTable', 0, 'string')">שלוחה <i class="fas fa-sort"></i></th> <th onclick="sortTable('extTable', 1, 'number')">כניסות <i class="fas fa-sort"></i></th> <th onclick="sortTable('extTable', 2, 'number')">ייחודיים <i class="fas fa-sort"></i></th> <th onclick="sortTable('extTable', 3, 'number')">סה"כ דקות <i class="fas fa-sort"></i></th> <th onclick="sortTable('extTable', 4, 'number')">ממוצע <i class="fas fa-sort"></i></th> </tr> </thead> <tbody></tbody> </table> </div> <div id="play-tab" class="tab-content hidden"> <div class="control-bar"> <input type="text" id="playSearch" class="search-input" placeholder="חפש קובץ, שלוחה או טלפון..." onkeyup="renderPlays()"> <button class="btn-export" onclick="exportTableToCSV('playTable', 'השמעות')"><i class="fas fa-file-excel"></i> ייצוא</button> </div> <table id="playTable"> <thead> <tr> <th onclick="sortTable('playTable', 0, 'string')">זמן אחרון <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 1, 'string')">שלוחה <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 2, 'string')">קובץ <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 3, 'string')">מאזין אחרון <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 4, 'number')">השמעות <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 5, 'number')">סה"כ דק' <i class="fas fa-sort"></i></th> <th onclick="sortTable('playTable', 6, 'number')">אחוז <i class="fas fa-sort"></i></th> <th>פעולה</th> </tr> </thead> <tbody></tbody> </table> </div> <div id="users-tab" class="tab-content hidden"> <div class="control-bar"> <input type="text" id="userSearch" class="search-input" placeholder="חפש טלפון..." onkeyup="renderUsers()"> <button class="btn-export" onclick="exportTableToCSV('usersTable', 'מאזינים')"><i class="fas fa-file-excel"></i> ייצוא</button> </div> <table id="usersTable"> <thead> <tr> <th onclick="sortTable('usersTable', 0, 'string')">מספר טלפון <i class="fas fa-sort"></i></th> <th onclick="sortTable('usersTable', 1, 'number')">דקות האזנה <i class="fas fa-sort"></i></th> <th onclick="sortTable('usersTable', 2, 'number')">פעולות <i class="fas fa-sort"></i></th> <th onclick="sortTable('usersTable', 3, 'string')">סוג <i class="fas fa-sort"></i></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:15px; height:450px; overflow-y:auto; font-family:monospace; font-size: 12px; line-height: 1.4;"> <div>מערכת v36.0 מוכנה לאחסון בשרת. הטוקן הוסר מהקוד.</div> </div> </div> </div> </div> <div id="playerModal" class="hidden" style="position:fixed; bottom:20px; left:20px; background:var(--card); padding:15px; border-radius:12px; border:1px solid var(--primary); z-index:1000; box-shadow: 0 10px 30px rgba(0,0,0,0.5);"> <div style="display:flex; justify-content:space-between; margin-bottom:10px;"> <span id="playerTitle" style="font-size:0.8rem; color:var(--primary)">נגן השמעה</span> <i class="fas fa-times" style="cursor:pointer" onclick="closePlayer()"></i> </div> <audio id="audioPlayer" controls style="width:250px; height:35px;"></audio> <div id="playerError" style="color:var(--danger); font-size:11px; margin-top:5px; display:none;">שגיאה בטעינת הקובץ</div> </div> <script> const API = "https://www.call2all.co.il/ym/api/"; let dataStore = { exts: {}, plays: {}, users: {}, daily: {}, totalSec: 0, completed: 0 }; let dailyChart = null; let sortState = { tableId: null, colIndex: null, direction: 'asc' }; function setDefaultDates() { const now = new Date(); const firstDay = new Date(now.getFullYear(), now.getMonth(), 1); const f = (d) => { let year = d.getFullYear(); let month = String(d.getMonth() + 1).padStart(2, '0'); let day = String(d.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; document.getElementById('startDate').value = f(firstDay); document.getElementById('endDate').value = f(now); } function addLog(msg, color = '#22c55e') { const console = document.getElementById('debug-console'); const div = document.createElement('div'); div.style.color = color; div.innerHTML = `[${new Date().toLocaleTimeString()}] ${msg}`; console.appendChild(div); console.scrollTop = console.scrollHeight; } async function manualStart() { 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: {}, totalSec: 0, completed: 0 }; document.getElementById('progBar').style.display = 'block'; const monthKey = start.substring(0, 7); try { const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogFolderEnterExit-${monthKey}.ymgr&convertType=json`); const json = await res.json(); if (json.data) { json.data.forEach(row => { const ext = row["שלוחה"] || "ראשי"; const phone = row["טלפון"] || "חסוי"; const sec = parseInt(row["סה\"כ שניות"] || row["שניות"] || 0); const date = row["תאריך"] || start; if (!dataStore.exts[ext]) dataStore.exts[ext] = { count: 0, sec: 0, unique: new Set() }; dataStore.exts[ext].count++; dataStore.exts[ext].sec += sec; dataStore.exts[ext].unique.add(phone); trackUser(phone, sec); dataStore.daily[date] = (dataStore.daily[date] || 0) + 1; dataStore.totalSec += sec; }); } } catch(e) { addLog("לוג כניסות לא נמצא.", "#f59e0b"); } let days = []; let dt = new Date(start); const endDt = new Date(end); while(dt <= endDt) { days.push(new Date(dt).toISOString().split('T')[0]); dt.setDate(dt.getDate() + 1); } for (let day of days) { updateProgress(days.indexOf(day)+1, days.length); const paths = [`ivr2:/Log/LogPlaybackPlayStop/LogPlaybackPlayStop.${day}.ymgr`,`ivr2:/Log/LogPlaybackPlayStop.${day}.ymgr`,`ivr2:/Log/LogPlayback.${day}.ymgr`]; for (let path of paths) { try { const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=${path}&convertType=json`); const json = await res.json(); if (json.data && json.data.length > 0) { addLog(`יום ${day}: נמצאו נתוני השמעות.`); processPlaybackRows(json.data, day); break; } } catch(e) {} } } renderUI(); } function processPlaybackRows(rows, day) { rows.forEach(row => { const keys = Object.keys(row); const extKey = keys.find(k => k.includes("שלוחה") || k.includes("Folder") || k.includes("תיקייה")) || "שלוחה"; const fileKey = keys.find(k => k.includes("קובץ") || k.includes("השמעה") || k.includes("Play")) || keys[0]; const secKey = keys.find(k => k.includes("שניות") || k.includes("זמן") || k.includes("Sec")) || keys[1]; const exitKey = keys.find(k => k.includes("יציאה") || k.includes("Exit")) || ""; const timeKey = keys.find(k => k.includes("שעה") || k.includes("Time")) || ""; const extName = row[extKey] || "לא ידוע"; const fileName = row[fileKey] || "לא ידוע"; const phone = row["טלפון"] || "חסוי"; const sec = parseInt(row[secKey] || 0); const time = row[timeKey] || ""; const isEnd = (row[exitKey] || "").toString().includes("סוף") || (row[exitKey] || "").toString().toLowerCase() === "end"; const playId = `${extName}|${fileName}`; if (!dataStore.plays[playId]) { dataStore.plays[playId] = { ext: extName, file: fileName, lastPhone: phone, lastTime: `${day} ${time}`, count: 0, sec: 0, ends: 0 }; } dataStore.plays[playId].count++; dataStore.plays[playId].sec += sec; dataStore.plays[playId].lastPhone = phone; dataStore.plays[playId].lastTime = `${day} ${time}`; if (isEnd) dataStore.plays[playId].ends++; trackUser(phone, sec); dataStore.daily[day] = (dataStore.daily[day] || 0) + 1; dataStore.totalSec += sec; if (isEnd) dataStore.completed++; }); } async function playFile(ext, file) { const token = document.getElementById('apiToken').value; const modal = document.getElementById('playerModal'); const player = document.getElementById('audioPlayer'); const errDiv = document.getElementById('playerError'); errDiv.style.display = 'none'; modal.classList.remove('hidden'); document.getElementById('playerTitle').innerText = `טוען: שלוחה ${ext} | קובץ ${file}`; let cleanExt = ext.replace('ivr2:', '').replace(/^\//, ''); if (!cleanExt.startsWith('ivr2:')) cleanExt = 'ivr2:/' + cleanExt; const fileBase = file.padStart(3, '0'); const formats = ['.wav', '.mp3', '.amr']; let success = false; for (const fmt of formats) { const fullPath = `${cleanExt}/${fileBase}${fmt}`; const url = `${API}DownloadFile?token=${token}&path=${fullPath}`; try { player.src = url; await player.play(); success = true; document.getElementById('playerTitle').innerText = `מנגן: ${ext}/${fileBase}${fmt}`; break; } catch (e) {} } if (!success) errDiv.style.display = 'block'; } function closePlayer() { const modal = document.getElementById('playerModal'); const player = document.getElementById('audioPlayer'); modal.classList.add('hidden'); player.pause(); player.src = ""; } function trackUser(p, s) { if (!dataStore.users[p]) dataStore.users[p] = { sec: 0, count: 0 }; dataStore.users[p].sec += s; dataStore.users[p].count++; } function sortTable(tableId, colIndex, type) { const table = document.getElementById(tableId); const tbody = table.querySelector('tbody'); const rows = Array.from(tbody.querySelectorAll('tr')); const headers = table.querySelectorAll('th'); if (sortState.tableId === tableId && sortState.colIndex === colIndex) { sortState.direction = sortState.direction === 'asc' ? 'desc' : 'asc'; } else { sortState.tableId = tableId; sortState.colIndex = colIndex; sortState.direction = 'asc'; } headers.forEach(th => th.classList.remove('sort-asc', 'sort-desc')); headers[colIndex].classList.add(sortState.direction === 'asc' ? 'sort-asc' : 'sort-desc'); const sortedRows = rows.sort((a, b) => { let aVal = a.children[colIndex].innerText; let bVal = b.children[colIndex].innerText; if (type === 'number') { aVal = parseFloat(aVal.replace(/[^0-9.-]+/g, "")) || 0; bVal = parseFloat(bVal.replace(/[^0-9.-]+/g, "")) || 0; } else { aVal = aVal.toLowerCase(); bVal = bVal.toLowerCase(); } if (aVal < bVal) return sortState.direction === 'asc' ? -1 : 1; if (aVal > bVal) return sortState.direction === 'asc' ? 1 : -1; return 0; }); tbody.innerHTML = ''; sortedRows.forEach(row => tbody.appendChild(row)); } 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(); } function renderExts() { const q = document.getElementById('extSearch').value.toLowerCase(); let h = ""; Object.entries(dataStore.exts).forEach(([n, d]) => { if (n.toLowerCase().includes(q)) { h += `<tr><td style="color:var(--primary); font-weight:bold">${n}</td><td>${d.count}</td><td>${d.unique.size}</td><td>${(d.sec/60).toFixed(1)}</td><td>${Math.round(d.sec/d.count || 0)} ש'</td></tr>`; } }); document.querySelector('#extTable tbody').innerHTML = h; } function renderPlays() { const q = document.getElementById('playSearch').value.toLowerCase(); let h = ""; Object.values(dataStore.plays).forEach(d => { if (d.file.toLowerCase().includes(q) || d.ext.toLowerCase().includes(q) || d.lastPhone.includes(q)) { const pct = Math.round((d.ends/d.count)*100); h += `<tr> <td style="font-size:0.75rem; color:#94a3b8">${d.lastTime}</td> <td style="color:var(--primary)">${d.ext}</td> <td style="font-weight:bold">${d.file}</td> <td>${d.lastPhone}</td> <td>${d.count}</td> <td>${(d.sec/60).toFixed(1)}</td> <td>${pct}%</td> <td><button class="btn-play" onclick="playFile('${d.ext}', '${d.file}')"><i class="fas fa-play"></i></button></td> </tr>`; } }); document.querySelector('#playTable tbody').innerHTML = h || "<tr><td colspan='8' style='text-align:center'>אין נתונים</td></tr>"; } function renderUsers() { const q = document.getElementById('userSearch').value; let h = ""; Object.entries(dataStore.users).forEach(([p, d]) => { if (p.includes(q)) { h += `<tr><td>${p}</td><td>${(d.sec/60).toFixed(1)}</td><td>${d.count}</td><td>מאזין</td></tr>`; } }); document.querySelector('#usersTable tbody').innerHTML = h; } function exportTableToCSV(tableId, filename) { let csv = []; const rows = document.querySelectorAll(`#${tableId} tr`); for (let i = 0; i < rows.length; i++) { let row = [], cols = rows[i].querySelectorAll("td, th"); for (let j = 0; j < cols.length; j++) row.push('"' + cols[j].innerText + '"'); csv.push(row.join(",")); } const csvFile = new Blob(["\ufeff" + csv.join("\n")], { type: "text/csv" }); const downloadLink = document.createElement("a"); downloadLink.download = `${filename}.csv`; downloadLink.href = window.URL.createObjectURL(csvFile); downloadLink.style.display = "none"; document.body.appendChild(downloadLink); downloadLink.click(); } 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'); const labels = Object.keys(dataStore.daily).sort(); dailyChart = new Chart(ctx, { type: 'line', data: { labels, datasets: [{ label: 'פעולות', data: labels.map(l => dataStore.daily[l]), borderColor: '#38bdf8', tension: 0.3, fill: true, backgroundColor: 'rgba(56, 189, 248, 0.1)' }] }, options: { scales: { y: { beginAtZero: true } } } }); } window.onload = setDefaultDates; </script> </body> </html>
  • אם אתם בטוחים ב100% שזו תקלה במערכת, ולא שזו תקלה שנובעת מפני שלא הגדרתם נכון, כיתבו כאן.

    826 נושאים
    5k פוסטים
    א
    @אA @ben-zion אבל לפחות לשלוחה הראשית זה עובד, והרבה מאד מהקווים זה כבר מספיק (הרבה פעמים גם ההבדל במספר הוא רק לדעת למה הצינתוק) אפשר גם לעשות בשלוחה הראשית פילטר לפי רשימת הצינתוקים!
  • הסברים, שאלות, הצעות, דיווחי באגים או כל דבר על הפורום שלא קשור למערכות הטלפוניות

    555 נושאים
    4k פוסטים
    C
    @יענקי-פולק סליחה, התבלבלתי בנושא
  • שאלות המשתמשים וארכיון הפורום