diff --git a/example-servers-billing.json b/example-servers-billing.json index 90887e2..4f802bd 100644 --- a/example-servers-billing.json +++ b/example-servers-billing.json @@ -7,9 +7,11 @@ "provider": "VDSINA", "loginUrl": "cp.vdsina.com", "monthlyCost": 12.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2026-04-25", "lastPaymentDate": "2025-05-05", "lastPaymentAmount": 12.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -21,9 +23,11 @@ "provider": "Macloud", "loginUrl": "cp.macloud.ru", "monthlyCost": 7.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-09-02", "lastPaymentDate": "2025-02-03", "lastPaymentAmount": 7.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -35,9 +39,11 @@ "provider": "Hosting VDS", "loginUrl": "my.hosting-vds.com/", "monthlyCost": 11.95, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-12-21", "lastPaymentDate": "2025-06-13", "lastPaymentAmount": 10.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -49,9 +55,11 @@ "provider": "Waicore", "loginUrl": "my.waicore.com/billmgr", "monthlyCost": 9.60, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2026-04-25", "lastPaymentDate": "2025-04-25", "lastPaymentAmount": 9.60, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -63,9 +71,11 @@ "provider": "IHOR", "loginUrl": "billing.ihor-hosting.ru/billmgr", "monthlyCost": 10.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-09-10", "lastPaymentDate": "2025-06-25", "lastPaymentAmount": 10.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" } diff --git a/frontend/src/BillingManager.jsx b/frontend/src/BillingManager.jsx index 9df2168..57e8e53 100644 --- a/frontend/src/BillingManager.jsx +++ b/frontend/src/BillingManager.jsx @@ -37,6 +37,14 @@ function BillingManager() { const [selectedItem, setSelectedItem] = useState(null); const [editingItem, setEditingItem] = useState({}); + // Состояние для курсов валют + const [exchangeRates, setExchangeRates] = useState({ + USD: 1, + EUR: 1, + RUB: 1 + }); + const [ratesLoading, setRatesLoading] = useState(false); + // Новый элемент для добавления const [newItem, setNewItem] = useState({ hostName: '', @@ -45,17 +53,45 @@ function BillingManager() { provider: '', loginUrl: '', monthlyCost: 0, + monthlyCostCurrency: 'USD', nextPaymentDate: '', lastPaymentDate: '', lastPaymentAmount: 0, + lastPaymentCurrency: 'USD', status: 'active', notes: '' }); useEffect(() => { fetchBillingData(); + fetchExchangeRates(); }, []); + const fetchExchangeRates = async () => { + setRatesLoading(true); + try { + // Используем бесплатный API для получения курсов валют + const response = await axios.get('https://api.exchangerate-api.com/v4/latest/USD'); + const rates = response.data.rates; + + setExchangeRates({ + USD: 1, + EUR: rates.EUR || 1, + RUB: rates.RUB || 1 + }); + } catch (error) { + console.error('Ошибка при загрузке курсов валют:', error); + // Используем примерные курсы если API недоступен + setExchangeRates({ + USD: 1, + EUR: 0.85, + RUB: 95 + }); + } finally { + setRatesLoading(false); + } + }; + const fetchBillingData = async () => { setLoading(true); try { @@ -75,9 +111,11 @@ function BillingManager() { "provider": "VDSINA", "loginUrl": "cp.vdsina.com", "monthlyCost": 12.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2026-04-25", "lastPaymentDate": "2025-05-05", "lastPaymentAmount": 12.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -89,9 +127,11 @@ function BillingManager() { "provider": "Macloud", "loginUrl": "cp.macloud.ru", "monthlyCost": 7.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-09-02", "lastPaymentDate": "2025-02-03", "lastPaymentAmount": 7.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -103,9 +143,11 @@ function BillingManager() { "provider": "Hosting VDS", "loginUrl": "my.hosting-vds.com/", "monthlyCost": 11.95, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-12-21", "lastPaymentDate": "2025-06-13", "lastPaymentAmount": 10.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -117,9 +159,11 @@ function BillingManager() { "provider": "Waicore", "loginUrl": "my.waicore.com/billmgr", "monthlyCost": 9.60, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2026-04-25", "lastPaymentDate": "2025-04-25", "lastPaymentAmount": 9.60, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" }, @@ -131,9 +175,11 @@ function BillingManager() { "provider": "IHOR", "loginUrl": "billing.ihor-hosting.ru/billmgr", "monthlyCost": 10.00, + "monthlyCostCurrency": "USD", "nextPaymentDate": "2025-09-10", "lastPaymentDate": "2025-06-25", "lastPaymentAmount": 10.00, + "lastPaymentCurrency": "USD", "status": "active", "notes": "" } @@ -247,8 +293,14 @@ function BillingManager() { const totalPages = Math.ceil(filteredData.length / pageSize); // Статистика - const totalMonthlyCost = billingData.reduce((sum, item) => sum + item.monthlyCost, 0); - const totalLastPayments = billingData.reduce((sum, item) => sum + item.lastPaymentAmount, 0); + const totalMonthlyCost = billingData.reduce((sum, item) => { + const currency = item.monthlyCostCurrency || 'USD'; + return sum + convertToRUB(item.monthlyCost, currency); + }, 0); + const totalLastPayments = billingData.reduce((sum, item) => { + const currency = item.lastPaymentCurrency || 'USD'; + return sum + convertToRUB(item.lastPaymentAmount, currency); + }, 0); const activeProviders = [...new Set(billingData.map(item => item.provider))].length; const activeNodes = billingData.filter(item => item.status === 'active').length; @@ -274,13 +326,26 @@ function BillingManager() { }); } - function formatCurrency(amount) { + function formatCurrency(amount, currency = 'USD') { return new Intl.NumberFormat('en-US', { style: 'currency', - currency: 'USD' + currency: currency }).format(amount); } + function convertToRUB(amount, currency) { + const rate = exchangeRates[currency] || 1; + return amount * rate; + } + + function formatCurrencyInRUB(amount, currency) { + const rubAmount = convertToRUB(amount, currency); + return new Intl.NumberFormat('ru-RU', { + style: 'currency', + currency: 'RUB' + }).format(rubAmount); + } + function formatPurpose(purpose) { const purposeMap = { 'relay': 'Relay VPS', @@ -375,7 +440,7 @@ function BillingManager() {