• פוסט מסודר לנותני שירות בניית מערכות בתשלום

    נעוץ
    90
    11 הצבעות
    90 פוסטים
    4k צפיות
    א
    @y6714453 עיין בפוסט זה כיצד נרשמים
  • אני צריך דוח על שלוחה מסוימת איך אני מוציא את זה

    3
    0 הצבעות
    3 פוסטים
    13 צפיות
    ע
    @הפצת-התורה יש לך את זה וגם את זה: (תפתח בפנקס רשימות ותשמור בשם עם סיומת HTML) <!DOCTYPE html> <html lang="he" dir="rtl"> <head> <meta charset="UTF-8"> <title>ניתוח נתוני מערכות | גרסה יציבה ומדויקת</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; } input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(1); cursor: pointer; } .btn-run { background: var(--primary); color: #0f172a; border: none; padding: 10px 25px; border-radius: 8px; font-weight: bold; cursor: pointer; transition: 0.3s; } .btn-run:hover { opacity: 0.8; } .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: 20px; display: none; position: relative; text-align: center; } #progress-fill { height: 100%; background: var(--primary); width: 0%; transition: 0.4s; position: absolute; top:0; right:0; } #progress-text { position: relative; z-index: 2; font-size: 0.8rem; font-weight: bold; color: white; line-height: 20px; } .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> <span id="progress-text">0%</span> </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><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="avg">אחוז השלמה</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><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><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; border-radius: 8px;"></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); color:white; border: 1px solid var(--primary); padding: 5px 15px; border-radius: 5px;"> <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> <!-- מודאל פירוט שלוחה --> <div id="extModal" class="modal-overlay" onclick="closeExtModal()"> <div class="modal-content" onclick="event.stopPropagation()"> <span class="close-modal" onclick="closeExtModal()">&times;</span> <h2 id="extModalTitle" style="color: var(--primary); margin-bottom: 20px;"></h2> <table id="extModalTable"> <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, names: {} }; 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); console.scrollTop = console.scrollHeight; } function normalizePhone(p) { if (!p) return "חסוי"; let s = p.toString().replace(/\D/g, ''); if (s.length > 0 && !s.startsWith('0') && s.length >= 8) s = '0' + s; return s; } function formatExtName(ext) { if (!ext) return "ראשית"; let str = ext.toString().trim(); if (str === "" || str === "/" || str.toLowerCase() === "main" || str.toLowerCase() === "root") { return "ראשית"; } return str; } function parseYemotDateToIso(dStr) { if (!dStr || !dStr.includes('/')) return null; const parts = dStr.split('/'); if (parts.length === 3) { const d = parts[0].padStart(2, '0'); const m = parts[1].padStart(2, '0'); const y = parts[2]; return `${y}-${m}-${d}`; } return null; } function timeStrToSeconds(tStr) { if (!tStr) return 0; if (!tStr.includes(':')) return parseInt(tStr) || 0; const p = tStr.split(':').map(Number); if (p.length === 3) return (p[0] * 3600) + (p[1] * 60) + p[2]; if (p.length === 2) return (p[0] * 60) + p[1]; return parseInt(tStr) || 0; } function ensureUser(phone) { if (!dataStore.users[phone]) { dataStore.users[phone] = { sec: 0, calls: 0 }; } } async function fetchNames(token) { try { const res = await fetch(`${API}DownloadFile?token=${token}&path=ivr2:/EnterIDValName.ini`); const text = await res.text(); if(text && !text.includes("NOT_FOUND")) { text.split(/\r?\n/).forEach(line => { if (line.includes('=')) { const [phone, name] = line.split('='); const cleanPhone = normalizePhone(phone); if (cleanPhone && name) dataStore.names[cleanPhone] = name.trim(); } }); addLog(`נטענו שמות מקובץ ההגדרות הראשי`); } } catch(e) { } } async function manualStart() { if(autoRefreshTimer) clearInterval(autoRefreshTimer); await startFullAnalysis(); document.getElementById('live-dot').classList.add('active'); document.getElementById('live-text').innerText = "LIVE (פעיל)"; } async function startFullAnalysis() { const token = document.getElementById('apiToken').value; const startStr = document.getElementById('startDate').value; const endStr = document.getElementById('endDate').value; if (!token) return alert("נא להזין טוקן API"); addLog(`מתחיל עיבוד נתונים מתאריך ${startStr} עד ${endStr}...`); document.getElementById('progBar').style.display = 'block'; updateProgress(5, 100); dataStore = { exts: {}, plays: {}, users: {}, daily: {}, rawActivity: [], totalSec: 0, completed: 0, names: {} }; await fetchNames(token); updateProgress(10, 100); // חישוב חודשים בטוח (מניעת תקלות של אזור זמן) let currM = new Date(startStr); currM.setDate(1); // עקיפת בעיית 31 לחודש let endM = new Date(endStr); let monthsToFetch = []; while (currM <= endM || (currM.getFullYear() === endM.getFullYear() && currM.getMonth() === endM.getMonth())) { let y = currM.getFullYear(); let m = String(currM.getMonth() + 1).padStart(2, '0'); monthsToFetch.push(`${y}-${m}`); currM.setMonth(currM.getMonth() + 1); } // אובייקט לאיתור שיחות כפולות (למניעת קפיצת דקות) let callMap = {}; for (let month of monthsToFetch) { try { addLog(`מייבא לוג כניסות עבור חודש ${month}...`); const res = await fetch(`${API}RenderYMGRFile?token=${token}&wath=ivr2:/Log/LogFolderEnterExit-${month}.ymgr&convertType=json`); const json = await res.json(); if (json.data && Array.isArray(json.data)) { json.data.forEach(row => { const gregDate = row["תאריך"]; const hebDate = row["תאריך עברי"] || row["עברי"] || ""; const isoDate = parseYemotDateToIso(gregDate); if (!isoDate) return; // סינון מוחלט של ימים לפי טקסט (למשל "2026-03-31") - מונע כפילויות! if (isoDate >= startStr && isoDate <= endStr) { const extName = formatExtName(row["שלוחה"]); const phone = normalizePhone(row["טלפון"]); const sec = parseInt(row["סה\"כ שניות"]) || 0; const callId = row["מזהה שיחה"]; const nameFromLog = row["שם מזהה"]; if (nameFromLog && !dataStore.names[phone]) dataStore.names[phone] = nameFromLog; // -- חישוב נתונים לשלוחות -- if (!dataStore.exts[extName]) { dataStore.exts[extName] = { count: 0, sec: 0, title: row["כותרת שלוחה"] || "", extUsers: {} }; } dataStore.exts[extName].count++; dataStore.exts[extName].sec += sec; if (!dataStore.exts[extName].extUsers[phone]) { dataStore.exts[extName].extUsers[phone] = { count: 0, sec: 0 }; } dataStore.exts[extName].extUsers[phone].count++; dataStore.exts[extName].extUsers[phone].sec += sec; // -- איסוף זמן למאזין וכללי במערכת (עם מניעת כפילויות של מזהה שיחה) -- if (callId) { if (!callMap[callId]) callMap[callId] = { phone: phone, maxSec: 0 }; if (sec > callMap[callId].maxSec) callMap[callId].maxSec = sec; } else { // במקרה נדיר שאין מזהה שיחה ensureUser(phone); dataStore.users[phone].sec += sec; dataStore.users[phone].calls++; dataStore.totalSec += sec; } if (!dataStore.daily[isoDate]) dataStore.daily[isoDate] = 0; dataStore.daily[isoDate]++; const displayDate = hebDate ? `${hebDate} (${gregDate})` : gregDate; dataStore.rawActivity.push({ phone, type: 'שלוחה', name: extName, sec: sec + " ש'", date: `${displayDate} ${row["התחלה שעה"]||''}` }); } }); } } catch(e) { addLog(`לא נמצא לוג כניסות בחודש ${month}`, "orange"); } } // עדכון סך הדקות והשיחות במערכת (מסונן ללא כפילויות!) Object.values(callMap).forEach(call => { dataStore.totalSec += call.maxSec; ensureUser(call.phone); dataStore.users[call.phone].sec += call.maxSec; dataStore.users[call.phone].calls += 1; }); updateProgress(50, 100); // חישוב ימים להשמעות בטוח let daysToFetch = []; let currDay = new Date(startStr); let endDay = new Date(endStr); while(currDay <= endDay) { let y = currDay.getFullYear(); let m = String(currDay.getMonth() + 1).padStart(2, '0'); let d = String(currDay.getDate()).padStart(2, '0'); daysToFetch.push(`${y}-${m}-${d}`); currDay.setDate(currDay.getDate() + 1); } for (let i=0; i<daysToFetch.length; i++) { const day = daysToFetch[i]; 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 && Array.isArray(json.data)) { json.data.forEach(row => { const gregDate = row["תאריך"] || day; const isoDate = parseYemotDateToIso(gregDate); // וידוא שההשמעה בטווח התאריכים המדויק if (isoDate && (isoDate < startStr || isoDate > endStr)) return; const file = row["השמעה"]; if (!file) return; const folder = formatExtName(row["שלוחה"]); const phone = normalizePhone(row["טלפון"]); const sec = parseInt(row["סה\"כ שניות"]) || 0; const fileLenSec = timeStrToSeconds(row["אורך הקובץ"]); const exitPoint = row["נקודת יציאה"]; const nameFromLog = row["שם"]; const hebDate = row["עברי"] || row["תאריך עברי"] || ""; const displayDate = hebDate ? `${hebDate} (${gregDate})` : gregDate; if (nameFromLog && !dataStore.names[phone]) dataStore.names[phone] = nameFromLog; ensureUser(phone); // מוודא שמי שהאזין לקובץ יופיע בטבלת מאזינים גם אם לא נכנס לשלוחה רשמית const isEnd = (exitPoint === "סוף") || (fileLenSec > 0 && sec >= fileLenSec - 2); if (isEnd) dataStore.completed++; if (!dataStore.plays[file]) dataStore.plays[file] = { count: 0, sec: 0, drops: 0, pcts: [], folder: folder }; dataStore.plays[file].count++; dataStore.plays[file].sec += sec; const pct = fileLenSec > 0 ? Math.min(100, Math.round((sec / fileLenSec) * 100)) : (isEnd ? 100 : 0); dataStore.plays[file].pcts.push(pct); if (!isEnd) dataStore.plays[file].drops++; dataStore.rawActivity.push({ phone, type: 'השמעה', name: file, sec: sec + " ש'", date: `${displayDate} ${row["התחלה שעה"]||''}` }); }); } } catch(e) {} updateProgress(50 + Math.round(((i + 1) / daysToFetch.length) * 50), 100); } addLog("עיבוד הנתונים הסתיים בהצלחה."); renderUI(); } function updateProgress(c, t) { const pct = Math.round((c/t)*100); document.getElementById('progress-fill').style.width = pct + '%'; document.getElementById('progress-text').innerText = pct + '%'; } 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 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 class="clickable" onclick="openExtDetail('${i.name}')"> <td style="color:var(--primary); font-weight:600">${i.name}</td> <td>${i.title || '-'}</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 && d.pcts.length ? Math.round(d.pcts.reduce((a,b)=>a+b,0)/d.pcts.length) : 0; const drop = d.count ? Math.round((d.drops/d.count)*100) : 0; 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.folder || '-'}</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, name: dataStore.names[phone] || "לא ידוע", sec: d.sec || 0, calls: d.calls || 0 })).filter(i => i.phone.includes(q) || i.name.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(--warning)">${i.name}</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} (${dataStore.names[phone] || "לא ידוע"})`; 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 openExtDetail(extName) { document.getElementById('extModalTitle').innerText = `פירוט מאזינים בשלוחה: ${extName}`; const extData = dataStore.exts[extName]; if(!extData) return; let usersArr = Object.entries(extData.extUsers).map(([phone, d]) => { return { phone, name: dataStore.names[phone] || "לא ידוע", count: d.count, sec: d.sec }; }); usersArr.sort((a,b) => b.sec - a.sec); document.querySelector('#extModalTable tbody').innerHTML = usersArr.map(u => ` <tr> <td style="color:var(--warning)">${u.name}</td> <td style="font-weight:bold">${u.phone}</td> <td>${u.count}</td> <td style="color:var(--primary); font-weight:bold">${(u.sec/60).toFixed(1)} דק'</td> </tr> `).join(''); document.getElementById('extModal').style.display = 'flex'; } function closeExtModal() { document.getElementById('extModal').style.display = 'none'; } 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 sortedDates = Object.keys(dataStore.daily).sort(); const sortedData = sortedDates.map(d => dataStore.daily[d]); dailyChart = new Chart(ctx, { type: 'line', data: { labels: sortedDates, datasets: [{ label: 'פעולות במערכת', data: sortedData, borderColor: '#38bdf8', tension: 0.4, fill: true, backgroundColor: 'rgba(56, 189, 248, 0.1)' }] }, options: { plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } } }); } let dEnd = new Date(); let dStart = new Date(); dStart.setDate(dEnd.getDate() - 7); document.getElementById('endDate').value = dEnd.toISOString().split('T')[0]; document.getElementById('startDate').value = dStart.toISOString().split('T')[0]; </script> </body> </html>
  • getting failed while uploading

    לא נפתר
    4
    1
    0 הצבעות
    4 פוסטים
    34 צפיות
    שמואלש
    @15183299387 תבדוק אם זה עדיין קורה לך. אם כן - תשלח לי פרטים מדוייקים במייל, או לכל הפחות אם תוכל להעלות כאן מה התגובה של ה API על העלאה - דרך לשונית network בכלי פיתוח בדפדפן.
  • הודעה באיזה שאלה היה טעות במבחן טלפוני

    4
    0 הצבעות
    4 פוסטים
    21 צפיות
    ה
    זה לא עובד עכשיו נסיתי
  • האם אפשר להגביל את הכניסה למערכת לפי שעות וימים

    2
    0 הצבעות
    2 פוסטים
    10 צפיות
    S
    @ש-פ עי' כאן
  • 7 הצבעות
    201 פוסטים
    3k צפיות
    ש
    הקפצה...
  • מבחן אמריקאי

    10
    0 הצבעות
    10 פוסטים
    385 צפיות
    ה
    מה אני עושה שכאשר נבחן טעה בשאלה לאחר המבחן המערכת תגיד לו באיזה שאלה הוא טעה
  • נושא זה נמחק!

    1
    0 הצבעות
    1 פוסטים
    5 צפיות
    אין תגובות
  • נושא זה נמחק!

    1
    0 הצבעות
    1 פוסטים
    1 צפיות
    אין תגובות
  • מספר 1-700 - למי שיש פרטים, שיכנס!!!

    35
    0 הצבעות
    35 פוסטים
    859 צפיות
    ז
    זה כנראה משהו יותר מכך. עוד ועוד מערכות גדולות, משלל חברות של קווי תוכן מעבירים את מספר הקו ל1-700. מעניין שאין בפורום אפילו אחד שיודע לומר בבירור מה זה.
  • קליקי

    לא נפתר קליקי
    4
    0 הצבעות
    4 פוסטים
    64 צפיות
    פ
    @פורום-מוזיקה אני אוכל לעזור לך smstop770@gmail.com
  • קו עם כל הקווים

    25
    0 הצבעות
    25 פוסטים
    224 צפיות
    ע
    @יענקי-פולק תודה רבה
  • 0 הצבעות
    22 פוסטים
    131 צפיות
    י
    @יענקלה-פאדראדצ-יק כדי ליצור טוקן תיכנס באתר הישן בלשונית אבטחה ואחרי זה בלשונית מפתחות גישה ותפתח שם טוקן והקוד שהוא נותן לך תעתיק בשורה שצריכים להכניס את הטוקן ואל תיהה טמבל שכותב אות אחר אות מה שכתוב בטוקן רק תעתיק את זה בעניים סגורות בהצלחה!!
  • שידור חי אינטרנטי תקלה

    9
    1
    0 הצבעות
    9 פוסטים
    86 צפיות
    ע
    @שואל-שאלה תגדיר כך: type=nitoviya nitoviya_dial_to=1700111010 title=ר' מיילך
  • מודל ניתוביה בזיהוי שונה

    3
    0 הצבעות
    3 פוסטים
    38 צפיות
    י
    @המומחה תעשה בקו הראשון מודול תור עם זיהוי המערכת שמתקשר לקו השני Spoiler יש להגדיר בקובץ ext.ini type=routing_queue queue_caller_id=customer_did יש להכניס בקובץ queue.ini את המספר של הקו השני (שאליו יתקשר) 07XXXXXXXX כל ההגדרות ובקו השני תעשה רשימה לבנה שרק המספר הראשון יוכל להכנס Spoiler יש להגדיר בקובץ ext.ini white_list=yes יש להכניס בקובץ WhiteList.ini את המספר של הקו הראשון 07XXXXXXXX כל ההגדרות
  • טריוויה לפי שבוע עברי

    לא נפתר
    8
    0 הצבעות
    8 פוסטים
    37 צפיות
    י
    הבנתי ממישהו עכשיו שזה לא עוזר ההגדרה ש @ben-zion נתן לי, כי בברירת מחדל המערכת מוגדרת כך אלא אם כן כתוב במפורש jcalendar_realdate=0 וטריויה לפי תאריך לועזי מתחלפת תמיד בחצות, ואין מה לעשות. אני בכל זאת אנסה, ואחכה לשבוע הבא. אבל אם למישהו יש רעיון אחר איך לעשות את זה, או עם קומבינה או אולי יש הגדרה פשוטה כזאת, (או אם מישהו שיכול להגיד לי שבאמת ההגדרה הנ"ל כן עובדת...), אשמח שיענה פה לתועלת הכלל.
  • השיתוף בוצע בהצלחה

    6
    0 הצבעות
    6 פוסטים
    98 צפיות
    י
    @BEN-ZION לתועלת הציבור: יש שני סוגים של "השיתוף בוצע בהצלחה" זה שמופיע בדף הודעות מערכת (3392) (למה זה מיועד, @אa?). ויש אחד חדש שהוא ברצף של כל ההודעות "הקש מספר טלפון לשיתוף...", "התקשר למספר שהוקש", וכו' (6300 עד 6313) שהרצף הזה שייך לשיתוף מערכת בין מאזינים, וקבלת שיחה חוזרת ומספר ההודעת מערכת של "השיתוף בוצע בהצלחה" של שירות זה הוא: M6306 אני לא יודע למה התכוון @מערכת-המשפחה כששאל את זה, אבל אני הייתי צריך את השני. מקווה שעזרתי לכם יצחק י. Spoiler אני השתמשתי בזה: מדריך לחסוך בדקות שיחה למאזינים שלכם, ללא מספר נוסף, עם אפשרות להגדיר ע"י המאזין בעצמו! וההודעה M6306: בעוד רגע תקבל שיחה חוזרת
  • יש אופציה לשנות את ההודעה כשעונים לצינתוק?

    6
    0 הצבעות
    6 פוסטים
    17 צפיות
    פ
    @י.ע כרגע כל המערכות משובשות. אני בכלל לא מצליח להתקשר.
  • מה זה השגיאה הזה במודל הורדת נתונים לגלול שיטס

    3
    1
    0 הצבעות
    3 פוסטים
    36 צפיות
    א
    @AYY כתב במה זה השגיאה הזה במודל הורדת נתונים לגלול שיטס: הקובץ לוג גדול מידי לאחזור עם גוגל סקריפט, שזה אומר למעשה שהקובץ גדול מ50 מ"ב, יש לי מודול משודרג לגוגל שיטס שיכול להתמודד עם זה (זה בעצם מעקף דרך שרת חיצוני) ב250 ש"ח לשנה,
  • האם אפשר לשלם בהו''ק בנקאית להסרת פרסומות?

    3
    0 הצבעות
    3 פוסטים
    38 צפיות
    ז
    @amram בשירות לקוחות הפנו אותי למחלקת הנהלת חשבונות, הם עשו פרצופים, ובסוף לא אישרו. אבל הם לא שללו את זה בעתיד.