Рассчитывает цену за корзину (расход / в корзину) и отображает результат
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})();