MP Manager WB Cluster Auto Strategy Setter

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

Size

144.0 KB

Version

1.8.145

Created

Mar 27, 2026

Updated

20 days ago

1// ==UserScript==
2// @name		MP Manager WB Cluster Auto Strategy Setter
3// @description		Автоматическая установка стратегии рекламной кампании на основе статистики
4// @version		1.8.145
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 = 'eyJjYW1wYWlnblR5cGUiOiJTZWFyY2hDYXRhbG9nIiwidmVyc2lvbiI6MiwiZGF0YSI6eyJzdGF0ZSI6IkVuYWJsZWQiLCJtb2RlIjp7InR5cGUiOiJQb3NpdGlvbiIsInBhdXNlVHlwZSI6IlJlc3VtZSJ9LCJzdHJhdGVneSI6eyJ0eXBlIjoiQ2FtcGFpZ25TdGF0cyIsIm1vZGUiOiJQbGFjZSIsImJpZE1vZGUiOiJDb3N0UGVyQ2xpY2siLCJjYW1wYWlnblN0YXRzIjp7Im1heFByaWNlIjo2MCwibWluUHJpY2UiOjEsInBsYXRmb3JtcyI6W10sImludGVydmFsIjoiV2VlayIsInJ1bGVzIjpbeyJ0eXBlIjoiQ29zdFBlckFkZGVkVG9DYXJ0IiwibW9kZSI6IlZhbHVlIiwidmFsdWUiOiIifV19fSwicGxhY2VTdHJhdGVneSI6eyJ0eXBlIjoiS2V5d29yZHMiLCJrZXl3b3JkcyI6eyJrZXl3b3JkcyI6W119fSwiaXNDbHVzdGVyIjpmYWxzZX19';
20    const CLUSTER_STRATEGY_CODE = 'eyJjYW1wYWlnblR5cGUiOiJTZWFyY2hDYXRhbG9nIiwidmVyc2lvbiI6MiwiZGF0YSI6eyJzdGF0ZSI6IkVuYWJsZWQiLCJtb2RlIjp7InR5cGUiOiJQb3NpdGlvbiIsInBhdXNlVHlwZSI6IlJlc3VtZSJ9LCJzdHJhdGVneSI6eyJ0eXBlIjoiQ2FtcGFpZ25TdGF0cyIsIm1vZGUiOiJQbGFjZSIsImJpZE1vZGUiOiJDb3N0UGVyQ2xpY2siLCJjYW1wYWlnblN0YXRzIjp7Im1heFByaWNlIjo2MCwibWluUHJpY2UiOjEsInBsYXRmb3JtcyI6W10sImludGVydmFsIjoiV2VlayIsInJ1bGVzIjpbeyJ0eXBlIjoiQ29zdFBlckFkZGVkVG9DYXJ0IiwibW9kZSI6IlZhbHVlIiwidmFsdWUiOiIifV19fSwicGxhY2VTdHJhdGVneSI6eyJ0eXBlIjoiS2V5d29yZHMiLCJrZXl3b3JkcyI6eyJrZXl3b3JkcyI6W119fSwiaXNDbHVzdGVyIjp0cnVlfX0=';
21    
22    // Стратегия для удержания места (обычная)
23    const HOLD_POSITION_STRATEGY_CODE = 'eyJjYW1wYWlnblR5cGUiOiJTZWFyY2hDYXRhbG9nIiwidmVyc2lvbiI6MiwiZGF0YSI6eyJzdGF0ZSI6IkVuYWJsZWQiLCJtb2RlIjp7InR5cGUiOiJQb3NpdGlvbiIsInBhdXNlVHlwZSI6IlJlc3VtZSJ9LCJzdHJhdGVneSI6eyJ0eXBlIjoiQ2FtcGFpZ25TdGF0cyIsIm1vZGUiOiJQbGFjZSIsImJpZE1vZGUiOiJDb3N0UGVyQ2xpY2siLCJjYW1wYWlnblN0YXRzIjp7Im1heFByaWNlIjo2MCwibWluUHJpY2UiOjEsInBsYXRmb3JtcyI6W10sImludGVydmFsIjoiV2VlayIsInJ1bGVzIjpbeyJ0eXBlIjoiQ29zdFBlckFkZGVkVG9DYXJ0IiwibW9kZSI6IlZhbHVlIiwidmFsdWUiOiIifV19fSwicGxhY2VTdHJhdGVneSI6eyJ0eXBlIjoiS2V5d29yZHMiLCJrZXl3b3JkcyI6eyJrZXl3b3JkcyI6W119fSwiaXNDbHVzdGVyIjpmYWxzZX19';
24
25    // Стратегия для удержания места (кластерная)
26    const HOLD_POSITION_CLUSTER_STRATEGY_CODE = 'eyJjYW1wYWlnblR5cGUiOiJTZWFyY2hDYXRhbG9nIiwidmVyc2lvbiI6MiwiZGF0YSI6eyJzdGF0ZSI6IkVuYWJsZWQiLCJtb2RlIjp7InR5cGUiOiJQb3NpdGlvbiIsInBhdXNlVHlwZSI6IlJlc3VtZSJ9LCJzdHJhdGVneSI6eyJ0eXBlIjoiQ2FtcGFpZ25TdGF0cyIsIm1vZGUiOiJQbGFjZSIsImJpZE1vZGUiOiJDb3N0UGVyQ2xpY2siLCJjbHVzdGVyU3RhdHMiOnsibWF4QmlkIjo4MDAwLCJtaW5CaWQiOjQwMCwiaW50ZXJ2YWwiOiJUaHJlZURheXMiLCJydWxlcyI6W3sidHlwZSI6IkF2ZXJhZ2VQb3NpdGlvbiIsIm1vZGUiOiJWYWx1ZSIsInZhbHVlIjoyfSx7InR5cGUiOiJDb3N0UGVyQWRkZWRUb0NhcnQiLCJtb2RlIjoiQXZlcmFnZVZhbHVlIn1dfSwicGxhY2VTdHJhdGVneSI6eyJ0eXBlIjoiS2V5d29yZHMiLCJrZXl3b3JkcyI6eyJrZXl3b3JkcyI6W119fSwiaXNDbHVzdGVyIjpmYWxzZX19';
27
28    // Глобальные переменные для массовой обработки
29    let isBulkProcessing = false;
30    let bulkDesiredPercentage = 30;
31    let bulkPaused = false;
32
33    // Функция для получения сохраненных стратегий
34    async function getSavedStrategies() {
35        let strategies = await GM.getValue('saved_strategies', []);
36        
37        // Миграция: добавляем ID к стратегиям, у которых его нет
38        let needsMigration = false;
39        strategies = strategies.map((strategy, index) => {
40            if (!strategy.id) {
41                needsMigration = true;
42                return {
43                    ...strategy,
44                    id: 'strategy_migrated_' + Date.now() + '_' + index
45                };
46            }
47            return strategy;
48        });
49        
50        // Сохраняем обновленные стратегии, если была миграция
51        if (needsMigration) {
52            await GM.setValue('saved_strategies', strategies);
53            console.log('Миграция стратегий выполнена: добавлены ID');
54        }
55        
56        // Если нет сохраненных стратегий, добавляем стратегию по умолчанию
57        if (strategies.length === 0) {
58            return [{
59                id: 'default',
60                name: 'Стратегия по умолчанию',
61                data: STRATEGY_CODE
62            }];
63        }
64        return strategies;
65    }
66
67    // Функция для получения сохраненных стратегий для кластеров
68    async function getSavedClusterStrategies() {
69        let strategies = await GM.getValue('saved_cluster_strategies', []);
70        
71        // Миграция: добавляем ID к стратегиям, у которых его нет
72        let needsMigration = false;
73        strategies = strategies.map((strategy, index) => {
74            if (!strategy.id) {
75                needsMigration = true;
76                return {
77                    ...strategy,
78                    id: 'cluster_strategy_migrated_' + Date.now() + '_' + index
79                };
80            }
81            return strategy;
82        });
83        
84        // Сохраняем обновленные стратегии, если была миграция
85        if (needsMigration) {
86            await GM.setValue('saved_cluster_strategies', strategies);
87            console.log('Миграция кластерных стратегий выполнена: добавлены ID');
88        }
89        
90        // Если нет сохраненных стратегий, добавляем стратегию по умолчанию
91        if (strategies.length === 0) {
92            return [{
93                id: 'cluster_default',
94                name: 'Кластерная стратегия по умолчанию',
95                data: CLUSTER_STRATEGY_CODE
96            }];
97        }
98        return strategies;
99    }
100
101    // Функция для получения текущей стратегии
102    async function getCurrentStrategy() {
103        const currentId = await GM.getValue('current_strategy_id', 'default');
104        const strategies = await getSavedStrategies();
105        const strategy = strategies.find(s => s.id === currentId);
106        return strategy ? strategy.data : STRATEGY_CODE;
107    }
108
109    // Функция для получения текущей кластерной стратегии
110    async function getCurrentClusterStrategy() {
111        const currentId = await GM.getValue('current_cluster_strategy_id', 'cluster_default');
112        const strategies = await getSavedClusterStrategies();
113        const strategy = strategies.find(s => s.id === currentId);
114        return strategy ? strategy.data : CLUSTER_STRATEGY_CODE;
115    }
116
117    // Функция для получения стратегии удержания места
118    async function getHoldPositionStrategy() {
119        const holdPositionId = await GM.getValue('hold_position_strategy_id', null);
120        if (holdPositionId) {
121            const strategies = await getSavedStrategies();
122            const strategy = strategies.find(s => s.id === holdPositionId);
123            if (strategy) {
124                return strategy.data;
125            }
126        }
127        // Если стратегия удержания места не установлена, используем текущую выбранную стратегию
128        const currentId = await GM.getValue('current_strategy_id', 'default');
129        if (currentId !== 'default') {
130            const strategies = await getSavedStrategies();
131            const strategy = strategies.find(s => s.id === currentId);
132            if (strategy) {
133                console.log('⚠️ Стратегия удержания места не установлена, используем текущую стратегию:', strategy.name);
134                return strategy.data;
135            }
136        }
137        // Возвращаем специальную стратегию удержания места по умолчанию
138        return HOLD_POSITION_STRATEGY_CODE;
139    }
140
141    // Функция для получения кластерной стратегии удержания места
142    async function getHoldPositionClusterStrategy() {
143        const holdPositionId = await GM.getValue('hold_position_cluster_strategy_id', null);
144        if (holdPositionId) {
145            const strategies = await getSavedClusterStrategies();
146            const strategy = strategies.find(s => s.id === holdPositionId);
147            if (strategy) {
148                return strategy.data;
149            }
150        }
151        // Возвращаем специальную кластерную стратегию удержания места по умолчанию
152        return HOLD_POSITION_CLUSTER_STRATEGY_CODE;
153    }
154
155    // Функция для создания модального окна управления стратегиями
156    function createStrategyManagementModal() {
157        return new Promise(async (resolve) => {
158            // Создаем оверлей
159            const overlay = document.createElement('div');
160            overlay.style.cssText = `
161                position: fixed;
162                top: 0;
163                left: 0;
164                width: 100%;
165                height: 100%;
166                background: rgba(0, 0, 0, 0.5);
167                display: flex;
168                justify-content: center;
169                align-items: center;
170                z-index: 10001;
171            `;
172            
173            // Создаем модальное окно
174            const modal = document.createElement('div');
175            modal.style.cssText = `
176                background: white;
177                border-radius: 12px;
178                padding: 24px;
179                min-width: 500px;
180                max-width: 600px;
181                max-height: 80vh;
182                overflow-y: auto;
183                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
184            `;
185            
186            // Заголовок
187            const title = document.createElement('h2');
188            title.textContent = 'Управление стратегиями';
189            title.style.cssText = `
190                margin: 0 0 20px 0;
191                font-size: 24px;
192                font-weight: bold;
193                color: #333;
194            `;
195            modal.appendChild(title);
196            
197            // Контейнер для списка стратегий
198            const listContainer = document.createElement('div');
199            listContainer.style.cssText = `
200                margin-bottom: 20px;
201                max-height: 300px;
202                overflow-y: auto;
203            `;
204            
205            // Функция для обновления списка
206            const updateList = async () => {
207                const currentStrategies = await getSavedStrategies();
208                const selectedStrategy = await GM.getValue('current_strategy_id', 'default');
209                const holdPositionStrategyId = await GM.getValue('hold_position_strategy_id', null);
210                listContainer.innerHTML = '';
211                
212                if (currentStrategies.length === 0) {
213                    const emptyMessage = document.createElement('p');
214                    emptyMessage.textContent = 'Нет сохраненных стратегий. Используется стратегия по умолчанию.';
215                    emptyMessage.style.cssText = `
216                        color: #666;
217                        font-style: italic;
218                        padding: 20px;
219                        text-align: center;
220                    `;
221                    listContainer.appendChild(emptyMessage);
222                } else {
223                    currentStrategies.forEach((strategy, index) => {
224                        const item = document.createElement('div');
225                        const isSelected = strategy.id === selectedStrategy;
226                        const isHoldPosition = strategy.id === holdPositionStrategyId;
227                        item.style.cssText = `
228                            display: flex;
229                            justify-content: space-between;
230                            align-items: center;
231                            padding: 12px;
232                            margin-bottom: 8px;
233                            background: ${isSelected ? '#e3f2fd' : '#f5f5f5'};
234                            border-radius: 8px;
235                            border: ${isSelected ? '2px solid #2196f3' : '1px solid #ddd'};
236                        `;
237                        
238                        const nameSpan = document.createElement('span');
239                        nameSpan.textContent = strategy.name + (isSelected ? ' ✓' : '') + (isHoldPosition ? ' 📍' : '');
240                        nameSpan.style.cssText = `
241                            font-size: 16px;
242                            color: #333;
243                            flex: 1;
244                            font-weight: ${isSelected ? 'bold' : 'normal'};
245                        `;
246                        
247                        const buttonsContainer = document.createElement('div');
248                        buttonsContainer.style.cssText = `
249                            display: flex;
250                            gap: 8px;
251                        `;
252                        
253                        // Кнопка выбора
254                        if (!isSelected) {
255                            const selectBtn = document.createElement('button');
256                            selectBtn.textContent = '✓ Выбрать';
257                            selectBtn.style.cssText = `
258                                background: #2196f3;
259                                color: white;
260                                border: none;
261                                padding: 6px 12px;
262                                border-radius: 6px;
263                                cursor: pointer;
264                                font-size: 14px;
265                            `;
266                            selectBtn.onmouseover = () => selectBtn.style.background = '#1976d2';
267                            selectBtn.onmouseout = () => selectBtn.style.background = '#2196f3';
268                            selectBtn.onclick = async () => {
269                                await GM.setValue('current_strategy_id', strategy.id);
270                                console.log(`Выбрана стратегия: ${strategy.name} (ID: ${strategy.id})`);
271                                await updateList();
272                            };
273                            buttonsContainer.appendChild(selectBtn);
274                        }
275                        
276                        // Кнопка "Удержание места"
277                        const holdBtn = document.createElement('button');
278                        holdBtn.textContent = isHoldPosition ? '📍 Удалить' : '📍 Удержание';
279                        holdBtn.style.cssText = `
280                            background: ${isHoldPosition ? '#ff9800' : '#4caf50'};
281                            color: white;
282                            border: none;
283                            padding: 6px 12px;
284                            border-radius: 6px;
285                            cursor: pointer;
286                            font-size: 14px;
287                        `;
288                        holdBtn.onmouseover = () => holdBtn.style.background = isHoldPosition ? '#f57c00' : '#45a049';
289                        holdBtn.onmouseout = () => holdBtn.style.background = isHoldPosition ? '#ff9800' : '#4caf50';
290                        holdBtn.onclick = async () => {
291                            if (isHoldPosition) {
292                                await GM.deleteValue('hold_position_strategy_id');
293                                console.log('Стратегия удержания места удалена');
294                            } else {
295                                await GM.setValue('hold_position_strategy_id', strategy.id);
296                                console.log(`Установлена стратегия удержания места: ${strategy.name} (ID: ${strategy.id})`);
297                            }
298                            await updateList();
299                        };
300                        buttonsContainer.appendChild(holdBtn);
301                        
302                        // Кнопка удаления
303                        const deleteBtn = document.createElement('button');
304                        deleteBtn.textContent = '🗑️';
305                        deleteBtn.style.cssText = `
306                            background: #f44336;
307                            color: white;
308                            border: none;
309                            padding: 6px 12px;
310                            border-radius: 6px;
311                            cursor: pointer;
312                            font-size: 14px;
313                        `;
314                        deleteBtn.onmouseover = () => deleteBtn.style.background = '#d32f2f';
315                        deleteBtn.onmouseout = () => deleteBtn.style.background = '#f44336';
316                        deleteBtn.onclick = async () => {
317                            if (confirm(`Удалить стратегию "${strategy.name}"?`)) {
318                                currentStrategies.splice(index, 1);
319                                await GM.setValue('saved_strategies', currentStrategies);
320                                // Если удаляем выбранную стратегию, возвращаемся к дефолтной
321                                if (isSelected) {
322                                    await GM.setValue('current_strategy_id', 'default');
323                                }
324                                // Если удаляем стратегию удержания места, очищаем её
325                                if (isHoldPosition) {
326                                    await GM.deleteValue('hold_position_strategy_id');
327                                }
328                                await updateList();
329                            }
330                        };
331                        buttonsContainer.appendChild(deleteBtn);
332                        
333                        item.appendChild(nameSpan);
334                        item.appendChild(buttonsContainer);
335                        listContainer.appendChild(item);
336                    });
337                }
338            };
339            
340            await updateList();
341            modal.appendChild(listContainer);
342            
343            // Кнопка добавления стратегии
344            const addButton = document.createElement('button');
345            addButton.textContent = '➕ Добавить новую стратегию';
346            addButton.style.cssText = `
347                width: 100%;
348                background: #4caf50;
349                color: white;
350                border: none;
351                padding: 12px;
352                border-radius: 8px;
353                cursor: pointer;
354                font-size: 16px;
355                font-weight: bold;
356                margin-bottom: 12px;
357            `;
358            addButton.onmouseover = () => addButton.style.background = '#45a049';
359            addButton.onmouseout = () => addButton.style.background = '#4caf50';
360            addButton.onclick = async () => {
361                const name = prompt('Введите название стратегии:');
362                if (!name) return;
363                
364                const data = prompt('Вставьте код стратегии (скопируйте из MP Manager):');
365                if (!data) return;
366                
367                const currentStrategies = await GM.getValue('saved_strategies', []);
368                const newId = 'strategy_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
369                currentStrategies.push({ id: newId, name, data });
370                await GM.setValue('saved_strategies', currentStrategies);
371                alert(`Стратегия "${name}" сохранена!`);
372                await updateList();
373            };
374            modal.appendChild(addButton);
375            
376            // Кнопка закрытия
377            const closeButton = document.createElement('button');
378            closeButton.textContent = 'Закрыть';
379            closeButton.style.cssText = `
380                width: 100%;
381                background: #666;
382                color: white;
383                border: none;
384                padding: 12px;
385                border-radius: 8px;
386                cursor: pointer;
387                font-size: 16px;
388            `;
389            closeButton.onmouseover = () => closeButton.style.background = '#555';
390            closeButton.onmouseout = () => closeButton.style.background = '#666';
391            closeButton.onclick = () => {
392                document.body.removeChild(overlay);
393                resolve();
394            };
395            modal.appendChild(closeButton);
396            
397            overlay.appendChild(modal);
398            document.body.appendChild(overlay);
399            
400            // Закрытие по клику на оверлей
401            overlay.onclick = (e) => {
402                if (e.target === overlay) {
403                    document.body.removeChild(overlay);
404                    resolve();
405                }
406            };
407        });
408    }
409
410    // Функция для создания модального окна управления кластерными стратегиями
411    function createClusterStrategyManagementModal() {
412        return new Promise(async (resolve) => {
413            // Создаем оверлей
414            const overlay = document.createElement('div');
415            overlay.style.cssText = `
416                position: fixed;
417                top: 0;
418                left: 0;
419                width: 100%;
420                height: 100%;
421                background: rgba(0, 0, 0, 0.5);
422                display: flex;
423                justify-content: center;
424                align-items: center;
425                z-index: 10001;
426            `;
427            
428            // Создаем модальное окно
429            const modal = document.createElement('div');
430            modal.style.cssText = `
431                background: white;
432                border-radius: 12px;
433                padding: 24px;
434                min-width: 500px;
435                max-width: 600px;
436                max-height: 80vh;
437                overflow-y: auto;
438                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
439            `;
440            
441            // Заголовок
442            const title = document.createElement('h2');
443            title.textContent = 'Управление стратегиями для кластеров';
444            title.style.cssText = `
445                margin: 0 0 20px 0;
446                font-size: 24px;
447                font-weight: bold;
448                color: #333;
449            `;
450            modal.appendChild(title);
451            
452            // Контейнер для списка стратегий
453            const listContainer = document.createElement('div');
454            listContainer.style.cssText = `
455                margin-bottom: 20px;
456                max-height: 300px;
457                overflow-y: auto;
458            `;
459            
460            // Функция для обновления списка
461            const updateList = async () => {
462                const currentStrategies = await getSavedClusterStrategies();
463                const selectedStrategy = await GM.getValue('current_cluster_strategy_id', 'cluster_default');
464                const holdPositionStrategyId = await GM.getValue('hold_position_cluster_strategy_id', null);
465                listContainer.innerHTML = '';
466                
467                if (currentStrategies.length === 0) {
468                    const emptyMessage = document.createElement('p');
469                    emptyMessage.textContent = 'Нет сохраненных кластерных стратегий. Используется стратегия по умолчанию.';
470                    emptyMessage.style.cssText = `
471                        color: #666;
472                        font-style: italic;
473                        padding: 20px;
474                        text-align: center;
475                    `;
476                    listContainer.appendChild(emptyMessage);
477                } else {
478                    currentStrategies.forEach((strategy, index) => {
479                        const item = document.createElement('div');
480                        const isSelected = strategy.id === selectedStrategy;
481                        const isHoldPosition = strategy.id === holdPositionStrategyId;
482                        item.style.cssText = `
483                            display: flex;
484                            justify-content: space-between;
485                            align-items: center;
486                            padding: 12px;
487                            margin-bottom: 8px;
488                            background: ${isSelected ? '#e3f2fd' : '#f5f5f5'};
489                            border-radius: 8px;
490                            border: ${isSelected ? '2px solid #2196f3' : '1px solid #ddd'};
491                        `;
492                        
493                        const nameSpan = document.createElement('span');
494                        nameSpan.textContent = strategy.name + (isSelected ? ' ✓' : '') + (isHoldPosition ? ' 📍' : '');
495                        nameSpan.style.cssText = `
496                            font-size: 16px;
497                            color: #333;
498                            flex: 1;
499                            font-weight: ${isSelected ? 'bold' : 'normal'};
500                        `;
501                        
502                        const buttonsContainer = document.createElement('div');
503                        buttonsContainer.style.cssText = `
504                            display: flex;
505                            gap: 8px;
506                        `;
507                        
508                        // Кнопка выбора
509                        if (!isSelected) {
510                            const selectBtn = document.createElement('button');
511                            selectBtn.textContent = '✓ Выбрать';
512                            selectBtn.style.cssText = `
513                                background: #2196f3;
514                                color: white;
515                                border: none;
516                                padding: 6px 12px;
517                                border-radius: 6px;
518                                cursor: pointer;
519                                font-size: 14px;
520                            `;
521                            selectBtn.onmouseover = () => selectBtn.style.background = '#1976d2';
522                            selectBtn.onmouseout = () => selectBtn.style.background = '#2196f3';
523                            selectBtn.onclick = async () => {
524                                await GM.setValue('current_cluster_strategy_id', strategy.id);
525                                console.log(`Выбрана кластерная стратегия: ${strategy.name} (ID: ${strategy.id})`);
526                                await updateList();
527                            };
528                            buttonsContainer.appendChild(selectBtn);
529                        }
530                        
531                        // Кнопка "Удержание места"
532                        const holdBtn = document.createElement('button');
533                        holdBtn.textContent = isHoldPosition ? '📍 Удалить' : '📍 Удержание';
534                        holdBtn.style.cssText = `
535                            background: ${isHoldPosition ? '#ff9800' : '#4caf50'};
536                            color: white;
537                            border: none;
538                            padding: 6px 12px;
539                            border-radius: 6px;
540                            cursor: pointer;
541                            font-size: 14px;
542                        `;
543                        holdBtn.onmouseover = () => holdBtn.style.background = isHoldPosition ? '#f57c00' : '#45a049';
544                        holdBtn.onmouseout = () => holdBtn.style.background = isHoldPosition ? '#ff9800' : '#4caf50';
545                        holdBtn.onclick = async () => {
546                            if (isHoldPosition) {
547                                await GM.deleteValue('hold_position_cluster_strategy_id');
548                                console.log('Кластерная стратегия удержания места удалена');
549                            } else {
550                                await GM.setValue('hold_position_cluster_strategy_id', strategy.id);
551                                console.log(`Установлена кластерная стратегия удержания места: ${strategy.name} (ID: ${strategy.id})`);
552                            }
553                            await updateList();
554                        };
555                        buttonsContainer.appendChild(holdBtn);
556                        
557                        // Кнопка удаления
558                        const deleteBtn = document.createElement('button');
559                        deleteBtn.textContent = '🗑️';
560                        deleteBtn.style.cssText = `
561                            background: #f44336;
562                            color: white;
563                            border: none;
564                            padding: 6px 12px;
565                            border-radius: 6px;
566                            cursor: pointer;
567                            font-size: 14px;
568                        `;
569                        deleteBtn.onmouseover = () => deleteBtn.style.background = '#d32f2f';
570                        deleteBtn.onmouseout = () => deleteBtn.style.background = '#f44336';
571                        deleteBtn.onclick = async () => {
572                            if (confirm(`Удалить кластерную стратегию "${strategy.name}"?`)) {
573                                currentStrategies.splice(index, 1);
574                                await GM.setValue('saved_cluster_strategies', currentStrategies);
575                                // Если удаляем выбранную стратегию, возвращаемся к дефолтной
576                                if (isSelected) {
577                                    await GM.setValue('current_cluster_strategy_id', 'cluster_default');
578                                }
579                                // Если удаляем стратегию удержания места, очищаем её
580                                if (isHoldPosition) {
581                                    await GM.deleteValue('hold_position_cluster_strategy_id');
582                                }
583                                await updateList();
584                            }
585                        };
586                        buttonsContainer.appendChild(deleteBtn);
587                        
588                        item.appendChild(nameSpan);
589                        item.appendChild(buttonsContainer);
590                        listContainer.appendChild(item);
591                    });
592                }
593            };
594            
595            await updateList();
596            modal.appendChild(listContainer);
597            
598            // Кнопка добавления стратегии
599            const addButton = document.createElement('button');
600            addButton.textContent = '➕ Добавить новую кластерную стратегию';
601            addButton.style.cssText = `
602                width: 100%;
603                background: #4caf50;
604                color: white;
605                border: none;
606                padding: 12px;
607                border-radius: 8px;
608                cursor: pointer;
609                font-size: 16px;
610                font-weight: bold;
611                margin-bottom: 12px;
612            `;
613            addButton.onmouseover = () => addButton.style.background = '#45a049';
614            addButton.onmouseout = () => addButton.style.background = '#4caf50';
615            addButton.onclick = async () => {
616                const name = prompt('Введите название кластерной стратегии:');
617                if (!name) return;
618                
619                const data = prompt('Вставьте код кластерной стратегии (скопируйте из MP Manager):');
620                if (!data) return;
621                
622                const currentStrategies = await GM.getValue('saved_cluster_strategies', []);
623                const newId = 'cluster_strategy_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
624                currentStrategies.push({ id: newId, name, data });
625                await GM.setValue('saved_cluster_strategies', currentStrategies);
626                alert(`Кластерная стратегия "${name}" сохранена!`);
627                await updateList();
628            };
629            modal.appendChild(addButton);
630            
631            // Кнопка закрытия
632            const closeButton = document.createElement('button');
633            closeButton.textContent = 'Закрыть';
634            closeButton.style.cssText = `
635                width: 100%;
636                background: #666;
637                color: white;
638                border: none;
639                padding: 12px;
640                border-radius: 8px;
641                cursor: pointer;
642                font-size: 16px;
643            `;
644            closeButton.onmouseover = () => closeButton.style.background = '#555';
645            closeButton.onmouseout = () => closeButton.style.background = '#666';
646            closeButton.onclick = () => {
647                document.body.removeChild(overlay);
648                resolve();
649            };
650            modal.appendChild(closeButton);
651            
652            overlay.appendChild(modal);
653            document.body.appendChild(overlay);
654            
655            // Закрытие по клику на оверлей
656            overlay.onclick = (e) => {
657                if (e.target === overlay) {
658                    document.body.removeChild(overlay);
659                    resolve();
660                }
661            };
662        });
663    }
664
665    // Функция для создания модального окна управления стратегиями удержания места
666    function createHoldPositionStrategyManagementModal() {
667        return new Promise(async (resolve) => {
668            // Создаем оверлей
669            const overlay = document.createElement('div');
670            overlay.style.cssText = `
671                position: fixed;
672                top: 0;
673                left: 0;
674                width: 100%;
675                height: 100%;
676                background: rgba(0, 0, 0, 0.5);
677                display: flex;
678                justify-content: center;
679                align-items: center;
680                z-index: 10001;
681            `;
682            
683            // Создаем модальное окно
684            const modal = document.createElement('div');
685            modal.style.cssText = `
686                background: white;
687                border-radius: 12px;
688                padding: 24px;
689                min-width: 500px;
690                max-width: 600px;
691                max-height: 80vh;
692                overflow-y: auto;
693                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
694            `;
695            
696            // Заголовок
697            const title = document.createElement('h2');
698            title.textContent = 'Стратегии удержания места';
699            title.style.cssText = `
700                margin: 0 0 20px 0;
701                font-size: 24px;
702                font-weight: bold;
703                color: #333;
704            `;
705            modal.appendChild(title);
706            
707            // Описание
708            const description = document.createElement('p');
709            description.textContent = 'Здесь вы можете управлять стратегиями для обычных кампаний и кластеров, которые будут применяться при включенном чекбоксе "Удержание места".';
710            description.style.cssText = `
711                margin: 0 0 20px 0;
712                font-size: 14px;
713                color: #666;
714            `;
715            modal.appendChild(description);
716            
717            // Секция для обычных стратегий
718            const normalSection = document.createElement('div');
719            normalSection.style.cssText = `
720                margin-bottom: 30px;
721                padding: 15px;
722                background: #f9f9f9;
723                border-radius: 8px;
724            `;
725            
726            const normalTitle = document.createElement('h3');
727            normalTitle.textContent = '📋 Обычные кампании';
728            normalTitle.style.cssText = `
729                margin: 0 0 15px 0;
730                font-size: 18px;
731                font-weight: bold;
732                color: #333;
733            `;
734            normalSection.appendChild(normalTitle);
735            
736            const normalListContainer = document.createElement('div');
737            normalListContainer.style.cssText = `
738                margin-bottom: 15px;
739                max-height: 200px;
740                overflow-y: auto;
741            `;
742            
743            // Функция для обновления списка обычных стратегий
744            const updateNormalList = async () => {
745                const strategies = await getSavedStrategies();
746                const holdPositionStrategyId = await GM.getValue('hold_position_strategy_id', null);
747                normalListContainer.innerHTML = '';
748                
749                if (strategies.length === 0) {
750                    const emptyMessage = document.createElement('p');
751                    emptyMessage.textContent = 'Нет сохраненных стратегий.';
752                    emptyMessage.style.cssText = `
753                        color: #666;
754                        font-style: italic;
755                        padding: 10px;
756                        text-align: center;
757                    `;
758                    normalListContainer.appendChild(emptyMessage);
759                } else {
760                    strategies.forEach((strategy) => {
761                        const item = document.createElement('div');
762                        const isHoldPosition = strategy.id === holdPositionStrategyId;
763                        item.style.cssText = `
764                            display: flex;
765                            justify-content: space-between;
766                            align-items: center;
767                            padding: 10px;
768                            margin-bottom: 8px;
769                            background: ${isHoldPosition ? '#e8f5e9' : 'white'};
770                            border-radius: 6px;
771                            border: ${isHoldPosition ? '2px solid #4caf50' : '1px solid #ddd'};
772                        `;
773                        
774                        const nameSpan = document.createElement('span');
775                        nameSpan.textContent = strategy.name + (isHoldPosition ? ' ✓' : '');
776                        nameSpan.style.cssText = `
777                            font-size: 14px;
778                            color: #333;
779                            flex: 1;
780                            font-weight: ${isHoldPosition ? 'bold' : 'normal'};
781                        `;
782                        
783                        const selectBtn = document.createElement('button');
784                        selectBtn.textContent = isHoldPosition ? '✓ Выбрана' : 'Выбрать';
785                        selectBtn.disabled = isHoldPosition;
786                        selectBtn.style.cssText = `
787                            background: ${isHoldPosition ? '#4caf50' : '#2196f3'};
788                            color: white;
789                            border: none;
790                            padding: 6px 12px;
791                            border-radius: 6px;
792                            cursor: ${isHoldPosition ? 'default' : 'pointer'};
793                            font-size: 13px;
794                            opacity: ${isHoldPosition ? '0.7' : '1'};
795                        `;
796                        if (!isHoldPosition) {
797                            selectBtn.onmouseover = () => selectBtn.style.background = '#1976d2';
798                            selectBtn.onmouseout = () => selectBtn.style.background = '#2196f3';
799                            selectBtn.onclick = async () => {
800                                await GM.setValue('hold_position_strategy_id', strategy.id);
801                                console.log(`Установлена стратегия удержания места: ${strategy.name}`);
802                                await updateNormalList();
803                            };
804                        }
805                        
806                        item.appendChild(nameSpan);
807                        item.appendChild(selectBtn);
808                        normalListContainer.appendChild(item);
809                    });
810                }
811            };
812            
813            await updateNormalList();
814            normalSection.appendChild(normalListContainer);
815            
816            const normalResetBtn = document.createElement('button');
817            normalResetBtn.textContent = '🔄 Сбросить на стандартную';
818            normalResetBtn.style.cssText = `
819                width: 100%;
820                background: #ff9800;
821                color: white;
822                border: none;
823                padding: 10px;
824                border-radius: 6px;
825                cursor: pointer;
826                font-size: 14px;
827                font-weight: 600;
828            `;
829            normalResetBtn.onmouseover = () => normalResetBtn.style.background = '#f57c00';
830            normalResetBtn.onmouseout = () => normalResetBtn.style.background = '#ff9800';
831            normalResetBtn.onclick = async () => {
832                await GM.deleteValue('hold_position_strategy_id');
833                console.log('Стратегия удержания места сброшена на стандартную');
834                await updateNormalList();
835            };
836            normalSection.appendChild(normalResetBtn);
837            
838            modal.appendChild(normalSection);
839            
840            // Секция для кластерных стратегий
841            const clusterSection = document.createElement('div');
842            clusterSection.style.cssText = `
843                margin-bottom: 20px;
844                padding: 15px;
845                background: #f9f9f9;
846                border-radius: 8px;
847            `;
848            
849            const clusterTitle = document.createElement('h3');
850            clusterTitle.textContent = '🎯 Кластеры';
851            clusterTitle.style.cssText = `
852                margin: 0 0 15px 0;
853                font-size: 18px;
854                font-weight: bold;
855                color: #333;
856            `;
857            clusterSection.appendChild(clusterTitle);
858            
859            const clusterListContainer = document.createElement('div');
860            clusterListContainer.style.cssText = `
861                margin-bottom: 15px;
862                max-height: 200px;
863                overflow-y: auto;
864            `;
865            
866            // Функция для обновления списка кластерных стратегий
867            const updateClusterList = async () => {
868                const strategies = await getSavedClusterStrategies();
869                const holdPositionStrategyId = await GM.getValue('hold_position_cluster_strategy_id', null);
870                clusterListContainer.innerHTML = '';
871                
872                if (strategies.length === 0) {
873                    const emptyMessage = document.createElement('p');
874                    emptyMessage.textContent = 'Нет сохраненных кластерных стратегий.';
875                    emptyMessage.style.cssText = `
876                        color: #666;
877                        font-style: italic;
878                        padding: 10px;
879                        text-align: center;
880                    `;
881                    clusterListContainer.appendChild(emptyMessage);
882                } else {
883                    strategies.forEach((strategy) => {
884                        const item = document.createElement('div');
885                        const isHoldPosition = strategy.id === holdPositionStrategyId;
886                        item.style.cssText = `
887                            display: flex;
888                            justify-content: space-between;
889                            align-items: center;
890                            padding: 10px;
891                            margin-bottom: 8px;
892                            background: ${isHoldPosition ? '#e8f5e9' : 'white'};
893                            border-radius: 6px;
894                            border: ${isHoldPosition ? '2px solid #4caf50' : '1px solid #ddd'};
895                        `;
896                        
897                        const nameSpan = document.createElement('span');
898                        nameSpan.textContent = strategy.name + (isHoldPosition ? ' ✓' : '');
899                        nameSpan.style.cssText = `
900                            font-size: 14px;
901                            color: #333;
902                            flex: 1;
903                            font-weight: ${isHoldPosition ? 'bold' : 'normal'};
904                        `;
905                        
906                        const selectBtn = document.createElement('button');
907                        selectBtn.textContent = isHoldPosition ? '✓ Выбрана' : 'Выбрать';
908                        selectBtn.disabled = isHoldPosition;
909                        selectBtn.style.cssText = `
910                            background: ${isHoldPosition ? '#4caf50' : '#2196f3'};
911                            color: white;
912                            border: none;
913                            padding: 6px 12px;
914                            border-radius: 6px;
915                            cursor: ${isHoldPosition ? 'default' : 'pointer'};
916                            font-size: 13px;
917                            opacity: ${isHoldPosition ? '0.7' : '1'};
918                        `;
919                        if (!isHoldPosition) {
920                            selectBtn.onmouseover = () => selectBtn.style.background = '#1976d2';
921                            selectBtn.onmouseout = () => selectBtn.style.background = '#2196f3';
922                            selectBtn.onclick = async () => {
923                                await GM.setValue('hold_position_cluster_strategy_id', strategy.id);
924                                console.log(`Установлена кластерная стратегия удержания места: ${strategy.name}`);
925                                await updateClusterList();
926                            };
927                        }
928                        
929                        item.appendChild(nameSpan);
930                        item.appendChild(selectBtn);
931                        clusterListContainer.appendChild(item);
932                    });
933                }
934            };
935            
936            await updateClusterList();
937            clusterSection.appendChild(clusterListContainer);
938            
939            const clusterResetBtn = document.createElement('button');
940            clusterResetBtn.textContent = '🔄 Сбросить на стандартную';
941            clusterResetBtn.style.cssText = `
942                width: 100%;
943                background: #ff9800;
944                color: white;
945                border: none;
946                padding: 10px;
947                border-radius: 6px;
948                cursor: pointer;
949                font-size: 14px;
950                font-weight: 600;
951            `;
952            clusterResetBtn.onmouseover = () => clusterResetBtn.style.background = '#f57c00';
953            clusterResetBtn.onmouseout = () => clusterResetBtn.style.background = '#ff9800';
954            clusterResetBtn.onclick = async () => {
955                await GM.deleteValue('hold_position_cluster_strategy_id');
956                console.log('Кластерная стратегия удержания места сброшена на стандартную');
957                await updateClusterList();
958            };
959            clusterSection.appendChild(clusterResetBtn);
960            
961            modal.appendChild(clusterSection);
962            
963            // Кнопка закрытия
964            const closeButton = document.createElement('button');
965            closeButton.textContent = 'Закрыть';
966            closeButton.style.cssText = `
967                width: 100%;
968                background: #666;
969                color: white;
970                border: none;
971                padding: 12px;
972                border-radius: 8px;
973                cursor: pointer;
974                font-size: 16px;
975            `;
976            closeButton.onmouseover = () => closeButton.style.background = '#555';
977            closeButton.onmouseout = () => closeButton.style.background = '#666';
978            closeButton.onclick = () => {
979                document.body.removeChild(overlay);
980                resolve();
981            };
982            modal.appendChild(closeButton);
983            
984            overlay.appendChild(modal);
985            document.body.appendChild(overlay);
986            
987            // Закрытие по клику на оверлей
988            overlay.onclick = (e) => {
989                if (e.target === overlay) {
990                    document.body.removeChild(overlay);
991                    resolve();
992                }
993            };
994        });
995    }
996
997    // Функция для создания UI
998    function createUI() {
999        console.log('Создание UI панели');
1000        
1001        // Проверяем, есть ли сохраненный ДРР для массовой обработки
1002        GM.getValue('bulkProcessingDRR', null).then(savedDRR => {
1003            if (savedDRR !== null) {
1004                console.log(`Найден сохраненный ДРР для массовой обработки: ${savedDRR}`);
1005                // Автоматически запускаем стратегию с сохраненным ДРР
1006                setTimeout(async () => {
1007                    const input = document.getElementById('desired-percentage');
1008                    if (input) {
1009                        input.value = savedDRR;
1010                        
1011                        // Восстанавливаем состояние чекбоксов из сохраненных настроек
1012                        const savedApplyToClusters = await GM.getValue('bulkApplyToClusters', true);
1013                        const savedHoldPosition = await GM.getValue('bulkHoldPosition', true);
1014                        
1015                        const applyToClustersCheckbox = document.getElementById('apply-to-clusters');
1016                        const holdPositionCheckbox = document.getElementById('hold-position');
1017                        
1018                        if (applyToClustersCheckbox) {
1019                            applyToClustersCheckbox.checked = savedApplyToClusters;
1020                            console.log(`Восстановлено состояние "Применить к кластерам": ${savedApplyToClusters}`);
1021                        }
1022                        
1023                        if (holdPositionCheckbox) {
1024                            holdPositionCheckbox.checked = savedHoldPosition;
1025                            console.log(`Восстановлено состояние "Удержание места": ${savedHoldPosition}`);
1026                        }
1027                        
1028                        // Запускаем стратегию автоматически
1029                        runStrategy();
1030                    }
1031                }, 2000);
1032            }
1033        });
1034        
1035        const panel = document.createElement('div');
1036        panel.id = 'auto-strategy-panel';
1037        panel.style.cssText = `
1038            position: fixed;
1039            top: 20px;
1040            right: 20px;
1041            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1042            padding: 15px;
1043            border-radius: 12px;
1044            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
1045            z-index: 10000;
1046            min-width: 280px;
1047            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1048            color: white;
1049            transition: all 0.3s ease;
1050            cursor: move;
1051        `;
1052
1053        panel.innerHTML = `
1054            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: pointer;" id="panel-header">
1055                <h3 style="margin: 0; font-size: 16px; font-weight: 600;">🚀 Авто-стратегия</h3>
1056                <span id="toggle-icon" style="font-size: 18px;"></span>
1057            </div>
1058            
1059            <div id="panel-content" style="display: none;">
1060                <div style="margin-bottom: 15px;">
1061                    <label style="display: block; margin-bottom: 8px; font-size: 13px; font-weight: 500;">
1062                        Желаемый % рекламных расходов:
1063                    </label>
1064                    <input 
1065                        type="number" 
1066                        id="desired-percentage" 
1067                        value="30" 
1068                        min="1" 
1069                        max="100" 
1070                        step="0.1"
1071                        style="
1072                            width: 100%;
1073                            padding: 10px;
1074                            border: none;
1075                            border-radius: 8px;
1076                            font-size: 14px;
1077                            box-sizing: border-box;
1078                            background: rgba(255, 255, 255, 0.95);
1079                            color: #333;
1080                            cursor: text;
1081                        "
1082                    />
1083                </div>
1084
1085                <div style="margin-bottom: 15px;">
1086                    <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px; font-weight: 500;">
1087                        <input 
1088                            type="checkbox" 
1089                            id="apply-to-clusters" 
1090                            checked
1091                            style="
1092                                margin-right: 8px;
1093                                width: 18px;
1094                                height: 18px;
1095                                cursor: pointer;
1096                            "
1097                        />
1098                        Применить стратегию к кластерам
1099                    </label>
1100                </div>
1101
1102                <div style="margin-bottom: 15px;">
1103                    <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px; font-weight: 500;">
1104                        <input 
1105                            type="checkbox" 
1106                            id="hold-position" 
1107                            checked
1108                            style="
1109                                margin-right: 8px;
1110                                width: 18px;
1111                                height: 18px;
1112                                cursor: pointer;
1113                            "
1114                        />
1115                        Удержание места
1116                    </label>
1117                </div>
1118
1119                <button 
1120                    id="run-strategy-btn"
1121                    style="
1122                        width: 100%;
1123                        padding: 12px;
1124                        background: white;
1125                        color: #667eea;
1126                        border: none;
1127                        border-radius: 8px;
1128                        font-size: 14px;
1129                        font-weight: 600;
1130                        cursor: pointer;
1131                        transition: all 0.3s ease;
1132                        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1133                        margin-bottom: 10px;
1134                    "
1135                    onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 16px rgba(0, 0, 0, 0.2)';"
1136                    onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 12px rgba(0, 0, 0, 0.15)';"
1137                >
1138                    Запустить
1139                </button>
1140
1141                <button 
1142                    id="manage-strategies-btn"
1143                    style="
1144                        width: 100%;
1145                        padding: 10px;
1146                        background: rgba(255, 255, 255, 0.2);
1147                        color: white;
1148                        border: 1px solid rgba(255, 255, 255, 0.3);
1149                        border-radius: 8px;
1150                        font-size: 13px;
1151                        font-weight: 600;
1152                        cursor: pointer;
1153                        transition: all 0.3s ease;
1154                        margin-bottom: 8px;
1155                    "
1156                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
1157                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
1158                >
1159                    ⚙️ Управление стратегиями
1160                </button>
1161
1162                <button 
1163                    id="manage-cluster-strategies-btn"
1164                    style="
1165                        width: 100%;
1166                        padding: 10px;
1167                        background: rgba(255, 255, 255, 0.2);
1168                        color: white;
1169                        border: 1px solid rgba(255, 255, 255, 0.3);
1170                        border-radius: 8px;
1171                        font-size: 13px;
1172                        font-weight: 600;
1173                        cursor: pointer;
1174                        transition: all 0.3s ease;
1175                        margin-bottom: 8px;
1176                    "
1177                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
1178                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
1179                >
1180                    🎯 Стратегии для кластеров
1181                </button>
1182
1183                <button 
1184                    id="manage-hold-position-strategies-btn"
1185                    style="
1186                        width: 100%;
1187                        padding: 10px;
1188                        background: rgba(255, 255, 255, 0.2);
1189                        color: white;
1190                        border: 1px solid rgba(255, 255, 255, 0.3);
1191                        border-radius: 8px;
1192                        font-size: 13px;
1193                        font-weight: 600;
1194                        cursor: pointer;
1195                        transition: all 0.3s ease;
1196                    "
1197                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
1198                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
1199                >
1200                    📍 Стратегии удержания места
1201                </button>
1202
1203                <div id="status-message" style="
1204                    margin-top: 15px;
1205                    padding: 10px;
1206                    border-radius: 8px;
1207                    font-size: 12px;
1208                    background: rgba(255, 255, 255, 0.2);
1209                    display: none;
1210                "></div>
1211            </div>
1212        `;
1213
1214        document.body.appendChild(panel);
1215        console.log('UI панель создана');
1216
1217        // Добавляем возможность перетаскивания
1218        makeDraggable(panel);
1219
1220        // Добавляем обработчик клика на заголовок для разворачивания/сворачивания
1221        document.getElementById('panel-header').addEventListener('click', () => {
1222            const content = document.getElementById('panel-content');
1223            const icon = document.getElementById('toggle-icon');
1224            if (content.style.display === 'none') {
1225                content.style.display = 'block';
1226                icon.textContent = '▲';
1227            } else {
1228                content.style.display = 'none';
1229                icon.textContent = '▼';
1230            }
1231        });
1232
1233        // Добавляем обработчик клика на кнопку
1234        document.getElementById('run-strategy-btn').addEventListener('click', runStrategy);
1235        
1236        // Добавляем обработчик для кнопки управления стратегиями
1237        document.getElementById('manage-strategies-btn').addEventListener('click', async () => {
1238            await createStrategyManagementModal();
1239        });
1240        
1241        // Добавляем обработчик для кнопки управления кластерными стратегиями
1242        document.getElementById('manage-cluster-strategies-btn').addEventListener('click', async () => {
1243            await createClusterStrategyManagementModal();
1244        });
1245        
1246        // Добавляем обработчик для кнопки управления стратегиями удержания места
1247        document.getElementById('manage-hold-position-strategies-btn').addEventListener('click', async () => {
1248            await createHoldPositionStrategyManagementModal();
1249        });
1250    }
1251
1252    // Функция для создания UI панели массового изменения
1253    function createBulkUI() {
1254        console.log('Создание UI панели массового изменения');
1255        
1256        const panel = document.createElement('div');
1257        panel.id = 'bulk-strategy-panel';
1258        panel.style.cssText = `
1259            position: fixed;
1260            top: 20px;
1261            right: 20px;
1262            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
1263            padding: 15px;
1264            border-radius: 12px;
1265            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
1266            z-index: 10000;
1267            min-width: 300px;
1268            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1269            color: white;
1270            transition: all 0.3s ease;
1271            cursor: move;
1272        `;
1273
1274        panel.innerHTML = `
1275            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; cursor: pointer;" id="bulk-panel-header">
1276                <h3 style="margin: 0; font-size: 16px; font-weight: 600;">📦 Массовое изменение</h3>
1277                <span id="bulk-toggle-icon" style="font-size: 18px;"></span>
1278            </div>
1279            
1280            <div id="bulk-panel-content" style="display: none;">
1281                <div style="margin-bottom: 15px;">
1282                    <label style="display: block; margin-bottom: 8px; font-size: 13px; font-weight: 500;">
1283                        Желаемый % рекламных расходов (ДРР):
1284                    </label>
1285                    <input 
1286                        type="number" 
1287                        id="bulk-desired-percentage" 
1288                        value="30" 
1289                        min="1" 
1290                        max="100" 
1291                        step="0.1"
1292                        style="
1293                            width: 100%;
1294                            padding: 10px;
1295                            border: none;
1296                            border-radius: 8px;
1297                            font-size: 14px;
1298                            box-sizing: border-box;
1299                            background: rgba(255, 255, 255, 0.95);
1300                            color: #333;
1301                            cursor: text;
1302                        "
1303                    />
1304                </div>
1305
1306                <div id="bulk-campaigns-info" style="
1307                    margin-bottom: 15px;
1308                    padding: 10px;
1309                    border-radius: 8px;
1310                    font-size: 12px;
1311                    background: rgba(255, 255, 255, 0.2);
1312                ">
1313                    Найдено кампаний: <span id="campaigns-count">0</span>
1314                </div>
1315
1316                <button 
1317                    id="run-bulk-strategy-btn"
1318                    style="
1319                        width: 100%;
1320                        padding: 12px;
1321                        background: white;
1322                        color: #f5576c;
1323                        border: none;
1324                        border-radius: 8px;
1325                        font-size: 14px;
1326                        font-weight: 600;
1327                        cursor: pointer;
1328                        transition: all 0.3s ease;
1329                        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1330                        margin-bottom: 10px;
1331                    "
1332                    onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 16px rgba(0, 0, 0, 0.2)';"
1333                    onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='0 4px 12px rgba(0, 0, 0, 0.15)';"
1334                >
1335                    Запустить
1336                </button>
1337
1338                <button 
1339                    id="bulk-manage-strategies-btn"
1340                    style="
1341                        width: 100%;
1342                        padding: 10px;
1343                        background: rgba(255, 255, 255, 0.2);
1344                        color: white;
1345                        border: 1px solid rgba(255, 255, 255, 0.3);
1346                        border-radius: 8px;
1347                        font-size: 13px;
1348                        font-weight: 600;
1349                        cursor: pointer;
1350                        transition: all 0.3s ease;
1351                        margin-bottom: 10px;
1352                    "
1353                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
1354                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
1355                >
1356                    ⚙️ Управление стратегиями
1357                </button>
1358
1359                <button 
1360                    id="bulk-manage-cluster-strategies-btn"
1361                    style="
1362                        width: 100%;
1363                        padding: 10px;
1364                        background: rgba(255, 255, 255, 0.2);
1365                        color: white;
1366                        border: 1px solid rgba(255, 255, 255, 0.3);
1367                        border-radius: 8px;
1368                        font-size: 13px;
1369                        font-weight: 600;
1370                        cursor: pointer;
1371                        transition: all 0.3s ease;
1372                        margin-bottom: 10px;
1373                    "
1374                    onmouseover="this.style.background='rgba(255, 255, 255, 0.3)';"
1375                    onmouseout="this.style.background='rgba(255, 255, 255, 0.2)';"
1376                >
1377                    🎯 Стратегии для кластеров
1378                </button>
1379
1380                <div style="margin-bottom: 15px;">
1381                    <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px; font-weight: 500;">
1382                        <input 
1383                            type="checkbox" 
1384                            id="bulk-apply-to-clusters" 
1385                            checked
1386                            style="
1387                                margin-right: 8px;
1388                                width: 18px;
1389                                height: 18px;
1390                                cursor: pointer;
1391                            "
1392                        />
1393                        Применить стратегию к кластерам
1394                    </label>
1395                </div>
1396
1397                <div style="margin-bottom: 15px;">
1398                    <label style="display: flex; align-items: center; cursor: pointer; font-size: 13px; font-weight: 500;">
1399                        <input 
1400                            type="checkbox" 
1401                            id="bulk-hold-position" 
1402                            checked
1403                            style="
1404                                margin-right: 8px;
1405                                width: 18px;
1406                                height: 18px;
1407                                cursor: pointer;
1408                            "
1409                        />
1410                        Удержание места
1411                    </label>
1412                </div>
1413
1414                <div id="bulk-control-buttons" style="
1415                    margin-top: 10px;
1416                    display: none;
1417                    gap: 10px;
1418                ">
1419                    <button 
1420                        id="pause-bulk-btn"
1421                        style="
1422                            flex: 1;
1423                            padding: 10px;
1424                            background: rgba(255, 255, 255, 0.9);
1425                            color: #f5576c;
1426                            border: none;
1427                            border-radius: 8px;
1428                            font-size: 13px;
1429                            font-weight: 600;
1430                            cursor: pointer;
1431                            transition: all 0.3s ease;
1432                        "
1433                    >
1434                        ⏏️ Пауза
1435                    </button>
1436                    <button 
1437                        id="stop-bulk-btn"
1438                        style="
1439                            flex: 1;
1440                            padding: 10px;
1441                            background: rgba(255, 59, 48, 0.9);
1442                            color: white;
1443                            border: none;
1444                            border-radius: 8px;
1445                            font-size: 13px;
1446                            font-weight: 600;
1447                            cursor: pointer;
1448                            transition: all 0.3s ease;
1449                        "
1450                    >
1451                        ⏹️ Стоп
1452                    </button>
1453                </div>
1454
1455                <div id="bulk-status-message" style="
1456                    margin-top: 15px;
1457                    padding: 10px;
1458                    border-radius: 8px;
1459                    font-size: 12px;
1460                    background: rgba(255, 255, 255, 0.2);
1461                    display: none;
1462                "></div>
1463
1464                <div id="bulk-progress" style="
1465                    margin-top: 15px;
1466                    display: none;
1467                ">
1468                    <div style="margin-bottom: 5px; font-size: 12px;">
1469                        Прогресс: <span id="bulk-progress-text">0/0</span>
1470                    </div>
1471                    <div style="
1472                        width: 100%;
1473                        height: 8px;
1474                        background: rgba(255, 255, 255, 0.3);
1475                        border-radius: 4px;
1476                        overflow: hidden;
1477                    ">
1478                        <div id="bulk-progress-bar" style="
1479                            width: 0%;
1480                            height: 100%;
1481                            background: white;
1482                            transition: width 0.3s ease;
1483                        "></div>
1484                    </div>
1485                </div>
1486            </div>
1487        `;
1488
1489        document.body.appendChild(panel);
1490        console.log('UI панель массового изменения создана');
1491
1492        // Добавляем возможность перетаскивания
1493        makeDraggable(panel);
1494
1495        // Подсчитываем количество кампаний
1496        updateCampaignsCount();
1497
1498        // Добавляем обработчик клика на заголовок для разворачивания/сворачивания
1499        document.getElementById('bulk-panel-header').addEventListener('click', () => {
1500            const content = document.getElementById('bulk-panel-content');
1501            const icon = document.getElementById('bulk-toggle-icon');
1502            if (content.style.display === 'none') {
1503                content.style.display = 'block';
1504                icon.textContent = '▲';
1505            } else {
1506                content.style.display = 'none';
1507                icon.textContent = '▼';
1508            }
1509        });
1510
1511        // Добавляем обработчик клика на кнопку
1512        document.getElementById('run-bulk-strategy-btn').addEventListener('click', runBulkStrategy);
1513        
1514        // Добавляем обработчик для кнопки управления стратегиями
1515        document.getElementById('bulk-manage-strategies-btn').addEventListener('click', async () => {
1516            await createStrategyManagementModal();
1517        });
1518        
1519        // Добавляем обработчик для кнопки управления кластерными стратегиями
1520        document.getElementById('bulk-manage-cluster-strategies-btn').addEventListener('click', async () => {
1521            await createClusterStrategyManagementModal();
1522        });
1523        
1524        // Добавляем обработчики для кнопок управления
1525        document.getElementById('pause-bulk-btn').addEventListener('click', pauseBulkProcessing);
1526        document.getElementById('stop-bulk-btn').addEventListener('click', stopBulkProcessing);
1527        
1528        // Запускаем мониторинг прогресса
1529        startProgressMonitoring();
1530    }
1531    
1532    // Функция для мониторинга прогресса массовой обработки
1533    async function startProgressMonitoring() {
1534        setInterval(async () => {
1535            const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
1536            const totalCampaigns = await GM.getValue('bulkTotalCampaigns', 0);
1537            
1538            if (totalCampaigns > 0) {
1539                updateBulkProgress(currentIndex, totalCampaigns);
1540                
1541                const progressDiv = document.getElementById('bulk-progress');
1542                if (progressDiv && progressDiv.style.display === 'none') {
1543                    progressDiv.style.display = 'block';
1544                }
1545                
1546                const controlButtons = document.getElementById('bulk-control-buttons');
1547                if (controlButtons && controlButtons.style.display === 'none' && currentIndex < totalCampaigns) {
1548                    controlButtons.style.display = 'flex';
1549                }
1550            }
1551        }, 1000); // Обновляем каждую секунду
1552    }
1553
1554    // Функция для создания перетаскиваемого элемента
1555    function makeDraggable(element) {
1556        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
1557        let isDragging = false;
1558
1559        element.onmousedown = dragMouseDown;
1560
1561        function dragMouseDown(e) {
1562            // Не перетаскиваем, если кликнули на input, button или другие интерактивные элементы
1563            if (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA') {
1564                return;
1565            }
1566            
1567            e.preventDefault();
1568            isDragging = true;
1569            pos3 = e.clientX;
1570            pos4 = e.clientY;
1571            document.onmouseup = closeDragElement;
1572            document.onmousemove = elementDrag;
1573        }
1574
1575        function elementDrag(e) {
1576            if (!isDragging) return;
1577            pos1 = pos3 - e.clientX;
1578            pos2 = pos4 - e.clientY;
1579            pos3 = e.clientX;
1580            pos4 = e.clientY;
1581            element.style.top = (element.offsetTop - pos2) + 'px';
1582            element.style.left = (element.offsetLeft - pos1) + 'px';
1583            element.style.right = 'auto';
1584            element.style.bottom = 'auto';
1585        }
1586
1587        function closeDragElement() {
1588            isDragging = false;
1589            document.onmouseup = null;
1590            document.onmousemove = null;
1591        }
1592    }
1593
1594    // Функция для обновления количества кампаний
1595    function updateCampaignsCount() {
1596        const campaignLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
1597        const count = campaignLinks.length;
1598        const countElement = document.getElementById('campaigns-count');
1599        if (countElement) {
1600            countElement.textContent = count;
1601        }
1602        console.log(`Найдено кампаний: ${count}`);
1603    }
1604
1605    // Функция для показа статуса массовой обработки
1606    function showBulkStatus(message, isError = false) {
1607        const statusDiv = document.getElementById('bulk-status-message');
1608        if (statusDiv) {
1609            statusDiv.textContent = message;
1610            statusDiv.style.display = 'block';
1611            statusDiv.style.background = isError ? 'rgba(255, 59, 48, 0.9)' : 'rgba(52, 199, 89, 0.9)';
1612            console.log(`Статус массовой обработки: ${message}`);
1613        }
1614    }
1615
1616    // Функция для обновления прогресса
1617    function updateBulkProgress(current, total) {
1618        const progressDiv = document.getElementById('bulk-progress');
1619        const progressText = document.getElementById('bulk-progress-text');
1620        const progressBar = document.getElementById('bulk-progress-bar');
1621        
1622        if (progressDiv && progressText && progressBar) {
1623            progressDiv.style.display = 'block';
1624            progressText.textContent = `${current}/${total}`;
1625            const percentage = (current / total) * 100;
1626            progressBar.style.width = `${percentage}%`;
1627        }
1628    }
1629
1630    // Функция для прокрутки страницы вниз для загрузки всех кампаний
1631    async function scrollToLoadAllCampaigns() {
1632        console.log('Начинаем загрузку всех кампаний через прокрутку...');
1633        
1634        // Находим контейнер с прокруткой
1635        const tableContainer = document.querySelector('.container.MuiBox-root.css-9hf803');
1636        
1637        if (!tableContainer) {
1638            console.error('Контейнер таблицы не найден');
1639            return [];
1640        }
1641        
1642        console.log('Контейнер найден, начинаем прокрутку...');
1643        console.log(`Высота контейнера: ${tableContainer.scrollHeight}px`);
1644        
1645        // Собираем уникальные ссылки во время прокрутки
1646        const uniqueLinks = new Set();
1647        
1648        // Прокручиваем контейнер постепенно, чтобы загрузить все кампании
1649        let previousLinksCount = 0;
1650        let stableCount = 0;
1651        const maxAttempts = 200; // Максимум попыток
1652        let attempts = 0;
1653        const scrollStep = 500; // Прокручиваем по 500px за раз
1654        
1655        while (attempts < maxAttempts) {
1656            // Собираем ссылки на текущем шаге
1657            const currentLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
1658            currentLinks.forEach(link => {
1659                uniqueLinks.add(link.href);
1660            });
1661            
1662            const currentCount = uniqueLinks.size;
1663            console.log(`Загружено кампаний: ${currentCount}, прокрутка: ${tableContainer.scrollTop}/${tableContainer.scrollHeight}`);
1664            
1665            // Прокручиваем контейнер постепенно
1666            tableContainer.scrollTop += scrollStep;
1667            
1668            // Ждем загрузки новых элементов
1669            await wait(500);
1670            
1671            // Если количество не изменилось
1672            if (currentCount === previousLinksCount) {
1673                stableCount++;
1674                // Если количество стабильно 5 раз подряд - значит все загружено
1675                if (stableCount >= 5) {
1676                    console.log('Все кампании загружены');
1677                    break;
1678                }
1679            } else {
1680                stableCount = 0;
1681                previousLinksCount = currentCount;
1682            }
1683            
1684            // Если достигли конца контейнера
1685            if (tableContainer.scrollTop + tableContainer.clientHeight >= tableContainer.scrollHeight - 10) {
1686                console.log('Достигнут конец контейнера');
1687                // Ждем еще немного для загрузки последних элементов
1688                await wait(1000);
1689                
1690                // Собираем последние ссылки
1691                const finalLinks = document.querySelectorAll('a[href*="/campaigns/auto-campaigns/"][href*="/campaign"]');
1692                finalLinks.forEach(link => {
1693                    uniqueLinks.add(link.href);
1694                });
1695                
1696                // Проверяем еще раз количество
1697                if (uniqueLinks.size === previousLinksCount) {
1698                    break;
1699                }
1700                previousLinksCount = uniqueLinks.size;
1701            }
1702            
1703            attempts++;
1704        }
1705        
1706        // Преобразуем Set в массив URL (НЕ прокручиваем обратно!)
1707        const links = Array.from(uniqueLinks);
1708        
1709        console.log(`Найдено кампаний: ${links.length}`);
1710        console.log(`Всего попыток прокрутки: ${attempts}`);
1711        return links;
1712    }
1713
1714    // Функция для массовой обработки кампаний
1715    async function runBulkStrategy() {
1716        if (isBulkProcessing) {
1717            showBulkStatus('Обработка уже выполняется', true);
1718            return;
1719        }
1720
1721        try {
1722            isBulkProcessing = true;
1723            console.log('Начало массовой обработки кампаний');
1724            
1725            bulkDesiredPercentage = parseFloat(document.getElementById('bulk-desired-percentage').value);
1726            if (!bulkDesiredPercentage || bulkDesiredPercentage <= 0) {
1727                showBulkStatus('Ошибка: введите корректный процент', true);
1728                isBulkProcessing = false;
1729                return;
1730            }
1731            console.log(`Желаемый процент: ${bulkDesiredPercentage}%`);
1732
1733            // Сохраняем ДРР для автоматической обработки
1734            await GM.setValue('bulkProcessingDRR', bulkDesiredPercentage);
1735            console.log(`ДРР ${bulkDesiredPercentage} сохранен для массовой обработки`);
1736            
1737            // Сохраняем состояние чекбоксов
1738            const applyToClustersCheckbox = document.getElementById('bulk-apply-to-clusters');
1739            const holdPositionCheckbox = document.getElementById('bulk-hold-position');
1740            
1741            if (applyToClustersCheckbox) {
1742                await GM.setValue('bulkApplyToClusters', applyToClustersCheckbox.checked);
1743                console.log(`Сохранено состояние "Применить к кластерам": ${applyToClustersCheckbox.checked}`);
1744            }
1745            
1746            if (holdPositionCheckbox) {
1747                await GM.setValue('bulkHoldPosition', holdPositionCheckbox.checked);
1748                console.log(`Сохранено состояние "Удержание места": ${holdPositionCheckbox.checked}`);
1749            }
1750
1751            // Прокручиваем страницу для загрузки всех кампаний
1752            const campaignLinks = await scrollToLoadAllCampaigns();
1753            
1754            if (campaignLinks.length === 0) {
1755                showBulkStatus('Ошибка: кампании не найдены', true);
1756                isBulkProcessing = false;
1757                await GM.deleteValue('bulkProcessingDRR');
1758                return;
1759            }
1760
1761            console.log(`Найдено кампаний для обработки: ${campaignLinks.length}`);
1762            showBulkStatus(`Начинаем обработку ${campaignLinks.length} кампаний...`);
1763            updateBulkProgress(0, campaignLinks.length);
1764
1765            // Сохраняем список кампаний (массив URL), текущий индекс и общее количество
1766            await GM.setValue('bulkCampaigns', JSON.stringify(campaignLinks));
1767            await GM.setValue('bulkCurrentIndex', 0);
1768            await GM.setValue('bulkTotalCampaigns', campaignLinks.length);
1769
1770            // Показываем кнопки управления
1771            const controlButtons = document.getElementById('bulk-control-buttons');
1772            if (controlButtons) {
1773                controlButtons.style.display = 'flex';
1774            }
1775
1776            // Открываем первую кампанию в новой вкладке через window.open
1777            if (campaignLinks.length > 0) {
1778                console.log(`Открытие кампании 1/${campaignLinks.length}: ${campaignLinks[0]}`);
1779                window.open(campaignLinks[0], '_blank');
1780            }
1781
1782        } catch (error) {
1783            console.error('Ошибка при массовой обработке:', error);
1784            showBulkStatus(`Ошибка: ${error.message}`, true);
1785            isBulkProcessing = false;
1786            await GM.deleteValue('bulkProcessingDRR');
1787        }
1788    }
1789
1790    // Функция для паузы массовой обработки
1791    async function pauseBulkProcessing() {
1792        bulkPaused = !bulkPaused;
1793        const pauseBtn = document.getElementById('pause-bulk-btn');
1794        
1795        if (bulkPaused) {
1796            await GM.setValue('bulkPaused', true);
1797            pauseBtn.textContent = '▶️ Продолжить';
1798            showBulkStatus('⏸️ Обработка приостановлена');
1799            console.log('Массовая обработка приостановлена');
1800        } else {
1801            await GM.deleteValue('bulkPaused');
1802            pauseBtn.textContent = '⏸️ Пауза';
1803            showBulkStatus('▶️ Обработка возобновлена');
1804            console.log('Массовая обработка возобновлена');
1805            
1806            // Продолжаем обработку - открываем следующую кампанию
1807            const campaignsJson = await GM.getValue('bulkCampaigns', null);
1808            const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
1809            const totalCampaigns = await GM.getValue('bulkTotalCampaigns', 0);
1810            
1811            if (campaignsJson) {
1812                const campaigns = JSON.parse(campaignsJson);
1813                const nextIndex = currentIndex + 1;
1814                
1815                console.log(`Обработано кампаний: ${nextIndex} из ${totalCampaigns}`);
1816                
1817                if (nextIndex < campaigns.length) {
1818                    // Сохраняем новый индекс
1819                    await GM.setValue('bulkCurrentIndex', nextIndex);
1820                    
1821                    // Открываем следующую кампанию в новой вкладке через window.open
1822                    console.log(`Открываем кампанию ${nextIndex + 1}: ${campaigns[nextIndex]}`);
1823                    const newTab = window.open(campaigns[nextIndex], '_blank');
1824                    
1825                    if (newTab) {
1826                        // Закрываем текущую вкладку
1827                        await wait(1000);
1828                        window.close();
1829                    } else {
1830                        // Если блокировщик всплывающих окон, используем редирект
1831                        console.log('Блокировщик всплывающих окон, используем редирект');
1832                        window.location.href = campaigns[nextIndex];
1833                    }
1834                }
1835            }
1836        }
1837    }
1838
1839    // Функция для остановки массовой обработки
1840    async function stopBulkProcessing() {
1841        await GM.deleteValue('bulkProcessingDRR');
1842        await GM.deleteValue('bulkCampaigns');
1843        await GM.deleteValue('bulkCurrentIndex');
1844        await GM.deleteValue('bulkTotalCampaigns');
1845        
1846        showBulkStatus('⏹️ Обработка остановлена', true);
1847        console.log('Массовая обработка остановлена');
1848        
1849        // Скрываем кнопки управления
1850        const controlButtons = document.getElementById('bulk-control-buttons');
1851        if (controlButtons) {
1852            controlButtons.style.display = 'none';
1853        }
1854        
1855        isBulkProcessing = false;
1856        bulkPaused = false;
1857    }
1858
1859    // Функция для показа статуса
1860    function showStatus(message, isError = false) {
1861        const statusDiv = document.getElementById('status-message');
1862        if (statusDiv) {
1863            statusDiv.textContent = message;
1864            statusDiv.style.display = 'block';
1865            statusDiv.style.background = isError ? 'rgba(255, 59, 48, 0.9)' : 'rgba(52, 199, 89, 0.9)';
1866            console.log(`Статус: ${message}`);
1867        }
1868    }
1869
1870    // Функция для ожидания
1871    function wait(ms) {
1872        return new Promise(resolve => setTimeout(resolve, ms));
1873    }
1874
1875    // Функция для парсинга числа из строки
1876    function parseNumber(str) {
1877        if (!str) return 0;
1878        // Убираем все символы кроме цифр, точек и запятых
1879        const cleaned = str.replace(/[^\d.,]/g, '').replace(/\s/g, '');
1880        // Заменяем запятую на точку
1881        const normalized = cleaned.replace(',', '.');
1882        return parseFloat(normalized) || 0;
1883    }
1884
1885    // Функция для парсинга процента
1886    function parsePercentage(str) {
1887        if (!str) return 0;
1888        const cleaned = str.replace('%', '').replace(',', '.').trim();
1889        return parseFloat(cleaned) || 0;
1890    }
1891
1892    // Основная функция запуска стратегии
1893    async function runStrategy() {
1894        try {
1895            console.log('Начало выполнения стратегии');
1896            showStatus('Запуск процесса...');
1897
1898            const desiredPercentage = parseFloat(document.getElementById('desired-percentage').value);
1899            if (!desiredPercentage || desiredPercentage <= 0) {
1900                showStatus('Ошибка: введите корректный процент', true);
1901                await handleStrategyError();
1902                return;
1903            }
1904            console.log(`Желаемый процент: ${desiredPercentage}%`);
1905
1906            // Проверяем чекбоксы из обеих панелей
1907            const holdPositionCheckbox = document.getElementById('hold-position');
1908            const bulkHoldPositionCheckbox = document.getElementById('bulk-hold-position');
1909            const shouldApplyHoldPosition = holdPositionCheckbox ? holdPositionCheckbox.checked : 
1910                (bulkHoldPositionCheckbox ? bulkHoldPositionCheckbox.checked : false);
1911
1912            // Шаг 1: Кликаем на статистику
1913            showStatus('Открытие статистики...');
1914            const statsButton = document.querySelector('.css-amj7dw');
1915            if (!statsButton) {
1916                showStatus('Ошибка: кнопка статистики не найдена', true);
1917                await handleStrategyError();
1918                return;
1919            }
1920            statsButton.click();
1921            console.log('Клик на статистику выполнен');
1922            await wait(2000);
1923
1924            // Шаг 1.5: Выбираем режим "Товары"
1925            showStatus('Выбор режима "Товары"...');
1926            const modeLabels = Array.from(document.querySelectorAll('label'));
1927            let modeInput = null;
1928            
1929            for (const label of modeLabels) {
1930                if (label.textContent.trim() === 'Режим') {
1931                    const inputId = label.getAttribute('for');
1932                    if (inputId) {
1933                        modeInput = document.getElementById(inputId);
1934                        console.log(`Найдено поле Режим с id: ${inputId}`);
1935                        break;
1936                    }
1937                }
1938            }
1939            
1940            if (modeInput) {
1941                modeInput.value = 'Товары';
1942                const inputEvent = new Event('input', { bubbles: true });
1943                const changeEvent = new Event('change', { bubbles: true });
1944                modeInput.dispatchEvent(inputEvent);
1945                modeInput.dispatchEvent(changeEvent);
1946                
1947                console.log('Установлено значение: Товары');
1948                await wait(1000);
1949                
1950                const options = document.querySelectorAll('[role="option"]');
1951                console.log(`Найдено опций: ${options.length}`);
1952                
1953                if (options.length > 0) {
1954                    const tovarOption = Array.from(options).find(opt => opt.textContent.includes('Товары'));
1955                    if (tovarOption) {
1956                        tovarOption.click();
1957                        console.log('Выбран режим "Товары"');
1958                        await wait(1000);
1959                    }
1960                }
1961            }
1962
1963            // Шаг 2: Извлекаем данные из статистики
1964            showStatus('Извлечение данных...');
1965            await wait(500);
1966            
1967            const stats = Array.from(document.querySelectorAll('.MuiTypography-caption.css-1et52kr'));
1968            
1969            let sumOrders = 0;
1970            let ordersCount = 0;
1971            let cartToOrderPercent = 0;
1972
1973            stats.forEach(el => {
1974                const text = el.textContent.trim();
1975                const valueElement = el.closest('.MuiBox-root')?.querySelector('.MuiTypography-h3 .MuiTypography-body1');
1976                const value = valueElement ? valueElement.textContent.trim() : '';
1977
1978                console.log(`Найден показатель: ${text} = ${value}`);
1979
1980                if (text === 'Сумма заказов') {
1981                    sumOrders = parseNumber(value);
1982                    console.log(`Сумма заказов: ${sumOrders}`);
1983                } else if (text === 'Заказов') {
1984                    ordersCount = parseNumber(value);
1985                    console.log(`Заказов: ${ordersCount}`);
1986                } else if (text === 'Корзина → Заказ') {
1987                    cartToOrderPercent = parsePercentage(value);
1988                    console.log(`Корзина → Заказ: ${cartToOrderPercent}%`);
1989                }
1990            });
1991
1992            if (sumOrders === 0 || ordersCount === 0 || cartToOrderPercent === 0) {
1993                showStatus('Ошибка: не удалось получить данные статистики', true);
1994                console.error('Недостаточно данных:', { sumOrders, ordersCount, cartToOrderPercent });
1995                await handleStrategyError();
1996                return;
1997            }
1998
1999            // Шаг 3: Вычисляем стоимость корзины
2000            const cartCost = (sumOrders / ordersCount) * (desiredPercentage / 100) * (cartToOrderPercent / 100);
2001            const cartCostRounded = Math.round(cartCost * 100) / 100;
2002            console.log(`Расчет: (${sumOrders} / ${ordersCount}) * (${desiredPercentage} / 100) * (${cartToOrderPercent} / 100) = ${cartCostRounded}`);
2003            showStatus(`Рассчитано: ${cartCostRounded}`);
2004
2005            // Закрываем статистику
2006            statsButton.click();
2007            await wait(500);
2008
2009            // Шаг 4: Кликаем на "Вставить стратегию"
2010            showStatus('Вставка стратегии...');
2011            
2012            // Ищем ВСЕ кнопки и фильтруем по тексту
2013            const allButtonsForStrategy = document.querySelectorAll('button');
2014            const mainInsertStrategyButtons = [];
2015            
2016            for (const btn of allButtonsForStrategy) {
2017                if (btn.textContent.includes('Вставить стратегию')) {
2018                    mainInsertStrategyButtons.push(btn);
2019                }
2020            }
2021            
2022            console.log(`Найдено кнопок "Вставить стратегию": ${mainInsertStrategyButtons.length}`);
2023            
2024            // Берем первую кнопку для основной стратегии
2025            let insertButton = null;
2026            if (mainInsertStrategyButtons.length >= 1) {
2027                insertButton = mainInsertStrategyButtons[0];
2028                console.log('Используем первую кнопку "Вставить стратегию" для основной стратегии');
2029            }
2030            
2031            if (!insertButton) {
2032                console.error('Кнопка "Вставить стратегию" не найдена');
2033                showStatus('⚠️ Кнопка вставки стратегии не найдена', true);
2034                await handleStrategyError();
2035                return;
2036            }
2037
2038            // Получаем текущую выбранную стратегию
2039            let currentStrategyCode;
2040            if (shouldApplyHoldPosition) {
2041                currentStrategyCode = await getHoldPositionStrategy();
2042                console.log('Используем стратегию удержания места, длина:', currentStrategyCode.length);
2043            } else {
2044                currentStrategyCode = await getCurrentStrategy();
2045                console.log('Используем обычную стратегию, длина:', currentStrategyCode.length);
2046            }
2047            
2048            // Копируем код стратегии в буфер обмена
2049            console.log('Копируем стратегию в буфер обмена...');
2050            
2051            try {
2052                await navigator.clipboard.writeText(currentStrategyCode);
2053                console.log('✓ Стратегия скопирована через navigator.clipboard');
2054            } catch {
2055                console.log('navigator.clipboard не сработал, пробуем GM.setClipboard...');
2056                try {
2057                    await GM.setClipboard(currentStrategyCode);
2058                    console.log('✓ Стратегия скопирована через GM.setClipboard');
2059                } catch (e2) {
2060                    console.error('Ошибка копирования через GM.setClipboard:', e2.message);
2061                }
2062            }
2063            
2064            await wait(500);
2065
2066            insertButton.click();
2067            console.log('Клик на "Вставить стратегию" выполнен');
2068            await wait(500);
2069            
2070            console.log('✓ Стратегия вставлена из буфера обмена');
2071            await wait(500);
2072
2073            // Шаг 5: Находим поле "Желаемое значение" и вставляем результат
2074            showStatus('Заполнение поля...');
2075            
2076            const inputLabels = Array.from(document.querySelectorAll('.MuiInputLabel-root'));
2077            let targetInput = null;
2078
2079            for (const label of inputLabels) {
2080                const labelText = label.textContent;
2081                if (labelText.includes('Желаемое значение За корзину')) {
2082                    const inputId = label.getAttribute('for');
2083                    if (inputId) {
2084                        targetInput = document.getElementById(inputId);
2085                        console.log(`Найдено поле: ${labelText}, id: ${inputId}`);
2086                        break;
2087                    }
2088                }
2089            }
2090
2091            if (!targetInput) {
2092                const inputs = document.querySelectorAll('input[type="number"]');
2093                for (const input of inputs) {
2094                    const name = input.getAttribute('name') || '';
2095                    if (name.includes('rules') && name.includes('value')) {
2096                        targetInput = input;
2097                        break;
2098                    }
2099                }
2100            }
2101
2102            if (!targetInput) {
2103                showStatus('Ошибка: поле для ввода не найдено', true);
2104                console.error('Не удалось найти поле для ввода значения');
2105                await handleStrategyError();
2106                return;
2107            }
2108
2109            targetInput.focus();
2110            targetInput.value = cartCostRounded.toString();
2111            
2112            const inputEvent = new Event('input', { bubbles: true });
2113            const changeEvent = new Event('change', { bubbles: true });
2114            targetInput.dispatchEvent(inputEvent);
2115            targetInput.dispatchEvent(changeEvent);
2116            
2117            console.log(`Значение ${cartCostRounded} установлено в поле ${targetInput.id}`);
2118            await wait(500);
2119
2120            // Шаг 6: Нажимаем "Сохранить"
2121            showStatus('Сохранение...');
2122            const saveButtons = document.querySelectorAll('button');
2123            let saveButton = null;
2124
2125            for (const btn of saveButtons) {
2126                if (btn.textContent.trim() === 'Сохранить') {
2127                    saveButton = btn;
2128                    break;
2129                }
2130            }
2131
2132            if (!saveButton) {
2133                showStatus('Ошибка: кнопка "Сохранить" не найдена', true);
2134                await handleStrategyError();
2135                return;
2136            }
2137
2138            saveButton.click();
2139            console.log('Клик на "Сохранить" выполнен');
2140            await wait(500);
2141
2142            showStatus(`✅ Готово! Стоимость корзины: ${cartCostRounded}`);
2143            console.log('Стратегия успешно установлена');
2144
2145            // Шаг 7: Работа с кластерами
2146            // Проверяем чекбоксы из обеих панелей
2147            const applyToClusters = document.getElementById('apply-to-clusters');
2148            const bulkApplyToClusters = document.getElementById('bulk-apply-to-clusters');
2149            const shouldApplyToClusters = applyToClusters ? applyToClusters.checked : 
2150                (bulkApplyToClusters ? bulkApplyToClusters.checked : true);
2151            
2152            if (!shouldApplyToClusters) {
2153                console.log('Применение стратегии к кластерам отключено');
2154                showStatus('✅ Готово! Кластеры пропущены');
2155                
2156                // Проверяем, идет ли массовая обработка
2157                const savedDRR = await GM.getValue('bulkProcessingDRR', null);
2158                if (savedDRR !== null) {
2159                    console.log('Массовая обработка: переход к следующей кампании');
2160                    
2161                    // Обновляем счетчик ПЕРЕД переходом
2162                    const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
2163                    const nextIndex = currentIndex + 1;
2164                    await GM.setValue('bulkCurrentIndex', nextIndex);
2165                    console.log(`✅ Кампания ${nextIndex} обработана успешно`);
2166                    
2167                    await wait(2000);
2168                    
2169                    const campaignsJson = await GM.getValue('bulkCampaigns', null);
2170                    const totalCampaigns = await GM.getValue('bulkTotalCampaigns', 0);
2171                    
2172                    if (campaignsJson) {
2173                        const campaigns = JSON.parse(campaignsJson);
2174                        
2175                        console.log(`Обработано кампаний: ${nextIndex} из ${totalCampaigns}`);
2176                        
2177                        if (nextIndex < campaigns.length) {
2178                            console.log(`Переходим к кампании ${nextIndex + 1}: ${campaigns[nextIndex]}`);
2179                            // Просто перенаправляем текущую вкладку на следующую кампанию
2180                            window.location.href = campaigns[nextIndex];
2181                        } else {
2182                            console.log('Все кампании обработаны');
2183                            await GM.deleteValue('bulkProcessingDRR');
2184                            await GM.deleteValue('bulkCampaigns');
2185                            await GM.deleteValue('bulkCurrentIndex');
2186                            await GM.deleteValue('bulkTotalCampaigns');
2187                            
2188                            showStatus('✅ Все кампании обработаны!');
2189                            alert('✅ Все кампании обработаны!');
2190                        }
2191                    }
2192                }
2193                return;
2194            }
2195
2196            console.log('Применение стратегии к кластерам включено');
2197            
2198            // Переходим во вкладку "Кластеры"
2199            const tabs = Array.from(document.querySelectorAll('button[role="tab"]'));
2200            const clustersTab = tabs.find(tab => tab.textContent.trim() === 'Кластеры');
2201            if (!clustersTab) {
2202                console.error('Вкладка "Кластеры" не найдена');
2203                showStatus('⚠️ Вкладка "Кластеры" не найдена', true);
2204                return;
2205            }
2206
2207            clustersTab.click();
2208            console.log('Клик на "Кластеры" выполнен');
2209            await wait(1000);
2210            
2211            // Ждем загрузки кластеров
2212            let loadingAttempts = 0;
2213            while (loadingAttempts < 10) {
2214                const skeleton = document.querySelector('.MuiSkeleton-root');
2215                if (!skeleton) {
2216                    console.log('Кластеры загружены');
2217                    break;
2218                }
2219                console.log(`Ожидание загрузки кластеров, попытка ${loadingAttempts + 1}`);
2220                await wait(500);
2221                loadingAttempts++;
2222            }
2223            
2224            // СНАЧАЛА применяем обычную стратегию ко ВСЕМ кластерам
2225            showStatus('Применение обычной стратегии ко всем кластерам...');
2226            console.log('Шаг 1: Применяем обычную стратегию ко всем кластерам');
2227            
2228            // Выделяем отфильтрованные кластеры
2229            showStatus('Выделение отфильтрованных кластеров...');
2230            
2231            // Находим правильный чекбокс для выделения всех кластеров
2232            const selectAllCheckbox2 = document.querySelector('.css-9nib29 input.PrivateSwitchBase-input.css-j8yymo');
2233            
2234            if (!selectAllCheckbox2) {
2235                console.error('Checkbox для выделения всех кластеров не найден');
2236                return;
2237            }
2238
2239            selectAllCheckbox2.click();
2240            console.log('Клик на checkbox для выделения всех кластеров выполнен');
2241            await wait(1000);
2242            
2243            // Открываем меню "Действия"
2244            showStatus('Открытие меню действий...');
2245            console.log('Ищем кнопку "Действия"...');
2246            const actionsButton = document.querySelector('.css-1rll63h');
2247            if (!actionsButton) {
2248                console.error('Кнопка "Действия" не найдена');
2249                showStatus('⚠️ Кнопка "Действия" не найдена', true);
2250                return;
2251            }
2252
2253            console.log('Кнопка "Действия" найдена, кликаем...');
2254            actionsButton.click();
2255            console.log('Клик на "Действия" выполнен');
2256            await wait(300);
2257            
2258            // Кликаем на "Управление"
2259            showStatus('Открытие управления...');
2260            console.log('Ищем кнопку "Управление"...');
2261            const managementButtons = document.querySelectorAll('.css-86fwf5');
2262            console.log(`Найдено кнопок управления: ${managementButtons.length}`);
2263            
2264            let managementButton = null;
2265            for (const btn of managementButtons) {
2266                if (btn.textContent.includes('Управление')) {
2267                    managementButton = btn;
2268                    break;
2269                }
2270            }
2271            
2272            if (!managementButton) {
2273                console.error('Кнопка "Управление" не найдена');
2274                showStatus('⚠️ Кнопка "Управление" не найдена', true);
2275                return;
2276            }
2277
2278            console.log('Кликаем на кнопку "Управление"...');
2279            managementButton.click();
2280            console.log('Клик на "Управление" выполнен');
2281            await wait(300);
2282            
2283            // Кликаем на "Стратегия"
2284            showStatus('Открытие стратегии кластеров...');
2285            console.log('Ищем вкладку "Стратегия"...');
2286            const strategyTabs = document.querySelectorAll('.css-euoluq');
2287            console.log(`Найдено вкладок стратегии: ${strategyTabs.length}`);
2288            if (strategyTabs.length < 3) {
2289                console.error('Вкладка "Стратегия" не найдена');
2290                showStatus('⚠️ Вкладка "Стратегия" не найдена', true);
2291                return;
2292            }
2293
2294            console.log('Кликаем на третью вкладку "Стратегия"...');
2295            strategyTabs[2].click();
2296            console.log('Клик на "Стратегия" выполнен');
2297            await wait(300);
2298            
2299            // Вставляем ОБЫЧНУЮ стратегию для всех кластеров
2300            showStatus('Вставка обычной стратегии для всех кластеров...');
2301            
2302            // Ищем ВСЕ кнопки и фильтруем по тексту
2303            const allButtonsForCluster = document.querySelectorAll('button');
2304            const insertStrategyButtons = [];
2305            
2306            for (const btn of allButtonsForCluster) {
2307                if (btn.textContent.includes('Вставить стратегию')) {
2308                    insertStrategyButtons.push(btn);
2309                }
2310            }
2311            
2312            console.log(`Найдено кнопок "Вставить стратегию" для кластеров: ${insertStrategyButtons.length}`);
2313            
2314            // Берем вторую кнопку (индекс 1)
2315            let clusterInsertButton = null;
2316            if (insertStrategyButtons.length >= 2) {
2317                clusterInsertButton = insertStrategyButtons[1];
2318                console.log('Используем вторую кнопку "Вставить стратегию" для кластеров');
2319            } else if (insertStrategyButtons.length === 1) {
2320                clusterInsertButton = insertStrategyButtons[0];
2321                console.log('Найдена только одна кнопка, используем её');
2322            }
2323            
2324            if (!clusterInsertButton) {
2325                console.error('Кнопка "Вставить стратегию" для кластеров не найдена');
2326                showStatus('⚠️ Кнопка вставки стратегии не найдена', true);
2327                return;
2328            }
2329
2330            // Получаем ОБЫЧНУЮ кластерную стратегию
2331            const currentClusterStrategyCode = await getCurrentClusterStrategy();
2332            console.log('Используем обычную кластерную стратегию, длина:', currentClusterStrategyCode.length);
2333            
2334            // Копируем стратегию в буфер обмена
2335            try {
2336                await navigator.clipboard.writeText(currentClusterStrategyCode);
2337                console.log('✓ Обычная кластерная стратегия скопирована');
2338            } catch {
2339                await GM.setClipboard(currentClusterStrategyCode);
2340                console.log('✓ Обычная кластерная стратегия скопирована через GM');
2341            }
2342            
2343            await wait(500);
2344            
2345            clusterInsertButton.click();
2346            console.log('Клик на "Вставить стратегию" для всех кластеров выполнен');
2347            await wait(1000);
2348            
2349            // Находим поле для ввода ставки
2350            const clusterInputLabels = Array.from(document.querySelectorAll('.MuiInputLabel-root'));
2351            let clusterTargetInput = null;
2352        
2353            // Ищем второй input с меткой "Желаемое значение За корзину"
2354            let foundInputs = [];
2355            for (const label of clusterInputLabels) {
2356                const labelText = label.textContent.trim();
2357                if (labelText.includes('Желаемое значение За корзину')) {
2358                    const inputId = label.getAttribute('for');
2359                    if (inputId) {
2360                        const input = document.getElementById(inputId);
2361                        if (input) {
2362                            foundInputs.push(input);
2363                            console.log(`Найдено поле для кластеров: ${labelText}, id: ${inputId}`);
2364                        }
2365                    }
2366                }
2367            }
2368        
2369            // Берем второй найденный input (индекс 1)
2370            if (foundInputs.length >= 2) {
2371                clusterTargetInput = foundInputs[1];
2372                console.log(`Используем второй input для кластеров: ${clusterTargetInput.id}`);
2373            } else if (foundInputs.length === 1) {
2374                clusterTargetInput = foundInputs[0];
2375                console.log(`Найден только один input, используем его: ${clusterTargetInput.id}`);
2376            }
2377
2378            if (clusterTargetInput) {
2379                clusterTargetInput.focus();
2380                clusterTargetInput.value = cartCostRounded.toString();
2381                clusterTargetInput.dispatchEvent(new Event('input', { bubbles: true }));
2382                clusterTargetInput.dispatchEvent(new Event('change', { bubbles: true }));
2383                console.log(`Значение ${cartCostRounded} установлено для всех кластеров в поле ${clusterTargetInput.id}`);
2384                await wait(500);
2385            }
2386            
2387            // Нажимаем "Применить"
2388            showStatus('Применение обычной стратегии ко всем кластерам...');
2389            const clusterStrategyApplyButtons = document.querySelectorAll('.css-eqlbov');
2390            if (clusterStrategyApplyButtons.length >= 2) {
2391                clusterStrategyApplyButtons[1].click();
2392                console.log('Клик на "Применить" обычную стратегию выполнен');
2393                await wait(1000);
2394                
2395                // Закрываем модальное окно
2396                const closeModalButtons = document.querySelectorAll('button[aria-label="Close"]');
2397                if (closeModalButtons.length > 0) {
2398                    closeModalButtons[closeModalButtons.length - 1].click();
2399                    console.log('Модальное окно закрыто');
2400                    await wait(1000); // Ждем после закрытия модального окна, выделение снимется автоматически
2401                }
2402            }
2403            
2404            // ЗАТЕМ, если включен чекбокс "Удержание места", применяем фильтры
2405            if (shouldApplyHoldPosition) {
2406                console.log('Шаг 2: Применяем фильтры и стратегию удержания места');
2407                await applyHoldPositionToFilteredClusters(cartCostRounded);
2408            }
2409            
2410            // Работаем с автофильтрами
2411            await applyAutofilters();
2412
2413            showStatus(`✅ Полностью готово! Стоимость корзины: ${cartCostRounded}`);
2414
2415            // Проверяем, идет ли массовая обработка
2416            const savedDRR = await GM.getValue('bulkProcessingDRR', null);
2417            if (savedDRR !== null) {
2418                console.log('Массовая обработка: переход к следующей кампании');
2419                
2420                // Обновляем счетчик ПЕРЕД переходом
2421                const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
2422                const nextIndex = currentIndex + 1;
2423                await GM.setValue('bulkCurrentIndex', nextIndex);
2424                console.log(`✅ Кампания ${nextIndex} обработана успешно`);
2425                
2426                await wait(2000);
2427                
2428                const campaignsJson = await GM.getValue('bulkCampaigns', null);
2429                const totalCampaigns = await GM.getValue('bulkTotalCampaigns', 0);
2430                
2431                if (campaignsJson) {
2432                    const campaigns = JSON.parse(campaignsJson);
2433                    
2434                    console.log(`Обработано кампаний: ${nextIndex} из ${totalCampaigns}`);
2435                    
2436                    if (nextIndex < campaigns.length) {
2437                        console.log(`Переходим к кампании ${nextIndex + 1}: ${campaigns[nextIndex]}`);
2438                        // Просто перенаправляем текущую вкладку на следующую кампанию
2439                        window.location.href = campaigns[nextIndex];
2440                    } else {
2441                        console.log('Все кампании обработаны');
2442                        await GM.deleteValue('bulkProcessingDRR');
2443                        await GM.deleteValue('bulkCampaigns');
2444                        await GM.deleteValue('bulkCurrentIndex');
2445                        await GM.deleteValue('bulkTotalCampaigns');
2446                        
2447                        showStatus('✅ Все кампании обработаны!');
2448                        alert('✅ Все кампании обработаны!');
2449                    }
2450                }
2451            }
2452
2453        } catch (error) {
2454            console.error('Ошибка при выполнении стратегии:', error);
2455            showStatus(`Ошибка: ${error.message}`, true);
2456            await handleStrategyError();
2457        }
2458    }
2459
2460    // Функция для применения стратегии удержания места к отфильтрованным кластерам
2461    async function applyHoldPositionToFilteredClusters(cartCostRounded) {
2462        showStatus('Настройка фильтра "Удержание места"...');
2463        await wait(1500);
2464        
2465        // Выбираем дату "За 7 дней"
2466        showStatus('Выбор даты "За 7 дней"...');
2467        const jt7z00Elements = document.querySelectorAll('.css-jt7z00');
2468        
2469        if (jt7z00Elements.length >= 6) {
2470            const clusterIntervalInput = jt7z00Elements[5];
2471            Object.defineProperty(clusterIntervalInput, 'readOnly', { value: false, writable: true });
2472            clusterIntervalInput.focus();
2473            clusterIntervalInput.dispatchEvent(new Event('focusin', { bubbles: true }));
2474            clusterIntervalInput.click();
2475            
2476            await wait(2000);
2477            
2478            const dateButtons = document.querySelectorAll('.css-ghy8jd');
2479            if (dateButtons.length >= 2) {
2480                dateButtons[1].click();
2481                console.log('Клик на "За 7 дней" выполнен');
2482                await wait(1000);
2483                
2484                const applyDateButtons = document.querySelectorAll('.css-7wa720');
2485                if (applyDateButtons.length > 0) {
2486                    applyDateButtons[0].click();
2487                    console.log('Клик на "Применить" дату выполнен');
2488                    await wait(1500);
2489                }
2490            }
2491        }
2492        
2493        // Открываем фильтры
2494        const filtersButton = document.querySelector('.css-a54mx2');
2495        if (!filtersButton) {
2496            console.error('Кнопка "Фильтры" не найдена');
2497            return;
2498        }
2499
2500        filtersButton.click();
2501        console.log('Клик на "Фильтры" выполнен');
2502        await wait(1500);
2503        
2504        // Добавляем фильтр
2505        const addFilterButtons = document.querySelectorAll('.css-8h18y2');
2506        if (addFilterButtons.length < 2) {
2507            console.error('Кнопка "Добавить фильтр" не найдена');
2508            return;
2509        }
2510
2511        addFilterButtons[1].click();
2512        console.log('Клик на "Добавить фильтр" выполнен');
2513        await wait(1500);
2514        
2515        // Выбираем "Среднее место в выдаче"
2516        const filterOptions = document.querySelectorAll('.css-1ytbthu');
2517        if (filterOptions.length < 8) {
2518            console.error('Опция "Среднее место в выдаче" не найдена');
2519            return;
2520        }
2521
2522        filterOptions[8].click();
2523        console.log('Клик на "Среднее место в выдаче" выполнен');
2524        await wait(1500);
2525        
2526        // Очищаем фильтр
2527        const allInputsWithVse = document.querySelectorAll('input[value="Все"]');
2528        let avgPositionInput = allInputsWithVse.length >= 2 ? allInputsWithVse[1] : allInputsWithVse[0];
2529        
2530        if (!avgPositionInput) {
2531            console.error('Input "Среднее место в выдаче" не найден');
2532            return;
2533        }
2534
2535        const inputContainer = avgPositionInput.closest('.MuiInputBase-root');
2536        const clearButton = inputContainer?.querySelector('button');
2537        
2538        if (!clearButton) {
2539            console.error('Кнопка очистки не найдена');
2540            return;
2541        }
2542
2543        clearButton.click();
2544        console.log('Клик на кнопку очистки выполнен');
2545        await wait(1500);
2546        
2547        // Выбираем "Между"
2548        const hiddenInputsForComparison = document.querySelectorAll('input.MuiSelect-nativeInput');
2549        let comparisonContainer = null;
2550        
2551        for (const inp of hiddenInputsForComparison) {
2552            const container = inp.closest('.MuiFormControl-root');
2553            const label = container?.querySelector('label');
2554            if (label && label.textContent.includes('Сравнение')) {
2555                comparisonContainer = container;
2556                break;
2557            }
2558        }
2559        
2560        if (!comparisonContainer) {
2561            console.error('Контейнер "Сравнение" не найден');
2562            return;
2563        }
2564
2565        const arrowButton = comparisonContainer.querySelector('button');
2566        if (!arrowButton) {
2567            console.error('Кнопка со стрелкой не найдена');
2568            return;
2569        }
2570
2571        arrowButton.click();
2572        console.log('Клик на кнопку со стрелкой выполнен');
2573        await wait(1000);
2574        
2575        // Выбираем "Между"
2576        const options = document.querySelectorAll('[role="option"]');
2577        const betweenOption = Array.from(options).find(opt => opt.textContent.trim() === 'Между');
2578        
2579        if (!betweenOption) {
2580            console.error('Опция "Между" не найдена');
2581            return;
2582        }
2583
2584        betweenOption.click();
2585        console.log('Клик на "Между" выполнен');
2586        await wait(1500);
2587        
2588        // Устанавливаем значения "от" и "до"
2589        const allLabels = document.querySelectorAll('label');
2590        let fromInput = null;
2591        let toInput = null;
2592        
2593        for (const label of allLabels) {
2594            const text = label.textContent.trim();
2595            if (text === 'Значение от') {
2596                const inputId = label.getAttribute('for');
2597                if (inputId) {
2598                    fromInput = document.getElementById(inputId);
2599                }
2600            } else if (text === 'Значение до') {
2601                const inputId = label.getAttribute('for');
2602                if (inputId) {
2603                    toInput = document.getElementById(inputId);
2604                }
2605            }
2606        }
2607        
2608        if (!fromInput || !toInput) {
2609            console.error('Поля "от" и "до" не найдены');
2610            return;
2611        }
2612
2613        // Устанавливаем "от" = 1
2614        fromInput.focus();
2615        fromInput.value = '1';
2616        fromInput.dispatchEvent(new Event('input', { bubbles: true }));
2617        fromInput.dispatchEvent(new Event('change', { bubbles: true }));
2618        console.log('Установлено значение "от" = 1');
2619        await wait(500);
2620        
2621        // Устанавливаем "до" = 4
2622        toInput.focus();
2623        toInput.value = '4';
2624        toInput.dispatchEvent(new Event('input', { bubbles: true }));
2625        toInput.dispatchEvent(new Event('change', { bubbles: true }));
2626        console.log('Установлено значение "до" = 4');
2627        await wait(1000);
2628        
2629        // Выделяем отфильтрованные кластеры
2630        showStatus('Выделение отфильтрованных кластеров...');
2631        
2632        // Находим правильный чекбокс для выделения всех кластеров
2633        const selectAllCheckbox2 = document.querySelector('.css-9nib29 input.PrivateSwitchBase-input.css-j8yymo');
2634        
2635        if (!selectAllCheckbox2) {
2636            console.error('Checkbox для выделения всех кластеров не найден');
2637            return;
2638        }
2639
2640        selectAllCheckbox2.click();
2641        console.log('Клик на checkbox для выделения всех кластеров выполнен');
2642        await wait(1000);
2643        
2644        // Открываем меню "Действия"
2645        showStatus('Открытие меню действий для отфильтрованных кластеров...');
2646        const actionsButton2 = document.querySelector('.css-1rll63h');
2647        if (!actionsButton2) {
2648            console.error('Кнопка "Действия" не найдена');
2649            return;
2650        }
2651
2652        actionsButton2.click();
2653        await wait(300);
2654        
2655        // Кликаем на "Управление"
2656        showStatus('Открытие управления...');
2657        console.log('Ищем кнопку "Управление"...');
2658        const managementButtons2 = document.querySelectorAll('.css-86fwf5');
2659        console.log(`Найдено кнопок управления: ${managementButtons2.length}`);
2660        if (managementButtons2.length < 2) {
2661            console.error('Кнопка "Управление" не найдена');
2662            showStatus('⚠️ Кнопка "Управление" не найдена', true);
2663            return;
2664        }
2665
2666        console.log('Кликаем на вторую кнопку "Управление"...');
2667        managementButtons2[1].click();
2668        console.log('Клик на "Управление" выполнен');
2669        await wait(300);
2670        
2671        // Кликаем на "Стратегия"
2672        showStatus('Открытие стратегии кластеров...');
2673        console.log('Ищем вкладку "Стратегия"...');
2674        const strategyTabs2 = document.querySelectorAll('.css-euoluq');
2675        console.log(`Найдено вкладок стратегии: ${strategyTabs2.length}`);
2676        if (strategyTabs2.length < 3) {
2677            console.error('Вкладка "Стратегия" не найдена');
2678            showStatus('⚠️ Вкладка "Стратегия" не найдена', true);
2679            return;
2680        }
2681
2682        console.log('Кликаем на третью вкладку "Стратегия"...');
2683        strategyTabs2[2].click();
2684        console.log('Клик на "Стратегия" выполнен');
2685        await wait(300);
2686        
2687        // Вставляем стратегию УДЕРЖАНИЯ МЕСТА
2688        showStatus('Вставка стратегии удержания места...');
2689        
2690        // Ищем ВСЕ кнопки и фильтруем по тексту
2691        const allButtonsForHoldPosition = document.querySelectorAll('button');
2692        const insertStrategyButtons2 = [];
2693        
2694        for (const btn of allButtonsForHoldPosition) {
2695            if (btn.textContent.includes('Вставить стратегию')) {
2696                insertStrategyButtons2.push(btn);
2697            }
2698        }
2699        
2700        console.log(`Найдено кнопок "Вставить стратегию" для удержания места: ${insertStrategyButtons2.length}`);
2701        
2702        // Берем вторую кнопку (индекс 1)
2703        let clusterInsertButton2 = null;
2704        if (insertStrategyButtons2.length >= 2) {
2705            clusterInsertButton2 = insertStrategyButtons2[1];
2706            console.log('Используем вторую кнопку "Вставить стратегию" для отфильтрованных кластеров');
2707        } else if (insertStrategyButtons2.length === 1) {
2708            clusterInsertButton2 = insertStrategyButtons2[0];
2709            console.log('Найдена только одна кнопка, используем её');
2710        }
2711        
2712        if (!clusterInsertButton2) {
2713            console.error('Кнопка "Вставить стратегию" для отфильтрованных кластеров не найдена');
2714            return;
2715        }
2716
2717        // Получаем стратегию УДЕРЖАНИЯ МЕСТА
2718        const holdPositionClusterStrategyCode = await getHoldPositionClusterStrategy();
2719        console.log('Используем стратегию удержания места, длина:', holdPositionClusterStrategyCode.length);
2720        
2721        try {
2722            await navigator.clipboard.writeText(holdPositionClusterStrategyCode);
2723            console.log('✓ Стратегия удержания места скопирована');
2724        } catch {
2725            await GM.setClipboard(holdPositionClusterStrategyCode);
2726            console.log('✓ Стратегия удержания места скопирована через GM');
2727        }
2728        
2729        await wait(500);
2730        
2731        clusterInsertButton2.click();
2732        console.log('Клик на "Вставить стратегию" удержания места выполнен');
2733        await wait(1000);
2734        
2735        // Находим поле для ввода ставки
2736        const clusterInputLabels2 = Array.from(document.querySelectorAll('.MuiInputLabel-root'));
2737        let clusterTargetInput2 = null;
2738        
2739        // Ищем второй input с меткой "Желаемое значение За корзину"
2740        let foundInputs2 = [];
2741        for (const label of clusterInputLabels2) {
2742            const labelText = label.textContent.trim();
2743            if (labelText.includes('Желаемое значение За корзину')) {
2744                const inputId = label.getAttribute('for');
2745                if (inputId) {
2746                    const input = document.getElementById(inputId);
2747                    if (input) {
2748                        foundInputs2.push(input);
2749                        console.log(`Найдено поле для отфильтрованных кластеров: ${labelText}, id: ${inputId}`);
2750                    }
2751                }
2752            }
2753        }
2754        
2755        // Берем второй найденный input (индекс 1)
2756        if (foundInputs2.length >= 2) {
2757            clusterTargetInput2 = foundInputs2[1];
2758            console.log(`Используем второй input для отфильтрованных кластеров: ${clusterTargetInput2.id}`);
2759        } else if (foundInputs2.length === 1) {
2760            clusterTargetInput2 = foundInputs2[0];
2761            console.log(`Найден только один input, используем его: ${clusterTargetInput2.id}`);
2762        }
2763
2764        if (!clusterTargetInput2) {
2765            const clusterInputs2 = document.querySelectorAll('input[type="number"]');
2766            for (const input of clusterInputs2) {
2767                const name = input.getAttribute('name') || '';
2768                if (name.includes('CostPerAddedToCart') || name.includes('value')) {
2769                    clusterTargetInput2 = input;
2770                    break;
2771                }
2772            }
2773        }
2774        
2775        if (clusterTargetInput2) {
2776            clusterTargetInput2.focus();
2777            clusterTargetInput2.value = cartCostRounded.toString();
2778            clusterTargetInput2.dispatchEvent(new Event('input', { bubbles: true }));
2779            clusterTargetInput2.dispatchEvent(new Event('change', { bubbles: true }));
2780            console.log(`Значение ${cartCostRounded} установлено для отфильтрованных кластеров в поле ${clusterTargetInput2.id}`);
2781            await wait(500);
2782        }
2783        
2784        // Нажимаем "Применить"
2785        showStatus('Применение стратегии удержания места...');
2786        const clusterStrategyApplyButtons2 = document.querySelectorAll('.css-eqlbov');
2787        if (clusterStrategyApplyButtons2.length >= 2) {
2788            clusterStrategyApplyButtons2[1].click();
2789            console.log('Клик на "Применить" стратегию удержания места выполнен');
2790            await wait(1000);
2791            
2792            // Нажимаем "Сохранить"
2793            showStatus('Сохранение стратегии удержания места...');
2794            const saveButton = document.querySelector('.css-tn31lt');
2795            if (saveButton && saveButton.textContent.trim() === 'Сохранить') {
2796                saveButton.click();
2797                console.log('Клик на "Сохранить" стратегию удержания места выполнен');
2798                await wait(1000);
2799            } else {
2800                console.error('Кнопка "Сохранить" для стратегии удержания места не найдена');
2801            }
2802            
2803            // Закрываем модальное окно
2804            const closeModalButtons2 = document.querySelectorAll('button[aria-label="Close"]');
2805            if (closeModalButtons2.length > 0) {
2806                closeModalButtons2[closeModalButtons2.length - 1].click();
2807                console.log('Модальное окно закрыто');
2808                await wait(1000);
2809            }
2810        }
2811    }
2812
2813    // Функция для применения автофильтров
2814    async function applyAutofilters() {
2815        showStatus('Открытие автофильтров...');
2816        
2817        const autofilterAccordion = document.getElementById('bidder-constructor');
2818        if (!autofilterAccordion) {
2819            console.error('Аккордеон "Автофильтры" не найден');
2820            return;
2821        }
2822
2823        const accordionButton = autofilterAccordion.querySelector('button[aria-expanded]');
2824        const isExpanded = accordionButton && accordionButton.getAttribute('aria-expanded') === 'true';
2825        
2826        if (!isExpanded && accordionButton) {
2827            accordionButton.click();
2828            console.log('Аккордеон "Автофильтры" раскрыт');
2829            await wait(1000);
2830        }
2831        
2832        // Кликаем на "Шаблоны"
2833        showStatus('Открытие шаблонов...');
2834        const templatesButtons = autofilterAccordion.querySelectorAll('button');
2835        let templateButton = null;
2836        
2837        for (const btn of templatesButtons) {
2838            if (btn.textContent.trim() === 'Шаблоны') {
2839                templateButton = btn;
2840                break;
2841            }
2842        }
2843        
2844        if (!templateButton) {
2845            console.error('Кнопка "Шаблоны" не найдена');
2846            return;
2847        }
2848
2849        templateButton.click();
2850        console.log('Кнопка "Шаблоны" выбрана');
2851        await wait(500);
2852        
2853        // Выбираем "Расширение"
2854        showStatus('Выбор шаблона "Расширение"...');
2855        const allElements = document.querySelectorAll('div, button, span, p');
2856        let extensionTemplate = null;
2857        
2858        for (const el of allElements) {
2859            const text = el.textContent.trim();
2860            if (text === 'Расширение') {
2861                extensionTemplate = el;
2862                break;
2863            }
2864        }
2865        
2866        if (!extensionTemplate) {
2867            console.error('Шаблон "Расширение" не найден');
2868            return;
2869        }
2870
2871        extensionTemplate.click();
2872        console.log('Шаблон "Расширение" выбран');
2873        await wait(500);
2874        
2875        // Сохраняем
2876        showStatus('Сохранение автофильтров...');
2877        const saveButtonsAfterTemplate = document.querySelectorAll('button');
2878        let saveAutofilterButton = null;
2879        
2880        for (const btn of saveButtonsAfterTemplate) {
2881            if (btn.textContent.trim() === 'Сохранить') {
2882                saveAutofilterButton = btn;
2883                break;
2884            }
2885        }
2886        
2887        if (!saveAutofilterButton) {
2888            console.error('Кнопка "Сохранить" не найдена');
2889            return;
2890        }
2891
2892        saveAutofilterButton.click();
2893        console.log('Клик на "Сохранить" автофильтры выполнен');
2894        await wait(1000);
2895        
2896        // Применяем автофильтры вручную
2897        showStatus('Применение автофильтров вручную...');
2898        const applyButtonsAfterSave = document.querySelectorAll('button');
2899        let applyAutofilterButton = null;
2900        
2901        for (const btn of applyButtonsAfterSave) {
2902            if (btn.textContent.trim() === 'Применить автофильтры вручную') {
2903                applyAutofilterButton = btn;
2904                break;
2905            }
2906        }
2907        
2908        if (!applyAutofilterButton) {
2909            console.error('Кнопка "Применить автофильтры вручную" не найдена');
2910            return;
2911        }
2912
2913        applyAutofilterButton.click();
2914        console.log('Клик на "Применить автофильтры вручную" выполнен');
2915        await wait(1000);
2916    }
2917
2918    // Функция для обработки ошибок и перехода к следующей кампании
2919    async function handleStrategyError() {
2920        const savedDRR = await GM.getValue('bulkProcessingDRR', null);
2921        if (savedDRR !== null) {
2922            console.log('Обнаружена ошибка при массовой обработке, ждем 10 секунд');
2923            showStatus('⚠️ Ошибка! Переход к следующей кампании через 10 секунд...', true);
2924            
2925            for (let i = 10; i > 0; i--) {
2926                showStatus(`⚠️ Ошибка! Переход к следующей через ${i} сек...`, true);
2927                await wait(1000);
2928            }
2929            
2930            const campaignsJson = await GM.getValue('bulkCampaigns', null);
2931            const currentIndex = await GM.getValue('bulkCurrentIndex', 0);
2932            const totalCampaigns = await GM.getValue('bulkTotalCampaigns', 0);
2933            
2934            if (campaignsJson) {
2935                const campaigns = JSON.parse(campaignsJson);
2936                const nextIndex = currentIndex + 1;
2937                
2938                console.log(`Обработано кампаний: ${nextIndex} из ${totalCampaigns}`);
2939                
2940                if (nextIndex < campaigns.length) {
2941                    await GM.setValue('bulkCurrentIndex', nextIndex);
2942                    console.log(`Переходим к кампании ${nextIndex + 1}: ${campaigns[nextIndex]}`);
2943                    // Просто перенаправляем текущую вкладку на следующую кампанию
2944                    window.location.href = campaigns[nextIndex];
2945                } else {
2946                    console.log('Все кампании обработаны');
2947                    await GM.deleteValue('bulkProcessingDRR');
2948                    await GM.deleteValue('bulkCampaigns');
2949                    await GM.deleteValue('bulkCurrentIndex');
2950                    await GM.deleteValue('bulkTotalCampaigns');
2951                    
2952                    showStatus('✅ Все кампании обработаны!');
2953                    alert('✅ Все кампании обработаны!');
2954                }
2955            }
2956        }
2957    }
2958
2959    // Инициализация
2960    function init() {
2961        console.log('Инициализация расширения');
2962        
2963        if (window.location.href.includes('/advert/campaigns')) {
2964            console.log('Страница списка кампаний обнаружена');
2965            setTimeout(() => {
2966                if (document.body) {
2967                    createBulkUI();
2968                } else {
2969                    console.error('Body не найден');
2970                }
2971            }, 1000);
2972        } else if (window.location.href.includes('/campaigns/auto-campaigns/') && window.location.href.includes('/campaign')) {
2973            console.log('Страница кампании обнаружена');
2974            setTimeout(() => {
2975                if (document.body) {
2976                    createUI();
2977                } else {
2978                    console.error('Body не найден');
2979                }
2980            }, 1000);
2981        } else {
2982            console.log('Не на странице кампании, UI не создается');
2983        }
2984    }
2985
2986    // Запускаем инициализацию
2987    init();
2988
2989})();
MP Manager WB Cluster Auto Strategy Setter | Robomonkey