• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות

    השנה ההתרמה שלכם תראה אחרת!!!

    מתוזמן נעוץ נעול הועבר עזרה הדדית למשתמשים מתקדמים
    24 פוסטים 10 כותבים 362 צפיות 4 עוקבים
    טוען פוסטים נוספים
    • מהישן לחדש
    • מהחדש לישן
    • הכי הרבה הצבעות
    תגובה
    • תגובה כנושא
    התחברו כדי לפרסם תגובה
    נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
    • א מנותק
      אA @BEN ZION
      נערך לאחרונה על ידי

      @BEN-ZION
      עדיין?

      B תגובה 1 תגובה אחרונה תגובה ציטוט 0
      • B מנותק
        BEN ZION @אA
        נערך לאחרונה על ידי

        @אA 3959eafc-74d4-4cd0-8e31-7ddc0222bab2-image.png אולי בעיה של נטפרי?

        א תגובה 1 תגובה אחרונה תגובה ציטוט 0
        • א מנותק
          אA @BEN ZION
          נערך לאחרונה על ידי

          @BEN-ZION
          ממש לא.
          בכל פעם שאתה פותח מופיע כך?

          B תגובה 1 תגובה אחרונה תגובה ציטוט 0
          • B מנותק
            BEN ZION @אA
            נערך לאחרונה על ידי

            @אA ניסיתי כמה פעמים

            א תגובה 1 תגובה אחרונה תגובה ציטוט 0
            • א מנותק
              אA @BEN ZION
              נערך לאחרונה על ידי

              @BEN-ZION
              מוזר מאוד.
              הורדתי שוב ונפתח מעולה.
              ניסית לפתוח בקןבץ html?

              B תגובה 1 תגובה אחרונה תגובה ציטוט 0
              • B מנותק
                BEN ZION @אA
                נערך לאחרונה על ידי

                @אA הורדתי את הקובץ EXE והפעלתי אותו
                לקחתי את הקוד ויצרתי HTML אצלי הוא עובד רק התוכנה לא עובדת

                א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                • א מנותק
                  אA @BEN ZION
                  נערך לאחרונה על ידי

                  @BEN-ZION
                  לא ממש יודע מה לומר לך.
                  ניסית להוריד גם מפורום כאן?

                  א תגובה 1 תגובה אחרונה תגובה ציטוט 0
                  • א מנותק
                    אA @אA
                    נערך לאחרונה על ידי

                    אולי אנסה לשלוח כשזה מקופל אבל זאת נראת בעיה במחשב שלך

                    תגובה 1 תגובה אחרונה תגובה ציטוט 0
                    • ג מנותק
                      גלאט מערכות
                      נערך לאחרונה על ידי גלאט מערכות

                      @אa

                      יש מצב שאתה בונה גם משהו לניהול מכירות לפי מק"ט ?

                      B תגובה 1 תגובה אחרונה תגובה ציטוט 0
                      • B מנותק
                        BEN ZION @גלאט מערכות
                        נערך לאחרונה על ידי

                        @אa מי שרוצה כתבתי קוד PHP שמקבל וובהוק מנדרים ומוסיף למערכת בהערות צריך לכתוב את שם המתרים

                        <?php
                        // הגדרות API
                        $token = "{token}"; 
                        $api_url = "https://www.call2all.co.il/ym/api/";
                        
                        // נתיבים
                        $path_names = 'ivr2:Points/EnterIDValName.ini';
                        $path_total = 'ivr2:Points/points_total.ymgr';
                        $path_log   = 'ivr2:Points/manual_log.ini';
                        
                        // קבצי דיבוג מקומיים בשרת ה-PHP
                        $debug_file = 'debug_webhook.log';
                        $unassigned_csv = 'unassigned_donations.csv';
                        
                        // 1. קבלת הנתונים ושמירה לדיבוג ראשוני
                        $json_data = file_get_contents('php://input');
                        $data = json_decode($json_data, true);
                        
                        // רישום כל כניסה לקובץ דיבוג כדי שלא יאבד כלום
                        $timestamp_log = date("Y-m-d H:i:s");
                        file_put_contents($debug_file, "[$timestamp_log] Raw Data: " . $json_data . PHP_EOL, FILE_APPEND);
                        
                        if (!$data) die("No data received");
                        
                        $comment_name = trim($data['Comments'] ?? '');
                        $amount = floatval($data['Amount'] ?? 0);
                        
                        function call_yemot($method, $path, $token, $contents = null) {
                            global $api_url;
                            $url = $api_url . $method . "?token=" . $token . "&what=" . $path;
                            if ($contents !== null) $url .= "&contents=" . urlencode($contents);
                            $res = file_get_contents($url);
                            return json_decode($res, true);
                        }
                        
                        // 2. חיפוש גמיש (Fuzzy Matching)
                        $fundraiser_id = null;
                        $best_score = -1;
                        $res_names = call_yemot('GetTextFile', $path_names, $token);
                        
                        if (isset($res_names['contents']) && !empty($comment_name)) {
                            $lines = explode("\n", $res_names['contents']);
                            foreach ($lines as $line) {
                                $parts = explode('=', $line);
                                if (count($parts) === 2) {
                                    $current_id = trim($parts[0]);
                                    $current_name = trim($parts[1]);
                        
                                    // חישוב דמיון
                                    similar_text($comment_name, $current_name, $percent);
                                    
                                    if ($percent > $best_score) {
                                        $best_score = $percent;
                                        $fundraiser_id = $current_id;
                                    }
                                }
                            }
                        }
                        
                        // 3. ביצוע עדכון או שמירה ל-CSV במקרה של כישלון
                        // הורדתי את הסף ל-50% בגלל תארים כמו "הרב" ו"שליט"א"
                        if ($fundraiser_id && $best_score > 50) {
                            
                            // א. עדכון YMGR
                            $res_total = call_yemot('GetTextFile', $path_total, $token);
                            $t_lines = explode("\n", trim($res_total['contents'] ?? ""));
                            $found = false;
                            foreach ($t_lines as &$line) {
                                if (strpos($line, "EnterId#$fundraiser_id") !== false) {
                                    $found = true;
                                    preg_match('/PointsTotalAll#([\d.]+)/', $line, $matches);
                                    $new_val = (isset($matches[1]) ? floatval($matches[1]) : 0) + $amount;
                                    $line = preg_replace('/PointsTotalAll#[\d.]+/', "PointsTotalAll#$new_val", $line);
                                    $line = preg_replace('/PointsTotal#[\d.]+/', "PointsTotal#$new_val", $line);
                                }
                            }
                            if (!$found) $t_lines[] = "EnterId#{$fundraiser_id}%PointsTotalAll#{$amount}%PointsTotal#{$amount}";
                            call_yemot('UploadTextFile', $path_total, $token, implode("\n", $t_lines));
                        
                            // ב. רישום ללוג ה-HTML
                            $res_log = call_yemot('GetTextFile', $path_log, $token);
                            $time_ms = round(microtime(true) * 1000);
                            $time_hi = date("H:i");
                            $new_entry = "{$time_ms}|{$fundraiser_id}|{$amount}|{$time_hi}";
                            call_yemot('UploadTextFile', $path_log, $token, $new_entry . "\n" . ($res_log['contents'] ?? ""));
                        
                            file_put_contents($debug_file, "[$timestamp_log] SUCCESS: Matched $comment_name to ID $fundraiser_id ($best_score%)" . PHP_EOL, FILE_APPEND);
                            echo "Success";
                        
                        } else {
                            // שמירה ל-CSV עבור תרומות שלא זוהו
                            $is_new = !file_exists($unassigned_csv);
                            $fp = fopen($unassigned_csv, 'a');
                            if ($is_new) {
                                fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM לעברית
                                fputcsv($fp, ['תאריך', 'שם מהערה', 'סכום', 'טלפון', 'אחוז התאמה הכי קרוב']);
                            }
                            fputcsv($fp, [$timestamp_log, $comment_name, $amount, $data['Phone'] ?? '', $best_score . "%"]);
                            fclose($fp);
                        
                            file_put_contents($debug_file, "[$timestamp_log] FAILED: No match for $comment_name (Best: $best_score%)" . PHP_EOL, FILE_APPEND);
                            echo "Saved to CSV";
                        }
                        

                        מי שרוצה שידרגתי את שתי הקודים כך שיש גם יעד אישי לכל מתרים
                        מסך ניהול

                        <!DOCTYPE html>
                        <html lang="he" dir="rtl">
                        <head>
                        <meta charset="UTF-8">
                        <title>מנהל קמפיין - Points Sync</title>
                        <style>
                        :root { --primary: #0ea5e9; --success: #22c55e; --bg: #0f172a; --card: #1e293b; --border: #334155; --gold: #f59e0b; }
                        body { background: var(--bg); color: #f1f5f9; font-family: system-ui, sans-serif; margin: 0; padding: 20px; text-align: right; }
                        .manual-entry-box { max-width: 600px; margin: 50px auto; background: var(--card); padding: 30px; border-radius: 20px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); border: 1px solid var(--border); }
                        h1 { text-align: center; color: var(--primary); }
                        label { display: block; margin-top: 15px; font-weight: bold; }
                        input { width: 100%; padding: 15px; margin: 10px 0; border-radius: 10px; border: 1px solid var(--border); background: #0f172a; color: white; font-size: 1.2rem; box-sizing: border-box; }
                        .main-btn { background: var(--success); color: white; border: none; padding: 15px; border-radius: 10px; cursor: pointer; font-weight: bold; width: 100%; font-size: 1.1rem; margin-top: 20px; transition: 0.3s; }
                        .main-btn:hover { filter: brightness(1.1); transform: translateY(-2px); }
                        .settings-trigger { position: fixed; top: 20px; left: 20px; background: #334155; color: white; border: none; padding: 12px 20px; border-radius: 50px; cursor: pointer; font-weight: bold; display: flex; align-items: center; gap: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
                        .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); z-index: 1000; backdrop-filter: blur(5px); }
                        .modal-content { background: var(--card); width: 90%; max-width: 800px; margin: 40px auto; border-radius: 20px; padding: 25px; border: 1px solid var(--border); position: relative; max-height: 85vh; overflow-y: auto; }
                        .close-btn { position: absolute; top: 15px; right: 20px; font-size: 1.5rem; cursor: pointer; }
                        .tabs { display: flex; gap: 5px; border-bottom: 2px solid var(--border); margin-bottom: 20px; }
                        .tab-btn { background: none; border: none; color: #8b949e; padding: 10px 15px; cursor: pointer; font-size: 0.95rem; }
                        .tab-btn.active { color: var(--primary); border-bottom: 2px solid var(--primary); font-weight: bold; }
                        .tab-pane { display: none; }
                        .tab-pane.active { display: block; }
                        .log-list { background: #0f172a; padding: 10px; border-radius: 8px; max-height: 350px; overflow-y: auto; }
                        .log-item { display: flex; justify-content: space-between; padding: 12px; border-bottom: 1px solid var(--border); align-items: center; }
                        .log-item label { display: flex; align-items: center; cursor: pointer; width: 100%; gap: 15px; }
                        .badge { font-size: 0.75rem; padding: 3px 8px; border-radius: 5px; color: white; font-weight: bold; }
                        .badge-manual { background: var(--primary); }
                        .badge-phone { background: var(--success); }
                        .status { margin-top: 15px; font-size: 0.9rem; text-align: center; font-weight: bold; }
                        </style>
                        </head>
                        <body>
                        
                        <button class="settings-trigger" onclick="openModal()"><span>⚙️</span> הגדרות קמפיין</button>
                        
                        <div class="manual-entry-box">
                        <h1>💰 הזנת תרומה ידנית</h1>
                        <label>מספר אישי של המתרים:</label>
                        <input type="number" id="manualId" placeholder="למשל 215" autofocus>
                        <label>סכום התרומה (₪):</label>
                        <input type="number" id="manualAmount" placeholder="0.00">
                        <button class="main-btn" onclick="executeManualDonation()">✅ אשר והוסף למערכת</button>
                        <div id="mainStatus" class="status"></div>
                        </div>
                        
                        <div id="settingsModal" class="modal">
                        <div class="modal-content">
                        <span class="close-btn" onclick="closeModal()">✖️</span>
                        <h2 style="border-bottom: 1px solid var(--border); padding-bottom: 10px;">⚙️ ניהול והגדרות</h2>
                        <div class="tabs">
                        <button class="tab-btn active" onclick="switchTab(event, 'tabNames')">👥 שמות ויעדים</button>
                        <button class="tab-btn" onclick="switchTab(event, 'tabGoal')">📈 יעד ותאריך</button>
                        <button class="tab-btn" onclick="switchTab(event, 'tabTotals')">📊 עריכת סכומים</button>
                        <button class="tab-btn" onclick="switchTab(event, 'tabLogs')">🗑️ מחיקת לוג</button>
                        </div>
                        
                            <div id="tabNames" class="tab-pane active">
                                <div style="display:flex; gap:10px;">
                                    <input type="text" id="editId" placeholder="מספר אישי">
                                    <button onclick="findUser()" style="width:100px; background:var(--primary); border:none; border-radius:8px; color:white; cursor:pointer;">חפש</button>
                                </div>
                                <input type="text" id="editName" placeholder="שם המתרים">
                                <input type="number" id="editGoal" placeholder="יעד אישי (₪) - אופציונלי">
                                <button class="main-btn" style="background:var(--primary)" onclick="saveUser()">שמור פרטים ויעד</button>
                            </div>
                         
                            <div id="tabGoal" class="tab-pane">
                                <label>יעד הקמפיין הכולל (₪):</label><input type="number" id="goalVal">
                                <label>תאריך ושעת סיום:</label><input type="datetime-local" id="dateVal">
                                <button class="main-btn" onclick="saveConfig()">🔄 עדכן יעד ותאריך</button>
                                <hr style="border:0; border-top:1px solid var(--border); margin:25px 0;">
                                <label style="color:var(--gold)">מפתח אבטחה (Token) API:</label>
                                <input type="password" id="tokenInput" placeholder="הכנס טוקן חדש">
                                <button class="main-btn" style="background:#6366f1" onclick="updateToken()">🔄 עדכן מפתח Token</button>
                            </div>
                         
                            <div id="tabTotals" class="tab-pane"><div id="totalsList" class="log-list">טוען נתונים...</div></div>
                            <div id="tabLogs" class="tab-pane">
                                <div id="logsList" class="log-list">טוען לוג פעולות מהשרת...</div>
                                <button class="main-btn" style="background:#ef4444" onclick="deleteLogs()">❌ מחק פעולות וסנכרן שרת</button>
                            </div>
                            <div id="modalStatus" class="status"></div>
                        </div>
                        </div>
                        
                        <script>
                        let CURRENT_TOKEN = localStorage.getItem('campaign_token') || 'YOUR_TOKEN_HERE';
                        let nameMap = {};
                        let goalMap = {};
                        
                        // נתיבים בשרת - הכל בתיקיית Points
                        const PATH_TOTAL = 'ivr2:Points/points_total.ymgr';
                        const PATH_PHONE_LOG = 'ivr2:Points/points_log.2026-02.ymgr';
                        const PATH_MANUAL_LOG = 'ivr2:Points/manual_log.ini';
                        const PATH_CONFIG = 'ivr2:Points/config.ini';
                        const PATH_NAMES = 'ivr2:Points/EnterIDValName.ini';
                        const PATH_GOALS = 'ivr2:Points/EnterIDGoal.ini';
                         
                        document.getElementById('tokenInput').value = CURRENT_TOKEN;
                         
                        function updateToken() {
                            const newToken = document.getElementById('tokenInput').value.trim();
                            if(!newToken) return alert("נא להזין טוקן");
                            CURRENT_TOKEN = newToken;
                            localStorage.setItem('campaign_token', newToken);
                            alert("הטוקן עודכן במחשב זה!");
                            location.reload();
                        }
                         
                        function openModal() { document.getElementById('settingsModal').style.display = 'block'; }
                        function closeModal() { document.getElementById('settingsModal').style.display = 'none'; }
                         
                        async function callApi(cmd, path, content = "") {
                            let url = `https://www.call2all.co.il/ym/api/${cmd}?token=${CURRENT_TOKEN}&what=${path}`;
                            if(content) url += `&contents=${encodeURIComponent(content)}`;
                            return fetch(url).then(r => r.json());
                        }
                         
                        async function switchTab(e, id) {
                            document.querySelectorAll('.tab-pane, .tab-btn').forEach(el => el.classList.remove('active'));
                            document.getElementById(id).classList.add('active');
                            e.currentTarget.classList.add('active');
                            await fetchNames();
                            if(id === 'tabGoal') loadCurrentConfig();
                            if(id === 'tabTotals') fetchTotals();
                            if(id === 'tabLogs') fetchLogs();
                        }
                         
                        async function fetchNames() {
                            const [resNames, resGoals] = await Promise.all([
                                callApi('GetTextFile', PATH_NAMES),
                                callApi('GetTextFile', PATH_GOALS)
                            ]);
                            
                            nameMap = {}; 
                            goalMap = {};
                            
                            if (resNames.contents) {
                                resNames.contents.split(/[\r\n]+/).forEach(line => {
                                    const parts = line.split('=');
                                    if (parts.length === 2) nameMap[parts[0].trim()] = parts[1].trim();
                                });
                            }
                            if (resGoals.contents) {
                                resGoals.contents.split(/[\r\n]+/).forEach(line => {
                                    const parts = line.split('=');
                                    if (parts.length === 2) goalMap[parts[0].trim()] = parseFloat(parts[1].trim());
                                });
                            }
                        }
                        
                        async function findUser() {
                            const id = document.getElementById('editId').value;
                            if (!id) return alert("נא להזין מספר אישי");
                            await fetchNames();
                            document.getElementById('editName').value = nameMap[id] || "";
                            document.getElementById('editGoal').value = goalMap[id] || "";
                        }
                        
                        async function saveUser() {
                            const id = document.getElementById('editId').value;
                            const name = document.getElementById('editName').value;
                            const goal = document.getElementById('editGoal').value;
                            
                            if (!id) return alert("חובה להזין מספר אישי");
                        
                            let [resNames, resGoals] = await Promise.all([
                                callApi('GetTextFile', PATH_NAMES),
                                callApi('GetTextFile', PATH_GOALS)
                            ]);
                        
                            let linesNames = (resNames.contents || "").split('\n').filter(l => l.trim() && !l.startsWith(`${id}=`));
                            if (name) linesNames.push(`${id}=${name}`);
                        
                            let linesGoals = (resGoals.contents || "").split('\n').filter(l => l.trim() && !l.startsWith(`${id}=`));
                            if (goal) linesGoals.push(`${id}=${goal}`);
                        
                            await Promise.all([
                                callApi('UploadTextFile', PATH_NAMES, linesNames.join('\n')),
                                callApi('UploadTextFile', PATH_GOALS, linesGoals.join('\n'))
                            ]);
                        
                            alert("פרטי המתרים והיעד האישי עודכנו בהצלחה!");
                            await fetchNames();
                        }
                         
                        async function executeManualDonation() {
                            const id = document.getElementById('manualId').value;
                            const amt = parseFloat(document.getElementById('manualAmount').value);
                            if(!id || !amt) return alert("מלא מספר וסכום");
                            document.getElementById('mainStatus').innerText = "⏳ מעדכן שרת...";
                         
                            let resT = await callApi('GetTextFile', PATH_TOTAL);
                            let tLines = (resT.contents || "").trim().split('\n');
                            let found = false;
                            let updatedT = tLines.map(l => {
                                if(l.includes(`EnterId#${id}`)) {
                                    found = true;
                                    let old = parseFloat((l.match(/PointsTotalAll#([\d.]+)/) || [0,0])[1]);
                                    let sum = old + amt;
                                    return l.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${sum}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${sum}`);
                                }
                                return l;
                            });
                            if(!found) updatedT.push(`EnterId#${id}%PointsTotalAll#${amt}%PointsTotal#${amt}`);
                            
                            let resL = await callApi('GetTextFile', PATH_MANUAL_LOG);
                            let currentManualLog = resL.contents || "";
                            const timeStr = new Date().toLocaleTimeString('he-IL', {hour:'2-digit', minute:'2-digit'});
                            const newEntry = `${Date.now()}|${id}|${amt}|${timeStr}`;
                            const updatedManualLog = newEntry + "\n" + currentManualLog;
                         
                            await Promise.all([
                                callApi('UploadTextFile', PATH_TOTAL, updatedT.join('\n')),
                                callApi('UploadTextFile', PATH_MANUAL_LOG, updatedManualLog)
                            ]);
                         
                            document.getElementById('mainStatus').innerText = "✅ נרשם וסונכרן לשרת!";
                            document.getElementById('manualAmount').value = "";
                        }
                         
                        async function fetchLogs() {
                            let [resPhone, resManual] = await Promise.all([
                                callApi('GetTextFile', PATH_PHONE_LOG),
                                callApi('GetTextFile', PATH_MANUAL_LOG)
                            ]);
                         
                            let allEntries = [];
                            const todayStr = new Date().toISOString().split('T')[0];
                         
                            if (resPhone.contents) {
                                resPhone.contents.trim().split('\n').forEach(l => {
                                    let id = (l.match(/id#(\d+)/) || [])[1];
                                    let pts = (l.match(/Points#(\d+)/) || [])[1];
                                    let timeM = (l.match(/(\d{2}:\d{2})/) || [""])[0];
                                    if (id) allEntries.push({id, pts, time: timeM, type: 'phone', fullLine: l, ts: timeM ? new Date(`${todayStr}T${timeM}:00`).getTime() : 0});
                                });
                            }
                         
                            if (resManual.contents) {
                                resManual.contents.trim().split('\n').forEach(l => {
                                    let [ts, id, amt, time] = l.split('|');
                                    if (id) allEntries.push({id, pts: amt, time, type: 'manual', fullLine: l, ts: parseInt(ts)});
                                });
                            }
                         
                            allEntries.sort((a, b) => b.ts - a.ts);
                         
                            let html = allEntries.map(entry => {
                                let name = nameMap[entry.id] || entry.id;
                                return `<div class="log-item"><label><input type="checkbox" class="log-cb" data-id="${entry.id}" data-amt="${entry.pts}" data-type="${entry.type}" data-line="${entry.fullLine}"><span><span class="badge ${entry.type === 'manual' ? 'badge-manual' : 'badge-phone'}">${entry.type === 'manual' ? 'ידני' : 'טלפון'}</span> [${entry.time}] <b>${name}</b> - ₪${entry.pts}</span></label></div>`;
                            }).join('');
                            document.getElementById('logsList').innerHTML = html || "אין היסטוריה.";
                        }
                         
                        async function deleteLogs() {
                            const checkboxes = document.querySelectorAll('.log-cb:checked');
                            if (checkboxes.length === 0) return alert("בחר פעולות");
                            if (!confirm("זה ימחק את השורות מכל המחשבים ויקזז סכומים. המשך?")) return;
                         
                            document.getElementById('modalStatus').innerText = "⏳ מסנכרן שרת...";
                            let [resP, resM, resT] = await Promise.all([
                                callApi('GetTextFile', PATH_PHONE_LOG),
                                callApi('GetTextFile', PATH_MANUAL_LOG),
                                callApi('GetTextFile', PATH_TOTAL)
                            ]);
                         
                            let phoneLines = resP.contents ? resP.contents.trim().split('\n') : [];
                            let manualLines = resM.contents ? resM.contents.trim().split('\n') : [];
                            let totalLines = resT.contents ? resT.contents.trim().split('\n') : [];
                         
                            checkboxes.forEach(cb => {
                                const id = cb.getAttribute('data-id'), amt = parseFloat(cb.getAttribute('data-amt')), type = cb.getAttribute('data-type'), line = cb.getAttribute('data-line');
                                if (type === 'phone') phoneLines = phoneLines.filter(l => l !== line);
                                else manualLines = manualLines.filter(l => l !== line);
                         
                                totalLines = totalLines.map(tL => {
                                    if(tL.includes(`EnterId#${id}`)) {
                                        let old = parseFloat((tL.match(/PointsTotalAll#([\d.]+)/) || [0,0])[1]);
                                        let sum = Math.max(0, old - amt);
                                        return tL.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${sum}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${sum}`);
                                    } return tL;
                                });
                            });
                         
                            await Promise.all([
                                callApi('UploadTextFile', PATH_PHONE_LOG, phoneLines.join('\n')),
                                callApi('UploadTextFile', PATH_MANUAL_LOG, manualLines.join('\n')),
                                callApi('UploadTextFile', PATH_TOTAL, totalLines.join('\n'))
                            ]);
                            
                            document.getElementById('modalStatus').innerText = "✅ הסנכרון הושלם בכל המחשבים!";
                            fetchLogs();
                        }
                         
                        async function loadCurrentConfig() {
                            const res = await callApi('GetTextFile', PATH_CONFIG);
                            if(res.contents) {
                                const goal = (res.contents.match(/goal=(.*)/) || [])[1];
                                const date = (res.contents.match(/date=(.*)/) || [])[1];
                                if(goal) document.getElementById('goalVal').value = goal;
                                if(date) document.getElementById('dateVal').value = date;
                            }
                        }
                        async function saveConfig() {
                            const content = `goal=${document.getElementById('goalVal').value}\ndate=${document.getElementById('dateVal').value}`;
                            await callApi('UploadTextFile', PATH_CONFIG, content);
                            alert("עודכן בשרת!");
                        }
                        async function fetchTotals() {
                            let res = await callApi('GetTextFile', PATH_TOTAL);
                            if(!res.contents) return;
                            let html = res.contents.trim().split('\n').map(l => {
                                let id = (l.match(/EnterId#(\d+)/) || [])[1];
                                let val = (l.match(/PointsTotalAll#([\d.]+)/) || [])[1];
                                if(!id) return '';
                                let name = nameMap[id] || id;
                                return `<div class="log-item"><span><b>${name}</b> (${id})</span><div style="display:flex; gap:5px;"><input type="number" id="inp-${id}" value="${val}" style="width:110px;"><button onclick="updateTotal('${id}')" style="background:var(--primary); color:white; border:none; padding:8px 12px; border-radius:8px; cursor:pointer;">עדכן</button></div></div>`;
                            }).join('');
                            document.getElementById('totalsList').innerHTML = html;
                        }
                        async function updateTotal(id) {
                            const newVal = document.getElementById(`inp-${id}`).value;
                            let res = await callApi('GetTextFile', PATH_TOTAL);
                            let updated = res.contents.trim().split('\n').map(l => l.includes(`EnterId#${id}`) ? l.replace(/PointsTotalAll#[\d.]+/, `PointsTotalAll#${newVal}`).replace(/PointsTotal#[\d.]+/, `PointsTotal#${newVal}`) : l);
                            await callApi('UploadTextFile', PATH_TOTAL, updated.join('\n'));
                            alert("סכום עודכן בשרת!");
                        }
                        </script>
                        </body>
                        </html>
                        

                        מסך התרמה

                        <!DOCTYPE html>
                        <html lang="he" dir="rtl">
                        <head>
                        <meta charset="UTF-8">
                        <title>מערכת התרמה LIVE - Points Sync</title>
                        <style>
                        :root { --accent: #0ea5e9; --gold: #fbbf24; --bg: #020617; }
                        body { background: var(--bg); color: #f8fafc; font-family: system-ui, sans-serif; margin: 0; padding: 10px; overflow: hidden; }
                        .container { display: grid; grid-template-columns: 320px 1fr 320px; gap: 15px; height: 95vh; }
                        .card { background: rgba(30, 41, 59, 0.6); border: 1px solid rgba(255,255,255,0.1); border-radius: 20px; padding: 15px; backdrop-filter: blur(10px); display: flex; flex-direction: column; overflow: hidden; }
                        .center-card { display: flex; flex-direction: column; justify-content: space-between; align-items: center; text-align: center; padding: 40px 20px; }
                        h2 { font-size: 1.3rem; border-bottom: 2px solid var(--accent); padding-bottom: 8px; margin: 0 0 10px 0; color: white; text-align: center; }
                        
                            .countdown-timer { display: flex; gap: 15px; margin-bottom: 20px; }
                            .time-unit { background: rgba(14, 165, 233, 0.2); padding: 10px 15px; border-radius: 12px; border: 1px solid var(--accent); min-width: 60px; }
                            .time-num { display: block; font-size: 2rem; font-weight: bold; color: white; }
                            .time-label { font-size: 0.8rem; opacity: 0.7; }
                         
                            .total-amount { font-size: 8rem; font-weight: 900; color: var(--accent); text-shadow: 0 0 30px rgba(14, 165, 233, 0.4); margin: 10px 0; line-height: 1; }
                            
                            .progress-wrapper { width: 90%; }
                            .progress-bg { background: #1e293b; height: 40px; border-radius: 50px; border: 2px solid #334155; overflow: hidden; position: relative; }
                            .progress-fill { height: 100%; background: linear-gradient(90deg, #0ea5e9, #22d3ee); width: 0%; transition: width 2s; }
                            
                            .list-box { flex-grow: 1; overflow: hidden; display: flex; flex-direction: column; padding-right: 5px; }
                            .item { display: flex; flex-direction: column; align-items: stretch; padding: 10px; background: rgba(255,255,255,0.05); margin-bottom: 8px; border-radius: 10px; border-right: 4px solid var(--accent); flex-shrink: 0; transition: all 0.5s; }
                            .item-header { display: flex; justify-content: space-between; align-items: center; }
                            .item-info { display: flex; flex-direction: column; }
                            .item-name { font-weight: bold; font-size: 1.1rem; display: flex; align-items: center; gap: 6px; }
                            .item-time { font-size: 0.8rem; color: #94a3b8; font-weight: bold; }
                            .item-val { font-weight: 900; color: var(--gold); font-size: 1.3rem; }
                            
                            .badge { font-size: 0.6rem; padding: 2px 5px; border-radius: 4px; font-weight: bold; }
                            .badge-manual { background: #0ea5e9; color: white; }
                            .badge-phone { background: #22c55e; color: white; }
                         
                            .live-dot { height: 10px; width: 10px; background: #ef4444; border-radius: 50%; display: inline-block; margin-left: 8px; animation: pulse 1s infinite; }
                            @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
                        
                            /* עיצוב לאנימציה של הגעה ליעד */
                            @keyframes goldGlow {
                                0% { box-shadow: 0 0 5px rgba(251, 191, 36, 0.2); border-color: rgba(251, 191, 36, 0.5); }
                                50% { box-shadow: 0 0 20px rgba(251, 191, 36, 0.8); border-color: rgba(251, 191, 36, 1); }
                                100% { box-shadow: 0 0 5px rgba(251, 191, 36, 0.2); border-color: rgba(251, 191, 36, 0.5); }
                            }
                            .goal-reached {
                                animation: goldGlow 2s infinite;
                                background: rgba(251, 191, 36, 0.1) !important;
                                border-right-color: var(--gold) !important;
                            }
                            .goal-badge {
                                background: var(--gold); color: black; font-size: 0.75rem; padding: 2px 8px; border-radius: 12px; font-weight: bold; margin-right: 10px; display: inline-block;
                            }
                        </style>
                        </head>
                        <body>
                        
                        <div class="container">
                        <div class="card">
                        <h2>🏆 מובילים</h2>
                        <div id="leaderboard" class="list-box" style="overflow-y: auto;"></div>
                        </div>
                        
                        <div class="card center-card">
                            <div>
                                <div style="margin-bottom: 10px; font-size: 1.2rem; font-weight: bold;"><span class="live-dot"></span>הקמפיין מסתיים בעוד:</div>
                                <div id="countdown" class="countdown-timer">
                                    <div class="time-unit"><span id="days" class="time-num">00</span><span class="time-label">ימים</span></div>
                                    <div class="time-unit"><span id="hours" class="time-num">00</span><span class="time-label">שעות</span></div>
                                    <div class="time-unit"><span id="minutes" class="time-num">00</span><span class="time-label">דקות</span></div>
                                    <div class="time-unit"><span id="seconds" class="time-num">00</span><span class="time-label">שניות</span></div>
                                </div>
                            </div>
                         
                            <div>
                                <h1 style="margin:0; font-size: 1.8rem; opacity: 0.9;">סך הכל נאסף:</h1>
                                <div id="main-total" class="total-amount">₪0</div>
                            </div>
                         
                            <div class="progress-wrapper">
                                <div class="progress-bg"><div id="progress-bar" class="progress-fill"></div></div>
                                <div id="percent-label" style="font-size: 3rem; color: var(--gold); font-weight: bold; margin-top: 10px;">0%</div>
                                <div id="goal-text" style="font-size: 1.5rem; opacity: 0.6;">מחשב נתונים...</div>
                            </div>
                        </div>
                         
                        <div class="card">
                            <h2>🔔 תרומות אחרונות</h2>
                            <div id="recent-log" class="list-box" style="overflow-y: auto;"></div>
                        </div>
                        </div>
                        
                        <script>
                        // הגדרות שלוחה - הכל תחת תיקיית Points
                        const TOKEN = 'WU1BUElL.apik_MmtjfW7MhNRZGw4h--R54Q.zPUwopxRh5JxRpUutkWFKUhyDWtLfvYwWKQ30PTuXZw';
                        const PATH_TOTAL = 'ivr2:Points/points_total.ymgr';
                        const PATH_PHONE_LOG = 'ivr2:Points/points_log.2026-02.ymgr';
                        const PATH_MANUAL_LOG = 'ivr2:Points/manual_log.ini';
                        const PATH_CONFIG = 'ivr2:Points/config.ini';
                        const PATH_NAMES = 'ivr2:Points/EnterIDValName.ini';
                        const PATH_GOALS = 'ivr2:Points/EnterIDGoal.ini';
                        
                        let GOAL = 500000;
                        let DEADLINE = new Date(); 
                        let nameMap = {};
                        let goalMap = {};
                         
                        function updateCountdown() {
                            const now = new Date();
                            const diff = DEADLINE - now;
                            if (diff <= 0) {
                                document.querySelectorAll('.time-num').forEach(el => el.innerText = "00");
                                return;
                            }
                            document.getElementById('days').innerText = String(Math.floor(diff / (1000 * 60 * 60 * 24))).padStart(2, '0');
                            document.getElementById('hours').innerText = String(Math.floor((diff / (1000 * 60 * 60)) % 24)).padStart(2, '0');
                            document.getElementById('minutes').innerText = String(Math.floor((diff / 1000 / 60) % 60)).padStart(2, '0');
                            document.getElementById('seconds').innerText = String(Math.floor((diff / 1000) % 60)).padStart(2, '0');
                        }
                         
                        async function update() {
                            try {
                                const [resTotal, resLogPhone, resNames, resConfig, resLogManual, resGoals] = await Promise.all([
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_TOTAL}`).then(r => r.json()),
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_PHONE_LOG}`).then(r => r.json()),
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_NAMES}`).then(r => r.json()),
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_CONFIG}`).then(r => r.json()),
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_MANUAL_LOG}`).then(r => r.json()),
                                    fetch(`https://www.call2all.co.il/ym/api/GetTextFile?token=${TOKEN}&what=${PATH_GOALS}`).then(r => r.json())
                                ]);
                         
                                if (resConfig.contents) {
                                    const g = resConfig.contents.match(/goal=(.*)/);
                                    const d = resConfig.contents.match(/date=(.*)/);
                                    if (g) {
                                        GOAL = parseFloat(g[1]);
                                        document.getElementById('goal-text').innerText = `מתוך יעד של ${GOAL.toLocaleString()} ₪`;
                                    }
                                    if (d) DEADLINE = new Date(d[1]);
                                }
                         
                                if (resNames.contents) {
                                    resNames.contents.split(/[\r\n]+/).forEach(line => {
                                        const parts = line.split('=');
                                        if (parts.length === 2) nameMap[parts[0].trim()] = parts[1].trim();
                                    });
                                }
                        
                                if (resGoals.contents) {
                                    goalMap = {};
                                    resGoals.contents.split(/[\r\n]+/).forEach(line => {
                                        const parts = line.split('=');
                                        if (parts.length === 2) goalMap[parts[0].trim()] = parseFloat(parts[1].trim());
                                    });
                                }
                         
                                if (resTotal.contents) {
                                    const lines = resTotal.contents.trim().split(/[\r\n]+/);
                                    let totalSum = 0; let users = [];
                                    lines.forEach(l => {
                                        const idMatch = l.match(/EnterId#(\d+)/);
                                        const scoreMatch = l.match(/PointsTotalAll#([\d.]+)/);
                                        if (idMatch && scoreMatch) {
                                            const val = parseFloat(scoreMatch[1]);
                                            totalSum += val;
                                            users.push({id: idMatch[1], val: val});
                                        }
                                    });
                                    document.getElementById('main-total').innerText = '₪' + totalSum.toLocaleString();
                                    document.getElementById('progress-bar').style.width = Math.min((totalSum/GOAL)*100, 100) + '%';
                                    document.getElementById('percent-label').innerText = ((totalSum/GOAL)*100).toFixed(1) + '%';
                                    
                                    users.sort((a,b) => b.val - a.val);
                                    
                                    document.getElementById('leaderboard').innerHTML = users.map((u,i) => {
                                        const personalGoal = goalMap[u.id];
                                        let goalHtml = '';
                                        let reachedClass = '';
                                        let goalBadgeHtml = '';
                                        
                                        if (personalGoal && personalGoal > 0) {
                                            const rawPct = (u.val / personalGoal) * 100;
                                            const pct = Math.min(rawPct, 100).toFixed(0);
                                            
                                            if (rawPct >= 100) {
                                                reachedClass = 'goal-reached';
                                                goalBadgeHtml = `<span class="goal-badge">הגיע ליעד! 👑</span>`;
                                            }
                        
                                            goalHtml = `
                                                <div style="font-size: 0.8rem; color: #94a3b8; display: flex; align-items: center; gap: 8px; margin-top: 8px;">
                                                    <div style="background: rgba(255,255,255,0.1); height: 6px; flex-grow: 1; border-radius: 5px; overflow: hidden;">
                                                        <div style="background: var(--gold); height: 100%; width: ${pct}%; transition: width 1s;"></div>
                                                    </div>
                                                    <span style="min-width: 40px; text-align: left; font-weight: bold; color: ${rawPct >= 100 ? 'var(--gold)' : 'inherit'}">${pct}%</span>
                                                </div>
                                            `;
                                        }
                        
                                        return `
                                            <div class="item ${reachedClass}">
                                                <div class="item-header">
                                                    <span class="item-name"><b>${i+1}.</b> ${nameMap[u.id] || u.id} ${goalBadgeHtml}</span>
                                                    <span style="color:var(--accent); font-weight:bold;">₪${u.val.toLocaleString()}</span>
                                                </div>
                                                ${goalHtml}
                                            </div>
                                        `;
                                    }).join('');
                                }
                         
                                let allItems = [];
                                const todayStr = new Date().toISOString().split('T')[0];
                         
                                if (resLogPhone.contents) {
                                    resLogPhone.contents.trim().split(/[\r\n]+/).forEach((line, idx) => {
                                        const idM = line.match(/id#(\d+)/);
                                        const ptM = line.match(/Points#(\d+)/);
                                        const timeM = line.match(/(\d{2}:\d{2})/);
                                        if (idM && ptM) {
                                            let ts = timeM ? new Date(`${todayStr}T${timeM[1]}:00`).getTime() : (Date.now() - 500000);
                                            allItems.push({ id: idM[1], amount: ptM[1], type: 'phone', timestamp: ts, timeStr: timeM ? timeM[1] : "--:--" });
                                        }
                                    });
                                }
                         
                                if (resLogManual.contents) {
                                    resLogManual.contents.trim().split('\n').forEach(l => {
                                        let [ts, id, amt, time] = l.split('|');
                                        if (id) allItems.push({ id, amount: amt, type: 'manual', timestamp: parseInt(ts), timeStr: time });
                                    });
                                }
                         
                                allItems.sort((a, b) => b.timestamp - a.timestamp);
                         
                                document.getElementById('recent-log').innerHTML = allItems.map(item => `
                                    <div class="item" style="flex-direction: row; justify-content: space-between; align-items: center;">
                                        <div class="item-info">
                                            <span class="item-name">
                                                <span class="badge ${item.type === 'manual' ? 'badge-manual' : 'badge-phone'}">${item.type === 'manual' ? 'ידני' : 'טלפון'}</span>
                                                ${nameMap[item.id] || 'מתרים ' + item.id}
                                            </span>
                                            <span class="item-time">${item.timeStr}</span>
                                        </div>
                                        <span class="item-val">₪${parseFloat(item.amount).toLocaleString()}</span>
                                    </div>
                                `).join('');
                         
                            } catch (e) { console.error("Update Error:", e); }
                        }
                         
                        setInterval(updateCountdown, 1000);
                        setInterval(update, 5000);
                        updateCountdown();
                        update();
                        </script>
                        </body>
                        </html>
                        

                        קרדיט ל @אa על הפיתוח המועיל

                        תגובה 1 תגובה אחרונה תגובה ציטוט 0
                        • פוסט ראשון
                          פוסט אחרון