您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Плагин позволяет смотреть время работы банков ЛатАма и создавать напоминания для лидов.
// ==UserScript== // @name CRM_Tool // @version 1.0 // @description Плагин позволяет смотреть время работы банков ЛатАма и создавать напоминания для лидов. // @author Bakesh_Legend322 // @match *://semensemenovv0919.amocrm.ru/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @license MIT // @namespace https://greasyfork.org/ru/scripts/529118 // ==/UserScript== (function() { 'use strict'; console.log('CrmTool: Скрипт запущен'); const GITHUB_VERSION_URL = 'https://raw.githubusercontent.com/PoopSoftWare/Crm_Tool/main/upd'; const GITHUB_SCRIPT_URL = 'https://raw.githubusercontent.com/PoopSoftWare/Crm_Tool/main/crm_tool.js'; const GITHUB_HOLIDAYS_URL = 'https://raw.githubusercontent.com/PoopSoftWare/Crm_Tool/main/holidays.json'; const CURRENT_VERSION = '1.0'; let isRemindersListVisible = false; let holidaysData = { holidays: {}, holidayNames: {} }; // Переменная для хранения данных о праздниках // Стили для интерфейса const styles = ` .crm_tool-container { position: fixed; z-index: 10002; left: 0.6vw; bottom: 25vh; font-family: Arial, sans-serif; transition: all 0.3s ease; display: flex; flex-direction: column; align-items: flex-start; background: rgba(0, 0, 0, 0.1); } .crm_tool-reminder-button, .crm_tool-timer-button { width: 40px; height: 40px; border-radius: 50%; background-color: #4a4a4a; color: white; border: none; font-size: 24px; cursor: pointer; transition: all 0.3s ease; margin: 10px 0; display: flex; align-items: center; justify-content: center; animation: fadeIn 0.5s ease-in-out; } .crm_tool-reminder-button:hover, .crm_tool-timer-button:hover { background-color: #666; transform: scale(1.1); } .crm_tool-reminder-button.active, .crm_tool-timer-button.active { animation: blink 1s infinite; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes blink { 50% { background-color: #ff4444; } } .crm_tool-modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #113c5c; padding: 20px; border-radius: 10px; box-shadow: 0 0 15px rgba(0,0,0,0.2); z-index: 10003; width: 90%; max-width: 500px; animation: slideIn 0.3s ease-out; overflow: hidden; } @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -60%); } to { opacity: 1; transform: translate(-50%, -50%); } } .crm_tool-modal h2 { margin-top: 0; color: #ffffff; text-align: center; } .crm_tool-form { display: flex; flex-direction: column; gap: 10px; } .crm_tool-input { padding: 8px; border: 1px solid #ddd; border-radius: 4px; width: 100%; background-color: #1a4d6e; color: white; box-sizing: border-box; } .crm_tool-button-group { display: flex; justify-content: space-between; gap: 10px; margin-top: 15px; } .crm_tool-submit, .crm_tool-list, .crm_tool-close, .crm_tool-reset { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; transition: all 0.3s ease; flex: 1; font-weight: bold; box-sizing: border-box; } .crm_tool-submit { background-color: #4CAF50; color: white; } .crm_tool-submit:hover { background-color: #45a049; transform: translateY(-2px); } .crm_tool-list, .crm_tool-close, .crm_tool-reset { background-color: #f0f0f0; color: #333; } .crm_tool-list:hover, .crm_tool-close:hover, .crm_tool-reset:hover { background-color: #e0e0e0; transform: translateY(-2px); } .crm_tool-reminders { max-height: 300px; overflow-y: auto; margin-top: 15px; display: none; padding-right: 10px; } .crm_tool-reminder { background-color: #153043; border: 1px solid #ddd; border-radius: 4px; padding: 10px; margin-bottom: 10px; position: relative; transition: all 0.3s ease; } .crm_tool-reminder:hover { background-color: #1e4f70; } .crm_tool-reminder-toggle { cursor: pointer; font-weight: bold; } .crm_tool-reminder-details { display: none; margin-top: 5px; padding-right: 10px; } .crm_tool-reminder button { background-color: #ff4d4d; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; float: right; } .crm_tool-reminder button:hover { background-color: #ff3333; transform: scale(1.1); } .crm_tool-update { position: fixed; bottom: 20px; right: 20px; background-color: #4CAF50; color: white; padding: 10px 20px; border-radius: 4px; cursor: pointer; display: none; transition: all 0.3s ease; } .crm_tool-update:hover { background-color: #45a049; transform: translateY(-2px); } .crm_tool-settings { margin-top: 10px; color: #fff; } #time-widget-container { position: fixed; zIndex: 9999; backgroundColor: #1a2a44; border: 1px solid #ddd; padding: 10px; boxShadow: '0 0 10px rgba(0,0,0,0.1)'; borderRadius: '8px'; resize: both; overflow: auto; transition: all 0.3s ease; left: 70px; min-width: 200px; min-height: 100px; } #time-widget-container h3 { margin: 0 0 10px 0; color: #ffffff; font-size: 1.2em; } #time-widget-container .clock-item:hover { cursor: pointer; background-color: rgba(255, 255, 255, 0.1); } #time-widget-container .holiday-notice { color: #ff69b4; font-style: italic; margin-top: 5px; } .crm_tool-country-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #1a2a44; border: 1px solid #ddd; border-radius: 8px; padding: 15px; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 10005; display: none; color: white; max-height: 80vh; overflow-y: auto; } .crm_tool-country-modal h3 { margin: 0 0 10px 0; color: #ffffff; } .crm_tool-country-modal select { width: 100%; padding: 5px; margin-bottom: 10px; background-color: #4a4a4a; color: white; border: 1px solid #ddd; border-radius: 4px; } .crm_tool-country-modal button { padding: 5px 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 5px; } .crm_tool-country-modal button:hover { background-color: #45a049; } /* Стили для кастомного меню */ .crm_tool-timer-menu { position: fixed; background-color: #1a2a44; border: 1px solid #ddd; border-radius: 4px; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 10004; display: none; flex-direction: column; padding: 5px; width: 200px; } .crm_tool-timer-menu button { background-color: #4a4a4a; color: white; border: none; padding: 8px 12px; text-align: left; cursor: pointer; transition: background-color 0.3s ease; border-radius: 4px; margin: 2px 0; } .crm_tool-timer-menu button:hover { background-color: #666; } @media (max-width: 600px) { .crm_tool-container { left: 5px; } .crm_tool-reminder-button, .crm_tool-timer-button { width: 35px; height: 35px; font-size: 20px; } .crm_tool-modal { width: 95%; } .crm_tool-button-group { flex-direction: column; } .crm_tool-submit, .crm_tool-list, .crm_tool-close, .crm_tool-reset { width: 100%; } #time-widget-container { left: 50px; } .crm_tool-timer-menu { width: 150px; } } @media (max-height: 720px) { .crm_tool-container { bottom: 8vh; } #time-widget-container { top: 8vh; } } @media (max-height: 1080px) { .crm_tool-container { bottom: 8vh; } #time-widget-container { top: 8vh; } } @media (min-height: 1440px) { .crm_tool-container { bottom: 8vh; } #time-widget-container { top: 15vh; } } `; // Добавляем стили const styleElement = document.createElement('style'); styleElement.textContent = styles; document.head.appendChild(styleElement); // Создаем общий контейнер для кнопок const container = document.createElement('div'); container.className = 'crm_tool-container'; document.body.appendChild(container); console.log('Контейнер создан:', container); // Кнопка напоминаний const reminderButton = document.createElement('button'); reminderButton.className = 'crm_tool-reminder-button'; reminderButton.textContent = '+'; container.appendChild(reminderButton); console.log('Кнопка напоминаний добавлена:', reminderButton); // Кнопка таймера const timerButton = document.createElement('button'); timerButton.className = 'crm_tool-timer-button'; timerButton.innerHTML = ` <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="10" stroke="white" stroke-width="2"/> <line x1="12" y1="12" x2="16" y2="8" stroke="white" stroke-width="2"/> <line x1="12" y1="12" x2="12" y2="16" stroke="white" stroke-width="2"/> </svg> `; container.appendChild(timerButton); console.log('Кнопка таймера добавлена:', timerButton); // Создаем кастомное меню для выбора типа окна const timerMenu = document.createElement('div'); timerMenu.className = 'crm_tool-timer-menu'; timerMenu.innerHTML = ` <button class="crm_tool-timer-window">Открыть в новом окне</button> <button class="crm_tool-timer-panel">Открыть как виджет</button> `; document.body.appendChild(timerMenu); // Добавляем в body, чтобы позиционирование было фиксированным const modal = document.createElement('div'); modal.className = 'crm_tool-modal'; modal.innerHTML = ` <h2>Добавить напоминание</h2> <form class="crm_tool-form"> <input type="text" id="clientId" class="crm_tool-input" placeholder="ID Лида (опционально)"> <input type="text" id="leadLink" class="crm_tool-input" placeholder="Ссылка на лида (опционально)"> <input type="text" id="reminderText" class="crm_tool-input" placeholder="Текст напоминания" required> <input type="number" id="reminderHours" class="crm_tool-input" placeholder="Через сколько часов" min="0"> <input type="number" id="reminderMinutes" class="crm_tool-input" placeholder="Через сколько минут" min="0"> <div class="crm_tool-settings"> <label><input type="checkbox" id="openLink"> Открывать ссылку на лида после таймера</label> <select id="notificationSound" class="crm_tool-input"> <option value="https://www.soundjay.com/buttons/sounds/button-7.mp3">Стандартный</option> <option value="https://www.soundjay.com/buttons/beep-01a.mp3">Бип</option> <option value="https://www.soundjay.com/buttons/button-09.mp3">Клик</option> </select> </div> <div class="crm_tool-button-group"> <button type="button" class="crm_tool-submit">Сохранить</button> <button type="button" class="crm_tool-list">Список напоминаний</button> <button type="button" class="crm_tool-reset">Сбросить все</button> <button type="button" class="crm_tool-close">Закрыть</button> </div> </form> <div class="crm_tool-reminders"></div> `; document.body.appendChild(modal); console.log('Модальное окно добавлено:', modal); const updateButton = document.createElement('button'); updateButton.className = 'crm_tool-update'; updateButton.textContent = 'Обновить скрипт'; document.body.appendChild(updateButton); console.log('Кнопка обновления добавлена:', updateButton); // Получаем элементы const form = modal.querySelector('.crm_tool-form'); const clientIdInput = form.querySelector('#clientId'); const leadLinkInput = form.querySelector('#leadLink'); const reminderTextInput = form.querySelector('#reminderText'); const reminderHoursInput = form.querySelector('#reminderHours'); const reminderMinutesInput = form.querySelector('#reminderMinutes'); const openLinkCheckbox = form.querySelector('#openLink'); const notificationSoundSelect = form.querySelector('#notificationSound'); const submitButtonModal = form.querySelector('.crm_tool-submit'); const listButton = form.querySelector('.crm_tool-list'); const resetButton = form.querySelector('.crm_tool-reset'); const closeButton = form.querySelector('.crm_tool-close'); const remindersContainer = modal.querySelector('.crm_tool-reminders'); // Аудио для уведомлений let audio = new Audio(notificationSoundSelect.value); // Обновление звука уведомления notificationSoundSelect.addEventListener('change', () => { audio = new Audio(notificationSoundSelect.value); }); // Сохранение напоминания function saveReminder() { const clientId = clientIdInput.value.trim(); const leadLink = leadLinkInput.value.trim(); const reminderText = reminderTextInput.value.trim(); const reminderHours = parseInt(reminderHoursInput.value) || 0; const reminderMinutes = parseInt(reminderMinutesInput.value) || 0; const openLink = openLinkCheckbox.checked; if (!reminderText || (reminderHours === 0 && reminderMinutes === 0)) { alert('Укажите текст напоминания и время'); return; } const now = new Date(); const reminder = { clientId, leadLink, reminderText, reminderTime: reminderHours * 60 + reminderMinutes, reminderTimestamp: now.getTime() + (reminderHours * 60 + reminderMinutes) * 60000, openLink }; let reminders = JSON.parse(localStorage.getItem('crm_toolReminders') || '[]'); reminders.push(reminder); localStorage.setItem('crm_toolReminders', JSON.stringify(reminders)); alert('Напоминание сохранено'); form.reset(); showRemindersList(); } // Отображение списка напоминаний function showRemindersList() { const reminders = JSON.parse(localStorage.getItem('crm_toolReminders') || '[]'); if (!isRemindersListVisible) { remindersContainer.style.display = 'block'; remindersContainer.innerHTML = ''; reminders.forEach((reminder, index) => { const reminderTime = new Date(reminder.reminderTimestamp); const formattedTime = formatMoscowTime(reminderTime); const reminderElement = document.createElement('div'); reminderElement.className = 'crm_tool-reminder'; reminderElement.innerHTML = ` <div class="crm_tool-reminder-toggle" data-index="${index}">Лид: ${reminder.clientId || 'Нет ID'} | ${reminder.reminderText}</div> <div class="crm_tool-reminder-details" data-index="${index}"> <p><strong>Текст:</strong> ${reminder.reminderText}</p> <p><strong>Время (МСК):</strong> ${formattedTime}</p> <p><strong>Ссылка на лида:</strong> ${reminder.leadLink || 'Нет ссылки'}</p> <button data-index="${index}">Удалить</button> </div> `; remindersContainer.appendChild(reminderElement); reminderElement.querySelector('.crm_tool-reminder-toggle').addEventListener('click', function() { const details = this.nextElementSibling; details.style.display = details.style.display === 'block' ? 'none' : 'block'; }); reminderElement.querySelector('button').addEventListener('click', () => deleteReminder(index)); }); isRemindersListVisible = true; } else { remindersContainer.style.display = 'none'; isRemindersListVisible = false; } } // Удаление напоминания function deleteReminder(index) { let reminders = JSON.parse(localStorage.getItem('crm_toolReminders') || '[]'); reminders.splice(index, 1); localStorage.setItem('crm_toolReminders', JSON.stringify(reminders)); showRemindersList(); } // Сброс всех напоминаний function resetReminders() { if (confirm('Вы уверены, что хотите удалить все напоминания?')) { localStorage.removeItem('crm_toolReminders'); remindersContainer.innerHTML = ''; remindersContainer.style.display = 'none'; isRemindersListVisible = false; } } // Проверка напоминаний function checkReminders() { let reminders = JSON.parse(localStorage.getItem('crm_toolReminders') || '[]'); const now = Date.now(); reminders = reminders.filter(reminder => { if (now >= reminder.reminderTimestamp) { audio.play(); reminderButton.classList.add('active'); setTimeout(() => reminderButton.classList.remove('active'), 2000); alert(`Напоминание: ${reminder.clientId || 'Нет ID'}: ${reminder.reminderText}`); if (reminder.openLink && reminder.leadLink) { window.open(reminder.leadLink, '_blank'); } return false; } return true; }); localStorage.setItem('crm_toolReminders', JSON.stringify(reminders)); } // Форматирование времени по Москве function formatMoscowTime(date) { return date.toLocaleString('ru-RU', { timeZone: 'Europe/Moscow', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }); } // Проверка обновлений function checkForUpdates() { GM_xmlhttpRequest({ method: 'GET', url: GITHUB_VERSION_URL, onload: function(response) { const latestVersion = response.responseText.trim(); if (latestVersion && latestVersion !== CURRENT_VERSION) { updateButton.style.display = 'block'; if (confirm(`Доступна новая версия CrmTool (${latestVersion}). Обновить сейчас?`)) { window.location.href = GITHUB_SCRIPT_URL; } } }, onerror: function(error) { console.error('Ошибка проверки обновлений:', error); } }); } // Загрузка данных о праздниках function loadHolidaysData(callback) { GM_xmlhttpRequest({ method: 'GET', url: GITHUB_HOLIDAYS_URL, onload: function(response) { try { holidaysData = JSON.parse(response.responseText); console.log('Данные о праздниках загружены:', holidaysData); callback(); } catch (e) { console.error('Ошибка парсинга данных о праздниках:', e); alert('Не удалось загрузить данные о праздниках. Используются значения по умолчанию.'); holidaysData = { holidays: {}, holidayNames: {} }; callback(); } }, onerror: function(error) { console.error('Ошибка загрузки данных о праздниках:', error); alert('Не удалось загрузить данные о праздниках. Используются значения по умолчанию.'); holidaysData = { holidays: {}, holidayNames: {} }; callback(); } }); } // Обработчики событий reminderButton.addEventListener('click', () => { modal.style.display = 'block'; reminderButton.classList.add('active'); setTimeout(() => reminderButton.classList.remove('active'), 500); }); closeButton.addEventListener('click', () => modal.style.display = 'none'); submitButtonModal.addEventListener('click', saveReminder); listButton.addEventListener('click', showRemindersList); resetButton.addEventListener('click', resetReminders); updateButton.addEventListener('click', () => { if (confirm('Обновить CrmTool?')) { window.location.href = GITHUB_SCRIPT_URL; } }); // Таймер const timerScript = document.createElement('script'); timerScript.src = 'https://cdnjs.cloudflare.com/ajax/libs/luxon/2.3.0/luxon.min.js'; document.head.appendChild(timerScript); timerScript.onload = function() { const { DateTime } = luxon; const countries = { 'Боливия': 'America/La_Paz', 'Перу': 'America/Lima', 'Эквадор': 'America/Guayaquil', 'Колумбия': 'America/Bogota', 'Гватемала': 'America/Guatemala', 'Коста-Рика': 'America/Costa_Rica', 'Аргентина': 'America/Argentina/Buenos_Aires', 'Чили': 'America/Santiago', 'Парагвай': 'America/Asuncion', 'Уругвай': 'America/Montevideo', 'Бразилия': 'America/Sao_Paulo', 'Мексика': 'America/Mexico_City', 'Венесуэла': 'America/Caracas', 'Гондурас': 'America/Tegucigalpa', 'Никарагуа': 'America/Managua', 'Сальвадор': 'America/El_Salvador' }; const bankHours = { 'Боливия': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 12 }, 'Перу': { open: 9, close: 17, saturdayOpen: 9, saturdayClose: 13 }, 'Эквадор': { open: 9, close: 17, saturdayOpen: 9, saturdayClose: 13 }, 'Колумбия': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Гватемала': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 12 }, 'Коста-Рика': { open: 8, close: 16, saturdayOpen: 9, saturdayClose: 12 }, 'Аргентина': { open: 10, close: 15, saturdayOpen: 10, saturdayClose: 13 }, 'Чили': { open: 9, close: 14, saturdayOpen: 9, saturdayClose: 12 }, 'Парагвай': { open: 8, close: 15, saturdayOpen: 8, saturdayClose: 12 }, 'Уругвай': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Бразилия': { open: 10, close: 16, saturdayOpen: 10, saturdayClose: 14 }, 'Мексика': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Венесуэла': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Гондурас': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Никарагуа': { open: 9, close: 16, saturdayOpen: 9, saturdayClose: 13 }, 'Сальвадор': { open: 8, close: 16, saturdayOpen: 8, saturdayClose: 12 } }; function chooseMode() { console.log('chooseMode: Открытие меню'); // Если меню уже открыто, закрываем его if (timerMenu.style.display === 'flex') { timerMenu.style.display = 'none'; return; } // Показываем меню timerMenu.style.display = 'flex'; // Позиционируем меню относительно кнопки const buttonRect = timerButton.getBoundingClientRect(); let menuTop = buttonRect.bottom + 5; // Позиция ниже кнопки let menuLeft = buttonRect.left; // Убедимся, что меню не выходит за пределы экрана const menuHeight = timerMenu.offsetHeight; const menuWidth = timerMenu.offsetWidth; const windowHeight = window.innerHeight; const windowWidth = window.innerWidth; // Если меню выходит за нижнюю границу экрана, показываем его выше кнопки if (menuTop + menuHeight > windowHeight) { menuTop = buttonRect.top - menuHeight - 5; } // Если меню выходит за правую границу экрана, корректируем положение if (menuLeft + menuWidth > windowWidth) { menuLeft = windowWidth - menuWidth - 5; } // Убедимся, что меню не уходит за левую или верхнюю границу menuLeft = Math.max(5, menuLeft); menuTop = Math.max(5, menuTop); timerMenu.style.top = `${menuTop}px`; timerMenu.style.left = `${menuLeft}px`; console.log(`chooseMode: Меню позиционировано - top: ${menuTop}px, left: ${menuLeft}px`); // Добавляем обработчик для скрытия меню при клике вне его const closeMenuOnClickOutside = (event) => { if (!timerMenu.contains(event.target) && event.target !== timerButton) { console.log('chooseMode: Клик вне меню, закрытие'); timerMenu.style.display = 'none'; document.removeEventListener('click', closeMenuOnClickOutside); } }; // Добавляем обработчик с небольшой задержкой, чтобы не сработал сразу setTimeout(() => { document.addEventListener('click', closeMenuOnClickOutside); }, 100); } function createTimeWindow() { let timeWindow = window.open('', '', 'width=300,height=500'); if (!timeWindow) { alert('Разреши всплывающие окна для этого сайта!'); return; } let container = timeWindow.document.createElement('div'); container.id = 'time-widget-container'; Object.assign(container.style, { backgroundColor: '#1a2a44', border: '1px solid #ddd', padding: '10px', boxShadow: '0 0 10px rgba(0,0,0,0.1)', borderRadius: '8px', resize: 'both', overflow: 'auto', minWidth: '200px', minHeight: '100px' }); timeWindow.document.body.appendChild(container); setupClock(container); } function createTimePanel() { let container = document.createElement('div'); container.id = 'time-widget-container'; const savedPosition = GM_getValue('crm_toolTimerPosition', { top: '10px', left: '70px' }); Object.assign(container.style, { position: 'fixed', top: savedPosition.top, left: savedPosition.left, zIndex: '9999', backgroundColor: '#1a2a44', border: '1px solid #ddd', padding: '15px', boxShadow: '0 0 10px rgba(0,0,0,0.1)', borderRadius: '8px', resize: 'both', overflow: 'auto', minWidth: '200px', minHeight: '100px' }); let header = document.createElement('h3'); header.textContent = 'Банки Латинской Америки'; Object.assign(header.style, { color: '#ffffff', margin: '0 0 10px 0', fontSize: '1.2em' }); container.appendChild(header); let closeButton = document.createElement('button'); closeButton.textContent = 'X'; Object.assign(closeButton.style, { position: 'absolute', top: '10px', right: '10px', backgroundColor: 'red', color: 'white', border: 'none', borderRadius: '50%', cursor: 'pointer', width: '20px', height: '20px', zIndex: '10000' }); closeButton.addEventListener('click', () => container.remove()); container.appendChild(closeButton); document.body.appendChild(container); setupClock(container); } function setupClock(container) { let selectedCountries = GM_getValue('crm_toolSelectedCountries', Object.keys(countries)); function createCountryElement(country) { let clock = document.createElement('div'); Object.assign(clock.style, { marginBottom: '10px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }); clock.className = 'clock-item'; let countryDiv = document.createElement('div'); countryDiv.textContent = country; countryDiv.style.fontSize = '1.2em'; countryDiv.style.color = '#ffffff'; clock.appendChild(countryDiv); let timeDiv = document.createElement('div'); timeDiv.style.fontSize = '1.5em'; timeDiv.style.fontWeight = 'bold'; clock.appendChild(timeDiv); let removeButton = document.createElement('button'); removeButton.textContent = '✖'; Object.assign(removeButton.style, { marginLeft: '10px', cursor: 'pointer', color: '#ffffff', background: 'transparent', border: 'none' }); removeButton.addEventListener('click', () => { clock.remove(); selectedCountries = selectedCountries.filter(c => c !== country); GM_setValue('crm_toolSelectedCountries', selectedCountries); console.log('Страна удалена:', country); updateCountrySelect(); // Обновляем список стран после удаления }); clock.appendChild(removeButton); clock.timeDiv = timeDiv; clock.timeZone = countries[country]; clock.bankHours = bankHours[country]; clock.holidays = holidaysData.holidays[country] || []; clock.holidayNames = holidaysData.holidayNames[country] || {}; return clock; } function addCountry(country) { if (!selectedCountries.includes(country)) { selectedCountries.push(country); const newCountryElement = createCountryElement(country); container.insertBefore(newCountryElement, addCountryButton); GM_setValue('crm_toolSelectedCountries', selectedCountries); console.log('Страна добавлена:', country); updateCountrySelect(); // Обновляем список стран после добавления } else { alert('Эта страна уже добавлена!'); } } // Создание и добавление существующих стран selectedCountries.forEach(country => container.appendChild(createCountryElement(country))); // Кнопка для добавления страны let addCountryButton = document.createElement('button'); addCountryButton.textContent = 'Добавить страну'; Object.assign(addCountryButton.style, { marginTop: '10px', padding: '5px 10px', backgroundColor: '#4a4a4a', color: '#ffffff', border: 'none', borderRadius: '4px', cursor: 'pointer' }); // Создание модального окна для выбора страны const countryModal = document.createElement('div'); countryModal.className = 'crm_tool-country-modal'; countryModal.style.display = 'none'; // По умолчанию скрыто // Функция для обновления списка стран в модальном окне function updateCountrySelect() { const availableCountries = Object.keys(countries).filter(c => !selectedCountries.includes(c)); const countrySelect = countryModal.querySelector('#countrySelect'); countrySelect.innerHTML = availableCountries .map(country => `<option value="${country}">${country}</option>`) .join(''); if (availableCountries.length === 0) { countryModal.style.display = 'none'; alert('Все страны уже добавлены'); } } // Инициализация модального окна countryModal.innerHTML = ` <h3>Выберите страну</h3> <select id="countrySelect"> ${Object.keys(countries) .filter(c => !selectedCountries.includes(c)) .map(country => `<option value="${country}">${country}</option>`) .join('')} </select> <button id="addCountryBtn">Добавить</button> <button id="cancelCountryBtn">Отмена</button> `; container.appendChild(countryModal); // Обработчик для кнопки "Добавить страну" addCountryButton.addEventListener('click', () => { const availableCountries = Object.keys(countries).filter(c => !selectedCountries.includes(c)); if (!availableCountries.length) { alert('Все страны уже добавлены'); return; } updateCountrySelect(); // Обновляем список перед показом countryModal.style.display = 'block'; // Показываем модальное окно }); // Обработчики для модального окна const addCountryBtn = countryModal.querySelector('#addCountryBtn'); const cancelCountryBtn = countryModal.querySelector('#cancelCountryBtn'); const countrySelect = countryModal.querySelector('#countrySelect'); addCountryBtn.addEventListener('click', () => { const selectedCountry = countrySelect.value; if (selectedCountry && countries.hasOwnProperty(selectedCountry)) { addCountry(selectedCountry); countryModal.style.display = 'none'; // Скрываем модальное окно после добавления } }); cancelCountryBtn.addEventListener('click', () => { countryModal.style.display = 'none'; // Скрываем модальное окно при отмене }); // Добавляем кнопку в контейнер container.appendChild(addCountryButton); function isHoliday(now, holidays) { const monthDay = now.toFormat('MM-dd'); return holidays.includes(monthDay); } function isBankOpen(now, hours, holidays) { const day = now.weekday; const hour = now.hour; const isHolidayToday = isHoliday(now, holidays); if (isHolidayToday || day === 7) return false; if (day === 6) return hour >= hours.saturdayOpen && hour < hours.saturdayClose; return day >= 1 && day <= 5 && hour >= hours.open && hour < hours.close; } function getHolidayName(now, holidays, holidayNames) { const monthDay = now.toFormat('MM-dd'); return holidayNames[monthDay] || 'Неизвестный праздник'; } function updateTime() { let hasHoliday = false; [...container.children].forEach(clock => { if (clock.timeDiv && clock.className === 'clock-item') { let now = DateTime.now().setZone(clock.timeZone); clock.timeDiv.textContent = now.toLocaleString(DateTime.TIME_WITH_SECONDS); const isOpen = isBankOpen(now, clock.bankHours, clock.holidays); const isHolidayToday = isHoliday(now, clock.holidays); if (isHolidayToday) { clock.timeDiv.style.color = '#ff69b4'; clock.timeDiv.setAttribute('title', `Праздник: ${getHolidayName(now, clock.holidays, clock.holidayNames)}`); hasHoliday = true; } else { clock.timeDiv.style.color = isOpen ? 'green' : 'red'; clock.timeDiv.removeAttribute('title'); } clock.querySelector('div:nth-child(1)').setAttribute('title', isHolidayToday ? `Праздник: ${getHolidayName(now, clock.holidays, clock.holidayNames)}` : ''); } }); if (hasHoliday) { let notice = container.querySelector('.holiday-notice') || document.createElement('div'); notice.className = 'holiday-notice'; notice.textContent = 'Сегодня праздник в: ' + selectedCountries.filter(c => isHoliday(DateTime.now().setZone(countries[c]), holidaysData.holidays[c] || [])).join(', '); container.appendChild(notice); } else { let notice = container.querySelector('.holiday-notice'); if (notice) notice.remove(); } } setInterval(updateTime, 1000); updateTime(); if (container.id === 'time-widget-container') { container.onmousedown = function(event) { if (event.target.tagName.toLowerCase() === 'button' || event.target === closeButton) return; let shiftX = event.clientX - container.getBoundingClientRect().left; let shiftY = event.clientY - container.getBoundingClientRect().top; let initialWidth = container.offsetWidth; let initialHeight = container.offsetHeight; function moveAt(pageX, pageY) { let newLeft = pageX - shiftX; let newTop = pageY - shiftY; newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - initialWidth)); newTop = Math.max(0, Math.min(newTop, window.innerHeight - initialHeight)); container.style.left = newLeft + 'px'; container.style.top = newTop + 'px'; GM_setValue('crm_toolTimerPosition', { top: newTop + 'px', left: newLeft + 'px' }); } function onMouseMove(event) { moveAt(event.pageX, event.pageY); } document.addEventListener('mousemove', onMouseMove); container.onmouseup = function() { document.removeEventListener('mousemove', onMouseMove); container.onmouseup = null; }; }; container.ondragstart = () => false; } } // Обработчики для кнопок меню timerMenu.querySelector('.crm_tool-timer-window').addEventListener('click', () => { console.log('Выбрано: Открыть в новом окне'); createTimeWindow(); timerMenu.style.display = 'none'; }); timerMenu.querySelector('.crm_tool-timer-panel').addEventListener('click', () => { console.log('Выбрано: Открыть как виджет'); createTimePanel(); timerMenu.style.display = 'none'; }); timerButton.addEventListener('click', chooseMode); }; // Проверка напоминаний каждую минуту setInterval(checkReminders, 60000); // Проверка обновлений и загрузка праздников loadHolidaysData(() => { checkForUpdates(); }); // Повторная инициализация с отладкой function initializeButtons() { console.log('CrmTool: Проверка инициализации...'); if (!document.body || !document.body.contains(container)) { console.warn('CrmTool: document.body не доступен или контейнер не найден, пытаюсь добавить'); document.body.appendChild(container); console.log('CrmTool: Контейнер добавлен:', container); } else { console.log('CrmTool: Контейнер уже в DOM:', container); } applyScreenPosition(); } // Попытка инициализации при загрузке и с задержкой if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeButtons); } else { initializeButtons(); } setTimeout(() => { console.log('CrmTool: Повторная попытка инициализации через 1 сек...'); initializeButtons(); }, 1000); setTimeout(() => { console.log('CrmTool: Повторная попытка инициализации через 3 сек...'); initializeButtons(); }, 3000); // Ручной вызов для отладки window.showCrmToolButtons = function() { initializeButtons(); console.log('CrmTool: Кнопки показаны вручную'); }; // Обновление позиции при изменении размера окна window.addEventListener('resize', applyScreenPosition); // Функция для применения позиций в зависимости от разрешения function applyScreenPosition() { const height = window.innerHeight; if (height <= 720) { container.style.bottom = '8vh'; } else if (height <= 1080) { container.style.bottom = '8vh'; } else if (height <= 1440) { container.style.bottom = '8vh'; } else { container.style.bottom = '8vh'; } } })();