פאנל ניהול מותאם אישית
-
@אA כל מנהל/ת ת"ת בתי ספר שרוצים לתת גישה אם לב רגוע
לי יש במערכת כמה קווי ווצאפון שאני רוצה לתת לאנשים אחרים לנהל אבל אני לא יכול כי יש שם עוד דברים וטעות קטנה גורמת נזק יקר -
@BEN-ZION
התכוונתי מה נצרך להכניס בכזה פאנל.
הצורך בכזה דבר מאוד ברור... -
@אA את כל הניהול הבסיסי של שלוחה: העלאת קבצים, הורדה, מחיקה, ניהול קבצי EXT, INI, אפשרות לניהול רשימ"ת ספציפית,
זה בגדול אולי יש עוד פרטים שאני לא זוכר -
- העלאה
- הורדה
- מחיקה
- ניהול רשי"ת
- ניהול קבצי ini
ניהול קבצי ext נראה לי קצת פחות, הרי מזה בדיוק אתה מםחד שיטפלו בזה, לא?
-
@אA נכון אבל בשלוחה שלו אם ירצה להוסיף שלוחה פנימית יהיה חייב לערוך
לא אכפת לי שבשלוחה שלו יהיה נזק העיקר שהקו מתפקד
-
@אA
אם כבר מפתחים
להוסיף פיצ'רים לרשימת צינתוקים
וברישמת תפוצה נגיד לוג מי נוסף ומתי ואיך -
פעם פיתכתי משהו בערך
@אa
@ben-zion
יש את זה yemot_basic_manager.html -
@לימוד-בתורת-מרן תעלה את הקוד אי אפשר להעלות ככה או שתדחוס את זה
-
@BEN-ZION
מעלה את הקוד -
פוסט זה נמחק! -
@ben-zion
קוד חדש
כותבים פקודה בapi
ועוד דברים זה ישן<!doctype html> <html lang="he" dir="rtl"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>ניהול בסיסי לשלוחה - ימות המשיח</title> <style> body{ font-family:Arial,sans-serif; background:#f4f6f9; margin:0; padding:20px; color:#222; } .wrap{ max-width:1000px; margin:auto; } h1{ margin:0 0 20px; background:#243447; color:#fff; padding:14px; border-radius:12px; font-size:24px; } .grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); gap:16px; } .card{ background:#fff; border-radius:14px; padding:16px; box-shadow:0 2px 10px rgba(0,0,0,.08); } .card h2{ margin-top:0; font-size:20px; } label{ display:block; margin:10px 0 5px; font-weight:bold; } input, textarea, select, button{ width:100%; box-sizing:border-box; padding:10px; border:1px solid #cfd7df; border-radius:10px; font-size:15px; } textarea{ min-height:130px; resize:vertical; font-family:monospace; } button{ background:#0b57d0; color:#fff; border:none; cursor:pointer; font-weight:bold; margin-top:10px; } button:hover{ opacity:.92; } .btn-danger{ background:#c62828; } .btn-green{ background:#2e7d32; } .btn-gray{ background:#546e7a; } .row{ display:grid; grid-template-columns:1fr 1fr; gap:10px; } .small{ font-size:13px; color:#666; margin-top:6px; } #filesTable{ width:100%; border-collapse:collapse; margin-top:10px; font-size:14px; } #filesTable th,#filesTable td{ border:1px solid #ddd; padding:8px; text-align:right; } #filesTable th{ background:#eef3f8; } pre{ background:#111; color:#7CFC00; padding:14px; border-radius:12px; min-height:180px; overflow:auto; white-space:pre-wrap; word-break:break-word; } .muted{ color:#888; font-size:13px; } </style> </head> <body> <div class="wrap"> <h1>ניהול בסיסי לשלוחה - ימות המשיח</h1> <div class="card" style="margin-bottom:16px;"> <h2>הגדרות כלליות</h2> <label>טוקן</label> <input id="token" placeholder="077XXXXXXX:XXXXXX" /> <label>נתיב שלוחה</label> <input id="path" placeholder="לדוגמה: 1/2/3" /> <div class="small">הנתיב יישלח ל־API כ־ivr2:1/2/3</div> </div> <div class="grid"> <div class="card"> <h2>העלאת קובץ</h2> <label>בחר קובץ</label> <input type="file" id="uploadFileInput" /> <label>שם יעד לקובץ (לא חובה)</label> <input id="targetFileName" placeholder="לדוגמה: 000.wav או ext.ini" /> <label> <input type="checkbox" id="convertAudio" style="width:auto;transform:scale(1.2);margin-left:8px;"> המר אודיו ל־wav </label> <button onclick="uploadFile()">העלה קובץ</button> </div> <div class="card"> <h2>הורדת קובץ</h2> <label>שם קובץ להורדה</label> <input id="downloadFileName" placeholder="לדוגמה: 000.wav או ext.ini" /> <button class="btn-green" onclick="downloadFile()">הורד קובץ</button> </div> <div class="card"> <h2>מחיקה</h2> <label>שם קובץ / שלוחה למחיקה</label> <input id="deleteName" placeholder="לדוגמה: 000.wav או 8" /> <button class="btn-danger" onclick="deleteItem()">מחק</button> </div> <div class="card"> <h2>רשימת קבצים בשלוחה</h2> <button class="btn-gray" onclick="getDir()">רענן רשימת קבצים</button> <div id="filesArea" class="muted" style="margin-top:10px;">עדיין לא נטענה רשימה</div> </div> <div class="card"> <h2>ניהול ext.ini</h2> <div class="row"> <div> <button class="btn-gray" onclick="loadTextFile('ext.ini','extContent')">טען ext.ini</button> </div> <div> <button onclick="saveTextFile('ext.ini','extContent')">שמור ext.ini</button> </div> </div> <label>תוכן ext.ini</label> <textarea id="extContent" placeholder="type=menu title=בדיקה"></textarea> </div> <div class="card"> <h2>ניהול קובץ INI</h2> <label>שם קובץ ini</label> <input id="iniFileName" placeholder="לדוגמה: M1000.ini" /> <div class="row"> <div> <button class="btn-gray" onclick="loadNamedIni()">טען קובץ ini</button> </div> <div> <button onclick="saveNamedIni()">שמור קובץ ini</button> </div> </div> <label>תוכן קובץ ini</label> <textarea id="iniContent"></textarea> </div> <div class="card"> <h2>ניהול קובץ EXT נוסף</h2> <label>שם קובץ ext</label> <input id="extFileName" placeholder="לדוגמה: ext.ini או ext2.ini" /> <div class="row"> <div> <button class="btn-gray" onclick="loadNamedExt()">טען קובץ ext</button> </div> <div> <button onclick="saveNamedExt()">שמור קובץ ext</button> </div> </div> <label>תוכן קובץ ext</label> <textarea id="extCustomContent"></textarea> </div> <div class="card"> <h2>ניהול רשימ"ת / רשימת צינתוקים</h2> <label>שם רשימה</label> <input id="listName" placeholder="לדוגמה: 120" /> <div class="row"> <div><button class="btn-gray" onclick="getLists()">הצג כל הרשימות</button></div> <div><button class="btn-gray" onclick="getListEntries()">הצג מנויים</button></div> </div> <div class="row"> <div><button class="btn-gray" onclick="getListLog()">הצג לוג</button></div> <div><button class="btn-danger" onclick="resetList()">אפס רשימה</button></div> </div> <div class="small"> לפי התיעוד שמצאתי: יש צפייה ברשימות, מנויים, לוג ואיפוס. לא מצאתי כאן פעולה ברורה להוספה/מחיקה ידנית של מספר דרך ה־API הרגיל. </div> </div> </div> <div class="card" style="margin-top:16px;"> <h2>לוג / פלט</h2> <pre id="log"></pre> </div> </div> <script> const API = "https://www.call2all.co.il/ym/api/"; function log(msg, append = true) { const el = document.getElementById("log"); const text = typeof msg === "string" ? msg : JSON.stringify(msg, null, 2); el.textContent = append ? (el.textContent + (el.textContent ? "\n\n" : "") + text) : text; } function clearLog() { document.getElementById("log").textContent = ""; } function getToken() { return document.getElementById("token").value.trim(); } function getPathRaw() { return document.getElementById("path").value.trim().replace(/^\/+|\/+$/g, ""); } function getIvrPath() { const p = getPathRaw(); return p ? `ivr2:${p}` : "ivr2:"; } function buildFullPath(fileName) { const p = getPathRaw(); const cleanName = String(fileName || "").trim().replace(/^\/+/, ""); return p ? `ivr2:${p}/${cleanName}` : `ivr2:${cleanName}`; } function ensureTokenAndPath() { const token = getToken(); const path = getPathRaw(); if (!token) { alert("נא להזין טוקן"); return null; } if (!path) { alert("נא להזין נתיב שלוחה"); return null; } return { token, path }; } async function safeJson(res) { const txt = await res.text(); try { return JSON.parse(txt); } catch { return { raw: txt, httpStatus: res.status, ok: res.ok }; } } async function uploadFile() { clearLog(); const base = ensureTokenAndPath(); if (!base) return; const fileInput = document.getElementById("uploadFileInput"); const file = fileInput.files[0]; if (!file) { alert("נא לבחור קובץ"); return; } const targetFileName = document.getElementById("targetFileName").value.trim() || file.name; const convertAudio = document.getElementById("convertAudio").checked ? "1" : "0"; const form = new FormData(); form.append("token", base.token); form.append("path", buildFullPath(targetFileName)); form.append("convertAudio", convertAudio); form.append("qqfile", file, file.name); try { const res = await fetch(API + "UploadFile", { method: "POST", body: form }); const data = await safeJson(res); log(data, false); await getDir(); } catch (e) { log("שגיאה בהעלאה: " + e.message, false); } } function downloadFile() { clearLog(); const base = ensureTokenAndPath(); if (!base) return; const name = document.getElementById("downloadFileName").value.trim(); if (!name) { alert("נא להזין שם קובץ"); return; } const url = API + "DownloadFile?token=" + encodeURIComponent(base.token) + "&path=" + encodeURIComponent(buildFullPath(name)); log("פותח הורדה:\n" + url, false); window.open(url, "_blank"); } async function deleteItem() { clearLog(); const base = ensureTokenAndPath(); if (!base) return; const name = document.getElementById("deleteName").value.trim(); if (!name) { alert("נא להזין שם קובץ או שלוחה למחיקה"); return; } if (!confirm("למחוק את: " + name + " ?")) return; const url = API + "FileAction?token=" + encodeURIComponent(base.token) + "&action=delete" + "&what=" + encodeURIComponent(buildFullPath(name)); try { const res = await fetch(url); const data = await safeJson(res); log(data, false); await getDir(); } catch (e) { log("שגיאה במחיקה: " + e.message, false); } } async function getDir() { const base = ensureTokenAndPath(); if (!base) return; const url = API + "GetIVR2Dir?token=" + encodeURIComponent(base.token) + "&path=" + encodeURIComponent(base.path); try { const res = await fetch(url); const data = await safeJson(res); log(data, false); renderFiles(data); } catch (e) { log("שגיאה בקבלת רשימת קבצים: " + e.message, false); } } function renderFiles(data) { const area = document.getElementById("filesArea"); const files = data && data.files ? data.files : []; if (!files.length) { area.innerHTML = "לא נמצאו קבצים או שלא התקבלה רשימה."; return; } let html = ` <table id="filesTable"> <thead> <tr> <th>שם</th> <th>סוג</th> <th>גודל</th> </tr> </thead> <tbody> `; for (const f of files) { html += ` <tr> <td>${escapeHtml(f.name ?? "")}</td> <td>${escapeHtml(f.fileType ?? "")}</td> <td>${escapeHtml(String(f.size ?? ""))}</td> </tr> `; } html += `</tbody></table>`; area.innerHTML = html; } async function loadTextFile(fileName, targetTextareaId) { clearLog(); const base = ensureTokenAndPath(); if (!base) return; const url = API + "GetTextFile?token=" + encodeURIComponent(base.token) + "&what=" + encodeURIComponent(buildFullPath(fileName)); try { const res = await fetch(url); const data = await safeJson(res); log(data, false); if (data && typeof data.contents !== "undefined") { document.getElementById(targetTextareaId).value = data.contents; } else { alert("לא התקבל תוכן קובץ"); } } catch (e) { log("שגיאה בקריאת קובץ טקסט: " + e.message, false); } } async function saveTextFile(fileName, sourceTextareaId) { clearLog(); const base = ensureTokenAndPath(); if (!base) return; const content = document.getElementById(sourceTextareaId).value; const body = new URLSearchParams(); body.append("token", base.token); body.append("what", buildFullPath(fileName)); body.append("contents", content); try { const res = await fetch(API + "UploadTextFile", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" }, body: body.toString() }); const data = await safeJson(res); log(data, false); await getDir(); } catch (e) { log("שגיאה בשמירת קובץ טקסט: " + e.message, false); } } function loadNamedIni() { const name = document.getElementById("iniFileName").value.trim(); if (!name) return alert("נא להזין שם קובץ ini"); loadTextFile(name, "iniContent"); } function saveNamedIni() { const name = document.getElementById("iniFileName").value.trim(); if (!name) return alert("נא להזין שם קובץ ini"); saveTextFile(name, "iniContent"); } function loadNamedExt() { const name = document.getElementById("extFileName").value.trim(); if (!name) return alert("נא להזין שם קובץ ext"); loadTextFile(name, "extCustomContent"); } function saveNamedExt() { const name = document.getElementById("extFileName").value.trim(); if (!name) return alert("נא להזין שם קובץ ext"); saveTextFile(name, "extCustomContent"); } async function getLists() { clearLog(); const token = getToken(); if (!token) return alert("נא להזין טוקן"); try { const url = API + "?token=" + encodeURIComponent(token) + "&action=getLists"; const res = await fetch(url); const data = await safeJson(res); log(data, false); } catch (e) { log("שגיאה בקבלת רשימות: " + e.message, false); } } async function getListEntries() { clearLog(); const token = getToken(); const listName = document.getElementById("listName").value.trim(); if (!token) return alert("נא להזין טוקן"); if (!listName) return alert("נא להזין שם רשימה"); try { const url = API + "?token=" + encodeURIComponent(token) + "&action=getlistEnteres&TzintukimList=" + encodeURIComponent(listName); const res = await fetch(url); const data = await safeJson(res); log(data, false); } catch (e) { log("שגיאה בקבלת מנויי הרשימה: " + e.message, false); } } async function getListLog() { clearLog(); const token = getToken(); const listName = document.getElementById("listName").value.trim(); if (!token) return alert("נא להזין טוקן"); if (!listName) return alert("נא להזין שם רשימה"); try { const url = API + "?token=" + encodeURIComponent(token) + "&action=getLogList&TzintukimList=" + encodeURIComponent(listName); const res = await fetch(url); const data = await safeJson(res); log(data, false); } catch (e) { log("שגיאה בקבלת לוג הרשימה: " + e.message, false); } } async function resetList() { clearLog(); const token = getToken(); const listName = document.getElementById("listName").value.trim(); if (!token) return alert("נא להזין טוקן"); if (!listName) return alert("נא להזין שם רשימה"); if (!confirm("לאפס את הרשימה " + listName + " ?")) return; try { const url = API + "?token=" + encodeURIComponent(token) + "&action=resetList&TzintukimList=" + encodeURIComponent(listName); const res = await fetch(url); const data = await safeJson(res); log(data, false); } catch (e) { log("שגיאה באיפוס רשימה: " + e.message, false); } } function escapeHtml(str) { return String(str) .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } </script> </body> </html> -
@ben-zion
מה אומר -
יש חדש
@ben-zion -
@לימוד-בתורת-מרן
וואו!!!
זה ממש הכללל!
ודרך אגב יש בתיעוד הסבר איך להוסיף מספרים לרשי"ת. -
@לימוד-בתורת-מרן יפה אבל אני רוצה משהו יותר מסודר
-
@BEN-ZION
כלומר?
מבחינת העיצוב?
או שהכל יהיה בנוי על רשימת הקבצים המוצגת כמו זה<!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> -
@BEN-ZION
זה ישן לא בדקתי לא סידרתי -
@אA
יש לך קובץ html
של משהו על api. תוכל לעלות את הקוד
כי כותב שגיאה כי זה בתור html -
-
@אA @לימוד-בתורת-מרן כזה סגנון אני רוצה