קבצים ותוכנות לשימוש במערכות ימות המשיח
-
פוסט זה נמחק! -
פוסט זה נמחק! -
ממשק ניהול הקבצים במערכת
הקוד מצורף בספויילר
<!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
-
פוסט זה נמחק! -
ממשק ליצירת ניהול והפעלת קמפיין
לא בדקתי את הפעולה שלו בזמן אמת, אשמח אם יש מי שהשתמש בזה שיעדכן.
הקוד מצורף בספויילר
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<title>מערכת ניהול קמפיינים - Yemot API</title>
<style>
:root {
--primary-color: #2c3e50;
--accent-color: #3498db;
--bg-color: #f8f9fa;
}
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: var(--bg-color); margin: 0; padding: 20px; }
.container { max-width: 1100px; margin: auto; background: white; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); overflow: hidden; }/* תפריט עליון */ .tabs { display: flex; background: var(--primary-color); padding: 0 10px; } .tab-button { padding: 15px 25px; border: none; background: none; color: white; cursor: pointer; font-size: 16px; transition: 0.3s; border-bottom: 3px solid transparent; } .tab-button:hover { background: rgba(255,255,255,0.1); } .tab-button.active { border-bottom: 3px solid var(--accent-color); font-weight: bold; } /* תוכן החלונות */ .tab-content { display: none; padding: 30px; animation: fadeIn 0.4s; } .tab-content.active { display: block; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .form-group { margin-bottom: 20px; } label { display: block; margin-bottom: 8px; font-weight: 600; color: #444; } input, select, textarea { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; box-sizing: border-box; } .btn-row { display: flex; gap: 10px; margin-top: 20px; } button { padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; transition: 0.2s; } .btn-primary { background: var(--accent-color); color: white; } .btn-danger { background: #e74c3c; color: white; } .btn-success { background: #27ae60; color: white; } .response-area { margin-top: 25px; padding: 15px; background: #272c33; color: #61dafb; border-radius: 6px; font-family: monospace; font-size: 13px; white-space: pre-wrap; max-height: 250px; overflow-y: auto; direction: ltr; text-align: left; } .info-box { background: #e8f4fd; padding: 15px; border-radius: 6px; border-right: 4px solid var(--accent-color); margin-bottom: 20px; } </style></head>
<body><div class="container">
<div style="background: #eee; padding: 15px 30px; border-bottom: 1px solid #ddd; display: flex; align-items: center; gap: 15px;">
<label style="margin:0;">טוקן גישה (token):</label>
<input type="text" id="mainToken" placeholder="הכנס טוקן API כאן" style="width: 350px;">
</div><nav class="tabs"> <button class="tab-button active" onclick="openTab(event, 'setup')">הקמה והגדרות</button> <button class="tab-button" onclick="openTab(event, 'run')">הפעלת קמפיין</button> <button class="tab-button" onclick="openTab(event, 'contacts')">ניהול מספרים</button> <button class="tab-button" onclick="openTab(event, 'monitor')">בקרה בזמן אמת</button> <button class="tab-button" onclick="openTab(event, 'schedule')">תזמון</button> </nav> <div id="setup" class="tab-content active"> <h2>הקמת תבנית קמפיין חדשה</h2> <div class="form-group"> <label>שם הקמפיין (תיאור):</label> <input type="text" id="setup_desc" placeholder="לדוגמה: קמפיין התרמה"> </div> <button class="btn-primary" onclick="executeCall('CreateTemplate', {description: 'setup_desc'})">צור תבנית חדשה</button> <div class="response-area" id="res-setup">// ממתין לפעולה...</div> </div> <div id="run" class="tab-content"> <h2>הפעלת קמפיין</h2> <div class="form-group"> <label>מזהה תבנית:</label> <input type="number" id="run_tpl"> </div> <div class="form-group"> <label>רשימת מספרים - הפרדה בנקודותיים:</label> <textarea id="run_phones" rows="3" placeholder="0501234567:0507654321"></textarea> </div> <button class="btn-success" onclick="executeCall('RunCampaign', {templateId: 'run_tpl', phones: 'run_phones'})">שגר קמפיין עכשיו</button> <div class="response-area" id="res-run">// ממתין לפעולה...</div> </div> <div id="contacts" class="tab-content"> <h2>ניהול רשימות תפוצה</h2> <div class="form-group"> <label>מזהה תבנית:</label> <input type="number" id="list_tpl"> </div> <div class="form-group"> <label>נתוני טלפונים:</label> <textarea id="list_data" rows="5" placeholder="0501112233,ישראל ישראלי"></textarea> </div> <div class="btn-row"> <button class="btn-primary" onclick="executeCall('UploadPhoneList', {templateId: 'list_tpl', data: 'list_data'})">העלה רשימה</button> <button class="btn-danger" onclick="executeCall('ClearTemplateEntries', {templateId: 'list_tpl'})">מחק את כל הרשימה</button> </div> <div class="response-area" id="res-contacts">// ממתין לפעולה...</div> </div> <div id="monitor" class="tab-content"> <h2>ניהול קמפיין פעיל</h2> <div class="form-group"> <label>מזהה קמפיין רץ:</label> <input type="text" id="active_id"> </div> <div class="btn-row"> <button class="btn-primary" onclick="executeCall('GetCampaignStatus', {campaignId: 'active_id'})">בדוק סטטוס</button> <button class="btn-danger" onclick="executeCall('CampaignAction', {campaignId: 'active_id', action: 'stop'})">עצור קמפיין</button> <button style="background: #f39c12; color:white;" onclick="executeCall('CampaignAction', {campaignId: 'active_id', action: 'setPaused'})">השהה או המשך</button> </div> <div class="response-area" id="res-monitor">// ממתין לפעולה...</div> </div> <div id="schedule" class="tab-content"> <h2>תזמון קמפיין עתידי</h2> <div class="form-group"> <label>מזהה תבנית:</label> <input type="number" id="sched_tpl"> </div> <div class="form-group"> <label>זמן לביצוע:</label> <input type="text" id="sched_time" placeholder="yyyy-MM-dd HH:mm:ss"> </div> <button class="btn-primary" onclick="executeCall('ScheduleCampaign', {templateId: 'sched_tpl', time: 'sched_time'})">קבע תזמון</button> <div class="response-area" id="res-schedule">// ממתין לפעולה...</div> </div></div>
<script>
const API_BASE = "https://www.call2all.co.il/ym/api/";function openTab(evt, tabName) { var i, tabContent, tabButtons; tabContent = document.getElementsByClassName("tab-content"); for (i = 0; i < tabContent.length; i++) tabContent[i].classList.remove("active"); tabButtons = document.getElementsByClassName("tab-button"); for (i = 0; i < tabButtons.length; i++) tabButtons[i].classList.remove("active"); document.getElementById(tabName).classList.add("active"); evt.currentTarget.classList.add("active"); } function executeCall(command, params) { const token = document.getElementById('mainToken').value; if(!token) { alert("חובה להזין טוקן!"); return; } let url = new URL(API_BASE + command); url.searchParams.append("token", token); for (let key in params) { let val = params[key]; let element = document.getElementById(val); if(element) { url.searchParams.append(key, element.value); } else { url.searchParams.append(key, val); } } const activeResArea = document.querySelector('.tab-content.active .response-area'); activeResArea.innerHTML = "שולח בקשה...\n\nURL:\n" + url.href; }</script>
</body>
</html>קרדיט: @אA
-
הוספת טקסט למספר קבצים במערכת
הקוד מצורף בספויילר
<!DOCTYPE html> <html lang="he" dir="rtl"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ניהול קבצים - ימות המשיח</title> <style> :root { --primary-color: #4a90e2; --secondary-color: #2ecc71; --danger-color: #e74c3c; --bg-color: #f4f7f6; --text-color: #333; --card-bg: #ffffff; --border-radius: 12px; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: var(--bg-color); color: var(--text-color); margin: 0; padding: 20px; display: flex; justify-content: center; } .container { background-color: var(--card-bg); padding: 30px; border-radius: var(--border-radius); box-shadow: 0 10px 25px rgba(0,0,0,0.1); max-width: 650px; width: 100%; } h2 { text-align: center; color: var(--primary-color); margin-bottom: 30px; font-weight: 600; } .input-group { margin-bottom: 20px; } label { display: block; margin-bottom: 8px; font-weight: bold; font-size: 0.9em; } input[type="text"], textarea { width: 100%; padding: 12px; border: 2px solid #eee; border-radius: 8px; box-sizing: border-box; transition: border-color 0.3s; font-size: 16px; } input[type="text"]:focus, textarea:focus { border-color: var(--primary-color); outline: none; } .flex-row { display: flex; gap: 10px; align-items: center; } button { padding: 12px 20px; border: none; border-radius: 8px; cursor: pointer; font-weight: bold; transition: all 0.3s; display: inline-flex; align-items: center; justify-content: center; white-space: nowrap; } .btn-load { background-color: var(--primary-color); color: white; min-width: 120px; } .btn-load:hover { background-color: #357abd; transform: translateY(-1px); } .btn-add { background-color: var(--secondary-color); color: white; font-size: 0.9em; gap: 8px; } .btn-add:hover { background-color: #27ae60; } .btn-delete { background-color: var(--danger-color); color: white; padding: 10px; min-width: 40px; } .btn-delete:hover { background-color: #c0392b; } .file-input-wrapper { display: flex; gap: 8px; margin-bottom: 10px; animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } textarea { height: 180px; resize: vertical; background-color: #fafafa; font-family: monospace; margin-top: 10px; } /* עיצוב חדש לאזור העלאת קובץ מקומי */ .file-upload-zone { margin: 15px 0; padding: 15px; border: 2px dashed #ccc; border-radius: 8px; text-align: center; background-color: #f9f9f9; } .custom-file-upload { display: inline-block; padding: 8px 16px; cursor: pointer; background-color: #fff; border: 1px solid var(--primary-color); color: var(--primary-color); border-radius: 4px; font-weight: bold; transition: 0.3s; } .custom-file-upload:hover { background-color: var(--primary-color); color: white; } #localFileInput { display: none; } .btn-upload { background-color: #e67e22; color: white; width: 100%; font-size: 1.1em; margin-top: 10px; box-shadow: 0 4px 15px rgba(230, 126, 34, 0.3); } .btn-upload:hover { background-color: #d35400; } </style> </head> <body> <div class="container"> <h2>ניהול קבצי מערכת</h2> <div class="input-group"> <label>טוקן אישי</label> <input type="text" id="token" placeholder="הכנס את ה-Token שלך"> </div> <div class="input-group"> <label>מספר שלוחה</label> <div class="flex-row"> <input type="text" id="ext" placeholder="למשל: 1"> <button class="btn-load" onclick="loadFirstFile()">טען תוכן מהשרת</button> </div> </div> <div class="input-group"> <label>שמות קבצים ליעד</label> <div id="file-fields"> <div class="file-input-wrapper"> <input type="text" class="filename-input" placeholder="שם קובץ (למשל ext.ini)"> <button class="btn-add" onclick="addNewFileField()">קובץ נוסף +</button> </div> </div> </div> <div class="input-group"> <label>תוכן הקובץ</label> <textarea id="fileContents" placeholder="כאן יופיע תוכן הקובץ..."></textarea> <div class="file-upload-zone"> <label for="localFileInput" class="custom-file-upload"> 📂 טען טקסט מקובץ במחשב </label> <input type="file" id="localFileInput" accept=".txt,.ini,.csv,.text" onchange="readLocalFile(this)"> <div id="fileNameDisplay" style="margin-top: 8px; font-size: 0.8em; color: #666;"></div> </div> </div> <button class="btn-upload" onclick="uploadAll()">העלה קבצים למערכת</button> </div> <script> const baseUrl = 'https://www.call2all.co.il/ym/api/'; // פונקציה לקריאת קובץ מקומי מהמחשב function readLocalFile(input) { const file = input.files[0]; if (!file) return; const reader = new FileReader(); document.getElementById('fileNameDisplay').innerText = "קובץ שנבחר: " + file.name; reader.onload = function(e) { document.getElementById('fileContents').value = e.target.result; }; reader.readAsText(file); } function addNewFileField() { const container = document.getElementById('file-fields'); const newDiv = document.createElement('div'); newDiv.className = 'file-input-wrapper'; newDiv.innerHTML = ` <input type="text" class="filename-input" placeholder="שם קובץ נוסף"> <button class="btn-delete" onclick="removeField(this)" title="מחק שדה">🗑️</button> `; container.appendChild(newDiv); } function removeField(btn) { btn.parentElement.remove(); } async function loadFirstFile() { const token = document.getElementById('token').value; const ext = document.getElementById('ext').value; const firstInput = document.querySelector('.filename-input'); const fileName = firstInput ? firstInput.value : ''; if (!token || !fileName) { alert("נא למלא טוקן ושם קובץ בתיבה הראשונה"); return; } const path = `ivr2:${ext}/${fileName}`; try { const response = await fetch(`${baseUrl}GetTextFile?token=${token}&what=${path}`); const data = await response.json(); if (data.responseStatus === "OK") { document.getElementById('fileContents').value = data.contents || "הקובץ ריק"; } else { alert("שגיאה: " + (data.message || "לא ניתן לטעון קובץ")); } } catch (error) { alert("שגיאת תקשורת"); } } async function uploadAll() { const token = document.getElementById('token').value; const ext = document.getElementById('ext').value; const content = document.getElementById('fileContents').value; const fileInputs = document.querySelectorAll('.filename-input'); if (!token) { alert("אנא הזן טוקן"); return; } let successCount = 0; let fileCount = 0; for (let input of fileInputs) { const fileName = input.value; if (!fileName) continue; fileCount++; const path = `ivr2:${ext}/${fileName}`; const url = `${baseUrl}UploadTextFile?token=${token}&what=${path}&contents=${encodeURIComponent(content)}`; try { const res = await fetch(url); const data = await res.json(); if (data.responseStatus === "OK") successCount++; } catch (e) { console.error(e); } } if (fileCount === 0) { alert("לא הוזנו שמות קבצים ליעד"); } else { alert(`הסתיים! ${successCount} מתוך ${fileCount} קבצים עודכנו בהצלחה.`); } } </script> </body> </html> -
ממשק להתקנת תא קולי מתקדם על המערכת שלכם בהכנסת מספר וסיסמא בלבד!
הקוד הוא (מדריך להפיכת הקוד לקובץ בפוסט הראשון)
<!DOCTYPE html> <html lang="he" dir="rtl"> <head> <meta charset="UTF-8"> <title>מתקין מערכת - גרסה מתוקנת</title> <style> body { font-family: 'Segoe UI', Arial, sans-serif; background-color: #f4f7f9; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; padding: 20px; flex-direction: column; } .card { background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); width: 500px; text-align: center; } h2 { color: #2c3e50; margin-bottom: 20px; } input[type="text"], input[type="password"] { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #dcdfe6; border-radius: 8px; box-sizing: border-box; font-size: 16px; } .folder-input { background: #f9f9f9; padding: 20px; border: 2px dashed #409eff; border-radius: 8px; margin: 20px 0; cursor: pointer; transition: 0.3s; } .folder-input:hover { background: #ecf5ff; } button { background-color: #67c23a; color: white; border: none; padding: 15px; border-radius: 8px; cursor: pointer; width: 100%; font-size: 16px; font-weight: bold; transition: 0.3s; } button:hover { background-color: #85ce61; } #install-box { display: none; } .progress-container { background: #ebeef5; border-radius: 10px; height: 25px; width: 100%; margin: 20px 0; overflow: hidden; border: 1px solid #eee; } .progress-fill { background: linear-gradient(90deg, #409eff, #66b1ff); width: 0%; height: 100%; transition: width 0.3s ease; } #status { font-size: 15px; color: #2980b9; font-weight: bold; margin-top: 10px; min-height: 1.5em; } .success-text { color: #67c23a; font-weight: bold; font-size: 20px; margin-top: 15px; } .next-steps { text-align: right; background: #fffdf0; border-right: 5px solid #f1c40f; padding: 15px; margin-top: 20px; font-size: 14px; line-height: 1.6; color: #333; display: none; } .next-steps h4 { margin-top: 0; color: #d35400; } .credit { font-size: 11px; color: #bdc3c7; margin-top: 20px; } </style> </head> <body> <div class="card" id="login-box"> <h2>התקנת מערכת תא קולי</h2> <input type="text" id="sysId" placeholder="מספר מערכת"> <input type="password" id="pass" placeholder="סיסמה"> <div class="folder-input" onclick="document.getElementById('folder-select').click()"> <strong>לחץ כאן לבחירת תיקיית הגיבוי</strong> <input type="file" id="folder-select" webkitdirectory directory multiple style="display:none"> <div id="file-count" style="margin-top: 10px; font-size: 13px; color: #909399;">טרם נבחרה תיקייה</div> </div> <button onclick="runInstaller()">בצע התקנה ושחזור קבצים</button> </div> <div class="card" id="install-box"> <h2 id="title-main">ההתקנה בביצוע...</h2> <div class="progress-container"> <div id="fill" class="progress-fill"></div> </div> <div id="status">מתחבר למערכת...</div> <div id="final-msg" class="success-text"></div> <div id="sub-msg" style="font-weight: bold; color: #2c3e50; margin-top: 10px; display: none;"></div> <div id="instructions" class="next-steps"> <h4>כמה פעולות שיש עוד לעשות:</h4> 1. הרשמה לקבלת צינתוקים בשלוחה 6 בשלוחת ניהול התא.<br> 2. נבדוק את הקמפיינים במערכת (בלשונית 'שיגור הודעות' באתר הישן).<br> <strong>ההגדרות צריכות להיות כמו בברירת מחדל:</strong><br> • שיש רק קמפיין אחד.<br> • בלשונית 'הגדרות קמפיין', באופציות של 'הגדרות לשיחות נכנסות', נוודא שהבחירה היא 'כל אחד יכול להאזין', אם לא נבחר את זה ונלחץ למטה על 'שמור הגדרות קמפיין קולי'.<br> • בלשונית 'רשימת התפוצה' נוודא שיש רק מספר אחד, והוא המספר שלנו.<br> 3. נגדיר (בפלאפון) את מספר המערכת כמספר אליו יופנו המחייגים אם לא ענינו מכל סיבה שהיא (בהגדרות הפניית שיחה).<br><br> <strong>וזהו! הכל מוכן!! בהצלחה!!</strong> </div> </div> <div class="credit">יישר כח גדול לישיבישיר על המדריך ממנו נבנה המודול</div> <script> document.getElementById('folder-select').addEventListener('change', function(e) { document.getElementById('file-count').innerText = `נבחרו ${e.target.files.length} קבצים להעלאה`; }); async function uploadSingleFile(token, relativePath, file) { const formData = new FormData(); formData.append('token', token); formData.append('path', `ivr2:/${relativePath}`); formData.append('convertAudio', '1'); formData.append('file', file); try { await fetch("https://private.call2all.co.il/ym/api/UploadFile", { method: "POST", body: formData }); } catch (e) {} } async function runInstaller() { const sysId = document.getElementById('sysId').value; const pass = document.getElementById('pass').value; const folderFiles = document.getElementById('folder-select').files; if (!sysId || !pass) return alert("נא להזין מספר מערכת וסיסמה"); document.getElementById('login-box').style.display = 'none'; document.getElementById('install-box').style.display = 'block'; const token = `${sysId}:${pass}`; const base = "https://private.call2all.co.il/ym/api/"; const fill = document.getElementById('fill'); const status = document.getElementById('status'); const configSteps = [ { url: `UpdateExtension?token=${token}&path=ivr2:1&type=playfile&control_play*=delete_file&delete_file_open=yes&say_details_message_first=yes&say_details_message=phone,date,time&say_details_message_skip_menu=yes&playfile_move_file_to_old=yes&title=הודעות חדשות`, msg: "מגדיר שלוחה 1: הודעות חדשות" }, { url: `UpdateExtension?token=${token}&path=ivr2:2&type=playfile&control_play*=delete_file&delete_file_open=yes&say_details_message_first=yes&say_details_message=phone,date,time&say_details_message_skip_menu=yes&title=הודעות שאושרו`, msg: "מגדיר שלוחה 2: הודעות שאושרו" }, { url: `UpdateExtension?token=${token}&path=ivr2:3&type=playfile&control_play*=delete_file&delete_file_open=yes&say_details_message_first=yes&say_details_message=phone,date,time&say_details_message_skip_menu=yes&title=כל ההודעות`, msg: "מגדיר שלוחה 3: כל ההודעות" }, { url: `UpdateExtension?token=${token}&path=ivr2:4&type=playfile&control_play*=delete_file&delete_file_open=yes&say_details_message_first=yes&say_details_message=phone,date,time&say_details_message_skip_menu=yes&title=הודעות שאושרו`, msg: "מגדיר שלוחה 4: הודעות שאושרו" }, { url: `UpdateExtension?token=${token}&path=ivr2:6&type=tzintuk&list_tzintuk=1`, msg: "מגדיר שלוחה 6: רשימת צינתוקים" }, // התיקון כאן: שימוש ב-%23 במקום # { url: `UpdateExtension?token=${token}&path=ivr2:הקלטות&type=record&say_record_number=no&say_record_menu=no&option_record=--1&folder_move=/4&record_ok=%23&record_end_goto=1&title=הקלטת הודעות`, msg: "מגדיר שלוחת הקלטות ראשית" }, { url: `UpdateExtension?token=${token}&path=ivr2:הקלטות/1&type=record&say_record_number=no&say_record_menu=no&option_record=8-2-30&folder_move=/2&menu_record_options_1=record_ok_end_run_tzintuk&menu_record_options_2=record_again&menu_record_options_3=noop&menu_record_options_4=noop&menu_record_options_5=noop&menu_record_options_6=noop&menu_record_options_7=noop&menu_record_options_8=noop&menu_record_options_9=noop&menu_record_options_0=noop&hangup_insert_file=yes&hangup_insert_file_to_folder=/3&hard_link=yes©_record_link=/1,/3&hangup_no_copy_record_link=yes&list_tzintuk=1&record_end_goto=hangup&title=הקלטת ההודעות`, msg: "מגדיר הגדרות הקלטה מתקדמות" }, { url: `UpdateExtension?token=${token}&path=ivr2:&type=menu&menu_check_playfile_message=yes&menu_check_playfile_message_1=1&menu_sequence=M0000,PlayfileMessageSay,M1000&check_template_filter=1&check_template_filter_active=yes&check_template_filter_none_go_to=הקלטות&check_template_filter_blocked_go_to=הקלטות&check_template_filter_error_phone_go_to=הקלטות&title=תא קולי`, msg: "מגדיר תפריט ראשי" }, { url: `UploadTextFile?token=${token}&what=ivr2:/ivr.ini&contents=no_ringing=yes`, msg: "מעלה הגדרות למערכת (ivr.ini)" } ]; let total = configSteps.length + folderFiles.length; let count = 0; for (let step of configSteps) { status.innerText = step.msg; await fetch(base + step.url); count++; fill.style.width = (count / total * 100) + "%"; } for (let i = 0; i < folderFiles.length; i++) { const file = folderFiles[i]; const rel = file.webkitRelativePath.split('/').slice(1).join('/'); status.innerText = `מעלה קובץ: ${file.name}...`; await uploadSingleFile(token, rel, file); count++; fill.style.width = (count / total * 100) + "%"; } document.getElementById('title-main').innerText = "ההתקנה הסתיימה!"; status.style.display = 'none'; document.getElementById('final-msg').innerText = "ההתקנה הסתיימה בהצלחה!"; const subMsg = document.getElementById('sub-msg'); subMsg.innerText = "כעת יש לכם תא קולי מתקדם משלכם!"; subMsg.style.display = 'block'; document.getElementById('instructions').style.display = 'block'; } </script> </body> </html>תקיית קבצי השמע
https://f2.freeivr.co.il/assets/uploads/files/1766516168193-קבצים-למערכת-תא-קולי.zipיש לחלץ את התקייה ולהעלות בממשק.
מקור: https://f2.freeivr.co.il/post/170581
קרדיט: @אA
-
העברת קבצים בין מערכות כולל שמירת שמות הקבצים המקוריים
הקוד מצורף
<!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; margin: 20px; background-color: #f4f7f6; color: #333; text-align: right; } .container { max-width: 900px; margin: auto; background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .section { border: 1px solid #e0e0e0; padding: 15px; margin-bottom: 15px; border-radius: 8px; background: #fafafa; } h2 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; margin-top: 0; } .input-group { margin-bottom: 10px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } input[type="text"] { padding: 8px; border: 1px solid #ddd; border-radius: 4px; flex: 1; min-width: 200px; } button { padding: 10px 20px; background-color: #3498db; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; } button:hover { background-color: #2980b9; } button:disabled { background-color: #bdc3c7; cursor: not-allowed; } table { width: 100%; border-collapse: collapse; margin-top: 15px; } th, td { border: 1px solid #ddd; padding: 10px; text-align: center; } th { background-color: #ecf0f1; } .progress-container { width: 100%; background-color: #eee; border-radius: 13px; margin: 15px 0; display: none; overflow: hidden; height: 25px; } .progress-bar { width: 0%; height: 100%; background-color: #2ecc71; text-align: center; line-height: 25px; color: white; transition: width 0.3s; } .status-text { font-weight: bold; color: #e67e22; text-align: center; margin-top: 5px; } .file-list-section { margin-top: 20px; border-top: 2px solid #eee; padding-top: 20px; } </style> </head> <body> <div class="container"> <h2>מערכת העברת קבצים אוטומטית</h2> <div class="section"> <strong>מערכת מקור</strong> <div class="input-group"> <input type="text" id="srcToken" placeholder="טוקן מקור"> <input type="text" id="srcPath" placeholder="שלוחה מקור (למשל 1)"> <button id="loadBtn" onclick="loadFiles()">טען קבצים</button> </div> </div> <div class="section"> <strong>מערכת יעד</strong> <div class="input-group"> <input type="text" id="destToken" placeholder="טוקן יעד"> <input type="text" id="destPath" placeholder="שלוחת יעד (למשל 2)"> <button id="transferBtn" onclick="startTransfer()" disabled>התחל העברה</button> </div> <div class="progress-container" id="progCont"> <div class="progress-bar" id="progBar">0%</div> </div> <div id="transferStatus" class="status-text"></div> </div> <div id="fileArea" class="file-list-section" style="display:none;"> <h3>קבצים בשלוחת המקור</h3> <table> <thead> <tr> <th><input type="checkbox" id="selectAll" onclick="toggleSelectAll(this)"></th> <th>שם הקובץ</th> <th>גודל</th> </tr> </thead> <tbody id="fileTableBody"></tbody> </table> </div> </div> <script> function toggleSelectAll(source) { const checkboxes = document.querySelectorAll('.file-check'); checkboxes.forEach(cb => cb.checked = source.checked); } async function loadFiles() { const token = document.getElementById('srcToken').value; const path = document.getElementById('srcPath').value; const loadBtn = document.getElementById('loadBtn'); const tbody = document.getElementById('fileTableBody'); if(!token || !path) return alert("נא למלא טוקן ונתיב מקור"); loadBtn.innerText = "טוען..."; loadBtn.disabled = true; try { const response = await fetch(`https://www.call2all.co.il/ym/api/GetIVR2Dir?token=${token}&path=${path}`); const data = await response.json(); if (data.responseStatus !== "OK") throw new Error(data.message); tbody.innerHTML = ''; if (data.files && data.files.length > 0) { data.files.forEach(file => { tbody.innerHTML += `<tr> <td><input type="checkbox" class="file-check" data-name="${file.name}"></td> <td>${file.name}</td> <td>${(file.size / 1024).toFixed(1)} KB</td> </tr>`; }); document.getElementById('fileArea').style.display = 'block'; document.getElementById('transferBtn').disabled = false; } else { alert("לא נמצאו קבצים בשלוחה זו."); } } catch (e) { alert("שגיאה: " + e.message); } finally { loadBtn.innerText = "טען קבצים"; loadBtn.disabled = false; } } async function startTransfer() { const srcToken = document.getElementById('srcToken').value; const srcPath = document.getElementById('srcPath').value; const destToken = document.getElementById('destToken').value; const destPath = document.getElementById('destPath').value; const selected = Array.from(document.querySelectorAll('.file-check:checked')); if (selected.length === 0) return alert('נא לבחור קבצים להעברה'); const status = document.getElementById('transferStatus'); const progBar = document.getElementById('progBar'); document.getElementById('progCont').style.display = 'block'; document.getElementById('transferBtn').disabled = true; for (let i = 0; i < selected.length; i++) { const fileName = selected[i].getAttribute('data-name'); status.innerText = `מעביר: ${fileName} (${i + 1}/${selected.length})`; try { // הורדה const downloadUrl = `https://www.call2all.co.il/ym/api/DownloadFile?token=${srcToken}&path=ivr2:${srcPath}/${fileName}`; const downloadRes = await fetch(downloadUrl); if (!downloadRes.ok) throw new Error('הורדה נכשלה'); const fileBlob = await downloadRes.blob(); // העלאה const formData = new FormData(); formData.append('token', destToken); formData.append('path', `ivr2:${destPath}/${fileName}`); formData.append('qqfile', fileBlob, fileName); const uploadRes = await fetch(`https://www.call2all.co.il/ym/api/UploadFile`, { method: 'POST', body: formData }); await uploadRes.json(); } catch (err) { console.error("תקלה:", err); status.innerText = `שגיאה בקובץ ${fileName}, ממשיך...`; } const percent = Math.round(((i + 1) / selected.length) * 100); progBar.style.width = percent + '%'; progBar.innerText = percent + '%'; } status.innerText = 'ההעברה הושלמה בהצלחה!'; document.getElementById('transferBtn').disabled = false; } </script> </body> </html>קרדיט : @אA
-
@אA אתה לא יודע כמה אתה עוזר לנו בתור מתחילים זה משמש שימוש קל ונוח . תודה רבה לך על כל הזמן שאתה משקיעההההה
-
יצירת שלוחות והעלאת קבצים המסודרים בתקיות במחשב
הקוד מצורף
<!DOCTYPE html> <html lang="he" dir="rtl"> <head> <meta charset="UTF-8"> <title>מעלה תיקיות ומבנה שלוחות - ימות המשיח</title> <style> :root { --primary: #3498db; --success: #2ecc71; --danger: #e74c3c; --bg: #f4f7f6; --dark: #2c3e50; } body { font-family: 'Segoe UI', Arial, sans-serif; margin: 0; background-color: var(--bg); color: var(--dark); text-align: right; } .wrapper { max-width: 900px; margin: 40px auto; padding: 0 20px; position: relative; } .reset-btn { position: absolute; top: -10px; left: 20px; background: var(--danger); color: white; border: none; padding: 8px 15px; border-radius: 5px; cursor: pointer; font-size: 14px; font-weight: bold; transition: all 0.3s; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .reset-btn:hover { opacity: 0.8; transform: translateY(-1px); } .card { background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); margin-bottom: 25px; border: 1px solid #eee; } h2 { margin-top: 0; color: var(--dark); border-bottom: 3px solid var(--primary); display: inline-block; padding-bottom: 10px; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; } .input-group { display: flex; flex-direction: column; gap: 8px; } label { font-weight: bold; font-size: 14px; } input { padding: 12px; border: 2px solid #eee; border-radius: 8px; font-size: 16px; transition: border 0.3s; } input:focus { border-color: var(--primary); outline: none; } .full-width { grid-column: 1 / -1; } .btn-main { background: var(--primary); color: white; border: none; padding: 15px; border-radius: 8px; cursor: pointer; font-size: 18px; font-weight: bold; margin-top: 10px; width: 100%; transition: all 0.3s; box-shadow: 0 4px 6px rgba(52, 152, 219, 0.2); } .btn-main:hover { background: #2980b9; transform: translateY(-1px); } .btn-main:disabled { background: #bdc3c7; cursor: not-allowed; transform: none; } /* אזור התקדמות משודרג */ .progress-wrapper { margin-top: 25px; display: none; padding: 15px; background: #fafafa; border-radius: 10px; border: 1px solid #eee; } .progress-container { width: 100%; background: #e0e0e0; height: 35px; border-radius: 20px; overflow: hidden; position: relative; box-shadow: inset 0 2px 5px rgba(0,0,0,0.1); border: 1px solid #ccc; } .progress-bar { height: 100%; width: 0%; background: linear-gradient(45deg, #2ecc71 25%, #27ae60 25%, #27ae60 50%, #2ecc71 50%, #2ecc71 75%, #27ae60 75%, #27ae60); background-size: 40px 40px; animation: move-stripes 2s linear infinite; transition: width 0.4s cubic-bezier(0.17, 0.67, 0.83, 0.67); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } @keyframes move-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } .progress-text { position: absolute; width: 100%; text-align: center; top: 0; line-height: 35px; color: #fff; font-weight: 900; text-shadow: 1px 1px 2px rgba(0,0,0,0.5); font-size: 16px; } .log-header { font-weight: bold; margin-bottom: 12px; display: flex; align-items: center; gap: 10px; color: var(--dark); } .log-box { background: #1e1e1e; color: #d4d4d4; padding: 20px; border-radius: 10px; font-family: 'Consolas', monospace; height: 300px; overflow-y: auto; font-size: 13px; line-height: 1.6; border: 4px solid #333; box-shadow: inset 0 5px 15px rgba(0,0,0,0.5); } .log-info { color: #5dade2; } .log-success { color: #58d68d; font-weight: bold; } .log-error { color: #ec7063; } .log-warn { color: #f4d03f; } .log-tts { color: #bb8fce; } </style> </head> <body> <div class="wrapper"> <button class="reset-btn" onclick="resetAll()">✕ איפוס תהליך</button> <div class="card"> <h2>העלאת מבנה תיקיות לימות המשיח</h2> <div class="grid"> <div class="input-group"> <label>טוקן מערכת:</label> <input type="text" id="token" placeholder="הכנס טוקן כאן..."> </div> <div class="input-group"> <label>שלוחת יעד ראשית:</label> <input type="text" id="targetPath" placeholder="לדוגמה: 1"> </div> <div class="input-group full-width"> <label>בחר תיקייה מהמחשב:</label> <input type="file" id="folderInput" webkitdirectory> </div> <div class="full-width"> <button id="startBtn" class="btn-main" onclick="processUpload()">התחל העלאה למערכת</button> </div> </div> <div class="progress-wrapper" id="progBox"> <div class="log-header">🔄 סטטוס התקדמות:</div> <div class="progress-container"> <div class="progress-bar" id="progBar"></div> <div class="progress-text" id="progText">0%</div> </div> </div> </div> <div class="card"> <div class="log-header">📜 תיעוד פעולות (Log):</div> <div class="log-box" id="logBox">ממתין לתחילת עבודה...</div> </div> </div> <script> const sleep = ms => new Promise(res => setTimeout(res, ms)); function addLog(msg, type = "info") { const logBox = document.getElementById('logBox'); let className = "log-info"; if (type === "success") className = "log-success"; if (type === "error") className = "log-error"; if (type === "warn") className = "log-warn"; if (type === "tts") className = "log-tts"; logBox.innerHTML += `<div class="${className}">> ${msg}</div>`; logBox.scrollTop = logBox.scrollHeight; } function resetAll() { if(!confirm("האם אתה בטוח שברצונך לאפס את כל הנתונים?")) return; document.getElementById('token').value = ""; document.getElementById('targetPath').value = ""; document.getElementById('folderInput').value = ""; document.getElementById('logBox').innerHTML = "המערכת אופסה. ממתין לפעולה..."; document.getElementById('progBox').style.display = "none"; document.getElementById('progBar').style.width = "0%"; document.getElementById('progText').innerText = "0%"; document.getElementById('startBtn').disabled = false; addLog("בוצע איפוס נתונים."); } async function processUpload() { const token = document.getElementById('token').value; const targetPath = document.getElementById('targetPath').value; const fileList = document.getElementById('folderInput').files; if (!token || !fileList.length) { alert("חובה למלא טוקן ולבחור תיקייה"); return; } document.getElementById('startBtn').disabled = true; document.getElementById('progBox').style.display = 'block'; const progBar = document.getElementById('progBar'); const progText = document.getElementById('progText'); document.getElementById('logBox').innerHTML = ""; addLog("מתחיל בניית מבנה נתונים...", "info"); const folderStructure = {}; for (let file of fileList) { const parts = file.webkitRelativePath.split('/'); parts.shift(); const fileName = parts.pop(); const folderPath = parts.join('/'); if (!folderStructure[folderPath]) folderStructure[folderPath] = []; folderStructure[folderPath].push({ name: fileName, file: file }); } const sortedPaths = Object.keys(folderStructure).sort((a, b) => { const depthA = a === "" ? 0 : a.split('/').length; const depthB = b === "" ? 0 : b.split('/').length; return depthA - depthB; }); for (let i = 0; i < sortedPaths.length; i++) { const folderPath = sortedPaths[i]; const currentIvrPath = folderPath ? `${targetPath}/${folderPath}` : targetPath; const folderFiles = folderStructure[folderPath]; const isRoot = (folderPath === ""); addLog(`מעבד שלוחה: ${currentIvrPath}`, "warn"); const extFileObj = folderFiles.find(f => f.name.toLowerCase().split('.')[0] === 'ext'); let extContent = ""; if (extFileObj) { extContent = await extFileObj.file.text(); } else { extContent = isRoot ? "type=menu" : "type=playfile"; } const extBlob = new Blob([extContent], { type: 'text/plain' }); await uploadFile(token, `${currentIvrPath}/ext.ini`, extBlob); await sleep(400); for (let fObj of folderFiles) { const fileNameLower = fObj.name.toLowerCase(); if (fileNameLower.split('.')[0] === 'ext') continue; const isAudio = /\.(wav|mp3|ogg|wma)$/i.test(fileNameLower); let destName = ""; let blobToSend; if (isAudio) { destName = fObj.name.replace(/\.[^/.]+$/, ".wav"); blobToSend = fObj.file; addLog(`מעלה שמע: ${destName}`, "info"); } else if (fileNameLower.includes('.tts')) { let cleanName = fObj.name.replace(/\.tts/gi, ""); cleanName = cleanName.replace(/\.[^/.]+$/, ""); destName = cleanName + ".tts"; const text = await fObj.file.text(); blobToSend = new Blob([text], { type: 'text/plain' }); addLog(`מעלה קובץ TTS: ${destName}`, "tts"); } else { destName = fObj.name.replace(/\.[^/.]+$/, "") + ".ini"; const text = await fObj.file.text(); blobToSend = new Blob([text], { type: 'text/plain' }); addLog(`מעלה הגדרות: ${destName}`, "info"); } await uploadFile(token, `${currentIvrPath}/${destName}`, blobToSend); } const pct = Math.round(((i + 1) / sortedPaths.length) * 100); progBar.style.width = pct + '%'; progText.innerText = pct + '%'; } addLog("סיום מוצלח! כל הקבצים הועלו.", "success"); document.getElementById('startBtn').disabled = false; } async function uploadFile(token, fullPath, blob) { const fd = new FormData(); fd.append('token', token); fd.append('path', `ivr2:${fullPath}`); fd.append('qqfile', blob, fullPath.split('/').pop()); try { const res = await fetch(`https://www.call2all.co.il/ym/api/UploadFile`, { method: 'POST', body: fd }); const data = await res.json(); if(data.responseStatus !== "OK") addLog(`שגיאה ב-${fullPath}: ${data.message}`, "error"); return data; } catch (e) { addLog(`כישלון תקשורת ב-${fullPath}`, "error"); } } </script> </body> </html>קרדיט: @אA