class CurrencyManager { static CONFIG = { rub: { name: 'Рубль', default: 1, precision: 2 }, usd: { name: 'Доллар США', default: 75, precision: 2, code: 'USD' }, eur: { name: 'Евро', default: 85, precision: 2, code: 'EUR' }, cny: { name: 'Китайский юань', default: 12, precision: 2, code: 'CNY' } }; constructor() { this.cacheKey = 'currencyData_v3'; this.apiUrl = 'https://www.cbr-xml-daily.ru/daily_json.js'; this.cacheDuration = 6 * 60 * 60 * 1000; // 6 часов } async getRates() { try { // Пробуем загрузить свежие курсы const freshRates = await this.fetchRates(); if (freshRates) return freshRates; // Если не получилось, пробуем кэш const cachedRates = this.getCachedRates(); if (cachedRates) return cachedRates; // Возвращаем дефолтные значения return this.getDefaultRates(); } catch (error) { console.error('Ошибка получения курсов:', error); return this.getDefaultRates(); } } async fetchRates() { try { const response = await fetch(this.apiUrl); if (!response.ok) throw new Error(`Ошибка HTTP: ${response.status}`); const data = await response.json(); if (!data?.Valute) throw new Error('Некорректный формат данных'); const rates = {}; let hasValidData = false; for (const [key, config] of Object.entries(CurrencyManager.CONFIG)) { if (key === 'rub') { rates.rub = 1; continue; } const currencyData = data.Valute[config.code]; if (!currencyData) continue; const value = parseFloat(currencyData.Value); if (isNaN(value)) continue; rates[key] = parseFloat(value.toFixed(config.precision)); hasValidData = true; } if (hasValidData) { this.cacheRates(rates); return rates; } throw new Error('Нет данных по валютам'); } catch (error) { console.warn('Ошибка загрузки курсов:', error.message); return null; } } getCachedRates() { try { const cache = localStorage.getItem(this.cacheKey); if (!cache) return null; const { rates, timestamp } = JSON.parse(cache); if (!rates || !timestamp) return null; const cacheAge = Date.now() - timestamp; if (cacheAge > this.cacheDuration) return null; return rates; } catch (error) { console.warn('Ошибка чтения кэша:', error); return null; } } cacheRates(rates) { try { const cacheData = { rates, timestamp: Date.now() }; localStorage.setItem(this.cacheKey, JSON.stringify(cacheData)); } catch (error) { console.warn('Ошибка сохранения в кэш:', error); } } getDefaultRates() { const defaults = {}; for (const [key, config] of Object.entries(CurrencyManager.CONFIG)) { defaults[key] = config.default; } return defaults; } } class CurrencyUI { constructor(manager) { this.manager = manager; this.ratesContainer = document.getElementById('rates-info'); this.currencySelect = document.getElementById('currency'); this.exchangeInput = document.getElementById('exchange-rate'); } async init() { if (!this.ratesContainer) { console.error('Не найден контейнер для курсов'); return; } try { const rates = await this.manager.getRates(); this.displayRates(rates); this.setupCurrencySelect(rates); } catch (error) { console.error('Ошибка инициализации:', error); this.showError(); } } displayRates(rates) { let html = '
'; html += '

Курсы валют ЦБ РФ

'; html += '
'; for (const [key, config] of Object.entries(CurrencyManager.CONFIG)) { if (key === 'rub') continue; const value = rates[key] || config.default; html += `
${config.name} ${value.toFixed(config.precision)} ₽
`; } html += '
'; html += `
Обновлено: ${new Date().toLocaleString('ru-RU')}
`; html += '
'; this.ratesContainer.innerHTML = html; } setupCurrencySelect(rates) { if (!this.currencySelect || !this.exchangeInput) return; this.currencySelect.addEventListener('change', () => { const currency = this.currencySelect.value; const config = CurrencyManager.CONFIG[currency]; if (!config) return; const rate = rates[currency] || config.default; this.exchangeInput.value = rate.toFixed(config.precision); this.exchangeInput.readOnly = currency === 'rub'; }); } showError() { if (this.ratesContainer) { this.ratesContainer.innerHTML = `
⚠️ Не удалось загрузить курсы валют
`; } } } // Инициализация при загрузке страницы document.addEventListener('DOMContentLoaded', () => { const currencyManager = new CurrencyManager(); const currencyUI = new CurrencyUI(currencyManager); currencyUI.init(); // Обновление каждые 2 часа setInterval(() => currencyUI.init(), 2 * 60 * 60 * 1000); });