Ozon: Калькулятор цены за корзину

Рассчитывает цену за корзину (расход / в корзину) и отображает результат

Size

9.4 KB

Version

1.1.3

Created

Mar 24, 2026

Updated

22 days ago

1// ==UserScript==
2// @name		Ozon: Калькулятор цены за корзину
3// @description		Рассчитывает цену за корзину (расход / в корзину) и отображает результат
4// @version		1.1.3
5// @match		https://*.seller.ozon.ru/*
6// @icon		https://st.ozone.ru/s3/seller-ui-static/icon/favicon32.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Ozon: Калькулятор цены за корзину - запущен');
12
13    // Функция для извлечения числа из текста
14    function extractNumber(text) {
15        if (!text) return 0;
16        // Убираем все кроме цифр, запятых и точек
17        const cleaned = text.replace(/[^\d.,]/g, '').replace(',', '.');
18        const number = parseFloat(cleaned);
19        return isNaN(number) ? 0 : number;
20    }
21
22    // Функция для поиска индекса столбца по названию
23    function findColumnIndex(headerText) {
24        const headers = Array.from(document.querySelectorAll('thead th'));
25        return headers.findIndex(th => {
26            const text = th.textContent.trim();
27            return text.includes(headerText);
28        });
29    }
30
31    // Функция для создания кнопки расчета
32    function createCalculatorButton() {
33        console.log('Создание кнопки калькулятора');
34
35        // Проверяем, не создана ли уже кнопка
36        if (document.getElementById('ozon-calculator-btn')) {
37            console.log('Кнопка уже создана');
38            return;
39        }
40
41        // Ищем заголовок страницы
42        const titleElement = document.querySelector('h1.c7r110-a');
43        if (!titleElement) {
44            console.error('Не найден заголовок страницы');
45            return;
46        }
47
48        const titleContainer = titleElement.closest('.cs5110-a1');
49        if (!titleContainer) {
50            console.error('Не найден контейнер заголовка');
51            return;
52        }
53
54        // Создаем контейнер для кнопки и результата
55        const calculatorContainer = document.createElement('div');
56        calculatorContainer.id = 'ozon-calculator-container';
57        calculatorContainer.style.cssText = 'display: flex; flex-direction: column; gap: 12px; margin-top: 16px;';
58
59        // Создаем кнопку
60        const calcButton = document.createElement('button');
61        calcButton.id = 'ozon-calculator-btn';
62        calcButton.textContent = 'Рассчитать цену за корзину для всех товаров';
63        calcButton.style.cssText = `
64            padding: 10px 20px;
65            background-color: #005bff;
66            color: white;
67            border: none;
68            border-radius: 8px;
69            cursor: pointer;
70            font-size: 14px;
71            font-weight: 500;
72            transition: background-color 0.2s;
73            max-width: 350px;
74        `;
75
76        // Создаем область для результатов
77        const resultDiv = document.createElement('div');
78        resultDiv.id = 'ozon-calculator-result';
79        resultDiv.style.cssText = `
80            padding: 12px 16px;
81            background-color: #f5f5f5;
82            border-radius: 8px;
83            font-size: 14px;
84            color: #333;
85            display: none;
86            max-width: 600px;
87        `;
88
89        // Обработчик наведения
90        calcButton.addEventListener('mouseenter', () => {
91            calcButton.style.backgroundColor = '#0047cc';
92        });
93
94        calcButton.addEventListener('mouseleave', () => {
95            calcButton.style.backgroundColor = '#005bff';
96        });
97
98        // Обработчик клика
99        calcButton.addEventListener('click', () => {
100            console.log('Клик по кнопке расчета');
101            calculateAllProducts(resultDiv);
102        });
103
104        calculatorContainer.appendChild(calcButton);
105        calculatorContainer.appendChild(resultDiv);
106
107        // Добавляем контейнер после заголовка
108        titleContainer.parentNode.insertBefore(calculatorContainer, titleContainer.nextSibling);
109
110        console.log('Кнопка калькулятора создана успешно');
111    }
112
113    // Функция расчета для всех товаров
114    function calculateAllProducts(resultDiv) {
115        console.log('Начало расчета для всех товаров');
116
117        // Находим индексы столбцов "Расход" и "В корзину"
118        const expenseColumnIndex = findColumnIndex('Расход');
119        const cartColumnIndex = findColumnIndex('В корзину');
120
121        console.log('Индекс столбца "Расход":', expenseColumnIndex);
122        console.log('Индекс столбца "В корзину":', cartColumnIndex);
123
124        if (expenseColumnIndex === -1 || cartColumnIndex === -1) {
125            console.error('Не найдены необходимые столбцы');
126            alert('Ошибка: не найдены столбцы "Расход" или "В корзину"');
127            return;
128        }
129
130        // Получаем все строки товаров
131        const rows = document.querySelectorAll('tbody tr.ct5110-c');
132        console.log('Найдено строк товаров:', rows.length);
133
134        if (rows.length === 0) {
135            console.error('Не найдено строк товаров');
136            alert('Ошибка: не найдено товаров на странице');
137            return;
138        }
139
140        let calculatedCount = 0;
141
142        rows.forEach((row, index) => {
143            const cells = row.querySelectorAll('td');
144            
145            if (cells.length <= Math.max(expenseColumnIndex, cartColumnIndex)) {
146                console.warn(`Строка ${index} имеет недостаточно ячеек`);
147                return;
148            }
149
150            // Получаем название товара (обычно во 2-й ячейке - индекс 1)
151            const skuCell = cells[1];
152            const sku = skuCell ? skuCell.textContent.trim().split('\n')[0].substring(0, 20) : `Товар ${index + 1}`;
153
154            // Получаем значение расхода
155            const expenseCell = cells[expenseColumnIndex];
156            const expenseText = expenseCell ? expenseCell.textContent.trim() : '0';
157            const expenseValue = extractNumber(expenseText);
158
159            // Получаем значение "В корзину" - теперь ищем как текст, а не input
160            const cartCell = cells[cartColumnIndex];
161            const cartText = cartCell ? cartCell.textContent.trim() : '0';
162            const cartValue = extractNumber(cartText);
163
164            console.log(`Товар ${index + 1} (SKU: ${sku}): Расход="${expenseText}"=${expenseValue}, В корзину="${cartText}"=${cartValue}`);
165
166            // Рассчитываем цену за корзину
167            if (cartValue > 0) {
168                const pricePerCart = expenseValue / cartValue;
169                
170                // Добавляем результат в ячейку "В корзину"
171                const existingResult = cartCell.querySelector('.ozon-price-result');
172                if (!existingResult) {
173                    const priceDiv = document.createElement('div');
174                    priceDiv.className = 'ozon-price-result';
175                    priceDiv.style.cssText = `
176                        margin-top: 8px;
177                        padding: 6px 8px;
178                        background-color: #e6f7e6;
179                        border-radius: 6px;
180                        font-size: 13px;
181                        font-weight: 600;
182                        color: #28a745;
183                        border: 1px solid #28a745;
184                    `;
185                    priceDiv.textContent = `${pricePerCart.toFixed(2)}`;
186                    cartCell.appendChild(priceDiv);
187                }
188                calculatedCount++;
189            }
190        });
191
192        console.log(`Расчет завершен успешно. Рассчитано товаров: ${calculatedCount}`);
193    }
194
195    // Функция инициализации
196    function init() {
197        console.log('Инициализация расширения');
198
199        // Пробуем создать кнопку сразу
200        setTimeout(() => {
201            createCalculatorButton();
202        }, 1000);
203
204        // Наблюдаем за изменениями DOM на случай динамической загрузки
205        const observer = new MutationObserver(() => {
206            if (!document.getElementById('ozon-calculator-btn')) {
207                const titleElement = document.querySelector('h1.c7r110-a');
208                if (titleElement) {
209                    createCalculatorButton();
210                }
211            }
212        });
213
214        observer.observe(document.body, {
215            childList: true,
216            subtree: true
217        });
218
219        console.log('MutationObserver установлен');
220    }
221
222    // Запускаем после загрузки DOM
223    if (document.readyState === 'loading') {
224        document.addEventListener('DOMContentLoaded', init);
225    } else {
226        init();
227    }
228
229})();