MP Manager Auto Strategy Setter

Автоматическая установка стратегии рекламной кампании на основе статистики

Size

63.9 KB

Version

1.8.5

Created

Feb 9, 2026

Updated

about 1 month ago

1// ==UserScript==
2// @name		MP Manager Auto Strategy Setter
3// @description		Автоматическая установка стратегии рекламной кампании на основе статистики
4// @version		1.8.5
5// @match		https://*.app.mpmgr.ru/*
6// @icon		https://app.mpmgr.ru/favicon.ico
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.deleteValue
10// @grant		GM.openInTab
11// @grant		GM.setClipboard
12// ==/UserScript==
13(function() {
14    'use strict';
15
16    console.log('MP Manager Auto Strategy Setter загружен');
17
18    // Константы
19    const STRATEGY_CODE = 'eyJjYW1wYWlnblR5cGUiOiJTZWFyY2hDYXRhbG9nIiwidmVyc2lvbiI6MiwiZGF0YSI6eyJzdGF0ZSI6IkVuYWJsZWQiLCJtb2RlIjp7InR5cGUiOiJQb3NpdGlvbiIsInBhdXNlVHlwZSI6IlJlc3VtZSJ9LCJzdHJhdGVneSI6eyJ0eXBlIjoiQ2FtcGFpZ25TdGF0cyIsIm1vZGUiOiJQbGFjZSIsImJpZE1vZGUiOiJDb3N0UGVyQ2xpY2siLCJjYW1wYWlnblN0YXRzIjp7Im1heFByaWNlIjo2MCwibWluUHJpY2UiOjEsInBsYXRmb3JtcyI6W10sImludGVydmFsIjoiV2VlayIsInJ1bGVzIjpbeyJ0eXBlIjoiQ29zdFBlckFkZGVkVG9DYXJ0IiwibW9kZSI6IlZhbHVlIiwidmFsdWUiOiIifV19fSwicGxhY2VTdHJhdGVneSI6eyJ0eXBlIjoiS2V5d29yZHMiLCJrZXl3b3JkcyI6eyJrZXl3b3JkcyI6W119fSwic3RvY2tTdHJhdGVneSI6eyJtb2RlIjoiU3RvY2tzIn0sIm9yZGVyU3RyYXRlZ3kiOnsibW9kZSI6Ik9yZGVycyJ9LCJwcm9kdWN0UGxhY2VTdHJhdGVneSI6eyJwcm9kdWN0UGxhY2UiOiIifSwiaXNDbHVzdGVyIjpmYWxzZX19';
20
21    // Глобальные переменные для массовой обработки
22    let isBulkProcessing = false;
23    let bulkDesiredPercentage = 50;
24    let bulkPaused = false;
25
26    // Функция для получения сохраненных стратегий
27    async function getSavedStrategies() {
28        let strategies = await GM.getValue('saved_strategies', []);
29        
30        // Миграция: добавляем ID к стратегиям, у которых его нет
31        let needsMigration = false;
32        strategies = strategies.map((strategy, index) => {
33            if (!strategy.id) {
34                needsMigration = true;
35                return {
36                    ...strategy,
37                    id: 'strategy_migrated_' + Date.now() + '_' + index
38                };
39            }
40            return strategy;
41        });
42        
43        // Сохраняем обновленные стратегии, если была миграция
44        if (needsMigration) {
45            await GM.setValue('saved_strategies', strategies);
46            console.log('Миграция стратегий выполнена: добавлены ID');
47        }
48        
49        // Если нет сохраненных стратегий, добавляем стратегию по умолчанию
50        if (strategies.length === 0) {
51            return [{
52                id: 'default',
53                name: 'Стратегия по умолчанию',
54                data: STRATEGY_CODE
55            }];
56        }
57        return strategies;
58    }
59
60    // Функция для получения текущей стратегии
61    async function getCurrentStrategy() {
62        const currentId = await GM.getValue('current_strategy_id', 'default');
63        const strategies = await getSavedStrategies();
64        const strategy = strategies.find(s => s.id === currentId);
65        return strategy ? strategy.data : STRATEGY_CODE;
66    }
67
68    // Функция для создания модального окна управления стратегиями
69    function createStrategyManagementModal() {
70        return new Promise(async (resolve) => {
71            // Создаем оверлей
72            const overlay = document.createElement('div');
73            overlay.style.cssText = `
74                position: fixed;
75                top: 0;
76                left: 0;
77                width: 100%;
78                height: 100%;
79                background: rgba(0, 0, 0, 0.5);
80                display: flex;
81                justify-content: center;
82                align-items: center;
83                z-index: 10001;
84            `;
85            
86            // Создаем модальное окно
87            const modal = document.createElement('div');
88            modal.style.cssText = `
89                background: white;
90                border-radius: 12px;
91                padding: 24px;
92                min-width: 500px;
93                max-width: 600px;
94                max-height: 80vh;
95                overflow-y: auto;
96                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
97            `;
98            
99            // Заголовок
100            const title = document.createElement('h2');
101            title.textContent = 'Управление стратегиями';
102            title.style.cssText = `
103                margin: 0 0 20px 0;
104                font-size: 24px;
105                font-weight: bold;
106                color: #333;
107            `;
108            modal.appendChild(title);
109            
110            // Контейнер для списка стратегий
111            const listContainer = document.createElement('div');
112            listContainer.style.cssText = `
113                margin-bottom: 20px;
114                max-height: 300px;
115                overflow-y: auto;
116            `;
117            
118            // Функция для обновления списка
119            const updateList = async () => {
120                const currentStrategies = await getSavedStrategies();
121                const selectedStrategy = await GM.getValue('current_strategy_id', 'default');
122                listContainer.innerHTML = '';
123                
124                if (currentStrategies.length === 0) {
125                    const emptyMessage = document.createElement('p');
126                    emptyMessage.textContent = 'Нет сохраненных стратегий. Используется стратегия по умолчанию.';
127                    emptyMessage.style.cssText = `
128                        color: #666;
129                        font-style: italic;
130                        padding: 20px;
131                        text-align: center;
132                    `;
133                    listContainer.appendChild(emptyMessage);
134                } else {
135                    currentStrategies.forEach((strategy, index) => {
136                        const item = document.createElement('div');
137                        const isSelected = strategy.id === selectedStrategy;
138                        item.style.cssText = `
139                            display: flex;
140                            justify-content: space-between;
141                            align-items: center;
142                            padding: 12px;
143                            margin-bottom: 8px;
144                            background: ${isSelected ? '#e3f2fd' : '#f5f5f5'};
145                            border-radius: 8px;
146                            border: ${isSelected ? '2px solid #2196f3' : '1px solid #ddd'};
147                        `;
148                        
149                        const nameSpan = document.createElement('span');
150                        nameSpan.textContent = strategy.name + (isSelected ? ' ✓' : '');
151                        nameSpan.style.cssText = `
152                            font-size: 16px;
153                            color: #333;
154                            flex: 1;
155                            font-weight: ${isSelected ? 'bold' : 'normal'};
156                        `;
157                        
158                        const buttonsContainer = document.createElement('div');
159                        buttonsContainer.style.cssText = `
160                            display: flex;
161                            gap: 8px;
162                        `;
163                        
164                        // Кнопка выбора
165                        if (!isSelected) {
166                            const selectBtn = document.createElement('button');
167                            selectBtn.textContent = '✓ Выбрать';
168                            selectBtn.style.cssText = `
169                                background: #2196f3;
170                                color: white;
171                                border: none;
172                                padding: 6px 12px;
173                                border-radius: 6px;
174                                cursor: pointer;
175                                font-size: 14px;
176                            `;
177                            selectBtn.onmouseover = () => selectBtn.style.background = '#1976d2';
178                            selectBtn.onmouseout = () => selectBtn.style.background = '#2196f3';
179                            selectBtn.onclick = async () => {
180                                await GM.setValue('current_strategy_id', strategy.id);
181                                console.log(`Выбрана стратегия: ${strategy.name} (ID: ${strategy.id})`);
182                                await updateList();
183                            };
184                            buttonsContainer.appendChild(selectBtn);
185                        }
186                        
187                        // Кнопка удаления
188                        const deleteBtn = document.createElement('button');
189                        deleteBtn.textContent = '🗑️';
190                        deleteBtn.style.cssText = `
191                            background: #f44336;
192                            color: white;
193                            border: none;
194                            padding: 6px 12px;
195                            border-radius: 6px;
196                            cursor: pointer;
197                            font-size: 14px;
198                        `;
199                        deleteBtn.onmouseover = () => deleteBtn.style.background = '#d32f2f';
200                        deleteBtn.onmouseout = () => deleteBtn.style.background = '#f44336';
201                        deleteBtn.onclick = async () => {
202                            if (confirm(`Удалить стратегию "${strategy.name}"?`)) {
203                                currentStrategies.splice(index, 1);
204                                await GM.setValue('saved_strategies', currentStrategies);
205                                // Если удаляем выбранную стратегию, возвращаемся к дефолтной
206                                if (isSelected) {
207                                    await GM.setValue('current_strategy_id', 'default');
208                                }
209                                await updateList();
210                            }
211                        };
212                        buttonsContainer.appendChild(deleteBtn);
213                        
214                        item.appendChild(nameSpan);
215                        item.appendChild(buttonsContainer);
216                        listContainer.appendChild(item);
217                    });
218                }
219            };
220            
221            await updateList();
222            modal.appendChild(listContainer);
223            
224            // Кнопка добавления стратегии
225            const addButton = document.createElement('button');
226            addButton.textContent = '➕ Добавить новую стратегию';
227            addButton.style.cssText = `
228                width: 100%;
229                background: #4caf50;
230                color: white;
231                border: none;
232                padding: 12px;
233                border-radius: 8px;
234                cursor: pointer;
235                font-size: 16px;
236                font-weight: bold;
237                margin-bottom: 12px;
238            `;
239            addButton.onmouseover = () => addButton.style.background = '#45a049';
240            addButton.onmouseout = () => addButton.style.background = '#4caf50';
241            addButton.onclick = async () => {
242                const name = prompt('Введите название стратегии:');
243                if (!name) return;
244                
245                const data = prompt('Вставьте код стратегии (скопируйте из MP Manager):');
246                if (!data) return;
247                
248                const currentStrategies = await GM.getValue('saved_strategies', []);
249                const newId = 'strategy_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
250                currentStrategies.push({ id: newId, name, data });
251                await GM.setValue('saved_strategies', currentStrategies);
252                alert(`Стратегия "${name}" сохранена!`);
253                await updateList();
254            };
255            modal.appendChild(addButton);
256            
257            // Кнопка закрытия
258            const closeButton = document.createElement('button');
259            closeButton.textContent = 'Закрыть';
260            closeButton.style.cssText = `
261                width: 100%;
262                background: #666;
263                color: white;
264                border: none;
265                padding: 12px;
266                border-radius: 8px;
267                cursor: pointer;
268                font-size: 16px;
269            `;
270            closeButton.onmouseover = () => closeButton.style.background = '#555';
271            closeButton.onmouseout = () => closeButton.style.background = '#666';
272            closeButton.onclick = () => {
273                document.body.removeChild(overlay);
274                resolve();
275            };
276            modal.appendChild(closeButton);
277            
278            overlay.appendChild(modal);
279            document.body.appendChild(overlay);
280            
281            // Закрытие по клику на оверлей
282            overlay.onclick = (e) => {
283                if (e.target === overlay) {
284                    document.body.removeChild(overlay);
285                    resolve();
286                }
287            };
288        });
289    }
290
291    // Функция для создания UI
292    function createUI() {
293        console.log('Создание UI панели');
294        
295        // Проверяем, есть ли сохраненный ДРР для массовой обработки
296        GM.getValue('bulkProcessingDRR', null).then(savedDRR => {
297            if (savedDRR !== null) {
298                console.log(`Найден сохраненный ДРР для массовой обработки: ${savedDRR}`);
299                // Автоматически запускаем стратегию с сохраненным ДРР
300                setTimeout(() => {
301                    const input = document.getElementById('desired-percentage');
302                    if (input) {
303                        input.value = savedDRR;
304                        // Запускаем стратегию автоматически
305                        runStrategy();
306                    }
307                }, 2000);
308            }
309        });
310        
311        const panel = document.createElement('div');
312        panel.id = 'auto-strategy-panel';
313        panel.style.cssText = `
314            position: fixed;
315            top: 20px;
316            right: 20px;
317            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
318            padding: 15px;
319            border-radius: 12px;
320            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
321            z-index: 10000;
322            min-width: 280px;
323            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
324            color: white;
325            transition: all 0.3s ease;
326            cursor: move;
327        `;
328
329        panel.innerHTML = `
330            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: pointer;" id="panel-header">
331                <h3 style="margin: 0; font-size: 16px; font-weight: 600;">🚀 Авто-стратегия</h3>
332                <span id="toggle-icon" style="font-size: 18px;"></span>
333            </div>
334            
335            <div id="panel-content" style="display: none;">
336                <div style="margin-bottom: 15px;">
337                    <label style="display: block; margin-bottom: 8px; font-size: 13px; font-weight: 500;">
338                        Желаемый % рекламных расходов:
339                    </label>
340                    <input 
341                        type="number" 
342                        id="desired-percentage" 
343                        value="50" 
344                        min="1" 
345                        max="100" 
346                        step="0.1"
347                        style="
348                            width: 100%;
349                            padding: 10px;
350                            border: none;
351                            border-radius: 8px;
352                            font-size: 14px;
353                            box-sizing: border-box;
354                            background: rgba(255, 255, 255, 0.95);
355                            color: #333;
356                            cursor: text;
357                        "
358                    />
359                </div>
360
361                <button 
362                    id="run-strategy-btn"
363                    style="
364                        width: 100%;
365                        padding: 12px;
366                        background: white;
367                        color: #667eea;
368                        border: none;
369                        border-radius: 8px;
370                        font-size: 14px;
371                        font-weight: 600;
372                        cursor: pointer;
373                        transition: all 0.3s ease;
374                        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
375                        margin-bottom: 10px;
376                    "
377                    onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 16px rgba(0, 0, 0, 0.2)';"
378                    onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 12px rgba(0, 0, 0, 0.15)';"
379                >
380                    Запустить
381                </button>
382
383                <button 
384                    id="manage-strategies-btn"
385                    style="
386                        width: 100%;
387                        padding: 10px;
388                        background: rgba(255, 255, 255, 0.2);
389                        color: white;
390                        border: 1px solid rgba(255, 255, 255, 0.3);
391                        border-radius: 8px;
392                        font-size: 13px;
393                        font-weight: 600;
394                        cursor: pointer;
395                        transition: all 0.3s ease;
396                    "
397                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
398                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
399                >
400                    ⚙️ Управление стратегиями
401                </button>
402
403                <div id="status-message" style="
404                    margin-top: 15px;
405                    padding: 10px;
406                    border-radius: 8px;
407                    font-size: 12px;
408                    background: rgba(255, 255, 255, 0.2);
409                    display: none;
410                "></div>
411            </div>
412        `;
413
414        document.body.appendChild(panel);
415        console.log('UI панель создана');
416
417        // Добавляем возможность перетаскивания
418        makeDraggable(panel);
419
420        // Добавляем обработчик клика на заголовок для разворачивания/сворачивания
421        document.getElementById('panel-header').addEventListener('click', () => {
422            const content = document.getElementById('panel-content');
423            const icon = document.getElementById('toggle-icon');
424            if (content.style.display === 'none') {
425                content.style.display = 'block';
426                icon.textContent = '▲';
427            } else {
428                content.style.display = 'none';
429                icon.textContent = '▼';
430            }
431        });
432
433        // Добавляем обработчик клика на кнопку
434        document.getElementById('run-strategy-btn').addEventListener('click', runStrategy);
435        
436        // Добавляем обработчик для кнопки управления стратегиями
437        document.getElementById('manage-strategies-btn').addEventListener('click', async () => {
438            await createStrategyManagementModal();
439        });
440    }
441
442    // Функция для создания UI панели массового изменения
443    function createBulkUI() {
444        console.log('Создание UI панели массового изменения');
445        
446        const panel = document.createElement('div');
447        panel.id = 'bulk-strategy-panel';
448        panel.style.cssText = `
449            position: fixed;
450            top: 20px;
451            right: 20px;
452            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
453            padding: 15px;
454            border-radius: 12px;
455            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
456            z-index: 10000;
457            min-width: 300px;
458            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
459            color: white;
460            transition: all 0.3s ease;
461            cursor: move;
462        `;
463
464        panel.innerHTML = `
465            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: pointer;" id="bulk-panel-header">
466                <h3 style="margin: 0; font-size: 16px; font-weight: 600;">📦 Массовое изменение</h3>
467                <span id="bulk-toggle-icon" style="font-size: 18px;"></span>
468            </div>
469            
470            <div id="bulk-panel-content" style="display: none;">
471                <div style="margin-bottom: 15px;">
472                    <label style="display: block; margin-bottom: 8px; font-size: 13px; font-weight: 500;">
473                        Желаемый % рекламных расходов (ДРР):
474                    </label>
475                    <input 
476                        type="number" 
477                        id="bulk-desired-percentage" 
478                        value="50" 
479                        min="1" 
480                        max="100" 
481                        step="0.1"
482                        style="
483                            width: 100%;
484                            padding: 10px;
485                            border: none;
486                            border-radius: 8px;
487                            font-size: 14px;
488                            box-sizing: border-box;
489                            background: rgba(255, 255, 255, 0.95);
490                            color: #333;
491                            cursor: text;
492                        "
493                    />
494                </div>
495
496                <div id="bulk-campaigns-info" style="
497                    margin-bottom: 15px;
498                    padding: 10px;
499                    border-radius: 8px;
500                    font-size: 12px;
501                    background: rgba(255, 255, 255, 0.2);
502                ">
503                    Найдено кампаний: <span id="campaigns-count">0</span>
504                </div>
505
506                <button 
507                    id="run-bulk-strategy-btn"
508                    style="
509                        width: 100%;
510                        padding: 12px;
511                        background: white;
512                        color: #f5576c;
513                        border: none;
514                        border-radius: 8px;
515                        font-size: 14px;
516                        font-weight: 600;
517                        cursor: pointer;
518                        transition: all 0.3s ease;
519                        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
520                        margin-bottom: 10px;
521                    "
522                    onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 16px rgba(0, 0, 0, 0.2)';"
523                    onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 12px rgba(0, 0, 0, 0.15)';"
524                >
525                    Запустить
526                </button>
527
528                <button 
529                    id="bulk-manage-strategies-btn"
530                    style="
531                        width: 100%;
532                        padding: 10px;
533                        background: rgba(255, 255, 255, 0.2);
534                        color: white;
535                        border: 1px solid rgba(255, 255, 255, 0.3);
536                        border-radius: 8px;
537                        font-size: 13px;
538                        font-weight: 600;
539                        cursor: pointer;
540                        transition: all 0.3s ease;
541                        margin-bottom: 10px;
542                    "
543                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
544                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
545                >
546                    ⚙️ Управление стратегиями
547                </button>
548
549                <div id="bulk-control-buttons" style="
550                    margin-top: 10px;
551                    display: none;
552                    gap: 10px;
553                ">
554                    <button 
555                        id="pause-bulk-btn"
556                        style="
557                            flex: 1;
558                            padding: 10px;
559                            background: rgba(255, 255, 255, 0.9);
560                            color: #f5576c;
561                            border: none;
562                            border-radius: 8px;
563                            font-size: 13px;
564                            font-weight: 600;
565                            cursor: pointer;
566                            transition: all 0.3s ease;
567                        "
568                    >
569                        ⏸️ Пауза
570                    </button>
571                    <button 
572                        id="stop-bulk-btn"
573                        style="
574                            flex: 1;
575                            padding: 10px;
576                            background: rgba(255, 59, 48, 0.9);
577                            color: white;
578                            border: none;
579                            border-radius: 8px;
580                            font-size: 13px;
581                            font-weight: 600;
582                            cursor: pointer;
583                            transition: all 0.3s ease;
584                        "
585                    >
586                        ⏹️ Стоп
587                    </button>
588                </div>
589
590                <div id="bulk-status-message" style="
591                    margin-top: 15px;
592                    padding: 10px;
593                    border-radius: 8px;
594                    font-size: 12px;
595                    background: rgba(255, 255, 255, 0.2);
596                    display: none;
597                "></div>
598
599                <div id="bulk-progress" style="
600                    margin-top: 15px;
601                    display: none;
602                ">
603                    <div style="margin-bottom: 5px; font-size: 12px;">
604                        Прогресс: <span id="bulk-progress-text">0/0</span>
605                    </div>
606                    <div style="
607                        width: 100%;
608                        height: 8px;
609                        background: rgba(255, 255, 255, 0.3);
610                        border-radius: 4px;
611                        overflow: hidden;
612                    ">
613                        <div id="bulk-progress-bar" style="
614                            width: 0%;
615                            height: 100%;
616                            background: white;
617                            transition: width 0.3s ease;
618                        "></div>
619                    </div>
620                </div>
621            </div>
622        `;
623
624        document.body.appendChild(panel);
625        console.log('UI панель массового изменения создана');
626
627        // Добавляем возможность перетаскивания
628        makeDraggable(panel);
629
630        // Подсчитываем количество кампаний
631        updateCampaignsCount();
632
633        // Добавляем обработчик клика на заголовок для разворачивания/сворачивания
634        document.getElementById('bulk-panel-header').addEventListener('click', () => {
635            const content = document.getElementById('bulk-panel-content');
636            const icon = document.getElementById('bulk-toggle-icon');
637            if (content.style.display === 'none') {
638                content.style.display = 'block';
639                icon.textContent = '▲';
640            } else {
641                content.style.display = 'none';
642                icon.textContent = '▼';
643            }
644        });
645
646        // Добавляем обработчик клика на кнопку
647        document.getElementById('run-bulk-strategy-btn').addEventListener('click', runBulkStrategy);
648        
649        // Добавляем обработчик для кнопки управления стратегиями
650        document.getElementById('bulk-manage-strategies-btn').addEventListener('click', async () => {
651            await createStrategyManagementModal();
652        });
653        
654        // Добавляем обработчики для кнопок управления
655        document.getElementById('pause-bulk-btn').addEventListener('click', pauseBulkProcessing);
656        document.getElementById('stop-bulk-btn').addEventListener('click', stopBulkProcessing);
657    }
658
659    // Функция для создания перетаскиваемого элемента
660    function makeDraggable(element) {
661        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
662        let isDragging = false;
663
664        element.onmousedown = dragMouseDown;
665
666        function dragMouseDown(e) {
667            // Не перетаскиваем, если кликнули на input, button или другие интерактивные элементы
668            if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA') {
669                return;
670            }
671            
672            e.preventDefault();
673            isDragging = true;
674            pos3 = e.clientX;
675            pos4 = e.clientY;
676            document.onmouseup = closeDragElement;
677            document.onmousemove = elementDrag;
678        }
679
680        function elementDrag(e) {
681            if (!isDragging) return;
682            e.preventDefault();
683            pos1 = pos3 - e.clientX;
684            pos2 = pos4 - e.clientY;
685            pos3 = e.clientX;
686            pos4 = e.clientY;
687            element.style.top = (element.offsetTop - pos2) + 'px';
688            element.style.left = (element.offsetLeft - pos1) + 'px';
689            element.style.right = 'auto';
690            element.style.bottom = 'auto';
691        }
692
693        function closeDragElement() {
694            isDragging = false;
695            document.onmouseup = null;
696            document.onmousemove = null;
697        }
698    }
699
700    // Функция для обновления количества кампаний
701    function updateCampaignsCount() {
702        const campaignLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
703        const count = campaignLinks.length;
704        const countElement = document.getElementById('campaigns-count');
705        if (countElement) {
706            countElement.textContent = count;
707        }
708        console.log(`Найдено кампаний: ${count}`);
709    }
710
711    // Функция для показа статуса массовой обработки
712    function showBulkStatus(message, isError = false) {
713        const statusDiv = document.getElementById('bulk-status-message');
714        if (statusDiv) {
715            statusDiv.textContent = message;
716            statusDiv.style.display = 'block';
717            statusDiv.style.background = isError ? 'rgba(255, 59, 48, 0.9)' : 'rgba(52, 199, 89, 0.9)';
718            console.log(`Статус массовой обработки: ${message}`);
719        }
720    }
721
722    // Функция для обновления прогресса
723    function updateBulkProgress(current, total) {
724        const progressDiv = document.getElementById('bulk-progress');
725        const progressText = document.getElementById('bulk-progress-text');
726        const progressBar = document.getElementById('bulk-progress-bar');
727        
728        if (progressDiv && progressText && progressBar) {
729            progressDiv.style.display = 'block';
730            progressText.textContent = `${current}/${total}`;
731            const percentage = (current / total) * 100;
732            progressBar.style.width = `${percentage}%`;
733        }
734    }
735
736    // Функция для получения всех ссылок на кампании
737    function getAllCampaignLinks() {
738        const campaignLinks = Array.from(document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]'));
739        return campaignLinks.map(link => ({
740            url: link.href,
741            name: link.textContent.trim()
742        }));
743    }
744
745    // Функция для прокрутки страницы вниз для загрузки всех кампаний
746    async function scrollToLoadAllCampaigns() {
747        console.log('Начало прокрутки для загрузки всех кампаний');
748        showBulkStatus('Загрузка всех кампаний...');
749        
750        // Находим контейнер с прокруткой (ID динамический, поэтому используем атрибутный селектор)
751        const scrollContainer = document.querySelector('[id^="table-"][id$="-container"]');
752        if (!scrollContainer) {
753            console.error('Контейнер для прокрутки не найден');
754            return [];
755        }
756        
757        console.log(`Контейнер найден: ${scrollContainer.id}. ScrollHeight: ${scrollContainer.scrollHeight}, ClientHeight: ${scrollContainer.clientHeight}`);
758        
759        // Используем Set для хранения уникальных ссылок на кампании
760        const allCampaignLinks = new Set();
761        
762        let previousCount = 0;
763        let currentCount = 0;
764        let stableCount = 0;
765        let attempts = 0;
766        const maxAttempts = 100;
767        const scrollStep = 300; // Прокручиваем по 300px за раз для виртуализированной таблицы
768        
769        while (attempts < maxAttempts) {
770            // Прокручиваем контейнер постепенно вниз
771            const currentScrollTop = scrollContainer.scrollTop;
772            const maxScrollTop = scrollContainer.scrollHeight - scrollContainer.clientHeight;
773            
774            // Прокручиваем на один шаг вниз
775            scrollContainer.scrollTop = Math.min(currentScrollTop + scrollStep, maxScrollTop);
776            
777            console.log(`Прокрутка: ${scrollContainer.scrollTop} / ${maxScrollTop}`);
778            
779            // Ждем, чтобы виртуализированная таблица успела отрендерить новые элементы
780            await wait(1500);
781            
782            // Собираем все видимые ссылки на кампании
783            const visibleLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
784            visibleLinks.forEach(link => {
785                allCampaignLinks.add(JSON.stringify({
786                    url: link.href,
787                    name: link.textContent.trim()
788                }));
789            });
790            
791            currentCount = allCampaignLinks.size;
792            console.log(`Попытка ${attempts + 1}: собрано ${currentCount} уникальных кампаний`);
793            
794            // Обновляем статус
795            showBulkStatus(`Загружено ${currentCount} кампаний...`);
796            
797            // Если количество не изменилось
798            if (currentCount === previousCount) {
799                stableCount++;
800                console.log(`Количество стабильно: ${stableCount} раз подряд`);
801                
802                // Если достигли конца и количество стабильно 3 раза подряд
803                if (stableCount >= 3 && scrollContainer.scrollTop >= maxScrollTop - 10) {
804                    console.log('Все кампании загружены');
805                    break;
806                }
807            } else {
808                // Количество изменилось, сбрасываем счетчик
809                stableCount = 0;
810            }
811            
812            previousCount = currentCount;
813            attempts++;
814            
815            // Если достигли конца контейнера
816            if (scrollContainer.scrollTop >= maxScrollTop - 10) {
817                console.log('Достигнут конец контейнера, ждем финальной загрузки...');
818                await wait(2000);
819                
820                // Собираем последние видимые ссылки
821                const finalLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
822                finalLinks.forEach(link => {
823                    allCampaignLinks.add(JSON.stringify({
824                        url: link.href,
825                        name: link.textContent.trim()
826                    }));
827                });
828                
829                const finalCount = allCampaignLinks.size;
830                if (finalCount === currentCount) {
831                    console.log('Подтверждено: все кампании загружены');
832                    currentCount = finalCount;
833                    break;
834                }
835                currentCount = finalCount;
836            }
837        }
838        
839        // Прокручиваем обратно наверх
840        scrollContainer.scrollTop = 0;
841        await wait(500);
842        
843        console.log(`Загружено кампаний: ${currentCount}`);
844        showBulkStatus(`Загружено ${currentCount} кампаний`);
845        
846        // Преобразуем Set обратно в массив объектов
847        const campaignsArray = Array.from(allCampaignLinks).map(item => JSON.parse(item));
848        
849        return campaignsArray;
850    }
851
852    // Функция для массовой обработки кампаний
853    async function runBulkStrategy() {
854        if (isBulkProcessing) {
855            showBulkStatus('Обработка уже выполняется', true);
856            return;
857        }
858
859        try {
860            isBulkProcessing = true;
861            console.log('Начало массовой обработки кампаний');
862            
863            bulkDesiredPercentage = parseFloat(document.getElementById('bulk-desired-percentage').value);
864            if (!bulkDesiredPercentage || bulkDesiredPercentage <= 0) {
865                showBulkStatus('Ошибка: введите корректный процент', true);
866                isBulkProcessing = false;
867                return;
868            }
869
870            // Сохраняем ДРР для автоматической обработки
871            await GM.setValue('bulkProcessingDRR', bulkDesiredPercentage);
872            console.log(`ДРР ${bulkDesiredPercentage} сохранен для массовой обработки`);
873
874            // Прокручиваем страницу для загрузки всех кампаний
875            const campaigns = await scrollToLoadAllCampaigns();
876            
877            if (campaigns.length === 0) {
878                showBulkStatus('Ошибка: кампании не найдены', true);
879                isBulkProcessing = false;
880                await GM.deleteValue('bulkProcessingDRR');
881                return;
882            }
883
884            console.log(`Найдено кампаний для обработки: ${campaigns.length}`);
885            showBulkStatus(`Начинаем обработку ${campaigns.length} кампаний...`);
886            updateBulkProgress(0, campaigns.length);
887
888            // Сохраняем список кампаний и текущий индекс
889            await GM.setValue('bulkCampaigns', JSON.stringify(campaigns));
890            await GM.setValue('bulkCurrentIndex', 0);
891
892            // Показываем кнопки управления
893            const controlButtons = document.getElementById('bulk-control-buttons');
894            if (controlButtons) {
895                controlButtons.style.display = 'flex';
896            }
897
898            // Открываем первую кампанию в новой вкладке
899            if (campaigns.length > 0) {
900                console.log(`Открытие первой кампании: ${campaigns[0].name}`);
901                await GM.openInTab(campaigns[0].url, false);
902            }
903
904        } catch (error) {
905            console.error('Ошибка при массовой обработке:', error);
906            showBulkStatus(`Ошибка: ${error.message}`, true);
907            isBulkProcessing = false;
908            await GM.deleteValue('bulkProcessingDRR');
909        }
910    }
911
912    // Функция для паузы массовой обработки
913    async function pauseBulkProcessing() {
914        bulkPaused = !bulkPaused;
915        const pauseBtn = document.getElementById('pause-bulk-btn');
916        
917        if (bulkPaused) {
918            await GM.setValue('bulkPaused', true);
919            pauseBtn.textContent = '▶️ Продолжить';
920            showBulkStatus('⏸️ Обработка приостановлена');
921            console.log('Массовая обработка приостановлена');
922        } else {
923            await GM.deleteValue('bulkPaused');
924            pauseBtn.textContent = '⏸️ Пауза';
925            showBulkStatus('▶️ Обработка возобновлена');
926            console.log('Массовая обработка возобновлена');
927            
928            // Продолжаем обработку - открываем следующую кампанию
929            const campaignsJson = await GM.getValue('bulkCampaigns', null);
930            const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
931            
932            if (campaignsJson) {
933                const campaigns = JSON.parse(campaignsJson);
934                if (currentIndex < campaigns.length) {
935                    console.log(`Продолжение с кампании ${currentIndex + 1}: ${campaigns[currentIndex].name}`);
936                    await GM.openInTab(campaigns[currentIndex].url, false);
937                }
938            }
939        }
940    }
941
942    // Функция для остановки массовой обработки
943    async function stopBulkProcessing() {
944        await GM.deleteValue('bulkProcessingDRR');
945        await GM.deleteValue('bulkCampaigns');
946        await GM.deleteValue('bulkCurrentIndex');
947        await GM.deleteValue('bulkPaused');
948        
949        showBulkStatus('⏹️ Обработка остановлена', true);
950        console.log('Массовая обработка остановлена');
951        
952        // Скрываем кнопки управления
953        const controlButtons = document.getElementById('bulk-control-buttons');
954        if (controlButtons) {
955            controlButtons.style.display = 'none';
956        }
957        
958        isBulkProcessing = false;
959        bulkPaused = false;
960    }
961
962    // Функция для показа статуса
963    function showStatus(message, isError = false) {
964        const statusDiv = document.getElementById('status-message');
965        if (statusDiv) {
966            statusDiv.textContent = message;
967            statusDiv.style.display = 'block';
968            statusDiv.style.background = isError ? 'rgba(255, 59, 48, 0.9)' : 'rgba(52, 199, 89, 0.9)';
969            console.log(`Статус: ${message}`);
970        }
971    }
972
973    // Функция для ожидания
974    function wait(ms) {
975        return new Promise(resolve => setTimeout(resolve, ms));
976    }
977
978    // Функция для парсинга числа из строки
979    function parseNumber(str) {
980        if (!str) return 0;
981        // Убираем все символы кроме цифр, точек и запятых
982        const cleaned = str.replace(/[^\d.,]/g, '').replace(/\s/g, '');
983        // Заменяем запятую на точку
984        const normalized = cleaned.replace(',', '.');
985        return parseFloat(normalized) || 0;
986    }
987
988    // Функция для парсинга процента
989    function parsePercentage(str) {
990        if (!str) return 0;
991        const cleaned = str.replace('%', '').replace(',', '.').trim();
992        return parseFloat(cleaned) || 0;
993    }
994
995    // Основная функция запуска стратегии
996    async function runStrategy() {
997        try {
998            console.log('Начало выполнения стратегии');
999            showStatus('Запуск процесса...');
1000
1001            const desiredPercentage = parseFloat(document.getElementById('desired-percentage').value);
1002            if (!desiredPercentage || desiredPercentage <= 0) {
1003                showStatus('Ошибка: введите корректный процент', true);
1004                await handleStrategyError();
1005                return;
1006            }
1007            console.log(`Желаемый процент: ${desiredPercentage}%`);
1008
1009            // Шаг 1: Кликаем на статистику
1010            showStatus('Открытие статистики...');
1011            const statsButton = document.querySelector('.css-amj7dw');
1012            if (!statsButton) {
1013                showStatus('Ошибка: кнопка статистики не найдена', true);
1014                await handleStrategyError();
1015                return;
1016            }
1017            statsButton.click();
1018            console.log('Клик на статистику выполнен');
1019            await wait(2000); // Увеличена задержка для загрузки статистики
1020
1021            // Шаг 1.5: Выбираем режим "Товары"
1022            showStatus('Выбор режима "Товары"...');
1023            const modeLabels = Array.from(document.querySelectorAll('label'));
1024            let modeInput = null;
1025            
1026            for (const label of modeLabels) {
1027                if (label.textContent.trim() === 'Режим') {
1028                    const inputId = label.getAttribute('for');
1029                    if (inputId) {
1030                        modeInput = document.getElementById(inputId);
1031                        console.log(`Найдено поле Режим с id: ${inputId}`);
1032                        break;
1033                    }
1034                }
1035            }
1036            
1037            if (modeInput) {
1038                // Устанавливаем значение "Товары" напрямую
1039                modeInput.value = 'Товары';
1040                
1041                // Триггерим события для React
1042                const inputEvent = new Event('input', { bubbles: true });
1043                const changeEvent = new Event('change', { bubbles: true });
1044                modeInput.dispatchEvent(inputEvent);
1045                modeInput.dispatchEvent(changeEvent);
1046                
1047                console.log('Установлено значение: Товары');
1048                await wait(1000); // Увеличена задержка для загрузки опций
1049                
1050                // Проверяем, появились ли опции в выпадающем списке
1051                const options = document.querySelectorAll('[role="option"]');
1052                console.log(`Найдено опций: ${options.length}`);
1053                
1054                if (options.length > 0) {
1055                    // Ищем опцию "Товары" и кликаем на неё
1056                    const tovarOption = Array.from(options).find(opt => opt.textContent.includes('Товары'));
1057                    if (tovarOption) {
1058                        tovarOption.click();
1059                        console.log('Выбран режим "Товары"');
1060                        await wait(1500); // Увеличена задержка для загрузки данных после выбора режима
1061                    }
1062                }
1063            }
1064
1065            // Шаг 2: Извлекаем данные из статистики
1066            showStatus('Извлечение данных...');
1067            
1068            // Ждем дополнительное время для загрузки статистики
1069            await wait(1000);
1070            
1071            const stats = Array.from(document.querySelectorAll('.MuiTypography-caption.css-1et52kr'));
1072            
1073            let sumOrders = 0;
1074            let ordersCount = 0;
1075            let cartToOrderPercent = 0;
1076
1077            stats.forEach(el => {
1078                const text = el.textContent.trim();
1079                const valueElement = el.closest('.MuiBox-root')?.querySelector('.MuiTypography-h3 .MuiTypography-body1');
1080                const value = valueElement ? valueElement.textContent.trim() : '';
1081
1082                console.log(`Найден показатель: ${text} = ${value}`);
1083
1084                if (text === 'Сумма заказов') {
1085                    sumOrders = parseNumber(value);
1086                    console.log(`Сумма заказов: ${sumOrders}`);
1087                } else if (text === 'Заказов') {
1088                    ordersCount = parseNumber(value);
1089                    console.log(`Заказов: ${ordersCount}`);
1090                } else if (text === 'Корзина → Заказ') {
1091                    cartToOrderPercent = parsePercentage(value);
1092                    console.log(`Корзина → Заказ: ${cartToOrderPercent}%`);
1093                }
1094            });
1095
1096            if (sumOrders === 0 || ordersCount === 0 || cartToOrderPercent === 0) {
1097                showStatus('Ошибка: не удалось получить данные статистики', true);
1098                console.error('Недостаточно данных:', { sumOrders, ordersCount, cartToOrderPercent });
1099                await handleStrategyError();
1100                return;
1101            }
1102
1103            // Шаг 3: Вычисляем стоимость корзины
1104            const cartCost = (sumOrders / ordersCount) * (desiredPercentage / 100) * (cartToOrderPercent / 100);
1105            const cartCostRounded = Math.round(cartCost * 100) / 100;
1106            console.log(`Расчет: (${sumOrders} / ${ordersCount}) * (${desiredPercentage} / 100) * (${cartToOrderPercent} / 100) = ${cartCostRounded}`);
1107            showStatus(`Рассчитано: ${cartCostRounded}`);
1108
1109            // Закрываем статистику
1110            statsButton.click();
1111            await wait(500);
1112
1113            // Шаг 4: Кликаем на "Вставить стратегию"
1114            showStatus('Вставка стратегии...');
1115            const insertButtons = document.querySelectorAll('.css-5kbhos');
1116            let insertButton = null;
1117            
1118            // Ищем кнопку с текстом "Вставить стратегию"
1119            for (const btn of insertButtons) {
1120                if (btn.textContent.includes('Вставить стратегию')) {
1121                    insertButton = btn;
1122                    break;
1123                }
1124            }
1125
1126            if (!insertButton && insertButtons.length >= 2) {
1127                insertButton = insertButtons[1];
1128            } else if (!insertButton && insertButtons.length === 1) {
1129                insertButton = insertButtons[0];
1130            }
1131
1132            if (!insertButton) {
1133                showStatus('Ошибка: кнопка "Вставить стратегию" не найдена', true);
1134                await handleStrategyError();
1135                return;
1136            }
1137
1138            // Получаем текущую выбранную стратегию
1139            const currentStrategyCode = await getCurrentStrategy();
1140            console.log('Используем стратегию, длина:', currentStrategyCode.length);
1141
1142            // Копируем код стратегии в буфер обмена ПЕРЕД открытием модального окна
1143            console.log('Копируем стратегию в буфер обмена...');
1144            try {
1145                // Способ 1: navigator.clipboard (современный)
1146                await navigator.clipboard.writeText(currentStrategyCode);
1147                console.log('✓ Стратегия скопирована через navigator.clipboard');
1148            } catch (clipboardError) {
1149                console.log('navigator.clipboard не сработал, пробуем GM.setClipboard...');
1150                // Способ 2: GM.setClipboard (fallback)
1151                await GM.setClipboard(currentStrategyCode);
1152                console.log('✓ Стратегия скопирована через GM.setClipboard');
1153            }
1154            
1155            console.log('Длина стратегии:', currentStrategyCode.length);
1156            await wait(500);
1157
1158            insertButton.click();
1159            console.log('Клик на "Вставить стратегию" выполнен');
1160            await wait(1500); // Увеличена задержка для применения стратегии из буфера
1161            
1162            console.log('✓ Стратегия вставлена из буфера обмена');
1163            
1164            await wait(1000);
1165
1166            // Шаг 5: Находим поле "Желаемое значение" и вставляем результат
1167            showStatus('Заполнение поля...');
1168            
1169            // Ищем поле с текстом "За корзину" или "Желаемое значение"
1170            const inputLabels = Array.from(document.querySelectorAll('.MuiInputLabel-root'));
1171            let targetInput = null;
1172
1173            for (const label of inputLabels) {
1174                const labelText = label.textContent;
1175                if (labelText.includes('За корзину') || labelText.includes('Желаемое значение')) {
1176                    const inputId = label.getAttribute('for');
1177                    if (inputId) {
1178                        targetInput = document.getElementById(inputId);
1179                        console.log(`Найдено поле: ${labelText}`);
1180                        break;
1181                    }
1182                }
1183            }
1184
1185            // Если не нашли по лейблу, ищем по имени
1186            if (!targetInput) {
1187                const inputs = document.querySelectorAll('input[type="number"]');
1188                for (const input of inputs) {
1189                    const name = input.getAttribute('name') || '';
1190                    if (name.includes('CostPerAddedToCart') || name.includes('value')) {
1191                        targetInput = input;
1192                        console.log(`Найдено поле по имени: ${name}`);
1193                        break;
1194                    }
1195                }
1196            }
1197
1198            if (!targetInput) {
1199                showStatus('Ошибка: поле для ввода не найдено', true);
1200                console.error('Не удалось найти поле для ввода значения');
1201                await handleStrategyError();
1202                return;
1203            }
1204
1205            // Устанавливаем значение
1206            targetInput.focus();
1207            targetInput.value = cartCostRounded.toString();
1208            
1209            // Триггерим события для React
1210            const inputEvent = new Event('input', { bubbles: true });
1211            const changeEvent = new Event('change', { bubbles: true });
1212            targetInput.dispatchEvent(inputEvent);
1213            targetInput.dispatchEvent(changeEvent);
1214            
1215            console.log(`Значение ${cartCostRounded} установлено в поле`);
1216            await wait(500);
1217
1218            // Шаг 7: Нажимаем "Сохранить"
1219            showStatus('Сохранение...');
1220            const saveButtons = document.querySelectorAll('button');
1221            let saveButton = null;
1222
1223            for (const btn of saveButtons) {
1224                if (btn.textContent.trim() === 'Сохранить') {
1225                    saveButton = btn;
1226                    break;
1227                }
1228            }
1229
1230            if (!saveButton) {
1231                showStatus('Ошибка: кнопка "Сохранить" не найдена', true);
1232                await handleStrategyError();
1233                return;
1234            }
1235
1236            saveButton.click();
1237            console.log('Клик на "Сохранить" выполнен');
1238            await wait(1000);
1239
1240            showStatus(`✅ Готово! Стоимость корзины: ${cartCostRounded}`);
1241            console.log('Стратегия успешно установлена');
1242
1243            // Проверяем, есть ли массовая обработка
1244            const savedDRR = await GM.getValue('bulkProcessingDRR', null);
1245            if (savedDRR !== null) {
1246                console.log('Обнаружена массовая обработка, переходим к следующей кампании');
1247                
1248                // Получаем список кампаний и текущий индекс
1249                const campaignsJson = await GM.getValue('bulkCampaigns', null);
1250                const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
1251                
1252                if (campaignsJson) {
1253                    const campaigns = JSON.parse(campaignsJson);
1254                    const nextIndex = currentIndex + 1;
1255                    
1256                    console.log(`Обработано ${nextIndex} из ${campaigns.length} кампаний`);
1257                    
1258                    if (nextIndex < campaigns.length) {
1259                        // Сохраняем новый индекс
1260                        await GM.setValue('bulkCurrentIndex', nextIndex);
1261                        
1262                        // Открываем следующую кампанию в новой вкладке
1263                        console.log(`Открытие кампании ${nextIndex + 1}: ${campaigns[nextIndex].name}`);
1264                        await GM.openInTab(campaigns[nextIndex].url, false);
1265                        
1266                        // Закрываем текущую вкладку
1267                        await wait(1000);
1268                        window.close();
1269                    } else {
1270                        // Все кампании обработаны
1271                        console.log('Все кампании обработаны, очищаем данные');
1272                        await GM.deleteValue('bulkProcessingDRR');
1273                        await GM.deleteValue('bulkCampaigns');
1274                        await GM.deleteValue('bulkCurrentIndex');
1275                        
1276                        // Закрываем текущую вкладку
1277                        showStatus('✅ Все кампании обработаны! Закрытие вкладки...');
1278                        await wait(2000);
1279                        window.close();
1280                    }
1281                }
1282            }
1283
1284        } catch (error) {
1285            console.error('Ошибка при выполнении стратегии:', error);
1286            showStatus(`Ошибка: ${error.message}`, true);
1287            await handleStrategyError();
1288        }
1289    }
1290
1291    // Функция для обработки ошибок и перехода к следующей кампании
1292    async function handleStrategyError() {
1293        const savedDRR = await GM.getValue('bulkProcessingDRR', null);
1294        if (savedDRR !== null) {
1295            console.log('Обнаружена ошибка при массовой обработке, ждем 10 секунд перед переходом к следующей кампании');
1296            showStatus('⚠️ Ошибка! Переход к следующей кампании через 10 секунд...', true);
1297            
1298            // Ждем 10 секунд
1299            for (let i = 10; i > 0; i--) {
1300                showStatus(`⚠️ Ошибка! Переход к следующей через ${i} сек...`, true);
1301                await wait(1000);
1302            }
1303            
1304            // Получаем список кампаний и текущий индекс
1305            const campaignsJson = await GM.getValue('bulkCampaigns', null);
1306            const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
1307            
1308            if (campaignsJson) {
1309                const campaigns = JSON.parse(campaignsJson);
1310                const nextIndex = currentIndex + 1;
1311                
1312                console.log(`Пропускаем кампанию с ошибкой. Переход к ${nextIndex + 1} из ${campaigns.length}`);
1313                
1314                if (nextIndex < campaigns.length) {
1315                    // Сохраняем новый индекс
1316                    await GM.setValue('bulkCurrentIndex', nextIndex);
1317                    
1318                    // Открываем следующую кампанию в новой вкладке
1319                    console.log(`Открытие кампании ${nextIndex + 1}: ${campaigns[nextIndex].name}`);
1320                    await GM.openInTab(campaigns[nextIndex].url, false);
1321                    
1322                    // Закрываем текущую вкладку
1323                    await wait(1000);
1324                    window.close();
1325                } else {
1326                    // Все кампании обработаны
1327                    console.log('Все кампании обработаны, очищаем данные');
1328                    await GM.deleteValue('bulkProcessingDRR');
1329                    await GM.deleteValue('bulkCampaigns');
1330                    await GM.deleteValue('bulkCurrentIndex');
1331                    
1332                    // Закрываем текущую вкладку
1333                    showStatus('✅ Все кампании обработаны! Закрытие вкладки...');
1334                    await wait(2000);
1335                    window.close();
1336                }
1337            }
1338        }
1339    }
1340
1341    // Инициализация
1342    function init() {
1343        console.log('Инициализация расширения');
1344        
1345        // Проверяем, на какой странице мы находимся
1346        if (window.location.href.includes('/advert/campaigns')) {
1347            // Страница со списком кампаний
1348            console.log('Страница списка кампаний обнаружена');
1349            
1350            setTimeout(() => {
1351                if (document.body) {
1352                    createBulkUI();
1353                } else {
1354                    console.error('Body не найден');
1355                }
1356            }, 1000);
1357        } else if (window.location.href.includes('/campaigns/auto-campaigns/') && window.location.href.includes('/campaign')) {
1358            // Страница отдельной кампании
1359            console.log('Страница кампании обнаружена');
1360            
1361            // Создаем UI с небольшой задержкой, чтобы убедиться, что страница загружена
1362            setTimeout(() => {
1363                if (document.body) {
1364                    createUI();
1365                } else {
1366                    console.error('Body не найден');
1367                }
1368            }, 1000);
1369        } else {
1370            console.log('Не на странице кампании, UI не создается');
1371        }
1372    }
1373
1374    // Запускаем инициализацию
1375    init();
1376
1377})();