קבצים ותוכנות לשימוש במערכות ימות המשיח
-
-
קובץ להורדת קבצים מהמערכת (קבצי wav, tts, ini, html) כולל אפשרות להמרה + אפשרות להורדת קבצים מרובים
הקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>ממשק הורדת קובץ</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
padding: 20px;
background-color: #e9ecef;
text-align: right;
direction: rtl;
}
.container {
background-color: #ffffff;
padding: 30px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
max-width: 400px;
margin: 40px auto;
}
h2 {
font-size: 24px;
color: #343a40;
margin-bottom: 25px;
text-align: center;
border-bottom: 2px solid #007BFF;
padding-bottom: 10px;
}
label, input, button, select {
display: block;
width: 100%;
margin-bottom: 15px;
box-sizing: border-box;
}
label {
font-weight: 600;
color: #495057;
margin-bottom: 5px;
}
input[type="text"], select {
padding: 12px;
border: 1px solid #ced4da;
border-radius: 6px;
transition: border-color 0.3s;
}
input[type="text"]:focus, select:focus {
border-color: #007BFF;
outline: none;
}
button {
background-color: #007BFF;
color: white;
padding: 12px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
transition: background-color 0.3s;
}
button:hover {
background-color: #0056b3;
}
#conversionOptions {
display: none;
margin-top: -5px;
}
#iniWarning {
color: #721c24;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
padding: 10px;
border-radius: 5px;
margin-bottom: 15px;
display: none;
}
/* סגנון הודעת שגיאה כללית */
#generalError {
color: #721c24;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
padding: 10px;
border-radius: 5px;
margin-top: 15px;
font-weight: bold;
display: none;
text-align: center;
}
</style>
</head>
<body><div class="container">
<h2>
ממשק הורדת קובץ</h2><label for="token">טוקן (Token):</label> <input type="text" id="token" placeholder="יש ליצור טוקן בלשונית אבטחה" oninput="saveInputValues()"> <label for="path">נתיב השלוחה (לדוגמה: 1/2):</label> <input type="text" id="path" placeholder="נתיב השלוחה" oninput="saveInputValues()"> <label for="filename">שם הקובץ (לדוגמה: 001):</label> <input type="text" id="filename" placeholder="שם הקובץ" oninput="saveInputValues()"> <label for="filetype">סוג הקובץ:</label> <select id="filetype" onchange="toggleConversion(); saveInputValues();"> <option value="wav">wav</option> <option value="tts">tts</option> <option value="ini">ini</option> <option value="ymgr">ymgr</option> </select> <div id="iniWarning"> ⚠️ **שים לב: קובץ INI** <ul> <li>הקובץ יורד כקובץ **INI**. לאחר ההורדה, ייתכן שתידרש **לשנות את סיומת הקובץ ל-**.txt** באופן ידני** כדי לפתוח אותו כקובץ טקסט רגיל.</li> <li>בשל סוג הקובץ, תוכנת האנטי-וירוס או הדפדפן **עלולים למנוע את הורדת הקובץ** או להציג אזהרה.</li> </ul> </div> <div id="conversionOptions"> <label for="conversionFormat">פורמט המרה (עבור ymgr):</label> <select id="conversionFormat" onchange="saveInputValues()"> <option value="">ללא המרה (ymgr)</option> <option value="csv">אקסל (xlsx)</option> <option value="html">HTML</option> </select> </div> <button onclick="generateAndDownload()">הורד קובץ</button> <div id="generalError"></div></div>
<script>
// פונקציה לשמירת ערכי השדות ב-localStorage
function saveInputValues() {
localStorage.setItem('download_token', document.getElementById('token').value);
localStorage.setItem('download_path', document.getElementById('path').value);
localStorage.setItem('download_filename', document.getElementById('filename').value);
localStorage.setItem('download_filetype', document.getElementById('filetype').value);
localStorage.setItem('download_conversionFormat', document.getElementById('conversionFormat').value);
}// **פונקציה לטעינת ערכי השדות מ-localStorage** function loadInputValues() { document.getElementById('token').value = localStorage.getItem('download_token') || ''; document.getElementById('path').value = localStorage.getItem('download_path') || ''; document.getElementById('filename').value = localStorage.getItem('download_filename') || ''; // טעינת שדות Select const filetype = localStorage.getItem('download_filetype'); if (filetype) { document.getElementById('filetype').value = filetype; } const conversionFormat = localStorage.getItem('download_conversionFormat'); if (conversionFormat) { document.getElementById('conversionFormat').value = conversionFormat; } // נפעיל את toggleConversion כדי לוודא שהתצוגה מתאימה לערכים שנטענו toggleConversion(); } // פונקציה לבניית ה-URL function buildUrl(token, path, filename, filetype, conversionFormat) { const downloadUrlTemplate = "https://www.call2all.co.il/ym/api/DownloadFile?token=טוקן&path=ivr2:נתיב השלוחה/שם הקובץ.סיומת"; const renderUrlTemplate = "https://www.call2all.co.il/ym/api/RenderYMGRFile?token=טוקן&wath=ivr2:נתיב_השלוחה/שם_הקובץ.סיומת&convertType=סוג_ההמרה"; let finalUrl = ""; let downloadFilename = ""; if (filetype === 'ymgr' && conversionFormat !== '') { let conversionType = conversionFormat; finalUrl = renderUrlTemplate .replace("טוקן", encodeURIComponent(token)) .replace("נתיב_השלוחה", encodeURIComponent(path)) .replace("שם_הקובץ", encodeURIComponent(filename)) .replace("סיומת", encodeURIComponent(filetype)) .replace("סוג_ההמרה", encodeURIComponent(conversionType)); downloadFilename = (conversionType === 'csv') ? `${filename}.xlsx` : `${filename}.${conversionType}`; } else { // כולל ini, wav, tts, ו-ymgr ללא המרה finalUrl = downloadUrlTemplate .replace("טוקן", encodeURIComponent(token)) .replace("נתיב השלוחה", encodeURIComponent(path)) .replace("שם הקובץ", encodeURIComponent(filename)) .replace("סיומת", encodeURIComponent(filetype)); downloadFilename = (filetype === 'ini') ? `${filename}.ini` : `${filename}.${filetype}`; } return { finalUrl, downloadFilename }; } // פונקציה להצגה/הסתרה של אזהרות והמרות function toggleConversion() { const fileType = document.getElementById('filetype').value; const conversionOptions = document.getElementById('conversionOptions'); const iniWarning = document.getElementById('iniWarning'); conversionOptions.style.display = (fileType === 'ymgr') ? 'block' : 'none'; iniWarning.style.display = (fileType === 'ini') ? 'block' : 'none'; } // פונקציה להסתרת כל הודעות השגיאה function hideAllErrors() { document.getElementById('generalError').style.display = 'none'; } // הפונקציה הראשית (עכשיו אסינכרונית כדי לאפשר fetch) async function generateAndDownload() { const token = document.getElementById('token').value; const path = document.getElementById('path').value; const filename = document.getElementById('filename').value; const filetype = document.getElementById('filetype').value; const conversionFormat = document.getElementById('conversionFormat').value; const errorElement = document.getElementById('generalError'); // הסתרת שגיאות קודמות hideAllErrors(); if (!token || !path || !filename || !filetype) { alert("אנא מלא את כל השדות הנדרשים."); return; } const { finalUrl, downloadFilename } = buildUrl(token, path, filename, filetype, conversionFormat); try { // 1. נבצע fetch ל-API כדי לבדוק את התוכן const response = await fetch(finalUrl); const content = await response.text(); let errorMessage = ""; // ההודעה המקורית: {"yemotAPIVersion":7,"responseStatus":"EXCEPTION","message":"IllegalStateException(session token is invalid)"} const illegalStateErrorIdentifier = `"IllegalStateException(session token is invalid)"`; // 2. בדיקת שגיאות API ספציפיות // בדיקת שגיאת טוקן ספציפית if (content.includes(illegalStateErrorIdentifier)) { errorMessage = "❌ שגיאת טוקן חמור: הטוקן שהוזן אינו חוקי."; } // בדיקת שגיאת טוקן כללית else if (content.includes("Error: Token not found or wrong")) { errorMessage = "❌ שגיאת טוקן:הטוקן שהוזן אינו נכון."; } // בדיקת קובץ/נתיב לא קיים (הסרת כוביות והדגשה) else if (content.includes("Requested file does not exist")) { errorMessage = "❌ הקובץ אינו קיים: אנא ודא שגם הנתיב (" + path + ") וגם שם הקובץ (" + filename + ") נכונים."; } // 3. טיפול בשגיאות שנמצאו if (errorMessage) { errorElement.innerHTML = errorMessage; errorElement.style.display = 'block'; return; } // 4. אם אין שגיאה בתוכן, מפעילים הורדה const link = document.createElement('a'); link.href = finalUrl; link.download = downloadFilename; document.body.appendChild(link); link.click(); document.body.removeChild(link); } catch (error) { // שגיאת רשת או CORS errorElement.innerHTML = "⚠️ **שגיאה כללית/רשת:** לא ניתן לאמת את קיום הקובץ (יתכן חסימת CORS). אנא ודא את הנתונים."; errorElement.style.display = 'block'; } } document.addEventListener('DOMContentLoaded', () => { // טוען את הערכים השמורים בהתחלה loadInputValues(); // מוודא שהתצוגה נכונה לפי הערכים שנטענו (מופעל גם ב-loadInputValues) // toggleConversion(); });</script>
</body>
</html>קרדיט: @אA
-
קובץ להעלאה והורדה של כל סוגי הקבצים למערכות כולל קבצי ini - עם אפשרות להפעלת צינתוק בסיום העלאה!
הקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>מערכת ניהול קבצים מאוחדת - ימות המשיח</title>
<style>
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f4f7f6; margin: 0; padding: 20px; direction: rtl; }
.card { background: white; max-width: 900px; margin: auto; padding: 30px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); }
h2 { color: #2c3e50; text-align: center; margin-bottom: 25px; border-bottom: 2px solid #007BFF; padding-bottom: 10px; }.type-selector { display: flex; justify-content: center; gap: 15px; margin-bottom: 25px; background: #ecf0f1; padding: 10px; border-radius: 10px; } .type-option { cursor: pointer; padding: 10px 20px; border-radius: 8px; font-weight: bold; transition: 0.3s; flex: 1; text-align: center; } .type-option.active { background: #007BFF; color: white; } .form-group { margin-bottom: 20px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #495057; } input[type="text"], input[type="number"], input[type="file"], textarea { width: 100%; padding: 12px; border: 1px solid #ced4da; border-radius: 8px; box-sizing: border-box; font-size: 14px; } .ini-container { display: flex; gap: 20px; margin-bottom: 15px; } .ini-box { flex: 1; display: flex; flex-direction: column; } .ini-box textarea { height: 250px; resize: none; } .ini-box span { font-weight: bold; margin-bottom: 5px; color: #2c3e50; display: block; } .path-row { display: flex; gap: 8px; align-items: center; } .prefix { background: #dfe6e9; padding: 12px; border-radius: 8px; border: 1px solid #bdc3c7; font-weight: bold; } .progress-container { width: 100%; background-color: #eee; border-radius: 10px; margin: 20px 0; display: none; overflow: hidden; border: 1px solid #ccc; } .progress-bar { width: 0%; height: 25px; background-color: #28a745; text-align: center; line-height: 25px; color: white; font-weight: bold; transition: width 0.4s ease; } .tzintuk-section { border: 1px solid #ddd; padding: 15px; border-radius: 8px; background: #f9f9f9; margin-bottom: 20px; } .btn-container { display: flex; gap: 10px; margin-top: 10px; } .submit-btn { flex: 2; background-color: #28a745; color: white; border: none; padding: 15px; font-size: 16px; cursor: pointer; border-radius: 8px; font-weight: bold; transition: 0.3s; } .submit-btn:disabled { background-color: #6c757d; cursor: not-allowed; } .list-btn { flex: 1; background-color: #007BFF; color: white; border: none; padding: 15px; font-size: 16px; cursor: pointer; border-radius: 8px; font-weight: bold; } .load-btn-dynamic { background-color: #28a745; color: white; border: none; padding: 8px 20px; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: bold; margin-top: 10px; align-self: flex-start; transition: background-color 0.3s; min-width: 140px; } .load-btn-loading { background-color: #007BFF !important; } .hidden { display: none; } #fileListContainer { margin-top: 25px; border-top: 2px solid #eee; padding-top: 15px; display: none; } table { width: 100%; border-collapse: collapse; margin-top: 10px; background: white; } th, td { border: 1px solid #dee2e6; padding: 12px; text-align: center; } </style></head>
<body><div class="card">
<h2>
ניהול קבצי ימות המשיח</h2><div class="type-selector"> <div id="opt-file" class="type-option active" onclick="switchMode('file')">העלאת קובץ שמע</div> <div id="opt-text" class="type-option" onclick="switchMode('text')">העלאת קובץ טקסט</div> <div id="opt-ini" class="type-option" onclick="switchMode('ini')">העלאת קובץ INI</div> </div> <form id="uploadForm"> <div class="form-group"> <label>טוקן אישי (Token):</label> <input type="text" id="token" required placeholder="הזן טוקן כאן"> </div> <div class="form-group"> <label>שלוחות יעד (הפרד בפסיקים עבור מספר שלוחות):</label> <div class="path-row"> <span class="prefix">ivr2:</span> <input type="text" id="folder" placeholder="למשל: 5, 10, 15/1" required> </div> </div> <div id="progressContainer" class="progress-container"> <div id="progressBar" class="progress-bar">0%</div> </div> <div id="file-section"> <div class="form-group"> <label>בחר קובץ:</label> <input type="file" id="fileInput"> </div> <div class="form-group"> <label>שם קובץ (אופציונלי):</label> <input type="text" id="fileNameAudio" placeholder="למשל 000"> </div> </div> <div id="text-section" class="hidden"> <div class="form-group"> <label>הטקסט להעלאה:</label> <textarea id="textContent" style="height:150px;" placeholder="כתוב טקסט"></textarea> </div> <div class="form-group"> <label>שם קובץ (חובה):</label> <input type="text" id="fileNameText" placeholder="למשל 001.tts"> </div> </div> <div id="ini-section" class="hidden"> <div class="form-group"> <label>שם קובץ (ללא סיומת):</label> <input type="text" id="fileNameIni" value="ext" placeholder="למשל ext"> </div> <div class="ini-container"> <div class="ini-box"> <span>תוכן הקובץ הקיים</span> <textarea id="iniContentExisting" readonly placeholder="התוכן הקיים יופיע כאן"></textarea> <button type="button" id="loadIniBtn" onclick="fetchExistingText()" class="load-btn-dynamic">טען תוכן קיים</button> </div> <div class="ini-box"> <span>טען תוכן להעלאה</span> <textarea id="iniContentNew" placeholder="כתוב טקסט להעלאה..."></textarea> </div> </div> </div> <div id="tzintuk-wrapper" class="tzintuk-section"> <label style="display: flex; align-items: center; gap: 10px; cursor: pointer;"> <input type="checkbox" id="use-tzintuk" style="width: 18px; height: 18px;" onchange="document.getElementById('tz-fields').style.display = this.checked ? 'block' : 'none'"> <span style="font-weight: bold; color: #2c3e50;">הפעל צינתוק בסיום ההעלאה</span> </label> <div id="tz-fields" style="display: none; margin-top: 15px; border-top: 1px solid #eee; padding-top: 10px;"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px;"> <div> <label style="font-size: 13px;">זיהוי יוצא (callerId):</label> <input type="text" id="tz-caller" placeholder="הכנס את הזיהוי היוצא"> </div> <div> <label style="font-size: 13px;">זמן (9-16 שניות):</label> <input type="number" id="tz-time" value="9" min="9" max="16"> </div> </div> <div> <label style="font-size: 13px;">מספר רשימת הצינתוקים:</label> <input type="text" id="tz-phones" placeholder="הכנס את מספר רשימת הצינתוקים, למספר רשימות יש להפריד עם פסיק"> </div> </div> </div> <div class="btn-container"> <button type="button" id="mainSubmitBtn" onclick="executeUpload()" class="submit-btn">בצע העלאה</button> <button type="button" onclick="listFiles()" class="list-btn">הצג קבצים בשלוחה</button> </div> </form> <div id="fileListContainer"> <table id="filesTable"> <thead> <tr> <th>שם קובץ</th> <th>פעולות</th> </tr> </thead> <tbody id="filesBody"></tbody> </table> </div></div>
<script>
let currentMode = 'file';function switchMode(mode) { currentMode = mode; document.getElementById('opt-file').classList.toggle('active', mode === 'file'); document.getElementById('opt-text').classList.toggle('active', mode === 'text'); document.getElementById('opt-ini').classList.toggle('active', mode === 'ini'); document.getElementById('file-section').classList.toggle('hidden', mode !== 'file'); document.getElementById('text-section').classList.toggle('hidden', mode !== 'text'); document.getElementById('ini-section').classList.toggle('hidden', mode !== 'ini'); // הסתרת אפשרות הצינתוק אם אנחנו במצב INI const tzWrapper = document.getElementById('tzintuk-wrapper'); if (mode === 'ini') { tzWrapper.style.display = 'none'; } else { tzWrapper.style.display = 'block'; } } async function fetchExistingText() { const token = document.getElementById('token').value; const folder = document.getElementById('folder').value.split(',')[0].trim(); let fileName = document.getElementById('fileNameIni').value.trim() || "ext"; const btn = document.getElementById('loadIniBtn'); if (!token || !folder) { alert("נא למלא טוקן ושלוחה לפני הטעינה"); return; } btn.innerText = "טוען תוכן קובץ..."; btn.classList.add('load-btn-loading'); btn.disabled = true; if (!fileName.toLowerCase().endsWith('.ini')) fileName += ".ini"; const fullPath = `ivr2:${folder}/${fileName}`; try { const url = `https://www.call2all.co.il/ym/api/GetTextFile?token=${encodeURIComponent(token)}&what=${encodeURIComponent(fullPath)}`; const res = await fetch(url); const data = await res.json(); document.getElementById('iniContentExisting').value = data.responseStatus === "OK" ? (data.contents || "קובץ ריק") : "קובץ לא נמצא"; } catch (e) { alert("שגיאת תקשורת"); } finally { btn.innerText = "טען תוכן קיים"; btn.classList.remove('load-btn-loading'); btn.disabled = false; } } async function listFiles() { const token = document.getElementById('token').value; const folder = document.getElementById('folder').value.split(',')[0].trim(); const tbody = document.getElementById('filesBody'); if (!token || !folder) { alert("מלא טוקן ושלוחה (הראשונה)"); return; } try { const url = `https://www.call2all.co.il/ym/api/GetIVR2Dir?token=${token}&path=${folder}`; const res = await fetch(url); const data = await res.json(); if (data.responseStatus === "OK") { tbody.innerHTML = ""; data.files.forEach(f => { tbody.innerHTML += `<tr><td>${f.name}</td><td><button onclick="alert('נתיב: ivr2:${folder}/${f.name}')">פרטים</button></td></tr>`; }); document.getElementById('fileListContainer').style.display = "block"; } } catch (e) { alert("שגיאת תקשורת"); } } async function sendTzintuk() { // אם אנחנו במצב INI, לא לבצע צינתוק בכלל if (currentMode === 'ini') return; const token = document.getElementById('token').value.trim(); const rawPhones = document.getElementById('tz-phones').value.trim(); const callerId = document.getElementById('tz-caller').value.trim() || 'RAND'; const timeout = document.getElementById('tz-time').value; if (!rawPhones) return; const formattedPhones = rawPhones.split(',') .map(p => p.trim()) .filter(p => p !== "") .map(p => p.startsWith('tzl:') ? p : 'tzl:' + p) .join(','); const url = `https://www.call2all.co.il/ym/api/RunTzintuk?token=${token}&phones=${formattedPhones}&callerId=${callerId}&intTzintukTimeOut=${timeout}`; try { const response = await fetch(url); const result = await response.text(); console.log("תגובת צינתוק: " + result); } catch (error) { console.error("שגיאת צינתוק:", error); } } async function executeUpload() { const token = document.getElementById('token').value; const folderInput = document.getElementById('folder').value.trim(); if (!token || !folderInput) { alert("מלא פרטים"); return; } const folders = folderInput.split(',').map(f => f.trim()).filter(f => f !== ""); const submitBtn = document.getElementById('mainSubmitBtn'); const progBar = document.getElementById('progressBar'); const progContainer = document.getElementById('progressContainer'); submitBtn.disabled = true; progContainer.style.display = "block"; let successCount = 0; let failCount = 0; for (let i = 0; i < folders.length; i++) { const folder = folders[i]; submitBtn.innerText = `מעלה לשלוחה ${folder}... (${i+1}/${folders.length})`; const formData = new FormData(); formData.append('token', token); let apiUrl = "https://www.call2all.co.il/ym/api/UploadFile"; if (currentMode === 'file') { const fIn = document.getElementById('fileInput'); if (!fIn.files.length) { alert("בחר קובץ"); break; } formData.append('file', fIn.files[0]); formData.append('convertAudio', '1'); let name = document.getElementById('fileNameAudio').value.trim(); let pathValue = "ivr2:" + folder + "/"; if (name) { if (!name.toLowerCase().endsWith('.wav')) name += ".wav"; pathValue += name; formData.append('autoNumbering', 'false'); } else { formData.append('autoNumbering', 'true'); } formData.append('path', pathValue); } else { apiUrl = "https://www.call2all.co.il/ym/api/UploadTextFile"; let name = currentMode === 'text' ? document.getElementById('fileNameText').value.trim() : document.getElementById('fileNameIni').value.trim(); let content = currentMode === 'text' ? document.getElementById('textContent').value : document.getElementById('iniContentNew').value; if (currentMode === 'ini' && name && !name.toLowerCase().endsWith('.ini')) name += ".ini"; formData.append('what', `ivr2:${folder}/${name}`); formData.append('contents', content); } try { const res = await fetch(apiUrl, { method: "POST", body: formData }); const result = await res.json(); if (result.responseStatus === "OK") successCount++; else failCount++; } catch (e) { failCount++; } const percent = Math.round(((i + 1) / folders.length) * 100); progBar.style.width = percent + "%"; progBar.innerText = percent + "%"; } // ביצוע צינתוק בסיום - רק אם מסומן ורק אם לא במצב INI if (currentMode !== 'ini' && document.getElementById('use-tzintuk').checked) { await sendTzintuk(); } submitBtn.disabled = false; submitBtn.innerText = "בצע העלאה"; alert(`הסתיים. הצלחות: ${successCount}, כשלונות: ${failCount}`); setTimeout(() => { progContainer.style.display = "none"; }, 5000); }</script>
</body>
</html>קרדיט: @אA
-
קובץ להפעלת קמפיין - הנכנס לשלוחה במערכת
הפעלת קמפיין - הנכנס לשלוחה במערכת.html
הקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>שיגור קמפיין - הנכנס לשלוחה במערכת</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
:root {
--primary-color: #4a90e2;
--success-color: #27ae60;
--error-color: #e74c3c;
--border-radius: 12px;
}body { font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f7f9; margin: 0; padding: 20px; color: #333; } .container { max-width: 600px; margin: auto; background: white; padding: 30px; border-radius: var(--border-radius); box-shadow: 0 4px 15px rgba(0,0,0,0.1); } h2 { text-align: center; color: var(--primary-color); display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 25px; } .speaker-icon { width: 30px; height: 30px; background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%234a90e2"><path d="M14 3.23v17.54c0 .87-.98 1.34-1.6.84L7.37 15H2c-1.1 0-2-.9-2-2v-2c0-1.1.9-2 2-2h5.37L12.4 2.39c.62-.5 1.6-.03 1.6.84zM16.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM19 12c0 2.97-1.87 5.51-4.5 6.74v-13.48c2.63 1.23 4.5 3.77 4.5 6.74z"/></svg>'); background-repeat: no-repeat; background-position: center; background-size: contain; } .form-group { margin-bottom: 15px; } label { display: block; font-weight: bold; margin-bottom: 5px; } input, textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 8px; box-sizing: border-box; } .type-selector { display: flex; gap: 15px; margin-bottom: 15px; background: #f9f9f9; padding: 10px; border-radius: 8px; } .type-selector label { font-weight: normal; cursor: pointer; display: flex; align-items: center; gap: 5px; margin: 0; } .ivr-input-wrapper { display: flex; direction: ltr; border: 1px solid #ddd; border-radius: 8px; overflow: hidden; } .ivr-prefix { background: #eee; padding: 10px; border-right: 1px solid #ddd; font-weight: bold; } .ivr-input-wrapper input { border: none; flex: 1; outline: none; } button { background-color: var(--success-color); color: white; border: none; padding: 15px; cursor: pointer; border-radius: 8px; width: 100%; font-size: 18px; font-weight: bold; margin-top: 10px; } button:active { transform: scale(0.98); } button:disabled { background-color: #ccc; cursor: not-allowed; } #error-display { margin-top: 15px; padding: 15px; background: #fff5f5; border: 1px solid var(--error-color); border-radius: 8px; color: var(--error-color); display: none; font-size: 14px; } .modal { display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); backdrop-filter: blur(3px); } .modal-content { background: white; margin: 15% auto; padding: 25px; border-radius: var(--border-radius); width: 90%; max-width: 450px; text-align: center; box-shadow: 0 8px 25px rgba(0,0,0,0.2); } table { width: 100%; border-collapse: collapse; margin-top: 15px; direction: rtl; } th, td { border: 1px solid #ddd; padding: 10px; text-align: right; } th { background: #f9f9f9; } .close-btn { background: #666; color: white; padding: 8px 20px; border: none; border-radius: 5px; cursor: pointer; margin-top: 15px; } </style></head>
<body><div class="container">
<h2>
<div class="speaker-icon"></div>
שיגור קמפיין - הנכנס לשלוחה
</h2><div class="form-group"> <label>טוקן (Token):</label> <input type="text" id="token" placeholder="הכנס טוקן API"> </div> <div class="form-group"> <label>סוג יעד:</label> <div class="type-selector"> <label><input type="radio" name="targetType" value="manual" checked onchange="updateUI()"> רשימת מספרים</label> <label><input type="radio" name="targetType" value="tpl" onchange="updateUI()"> רשימת תפוצה</label> <label><input type="radio" name="targetType" value="tzl" onchange="updateUI()"> רשימת צינתוקים</label> </div> </div> <div class="form-group" id="excelGroup"> <label>טעינת אקסל (אופציונלי):</label> <input type="file" id="excelFile" accept=".xlsx, .xls, .csv"> </div> <div class="form-group"> <label id="targetLabel">מספרי טלפון:</label> <textarea id="targetInput" rows="4" placeholder="מספר בכל שורה"></textarea> </div> <div class="form-group"> <label>שלוחה במערכת:</label> <div class="ivr-input-wrapper"> <span class="ivr-prefix">ivr2:</span> <input type="text" id="ivrPath" placeholder="/1/100"> </div> </div> <div class="form-group"> <label>זיהוי שיחה (Caller ID) - אופציונלי:</label> <input type="text" id="callerId" placeholder="ברירת מחדל"> </div> <div class="form-group"> <label>זמן המתנה (30-35 שניות):</label> <input type="number" id="callsTimeOut" value="30" min="30" max="35"> </div> <button id="submitBtn" onclick="sendCampaign()">שיגור קמפיין</button> <div id="error-display"></div></div>
<div id="successModal" class="modal">
<div class="modal-content">
<h3 style="color: var(--success-color);">הקמפיין נוצר בהצלחה!</h3>
<table id="resultTable"></table>
<button class="close-btn" onclick="closeModal()">סגור</button>
</div>
</div><script>
function updateUI() {
const type = document.querySelector('input[name="targetType"]:checked').value;
const inputArea = document.getElementById('targetInput');
const excelGroup = document.getElementById('excelGroup');
const label = document.getElementById('targetLabel');inputArea.value = ''; // ניקוי התיבה במעבר בין סוגים if (type === 'manual') { label.innerText = 'מספרי טלפון:'; inputArea.placeholder = 'מספר בכל שורה'; excelGroup.style.display = 'block'; } else if (type === 'tpl') { label.innerText = 'מזהה רשימת תפוצה:'; inputArea.placeholder = 'הכנס מספר מזהה בלבד'; excelGroup.style.display = 'none'; } else { label.innerText = 'מזהה רשימת צינתוקים:'; inputArea.placeholder = 'הכנס מספר מזהה בלבד'; excelGroup.style.display = 'none'; } } document.getElementById('excelFile').addEventListener('change', function(e) { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = function(event) { try { const data = new Uint8Array(event.target.result); const workbook = XLSX.read(data, { type: 'array' }); const sheet = workbook.Sheets[workbook.SheetNames[0]]; const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 }); const phones = rows.map(r => r[0]).filter(c => c); document.getElementById('targetInput').value = phones.join('\n'); } catch (err) { alert("שגיאה בקריאת הקובץ"); } }; reader.readAsArrayBuffer(file); }); async function sendCampaign() { const btn = document.getElementById('submitBtn'); const errorDiv = document.getElementById('error-display'); errorDiv.style.display = "none"; btn.innerText = "שולח... נא להמתין"; btn.disabled = true; const token = document.getElementById('token').value.trim(); const userInput = document.getElementById('targetInput').value.trim(); let ivrPath = document.getElementById('ivrPath').value.trim(); const timeout = document.getElementById('callsTimeOut').value; const callerId = document.getElementById('callerId').value.trim(); const targetType = document.querySelector('input[name="targetType"]:checked').value; if (!token || !userInput || !ivrPath) { showError("חובה למלא את כל השדות"); resetBtn(); return; } // בניית פרמטר phones עם הקידומת המתאימה מאחורי הקלעים let phonesParam = ""; if (targetType === 'tpl') { phonesParam = `tpl:${userInput}`; } else if (targetType === 'tzl') { phonesParam = `tzl:${userInput}`; } else { phonesParam = userInput.split('\n').map(p => p.trim()).filter(p => p).join(':'); } if (!ivrPath.startsWith('/')) ivrPath = '/' + ivrPath; const finalIvrPath = `ivr2:${ivrPath}`; let url = `https://www.call2all.co.il/ym/api/CallExtensionBridging?token=${token}&phones=${phonesParam}&ivrPath=${finalIvrPath}&callsTimeOut=${timeout}`; if (callerId) url += `&callerId=${callerId}`; try { const response = await fetch(url); const result = await response.json(); if (result.responseStatus === "OK") { showSuccess(result); } else { showError("שגיאת מערכת: " + (result.message || "שגיאה")); } } catch (e) { showError("שגיאת תקשורת."); } finally { resetBtn(); } } function showSuccess(data) { const table = document.getElementById('resultTable'); table.innerHTML = `<tr><td>סטטוס</td><td>${data.responseStatus}</td></tr> <tr><td>מזהה קמפיין</td><td>${data.campaignId || 'אין'}</td></tr> <tr><td>מספרים שנקלטו</td><td>${data.callsCount || '0'}</td></tr>`; document.getElementById('successModal').style.display = "block"; } function showError(msg) { const errorDiv = document.getElementById('error-display'); errorDiv.innerText = msg; errorDiv.style.display = "block"; } function resetBtn() { const btn = document.getElementById('submitBtn'); btn.innerText = "שיגור קמפיין"; btn.disabled = false; } function closeModal() { document.getElementById('successModal').style.display = "none"; }</script>
</body>
</html>קרדיט: @אA
-
@אA כתב בקבצי HTML לשימוש במערכות ימות המשיח:
הפעלת קמפיין - הנכנס לשלוחה במערכת.html
מה הכוונה?
"הנכנס לשולחה במערכת"?שליחת קמפיין רגיל? משהו אחר?
(סליחה על ההתערבות בשירשור בלנ"ד אח"כ אמחק ) -
קובץ להוספת והגדרת שלוחות במערכות
הקובץ מתעדכן מידי פעם.
ניתן לעזור בשדרוג הקובץ כאןעידכון אחרון: א' טבת
יצירת והגדרת שלוחות.htmlהקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>ממשק יצירת והגדרת שלוחות - מתוקן</title>
<style>
:root { --primary: #3498db; --success: #2ecc71; --danger: #e74c3c; --dark: #2c3e50; --bg: #f4f7f6; }
body { font-family: 'Segoe UI', sans-serif; background-color: var(--bg); margin: 0; padding: 20px; direction: rtl; }
.container { max-width: 800px; margin: auto; background: white; border-radius: 12px; box-shadow: 0 8px 30px rgba(0,0,0,0.1); overflow: hidden; }
.header { background: var(--dark); color: white; padding: 20px; text-align: center; }
.content { padding: 30px; position: relative; }
.card { border: 1px solid #ddd; padding: 20px; border-radius: 8px; margin-bottom: 20px; background: #fff; position: relative; }
label { display: block; margin-bottom: 6px; font-weight: bold; }
input, select { width: 100%; padding: 12px; border: 1px solid #ccc; border-radius: 6px; box-sizing: border-box; font-size: 16px; margin-bottom: 10px; }.toolbar { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 15px; } .btn-small { padding: 8px 15px; font-size: 14px; cursor: pointer; border-radius: 6px; border: 1px solid var(--dark); background: white; } .btn { padding: 12px; border-radius: 6px; border: none; font-weight: bold; cursor: pointer; width: 100%; transition: 0.2s; font-size: 16px; } .btn-primary { background: var(--primary); color: white; } .btn-success { background: var(--success); color: white; } .btn-danger { background: var(--danger); color: white; } #wizard-box { text-align: center; border: 2px solid var(--primary); display: none; } #display-q { font-size: 22px; font-weight: bold; margin-bottom: 20px; color: var(--dark); min-height: 50px; } .choice-btns { display: flex; gap: 15px; justify-content: center; } .token-dropdown { position: absolute; width: calc(100% - 20px); background: white; border: 1px solid #ddd; border-radius: 6px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); z-index: 100; max-height: 200px; overflow-y: auto; display: none; } .token-item { padding: 10px; cursor: pointer; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; } .token-item:hover { background: #f0f8ff; } </style></head>
<body><div class="container">
<div class="header"><h1>ממשק יצירת והגדרת שלוחות</h1></div><div class="content"> <div class="toolbar"> <button class="btn-small" onclick="exportDatabase()">📥 הורדת גיבוי JSON</button> <button class="btn-small" onclick="document.getElementById('json-upload').click()">📁 ייבוא מאגר JSON</button> <input type="file" id="json-upload" accept=".json" style="display:none" onchange="handleJsonImport(this)"> </div> <div id="setup-card" class="card"> <div style="display:flex; gap:10px;"> <div style="flex:2; position: relative;"> <label>טוקן:</label> <input type="text" id="api-token" placeholder="הזן טוקן או בחר מרשימה" onfocus="showTokenList()"> <div id="token-list" class="token-dropdown"></div> </div> <div style="flex:1;"> <label>מספר שלוחה:</label> <input type="text" id="api-path" placeholder="למשל: 1/5"> </div> </div> <label>בחר סוג שלוחה:</label> <select id="run-main-select"></select> <button id="start-btn" class="btn btn-primary" onclick="initWizard()">התחל שאלון הגדרות</button> </div> <div id="wizard-box" class="card"> <div id="display-q">טוען שאלה...</div> <div id="sub-input-box" style="display:none; margin-bottom:20px;"> <p id="sub-q-label" style="font-weight:bold;"></p> <input type="text" id="user-sub-val" placeholder="הכנס ערך כאן..."> <button class="btn btn-primary" onclick="handleSubInput()">אישור והמשך</button> </div> <div id="choice-btns" class="choice-btns"> <button class="btn btn-success" style="width:120px;" onclick="processChoice(true)">כן</button> <button class="btn btn-danger" style="width:120px;" onclick="processChoice(false)">לא</button> </div> </div> <div id="final-box" class="card" style="display:none; text-align:center;"> <h3>הגדרות מוכנות:</h3> <div id="final-string" style="background:#eee; padding:10px; margin:10px 0; word-break:break-all; font-family:monospace;"></div> <button class="btn btn-success" onclick="sendToYemot()">🚀 שלח לימות המשיח</button> <button class="btn" style="margin-top:10px;" onclick="location.reload()">ביטול</button> </div> </div></div>
<script>
// מאגר ברירת מחדל אם אין כלום בזיכרון
const DEFAULT_DATA = {
"type=menu": [
{ "q": "האם להפעיל השמעת תפריט?", "v": "say_menu=yes", "hasSub": false },
{ "q": "האם להגדיר כותרת לשלוחה?", "v": "title=[VALUE]", "hasSub": true, "subQ": "מה הכותרת?", "subKey": "[VALUE]" }
],
"type=playfile": [
{ "q": "האם לאפשר דילוג על קבצים?", "v": "playfile_control=yes", "hasSub": false }
]
};let DATABASE_CONTENT = JSON.parse(localStorage.getItem('yemot_db')) || DEFAULT_DATA; let currentMainDef = ""; let currentStep = 0; let finalParams = []; window.onload = () => { updateDropdown(); renderTokenList(); }; // --- ייבוא / ייצוא --- function exportDatabase() { const blob = new Blob([JSON.stringify(DATABASE_CONTENT, null, 2)], { type: 'application/json' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'yemot_db.json'; a.click(); } function handleJsonImport(input) { const file = input.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { try { const imported = JSON.parse(e.target.result); DATABASE_CONTENT = imported; localStorage.setItem('yemot_db', JSON.stringify(DATABASE_CONTENT)); updateDropdown(); alert("המאגר עודכן בהצלחה!"); } catch(err) { alert("קובץ לא תקין"); } }; reader.readAsText(file); } // --- לוגיקת שאלון (התיקון כאן) --- function updateDropdown() { const select = document.getElementById('run-main-select'); select.innerHTML = '<option value="">-- בחר --</option>'; Object.keys(DATABASE_CONTENT).forEach(key => { const opt = document.createElement('option'); opt.value = key; opt.innerText = key; select.appendChild(opt); }); } function initWizard() { currentMainDef = document.getElementById('run-main-select').value; if(!currentMainDef) return alert("אנא בחר סוג שלוחה"); currentStep = 0; finalParams = [currentMainDef]; // מתחיל עם סוג השלוחה (למשל type=menu) document.getElementById('setup-card').style.display = 'none'; document.getElementById('wizard-box').style.display = 'block'; renderStep(); } function renderStep() { const questions = DATABASE_CONTENT[currentMainDef]; // בדיקה אם סיימנו את כל השאלות במאגר if(!questions || currentStep >= questions.length) { showFinal(); return; } const currentItem = questions[currentStep]; document.getElementById('display-q').innerText = currentItem.q; document.getElementById('choice-btns').style.display = 'flex'; document.getElementById('sub-input-box').style.display = 'none'; } function processChoice(isYes) { const item = DATABASE_CONTENT[currentMainDef][currentStep]; if(isYes) { if(item.hasSub) { // מעבר להזנת ערך ידני document.getElementById('choice-btns').style.display = 'none'; document.getElementById('sub-input-box').style.display = 'block'; document.getElementById('sub-q-label').innerText = item.subQ; } else { finalParams.push(item.v); currentStep++; renderStep(); } } else { currentStep++; renderStep(); } } function handleSubInput() { const item = DATABASE_CONTENT[currentMainDef][currentStep]; const val = document.getElementById('user-sub-val').value.trim(); if(!val) return alert("חובה להזין ערך"); // החלפת ה-Placeholder בערך שהמשתמש הזין const formattedVal = item.v.replace(item.subKey, val); finalParams.push(formattedVal); document.getElementById('user-sub-val').value = ''; currentStep++; renderStep(); } function showFinal() { document.getElementById('wizard-box').style.display = 'none'; document.getElementById('final-box').style.display = 'block'; document.getElementById('final-string').innerText = finalParams.join('&'); } // --- טוקנים ו-API --- function showTokenList() { document.getElementById('token-list').style.display = 'block'; } function selectToken(t) { document.getElementById('api-token').value = t; document.getElementById('token-list').style.display = 'none'; } function renderTokenList() { const saved = JSON.parse(localStorage.getItem('saved_yemot_tokens')) || []; const list = document.getElementById('token-list'); list.innerHTML = saved.map(i => `<div class="token-item" onclick="selectToken('${i.token}')"><span>${i.alias}</span></div>`).join(''); } async function sendToYemot() { const token = document.getElementById('api-token').value; const path = document.getElementById('api-path').value; const url = `https://www.call2all.co.il/ym/api/UpdateExtension?token=${token}&path=ivr2:${path}&${finalParams.join('&')}`; try { const r = await fetch(url); const txt = await r.text(); alert("תשובה מימות: " + txt); } catch(e) { alert("שגיאת תקשורת"); } }</script>
</body>
</html>קרדיט: @אA
-
@אA במערכת מעלה קבצים יש אפשרות לעלות לכמה שלוחות יחד? למחוק קבצים אפשר?
ואין אפשרות לראות % או משהו כזה עד לסיום הפעולה ? -
פוסט זה נמחק! -
פוסט זה נמחק! -
ממשק ניהול הקבצים במערכת
הקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>ניהול שלוחות ימות המשיח</title>
<style>
:root {
--primary: #2c3e50; --accent: #3498db; --success: #27ae60;
--danger: #e74c3c; --violet: #8e44ad; --orange: #f39c12;
}
body { font-family: 'Segoe UI', sans-serif; background: #f4f7f6; margin: 0; padding: 20px; }/* סרגל עליון */ .top-bar { background: white; padding: 15px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); display: flex; flex-direction: column; gap: 10px; margin-bottom: 20px; } .inputs-row { display: flex; gap: 10px; align-items: center; width: 100%; } input { padding: 8px; border: 1px solid #ddd; border-radius: 5px; flex: 1; } /* עיצוב רכיב הטוקנים */ .token-main { position: relative; flex: 1; display: flex; } /* גודל זהה לשדה הנתיב */ #tokenField { flex: 1; width: 100%; } .token-dropdown { position: absolute; width: 100%; background: white; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); z-index: 1000; max-height: 250px; overflow-y: auto; display: none; top: 100%; } .token-item { display: flex; justify-content: space-between; align-items: center; padding: 10px; cursor: pointer; border-bottom: 1px solid #eee; color: #333; } .token-item:hover { background: #f8f9fa; } .delete-item { color: #dc3545; font-weight: bold; padding: 5px 10px; cursor: pointer; border: none; background: none; } .dropdown-footer { padding: 8px; background: #f1f3f5; display: flex; gap: 5px; justify-content: center; border-top: 1px solid #ddd; } .footer-btn { font-size: 11px; padding: 4px 8px; cursor: pointer; border: 1px solid #ccc; background: white; border-radius: 4px; } /* כפתורים וטבלה */ .btn { cursor: pointer; border: none; border-radius: 4px; padding: 4px 8px; font-weight: bold; color: white; transition: 0.2s; font-size: 11px; text-align: center; display: inline-block; width: 100%; max-width: 75px; } .btn:hover { opacity: 0.85; transform: translateY(-1px); } .btn-load { background: var(--primary); padding: 8px 18px; width: auto; max-width: none; font-size: 14px; } .ext-container { background: #fff; padding: 15px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); margin-bottom: 20px; border-top: 4px solid var(--primary); } .ext-container h4 { margin: 0 0 10px 0; color: var(--primary); display: flex; justify-content: space-between; align-items: center; } #extTextArea { width: 100%; height: 120px; font-family: 'Consolas', monospace; font-size: 13px; padding: 10px; box-sizing: border-box; border: 1px solid #ddd; background: #fcfcfc; border-radius: 5px; } table { width: 100%; background: white; border-collapse: collapse; border-radius: 8px; overflow: hidden; } th { background: #f8f9fa; padding: 10px; font-size: 12px; border-bottom: 2px solid #eee; } td { padding: 5px 8px; border-bottom: 1px solid #eee; text-align: center; font-size: 12px; } .dl { background: var(--success); } .ed { background: var(--orange); } .up { background: var(--accent); } .del { background: var(--danger); } .view { background: var(--violet); } .modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.6); justify-content: center; align-items: center; z-index: 1000; } .modal-content { background: white; padding: 25px; border-radius: 12px; width: 600px; max-width: 95%; } .modal-footer { margin-top: 20px; display: flex; justify-content: flex-start; flex-direction: row-reverse; gap: 10px; } .convert-row { display: flex; gap: 10px; justify-content: center; margin-top: 20px; } </style></head>
<body><div class="top-bar">
<div class="inputs-row">
<div class="token-main">
<input type="text" id="tokenField" placeholder="הזן טוקן או בחר"
onclick="toggleDropdown(true)" oninput="filterDropdown(this.value)" onkeypress="handleEnter(event)" autocomplete="off">
<div id="tokenDropdown" class="token-dropdown"></div>
</div><input type="text" id="pathField" value="" placeholder="נתיב שלוחה" onkeypress="handleEnter(event)"> <button class="btn btn-load" onclick="startProcess()">טען רשימת קבצים</button> </div> <div style="display: flex; align-items: center; gap: 15px; padding-top: 5px;"> <div style="display: flex; align-items: center; gap: 5px;"> <input type="checkbox" id="saveTokenToggle" style="width: auto; cursor: pointer;" onchange="document.getElementById('tokenNameField').style.display = this.checked ? 'block' : 'none'"> <label for="saveTokenToggle" style="font-size: 12px; cursor: pointer; color: #666;">שמור טוקן זה במאגר</label> </div> <div id="tokenNameField" style="display:none;"> <input type="text" id="tokenAlias" placeholder="שם למזהה (למשל: המערכת שלי)" style="font-size: 12px; padding: 5px; width: 200px;"> </div> </div></div>
<div class="ext-container" id="extContainer" style="display:none;">
<h4>
<span>הגדרות שלוחה (ext.ini)</span>
<div style="display:flex; gap:8px;">
<button class="btn" style="background:var(--orange); width:auto; padding:5px 15px;" onclick="renameExtIni()">שנה שם</button>
<button class="btn" style="background:var(--success); width:auto; padding:5px 15px;" onclick="saveExtIni()">שמור שינויים</button>
</div>
</h4>
<textarea id="extTextArea"></textarea>
</div><table>
<thead>
<tr>
<th style="text-align: right; width: 25%;">שם קובץ</th>
<th>גודל</th>
<th>תצוגה</th>
<th>הורדה</th>
<th>שינוי שם</th>
<th>החלפה</th>
<th>מחיקה</th>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table><div id="mainModal" class="modal">
<div class="modal-content">
<h3 id="modalTitle" style="margin:0 0 15px 0; border-bottom:1px solid #eee; padding-bottom:10px;"></h3>
<div id="modalBody"></div>
<div class="modal-footer" id="modalFooter">
<button id="saveBtn" class="btn btn-load">שמור</button>
<button class="btn" onclick="closeModal()" style="background:#95a5a6;">ביטול</button>
</div>
</div>
</div><script>
const API_BASE = 'https://www.call2all.co.il/ym/api/';
const STORAGE_KEY = 'yemot_permanent_storage';
let savedTokens = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');document.addEventListener('click', (e) => { if (!e.target.closest('.token-main')) toggleDropdown(false); }); function toggleDropdown(show) { const dropdown = document.getElementById('tokenDropdown'); if (show) { renderDropdown(); dropdown.style.display = 'block'; } else { dropdown.style.display = 'none'; } } function renderDropdown(filter = "") { const dropdown = document.getElementById('tokenDropdown'); dropdown.innerHTML = ''; const filteredKeys = Object.keys(savedTokens).filter(a => a.toLowerCase().includes(filter.toLowerCase())); filteredKeys.forEach(alias => { const item = document.createElement('div'); item.className = 'token-item'; item.innerHTML = `<span>${alias}</span><button type="button" class="delete-item">✖</button>`; item.onclick = () => { document.getElementById('tokenField').value = savedTokens[alias]; toggleDropdown(false); }; item.querySelector('.delete-item').onclick = (e) => { e.stopPropagation(); if(confirm(`למחוק את ${alias}?`)) { delete savedTokens[alias]; localStorage.setItem(STORAGE_KEY, JSON.stringify(savedTokens)); renderDropdown(filter); } }; dropdown.appendChild(item); }); const footer = document.createElement('div'); footer.className = 'dropdown-footer'; footer.innerHTML = `<button type="button" class="footer-btn" style="color:red" onclick="if(confirm('למחוק הכל?')){savedTokens={};localStorage.setItem(STORAGE_KEY,'{}');renderDropdown();}">מחק הכל</button>`; footer.onclick = (e) => e.stopPropagation(); dropdown.appendChild(footer); } function filterDropdown(val) { renderDropdown(val); document.getElementById('tokenDropdown').style.display = 'block'; } function startProcess() { saveCurrentTokenIfRequested(); loadDirectory(); } function saveCurrentTokenIfRequested() { const token = document.getElementById('tokenField').value.trim(); const alias = document.getElementById('tokenAlias').value.trim(); if (document.getElementById('saveTokenToggle').checked && alias && token) { savedTokens[alias] = token; localStorage.setItem(STORAGE_KEY, JSON.stringify(savedTokens)); } } function handleEnter(event) { if (event.key === "Enter") startProcess(); } function getFullPath(fileName = "") { let rawPath = document.getElementById('pathField').value.trim(); if (rawPath && !rawPath.endsWith('/') && fileName !== "") rawPath += '/'; return `ivr2:${rawPath}${fileName}`; } async function callApi(method, params = {}) { const token = document.getElementById('tokenField').value.trim(); if (!token) return; let url = `${API_BASE}${method}?token=${token}`; for (let key in params) url += `&${key}=${encodeURIComponent(params[key])}`; const res = await fetch(url); return await res.json(); } async function loadDirectory() { const data = await callApi('GetIVR2Dir', { path: getFullPath() }); const body = document.getElementById('tableBody'); body.innerHTML = ''; if (data && data.files) { data.files.forEach(file => { const isText = file.name.endsWith('.ini') || file.name.endsWith('.tts'); body.innerHTML += ` <tr> <td style="text-align: right;"><strong>${file.name}</strong></td> <td style="color:#888;">${file.size} B</td> <td>${isText ? `<button class="btn view" onclick="openTextFile('${file.name}')">הצג</button>` : '-'}</td> <td><button class="btn dl" onclick="handleDownloadClick('${file.name}')">הורדה</button></td> <td><button class="btn ed" onclick="renameFile('${file.name}')">שינוי</button></td> <td><button class="btn up" onclick="uploadUI('${file.name}')">החלפה</button></td> <td><button class="btn del" onclick="deleteFile('${file.name}')">מחיקה</button></td> </tr>`; }); loadExtIni(); } } async function loadExtIni() { const data = await callApi('GetTextFile', { what: getFullPath('ext.ini') }); document.getElementById('extContainer').style.display = 'block'; document.getElementById('extTextArea').value = (data && data.exists !== false) ? data.contents || "" : "קובץ ext.ini לא נמצא."; } async function saveExtIni() { const res = await callApi('UploadTextFile', { what: getFullPath('ext.ini'), contents: document.getElementById('extTextArea').value }); if (res && res.responseStatus === "OK") alert("נשמר!"); } async function renameExtIni() { const newName = prompt("שם חדש ל-ext.ini:", "ext.ini"); if (newName) { const res = await callApi('FileAction', { action: 'move', what: getFullPath('ext.ini'), target: getFullPath(newName) }); if (res && res.responseStatus === "OK") loadDirectory(); } } function handleDownloadClick(name) { if (name.toLowerCase().endsWith('.ymgr')) showConvertModal(name); else window.open(`${API_BASE}DownloadFile?token=${document.getElementById('tokenField').value}&path=${getFullPath(name)}`); } function showConvertModal(name) { const html = ` <p style="text-align:center;">בחר פורמט המרה עבור קובץ הנתונים:</p> <div class="convert-row"> <button class="btn" style="background:var(--primary); max-width:none; flex:1; padding:10px;" onclick="executeRender('${name}', '')">ללא המרה</button> <button class="btn" style="background:var(--success); max-width:none; flex:1; padding:10px;" onclick="executeRender('${name}', 'csv')">אקסל (CSV)</button> <button class="btn" style="background:var(--violet); max-width:none; flex:1; padding:10px;" onclick="executeRender('${name}', 'html')">דף HTML</button> </div>`; showModal("המרה והורדה", html); document.getElementById('modalFooter').style.display = 'none'; } function executeRender(name, type) { const token = document.getElementById('tokenField').value; const url = type === "" ? `${API_BASE}DownloadFile?token=${token}&path=${getFullPath(name)}` : `${API_BASE}RenderYMGRFile?token=${token}&wath=${getFullPath(name)}&convertType=${type}`; window.open(url); closeModal(); } function showModal(title, html) { document.getElementById('modalTitle').innerText = title; document.getElementById('modalBody').innerHTML = html; document.getElementById('mainModal').style.display = 'flex'; document.getElementById('modalFooter').style.display = 'flex'; } function closeModal() { document.getElementById('mainModal').style.display = 'none'; } async function deleteFile(name) { if (confirm(`למחוק את ${name}?`)) { const res = await callApi('FileAction', { action: 'delete', what: getFullPath(name) }); if (res.responseStatus === "OK") loadDirectory(); } } function renameFile(name) { const newName = prompt("שם חדש:", name); if (newName) callApi('FileAction', { action: 'move', what: getFullPath(name), target: getFullPath(newName) }).then(loadDirectory); } async function openTextFile(name) { const data = await callApi('GetTextFile', { what: getFullPath(name) }); showModal(`עריכת ${name}`, `<textarea id="modalTextArea" style="width:100%; height:300px; font-family:monospace;">${data.contents || ''}</textarea>`); document.getElementById('saveBtn').onclick = async () => { await callApi('UploadTextFile', { what: getFullPath(name), contents: document.getElementById('modalTextArea').value }); closeModal(); loadDirectory(); }; } function uploadUI(name) { showModal(`החלפת ${name}`, `<input type="file" id="fInp" style="margin-top:10px;">`); document.getElementById('saveBtn').onclick = async () => { const token = document.getElementById('tokenField').value; const file = document.getElementById('fInp').files[0]; if (!file) return; const fd = new FormData(); fd.append('file', file); await fetch(`${API_BASE}UploadFile?token=${token}&path=${getFullPath()}`, { method: 'POST', body: fd }); closeModal(); loadDirectory(); }; }</script>
</body>
</html>קרדיט: @אA
-
פוסט זה נמחק!