Upload 2 files
Browse files- index.html +644 -100
index.html
CHANGED
|
@@ -1615,7 +1615,252 @@
|
|
| 1615 |
tbody tr:last-child td:last-child {
|
| 1616 |
border-bottom-right-radius: 12px;
|
| 1617 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1618 |
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1619 |
</head>
|
| 1620 |
|
| 1621 |
<body>
|
|
@@ -1667,7 +1912,10 @@
|
|
| 1667 |
</div>
|
| 1668 |
</div>
|
| 1669 |
<div class="header-actions">
|
| 1670 |
-
<div class="live-indicator"
|
|
|
|
|
|
|
|
|
|
| 1671 |
<div class="status-badge">
|
| 1672 |
<div class="status-dot"></div>
|
| 1673 |
<span id="statusText">All Systems Operational</span>
|
|
@@ -1677,15 +1925,42 @@
|
|
| 1677 |
|
| 1678 |
<!-- Tabs -->
|
| 1679 |
<div class="tabs">
|
| 1680 |
-
<button class="tab active" onclick="switchTab('market')"
|
| 1681 |
-
|
| 1682 |
-
|
| 1683 |
-
|
| 1684 |
-
<button class="tab" onclick="switchTab('
|
| 1685 |
-
|
| 1686 |
-
|
| 1687 |
-
|
| 1688 |
-
<button class="tab" onclick="switchTab('
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1689 |
</div>
|
| 1690 |
</div>
|
| 1691 |
|
|
@@ -1789,13 +2064,19 @@
|
|
| 1789 |
<!-- Market Table -->
|
| 1790 |
<div class="market-section">
|
| 1791 |
<div class="section-header">
|
| 1792 |
-
<div class="section-title gradient-text"
|
| 1793 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1794 |
</div>
|
| 1795 |
|
| 1796 |
<!-- Search Bar -->
|
| 1797 |
<div class="search-container">
|
| 1798 |
-
<span class="search-icon"
|
| 1799 |
<input type="text" class="search-input" id="marketSearch" placeholder="جستجوی ارز دیجیتال (مثال: Bitcoin, BTC, Ethereum)..." oninput="filterMarketTable()">
|
| 1800 |
</div>
|
| 1801 |
|
|
@@ -1803,9 +2084,18 @@
|
|
| 1803 |
<div class="filter-chips">
|
| 1804 |
<button class="filter-chip active" onclick="filterByCategory('all')">همه</button>
|
| 1805 |
<button class="filter-chip" onclick="filterByCategory('top10')">Top 10</button>
|
| 1806 |
-
<button class="filter-chip" onclick="filterByCategory('gainers')"
|
| 1807 |
-
|
| 1808 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1809 |
</div>
|
| 1810 |
<div style="overflow-x: auto;">
|
| 1811 |
<table id="marketTable">
|
|
@@ -1854,7 +2144,10 @@
|
|
| 1854 |
|
| 1855 |
<!-- Trending Section -->
|
| 1856 |
<div class="market-section">
|
| 1857 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 1858 |
<div id="trendingGrid"
|
| 1859 |
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
|
| 1860 |
<div class="loading">
|
|
@@ -1933,8 +2226,14 @@
|
|
| 1933 |
|
| 1934 |
<div class="market-section">
|
| 1935 |
<div class="section-header">
|
| 1936 |
-
<div class="section-title"
|
| 1937 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1938 |
</div>
|
| 1939 |
<div style="overflow-x: auto;">
|
| 1940 |
<table>
|
|
@@ -1957,7 +2256,10 @@
|
|
| 1957 |
</div>
|
| 1958 |
|
| 1959 |
<div class="market-section">
|
| 1960 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 1961 |
<div class="form-group">
|
| 1962 |
<label class="form-label">Enter crypto-related text (one per line):</label>
|
| 1963 |
<textarea class="form-textarea" id="sentimentText" rows="5"
|
|
@@ -1965,7 +2267,10 @@
|
|
| 1965 |
ETH looks weak
|
| 1966 |
Market is bullish today</textarea>
|
| 1967 |
</div>
|
| 1968 |
-
<button class="refresh-btn ripple" onclick="runSentiment()"
|
|
|
|
|
|
|
|
|
|
| 1969 |
<div id="sentimentResult"
|
| 1970 |
style="margin-top: 20px; padding: 20px; background: rgba(17, 24, 39, 0.6); border-radius: 12px; text-align: center; font-size: 36px; font-weight: 900;">
|
| 1971 |
—</div>
|
|
@@ -2099,12 +2404,18 @@ Market is bullish today</textarea>
|
|
| 2099 |
</div>
|
| 2100 |
|
| 2101 |
<div class="market-section">
|
| 2102 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 2103 |
<div id="apisList">Loading...</div>
|
| 2104 |
</div>
|
| 2105 |
|
| 2106 |
<div class="market-section">
|
| 2107 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 2108 |
<div class="form-group">
|
| 2109 |
<label class="form-label">API Check Interval (seconds)</label>
|
| 2110 |
<input type="number" class="form-input" id="checkInterval" value="30" min="10" max="300">
|
|
@@ -2117,7 +2428,10 @@ Market is bullish today</textarea>
|
|
| 2117 |
</div>
|
| 2118 |
|
| 2119 |
<div class="market-section">
|
| 2120 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 2121 |
<div class="stats-grid">
|
| 2122 |
<div class="stat-card">
|
| 2123 |
<div class="stat-value" id="statTotal">0</div>
|
|
@@ -2139,8 +2453,14 @@ Market is bullish today</textarea>
|
|
| 2139 |
<div id="tab-hf" class="tab-content">
|
| 2140 |
<div class="market-section">
|
| 2141 |
<div class="section-header">
|
| 2142 |
-
<div class="section-title"
|
| 2143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2144 |
</div>
|
| 2145 |
<pre id="healthOutput"
|
| 2146 |
style="background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 8px; overflow-x: auto; font-size: 12px; max-height: 200px; overflow-y: auto;">Loading...</pre>
|
|
@@ -2185,7 +2505,10 @@ Market is bullish today</textarea>
|
|
| 2185 |
</div>
|
| 2186 |
|
| 2187 |
<div class="market-section">
|
| 2188 |
-
<div class="section-title" style="margin-bottom: 20px;"
|
|
|
|
|
|
|
|
|
|
| 2189 |
<div class="form-group">
|
| 2190 |
<label class="form-label">Enter text samples (one per line):</label>
|
| 2191 |
<textarea class="form-textarea" id="sentimentTexts" rows="5"
|
|
@@ -2193,7 +2516,10 @@ Market is bullish today</textarea>
|
|
| 2193 |
ETH looks weak
|
| 2194 |
Crypto market is bullish today</textarea>
|
| 2195 |
</div>
|
| 2196 |
-
<button class="refresh-btn" onclick="doSentiment()"
|
|
|
|
|
|
|
|
|
|
| 2197 |
<div id="voteDisplay"
|
| 2198 |
style="margin-top: 20px; padding: 20px; background: rgba(17, 24, 39, 0.6); border-radius: 12px; text-align: center; font-size: 36px; font-weight: 900;">
|
| 2199 |
—</div>
|
|
@@ -2206,17 +2532,30 @@ Crypto market is bullish today</textarea>
|
|
| 2206 |
<div id="tab-logs" class="tab-content">
|
| 2207 |
<div class="market-section">
|
| 2208 |
<div class="section-header">
|
| 2209 |
-
<div class="section-title"
|
|
|
|
|
|
|
|
|
|
| 2210 |
<div style="display: flex; gap: 10px;">
|
| 2211 |
-
<button class="refresh-btn" onclick="loadLogs()"
|
| 2212 |
-
|
| 2213 |
-
|
| 2214 |
-
|
| 2215 |
-
<button class="refresh-btn" onclick="
|
| 2216 |
-
style="background: rgba(16, 185, 129, 0.2); color: var(--accent-green);"
|
| 2217 |
-
|
| 2218 |
-
|
| 2219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2220 |
</div>
|
| 2221 |
</div>
|
| 2222 |
|
|
@@ -2399,16 +2738,42 @@ Crypto market is bullish today</textarea>
|
|
| 2399 |
|
| 2400 |
<!-- Reports Tab -->
|
| 2401 |
<div id="tab-reports" class="tab-content">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2402 |
<div class="market-section">
|
| 2403 |
<div class="section-header">
|
| 2404 |
-
<div class="section-title"
|
|
|
|
|
|
|
|
|
|
| 2405 |
<div style="display: flex; gap: 10px;">
|
| 2406 |
-
<button class="refresh-btn" onclick="runDiagnostics(false)"
|
| 2407 |
-
style="background: rgba(59, 130, 246, 0.2); color: var(--accent-blue);"
|
| 2408 |
-
|
| 2409 |
-
|
| 2410 |
-
|
| 2411 |
-
<button class="refresh-btn" onclick="
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2412 |
</div>
|
| 2413 |
</div>
|
| 2414 |
|
|
@@ -2422,8 +2787,14 @@ Crypto market is bullish today</textarea>
|
|
| 2422 |
|
| 2423 |
<div class="market-section">
|
| 2424 |
<div class="section-header">
|
| 2425 |
-
<div class="section-title"
|
| 2426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2427 |
</div>
|
| 2428 |
<div id="discoveryReport">
|
| 2429 |
<div class="loading">
|
|
@@ -2434,8 +2805,14 @@ Crypto market is bullish today</textarea>
|
|
| 2434 |
|
| 2435 |
<div class="market-section">
|
| 2436 |
<div class="section-header">
|
| 2437 |
-
<div class="section-title"
|
| 2438 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2439 |
</div>
|
| 2440 |
<div id="modelsReport">
|
| 2441 |
<div class="loading">
|
|
@@ -2668,7 +3045,7 @@ Crypto market is bullish today</textarea>
|
|
| 2668 |
|
| 2669 |
// Call updateStats with validated data - double check before calling
|
| 2670 |
if (stats && stats.market && typeof stats.market === 'object' && !Array.isArray(stats.market)) {
|
| 2671 |
-
|
| 2672 |
} else {
|
| 2673 |
console.error('Failed final validation before updateStats:', { stats, sentiment });
|
| 2674 |
throw new Error('دادههای stats.market نامعتبر است');
|
|
@@ -2761,15 +3138,15 @@ Crypto market is bullish today</textarea>
|
|
| 2761 |
if (sentimentLabelEl) {
|
| 2762 |
sentimentLabelEl.innerHTML = `<span>${classification}</span>`;
|
| 2763 |
|
| 2764 |
-
|
| 2765 |
sentimentLabelEl.style.color = 'var(--accent-red)';
|
| 2766 |
-
|
| 2767 |
sentimentLabelEl.style.color = 'var(--accent-yellow)';
|
| 2768 |
-
|
| 2769 |
sentimentLabelEl.style.color = 'var(--text-secondary)';
|
| 2770 |
-
|
| 2771 |
sentimentLabelEl.style.color = 'var(--accent-blue)';
|
| 2772 |
-
|
| 2773 |
sentimentLabelEl.style.color = 'var(--accent-green)';
|
| 2774 |
}
|
| 2775 |
}
|
|
@@ -2783,7 +3160,7 @@ Crypto market is bullish today</textarea>
|
|
| 2783 |
function updateMarketTable(cryptos) {
|
| 2784 |
try {
|
| 2785 |
if (!cryptos || !Array.isArray(cryptos) || cryptos.length === 0) {
|
| 2786 |
-
|
| 2787 |
if (tbody) {
|
| 2788 |
tbody.innerHTML = '<tr><td colspan="6" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ دادهای یافت نشد</td></tr>';
|
| 2789 |
}
|
|
@@ -2808,22 +3185,22 @@ Crypto market is bullish today</textarea>
|
|
| 2808 |
|
| 2809 |
return `
|
| 2810 |
<tr data-name="${name.toLowerCase()}" data-symbol="${symbol.toLowerCase()}" data-change="${change24h}" data-rank="${crypto.rank || index + 1}">
|
| 2811 |
-
|
| 2812 |
-
|
| 2813 |
-
|
| 2814 |
${crypto.image ? `<img src="${crypto.image}" class="crypto-img" alt="${symbol}" onerror="this.style.display='none'">` :
|
| 2815 |
`<div class="crypto-img" style="background: linear-gradient(135deg, #3b82f6, #8b5cf6); display: flex; align-items: center; justify-content: center; font-weight: 700; color: white;">${symbol[0] || '?'}</div>`}
|
| 2816 |
-
|
| 2817 |
<div style="font-weight: 600;">${name}</div>
|
| 2818 |
<div class="crypto-symbol">${symbol}</div>
|
| 2819 |
-
|
| 2820 |
-
|
| 2821 |
-
|
| 2822 |
<td class="price number-counter">$${price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}</td>
|
| 2823 |
<td><span class="change ${changeClass} pulse-data">${changeIcon} ${change24h >= 0 ? '+' : ''}${change24h.toFixed(2)}%</span></td>
|
| 2824 |
<td style="font-weight: 600;">$${(marketCap / 1e9).toFixed(2)}B</td>
|
| 2825 |
<td style="color: var(--text-secondary);">$${(volume24h / 1e9).toFixed(2)}B</td>
|
| 2826 |
-
|
| 2827 |
`;
|
| 2828 |
}).join('');
|
| 2829 |
} catch (error) {
|
|
@@ -2837,7 +3214,7 @@ Crypto market is bullish today</textarea>
|
|
| 2837 |
|
| 2838 |
function updateTrending(trending) {
|
| 2839 |
try {
|
| 2840 |
-
|
| 2841 |
if (!grid) return;
|
| 2842 |
|
| 2843 |
if (!trending || !Array.isArray(trending) || trending.length === 0) {
|
|
@@ -2849,14 +3226,14 @@ Crypto market is bullish today</textarea>
|
|
| 2849 |
const name = coin.name || 'نامشخص';
|
| 2850 |
const symbol = coin.symbol || 'N/A';
|
| 2851 |
return `
|
| 2852 |
-
|
| 2853 |
-
|
| 2854 |
${coin.thumb ? `<img src="${coin.thumb}" style="width: 32px; height: 32px; border-radius: 8px;" onerror="this.style.display='none'">` : ''}
|
| 2855 |
-
|
| 2856 |
<div style="font-weight: 600;">${name}</div>
|
| 2857 |
<div style="font-size: 12px; color: var(--text-secondary);">${symbol}</div>
|
| 2858 |
-
|
| 2859 |
-
|
| 2860 |
`;
|
| 2861 |
}).join('');
|
| 2862 |
} catch (error) {
|
|
@@ -2870,18 +3247,18 @@ Crypto market is bullish today</textarea>
|
|
| 2870 |
|
| 2871 |
function updateDeFi(defi) {
|
| 2872 |
try {
|
| 2873 |
-
|
| 2874 |
if (!list) return;
|
| 2875 |
|
| 2876 |
const protocols = defi && defi.protocols ? defi.protocols : [];
|
| 2877 |
const totalTvl = defi && defi.total_tvl ? defi.total_tvl : 0;
|
| 2878 |
|
| 2879 |
-
|
| 2880 |
<div class="stat-card" style="margin-bottom: 20px; text-align: center; background: linear-gradient(135deg, rgba(59, 130, 246, 0.2), rgba(139, 92, 246, 0.2));">
|
| 2881 |
<div class="stat-value gradient-text" style="font-size: 42px; margin-bottom: 8px;">$${(totalTvl / 1e9).toFixed(2)}B</div>
|
| 2882 |
<div class="stat-label" style="font-size: 16px;">Total Value Locked</div>
|
| 2883 |
-
|
| 2884 |
-
|
| 2885 |
${protocols.length > 0 ? protocols.map((p, i) => {
|
| 2886 |
const name = p.name || 'نامشخص';
|
| 2887 |
const chain = p.chain || 'N/A';
|
|
@@ -2891,21 +3268,21 @@ Crypto market is bullish today</textarea>
|
|
| 2891 |
return `
|
| 2892 |
<div class="stat-card" style="animation-delay: ${i * 0.05}s; cursor: pointer;" onclick="showToast('${name}: $${(tvl / 1e9).toFixed(2)}B TVL', 'info', 'DeFi Protocol')">
|
| 2893 |
<div style="display: flex; justify-content: space-between; align-items: center;">
|
| 2894 |
-
|
| 2895 |
<div style="font-weight: 700; font-size: 16px; margin-bottom: 4px;">${i + 1}. ${name}</div>
|
| 2896 |
<div style="font-size: 12px; color: var(--text-secondary); display: flex; align-items: center; gap: 6px;">
|
| 2897 |
<span>🔗</span> <span>${chain}</span>
|
| 2898 |
</div>
|
| 2899 |
-
|
| 2900 |
-
|
| 2901 |
<div class="stat-value" style="font-size: 18px; margin-bottom: 4px;">$${(tvl / 1e9).toFixed(2)}B</div>
|
| 2902 |
<div class="stat-change ${changeClass}" style="font-size: 13px;">
|
| 2903 |
${change24h >= 0 ? '📈' : '📉'} ${change24h >= 0 ? '+' : ''}${change24h.toFixed(2)}%
|
| 2904 |
-
</div>
|
| 2905 |
-
</div>
|
| 2906 |
-
</div>
|
| 2907 |
</div>
|
| 2908 |
-
|
|
|
|
|
|
|
|
|
|
| 2909 |
}).join('') : '<div class="empty-state"><div class="empty-state-icon">📦</div><div>هیچ پروتکلی یافت نشد</div></div>'}
|
| 2910 |
</div>
|
| 2911 |
`;
|
|
@@ -3002,7 +3379,7 @@ Crypto market is bullish today</textarea>
|
|
| 3002 |
window.wsClient.on('stats_update', (message) => {
|
| 3003 |
console.log('📊 Stats update:', message.data);
|
| 3004 |
if (typeof updateOnlineStats === 'function') {
|
| 3005 |
-
|
| 3006 |
}
|
| 3007 |
});
|
| 3008 |
|
|
@@ -3030,10 +3407,10 @@ Crypto market is bullish today</textarea>
|
|
| 3030 |
// درخواست آمار هر 10 ثانیه (فقط یک بار تنظیم شود)
|
| 3031 |
if (!wsStatsInterval) {
|
| 3032 |
wsStatsInterval = setInterval(() => {
|
| 3033 |
-
|
| 3034 |
-
|
| 3035 |
-
|
| 3036 |
-
|
| 3037 |
}
|
| 3038 |
} else {
|
| 3039 |
wsConnectAttempts++;
|
|
@@ -3042,7 +3419,7 @@ Crypto market is bullish today</textarea>
|
|
| 3042 |
if (wsConnectAttempts % 5 === 0 || wsConnectAttempts === 1) {
|
| 3043 |
console.log(`⏳ در انتظار WebSocket Client... (${wsConnectAttempts}/${MAX_WS_CONNECT_ATTEMPTS})`);
|
| 3044 |
}
|
| 3045 |
-
|
| 3046 |
} else {
|
| 3047 |
console.warn('⚠️ WebSocket Client پس از ' + MAX_WS_CONNECT_ATTEMPTS + ' تلاش آماده نشد. ممکن است فایل websocket-client.js لود نشده باشد یا WebSocket پشتیبانی نشود.');
|
| 3048 |
console.warn('⚠️ بررسی کنید که فایل /static/js/websocket-client.js به درستی لود شده باشد.');
|
|
@@ -3136,21 +3513,21 @@ Crypto market is bullish today</textarea>
|
|
| 3136 |
if (providers.length === 0) {
|
| 3137 |
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ APIای یافت نشد</td></tr>';
|
| 3138 |
} else {
|
| 3139 |
-
|
| 3140 |
-
|
| 3141 |
-
|
| 3142 |
-
|
| 3143 |
|
| 3144 |
-
|
| 3145 |
-
|
| 3146 |
<td><strong>${p.name || 'نامشخص'}</strong></td>
|
| 3147 |
<td><span class="badge badge-info">${p.category || 'نامشخص'}</span></td>
|
| 3148 |
<td><span class="badge ${statusClass}">${(p.status || 'unknown').toUpperCase()}</span></td>
|
| 3149 |
<td>${p.response_time_ms || p.avg_response_time_ms || 0}ms</td>
|
| 3150 |
<td style="color: var(--text-secondary); font-size: 13px;">${p.last_fetch ? new Date(p.last_fetch).toLocaleTimeString() : 'نامشخص'}</td>
|
| 3151 |
-
|
| 3152 |
-
|
| 3153 |
-
|
| 3154 |
}
|
| 3155 |
}
|
| 3156 |
} catch (error) {
|
|
@@ -3847,7 +4224,7 @@ Crypto market is bullish today</textarea>
|
|
| 3847 |
// Auto hide after 3 seconds
|
| 3848 |
setTimeout(() => {
|
| 3849 |
hideFeedback();
|
| 3850 |
-
|
| 3851 |
}
|
| 3852 |
}
|
| 3853 |
|
|
@@ -4278,6 +4655,158 @@ Crypto market is bullish today</textarea>
|
|
| 4278 |
]);
|
| 4279 |
}
|
| 4280 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4281 |
async function runDiagnostics(autoFix = false) {
|
| 4282 |
const resultsDiv = document.getElementById('diagnosticsResults');
|
| 4283 |
resultsDiv.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
|
|
@@ -4289,10 +4818,19 @@ Crypto market is bullish today</textarea>
|
|
| 4289 |
const report = await response.json();
|
| 4290 |
|
| 4291 |
displayDiagnosticsReport(report);
|
| 4292 |
-
showToast(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4293 |
} catch (error) {
|
| 4294 |
-
resultsDiv.innerHTML = `<div class="alert alert-error"
|
| 4295 |
-
|
|
|
|
|
|
|
|
|
|
| 4296 |
}
|
| 4297 |
}
|
| 4298 |
|
|
@@ -4406,6 +4944,12 @@ Crypto market is bullish today</textarea>
|
|
| 4406 |
}
|
| 4407 |
|
| 4408 |
displayDiagnosticsReport(report);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4409 |
} catch (error) {
|
| 4410 |
console.error('Error loading last diagnostics:', error);
|
| 4411 |
}
|
|
|
|
| 1615 |
tbody tr:last-child td:last-child {
|
| 1616 |
border-bottom-right-radius: 12px;
|
| 1617 |
}
|
| 1618 |
+
|
| 1619 |
+
/* SVG Icon Styles */
|
| 1620 |
+
.icon {
|
| 1621 |
+
width: 20px;
|
| 1622 |
+
height: 20px;
|
| 1623 |
+
display: inline-flex;
|
| 1624 |
+
align-items: center;
|
| 1625 |
+
justify-content: center;
|
| 1626 |
+
flex-shrink: 0;
|
| 1627 |
+
}
|
| 1628 |
+
|
| 1629 |
+
.icon-sm {
|
| 1630 |
+
width: 16px;
|
| 1631 |
+
height: 16px;
|
| 1632 |
+
}
|
| 1633 |
+
|
| 1634 |
+
.icon-md {
|
| 1635 |
+
width: 24px;
|
| 1636 |
+
height: 24px;
|
| 1637 |
+
}
|
| 1638 |
+
|
| 1639 |
+
.icon-lg {
|
| 1640 |
+
width: 32px;
|
| 1641 |
+
height: 32px;
|
| 1642 |
+
}
|
| 1643 |
+
|
| 1644 |
+
.icon-xl {
|
| 1645 |
+
width: 48px;
|
| 1646 |
+
height: 48px;
|
| 1647 |
+
}
|
| 1648 |
+
|
| 1649 |
+
.icon svg {
|
| 1650 |
+
width: 100%;
|
| 1651 |
+
height: 100%;
|
| 1652 |
+
stroke: currentColor;
|
| 1653 |
+
fill: none;
|
| 1654 |
+
stroke-width: 2;
|
| 1655 |
+
stroke-linecap: round;
|
| 1656 |
+
stroke-linejoin: round;
|
| 1657 |
+
}
|
| 1658 |
+
|
| 1659 |
+
.icon-filled svg {
|
| 1660 |
+
fill: currentColor;
|
| 1661 |
+
stroke: none;
|
| 1662 |
+
}
|
| 1663 |
+
|
| 1664 |
+
.icon-gradient {
|
| 1665 |
+
background: linear-gradient(135deg, var(--accent-blue), var(--accent-purple));
|
| 1666 |
+
-webkit-background-clip: text;
|
| 1667 |
+
-webkit-text-fill-color: transparent;
|
| 1668 |
+
background-clip: text;
|
| 1669 |
+
}
|
| 1670 |
+
|
| 1671 |
+
/* Tab Icons */
|
| 1672 |
+
.tab-icon {
|
| 1673 |
+
width: 18px;
|
| 1674 |
+
height: 18px;
|
| 1675 |
+
margin-right: 8px;
|
| 1676 |
+
display: inline-flex;
|
| 1677 |
+
align-items: center;
|
| 1678 |
+
justify-content: center;
|
| 1679 |
+
}
|
| 1680 |
+
|
| 1681 |
+
.tab-icon svg {
|
| 1682 |
+
width: 100%;
|
| 1683 |
+
height: 100%;
|
| 1684 |
+
}
|
| 1685 |
+
|
| 1686 |
+
/* Status Icons */
|
| 1687 |
+
.status-icon {
|
| 1688 |
+
width: 20px;
|
| 1689 |
+
height: 20px;
|
| 1690 |
+
display: inline-flex;
|
| 1691 |
+
align-items: center;
|
| 1692 |
+
justify-content: center;
|
| 1693 |
+
}
|
| 1694 |
+
|
| 1695 |
+
.status-icon-success svg {
|
| 1696 |
+
color: var(--accent-green);
|
| 1697 |
+
}
|
| 1698 |
+
|
| 1699 |
+
.status-icon-error svg {
|
| 1700 |
+
color: var(--accent-red);
|
| 1701 |
+
}
|
| 1702 |
+
|
| 1703 |
+
.status-icon-warning svg {
|
| 1704 |
+
color: var(--accent-yellow);
|
| 1705 |
+
}
|
| 1706 |
+
|
| 1707 |
+
.status-icon-info svg {
|
| 1708 |
+
color: var(--accent-blue);
|
| 1709 |
+
}
|
| 1710 |
</style>
|
| 1711 |
+
|
| 1712 |
+
<!-- SVG Icon Definitions -->
|
| 1713 |
+
<svg style="display: none;" xmlns="http://www.w3.org/2000/svg">
|
| 1714 |
+
<!-- Success Icon -->
|
| 1715 |
+
<symbol id="icon-success" viewBox="0 0 24 24">
|
| 1716 |
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1717 |
+
<path d="M8 12l2 2 4-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1718 |
+
</symbol>
|
| 1719 |
+
|
| 1720 |
+
<!-- Error Icon -->
|
| 1721 |
+
<symbol id="icon-error" viewBox="0 0 24 24">
|
| 1722 |
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1723 |
+
<path d="M12 8v4M12 16h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1724 |
+
</symbol>
|
| 1725 |
+
|
| 1726 |
+
<!-- Warning Icon -->
|
| 1727 |
+
<symbol id="icon-warning" viewBox="0 0 24 24">
|
| 1728 |
+
<path d="M12 2L2 22h20L12 2z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1729 |
+
<path d="M12 9v4M12 17h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1730 |
+
</symbol>
|
| 1731 |
+
|
| 1732 |
+
<!-- Info Icon -->
|
| 1733 |
+
<symbol id="icon-info" viewBox="0 0 24 24">
|
| 1734 |
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1735 |
+
<path d="M12 16v-4M12 8h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1736 |
+
</symbol>
|
| 1737 |
+
|
| 1738 |
+
<!-- Market/Chart Icon -->
|
| 1739 |
+
<symbol id="icon-market" viewBox="0 0 24 24">
|
| 1740 |
+
<path d="M3 3v18h18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1741 |
+
<path d="M7 12l4-4 4 4 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1742 |
+
</symbol>
|
| 1743 |
+
|
| 1744 |
+
<!-- Monitor/API Icon -->
|
| 1745 |
+
<symbol id="icon-monitor" viewBox="0 0 24 24">
|
| 1746 |
+
<rect x="2" y="3" width="20" height="14" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1747 |
+
<path d="M8 21h8M12 17v4" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1748 |
+
</symbol>
|
| 1749 |
+
|
| 1750 |
+
<!-- Advanced/Flash Icon -->
|
| 1751 |
+
<symbol id="icon-advanced" viewBox="0 0 24 24">
|
| 1752 |
+
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1753 |
+
</symbol>
|
| 1754 |
+
|
| 1755 |
+
<!-- Settings/Gear Icon -->
|
| 1756 |
+
<symbol id="icon-settings" viewBox="0 0 24 24">
|
| 1757 |
+
<circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1758 |
+
<path d="M12 1v6m0 6v6M5.64 5.64l4.24 4.24m4.24 4.24l4.24 4.24M1 12h6m6 0h6M5.64 18.36l4.24-4.24m4.24-4.24l4.24-4.24" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1759 |
+
</symbol>
|
| 1760 |
+
|
| 1761 |
+
<!-- HuggingFace Icon -->
|
| 1762 |
+
<symbol id="icon-hf" viewBox="0 0 24 24">
|
| 1763 |
+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2z" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1764 |
+
<path d="M8 12h8M12 8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1765 |
+
</symbol>
|
| 1766 |
+
|
| 1767 |
+
<!-- Pools/Refresh Icon -->
|
| 1768 |
+
<symbol id="icon-pools" viewBox="0 0 24 24">
|
| 1769 |
+
<path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1770 |
+
</symbol>
|
| 1771 |
+
|
| 1772 |
+
<!-- Logs/File Icon -->
|
| 1773 |
+
<symbol id="icon-logs" viewBox="0 0 24 24">
|
| 1774 |
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1775 |
+
<path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1776 |
+
</symbol>
|
| 1777 |
+
|
| 1778 |
+
<!-- Resources/Box Icon -->
|
| 1779 |
+
<symbol id="icon-resources" viewBox="0 0 24 24">
|
| 1780 |
+
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1781 |
+
<path d="M3.27 6.96L12 12.01l8.73-5.05M12 22.08V12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1782 |
+
</symbol>
|
| 1783 |
+
|
| 1784 |
+
<!-- Reports/Chart Icon -->
|
| 1785 |
+
<symbol id="icon-reports" viewBox="0 0 24 24">
|
| 1786 |
+
<path d="M3 3v18h18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1787 |
+
<path d="M18 17V9M12 17V5M6 17v-3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1788 |
+
</symbol>
|
| 1789 |
+
|
| 1790 |
+
<!-- Search Icon -->
|
| 1791 |
+
<symbol id="icon-search" viewBox="0 0 24 24">
|
| 1792 |
+
<circle cx="11" cy="11" r="8" fill="none" stroke="currentColor" stroke-width="2"/>
|
| 1793 |
+
<path d="m21 21-4.35-4.35" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1794 |
+
</symbol>
|
| 1795 |
+
|
| 1796 |
+
<!-- Refresh Icon -->
|
| 1797 |
+
<symbol id="icon-refresh" viewBox="0 0 24 24">
|
| 1798 |
+
<path d="M23 4v6h-6M1 20v-6h6M3.51 9a10 10 0 0 1 17.8-4.3M20.49 15a10 10 0 0 1-17.8 4.3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1799 |
+
</symbol>
|
| 1800 |
+
|
| 1801 |
+
<!-- Trending Up Icon -->
|
| 1802 |
+
<symbol id="icon-trending-up" viewBox="0 0 24 24">
|
| 1803 |
+
<path d="M23 6l-9.5 9.5-5-5L1 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1804 |
+
<path d="M17 6h6v6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1805 |
+
</symbol>
|
| 1806 |
+
|
| 1807 |
+
<!-- Trending Down Icon -->
|
| 1808 |
+
<symbol id="icon-trending-down" viewBox="0 0 24 24">
|
| 1809 |
+
<path d="M23 18l-9.5-9.5-5 5L1 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1810 |
+
<path d="M17 18h6v-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1811 |
+
</symbol>
|
| 1812 |
+
|
| 1813 |
+
<!-- Volume Icon -->
|
| 1814 |
+
<symbol id="icon-volume" viewBox="0 0 24 24">
|
| 1815 |
+
<path d="M11 5L6 9H2v6h4l5 4V5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1816 |
+
<path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1817 |
+
</symbol>
|
| 1818 |
+
|
| 1819 |
+
<!-- Diamond/Gem Icon -->
|
| 1820 |
+
<symbol id="icon-diamond" viewBox="0 0 24 24">
|
| 1821 |
+
<path d="M6 3h12l4 6-10 12L2 9l4-6z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1822 |
+
<path d="M11 3l1 18M13 3l-1 18M6 3l5 18M18 3l-5 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1823 |
+
</symbol>
|
| 1824 |
+
|
| 1825 |
+
<!-- Fire/Trending Icon -->
|
| 1826 |
+
<symbol id="icon-fire" viewBox="0 0 24 24">
|
| 1827 |
+
<path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1828 |
+
</symbol>
|
| 1829 |
+
|
| 1830 |
+
<!-- Link/Chain Icon -->
|
| 1831 |
+
<symbol id="icon-link" viewBox="0 0 24 24">
|
| 1832 |
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1833 |
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1834 |
+
</symbol>
|
| 1835 |
+
|
| 1836 |
+
<!-- Export/Download Icon -->
|
| 1837 |
+
<symbol id="icon-export" viewBox="0 0 24 24">
|
| 1838 |
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1839 |
+
<path d="M7 10l5 5 5-5M12 15V3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1840 |
+
</symbol>
|
| 1841 |
+
|
| 1842 |
+
<!-- Delete/Trash Icon -->
|
| 1843 |
+
<symbol id="icon-delete" viewBox="0 0 24 24">
|
| 1844 |
+
<path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1845 |
+
<path d="M10 11v6M14 11v6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
| 1846 |
+
</symbol>
|
| 1847 |
+
|
| 1848 |
+
<!-- Brain/AI Icon -->
|
| 1849 |
+
<symbol id="icon-brain" viewBox="0 0 24 24">
|
| 1850 |
+
<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44L2 22v-4a2.5 2.5 0 0 1 2.5-2.5h5z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1851 |
+
<path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44L22 22v-4a2.5 2.5 0 0 0-2.5-2.5h-5z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1852 |
+
</symbol>
|
| 1853 |
+
|
| 1854 |
+
<!-- Arrow Up Icon -->
|
| 1855 |
+
<symbol id="icon-arrow-up" viewBox="0 0 24 24">
|
| 1856 |
+
<path d="M12 19V5M5 12l7-7 7 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
| 1857 |
+
</symbol>
|
| 1858 |
+
|
| 1859 |
+
<!-- Live/Dot Icon -->
|
| 1860 |
+
<symbol id="icon-live" viewBox="0 0 24 24">
|
| 1861 |
+
<circle cx="12" cy="12" r="10" fill="currentColor"/>
|
| 1862 |
+
</symbol>
|
| 1863 |
+
</svg>
|
| 1864 |
</head>
|
| 1865 |
|
| 1866 |
<body>
|
|
|
|
| 1912 |
</div>
|
| 1913 |
</div>
|
| 1914 |
<div class="header-actions">
|
| 1915 |
+
<div class="live-indicator">
|
| 1916 |
+
<span class="status-icon"><svg><use href="#icon-live"></use></svg></span>
|
| 1917 |
+
LIVE
|
| 1918 |
+
</div>
|
| 1919 |
<div class="status-badge">
|
| 1920 |
<div class="status-dot"></div>
|
| 1921 |
<span id="statusText">All Systems Operational</span>
|
|
|
|
| 1925 |
|
| 1926 |
<!-- Tabs -->
|
| 1927 |
<div class="tabs">
|
| 1928 |
+
<button class="tab active" onclick="switchTab('market')">
|
| 1929 |
+
<span class="tab-icon"><svg><use href="#icon-market"></use></svg></span>
|
| 1930 |
+
Market
|
| 1931 |
+
</button>
|
| 1932 |
+
<button class="tab" onclick="switchTab('monitor')">
|
| 1933 |
+
<span class="tab-icon"><svg><use href="#icon-monitor"></use></svg></span>
|
| 1934 |
+
API Monitor
|
| 1935 |
+
</button>
|
| 1936 |
+
<button class="tab" onclick="switchTab('advanced')">
|
| 1937 |
+
<span class="tab-icon"><svg><use href="#icon-advanced"></use></svg></span>
|
| 1938 |
+
Advanced
|
| 1939 |
+
</button>
|
| 1940 |
+
<button class="tab" onclick="switchTab('admin')">
|
| 1941 |
+
<span class="tab-icon"><svg><use href="#icon-settings"></use></svg></span>
|
| 1942 |
+
Admin
|
| 1943 |
+
</button>
|
| 1944 |
+
<button class="tab" onclick="switchTab('hf')">
|
| 1945 |
+
<span class="tab-icon"><svg><use href="#icon-hf"></use></svg></span>
|
| 1946 |
+
HuggingFace
|
| 1947 |
+
</button>
|
| 1948 |
+
<button class="tab" onclick="switchTab('pools')">
|
| 1949 |
+
<span class="tab-icon"><svg><use href="#icon-pools"></use></svg></span>
|
| 1950 |
+
Pools
|
| 1951 |
+
</button>
|
| 1952 |
+
<button class="tab" onclick="switchTab('logs')">
|
| 1953 |
+
<span class="tab-icon"><svg><use href="#icon-logs"></use></svg></span>
|
| 1954 |
+
Logs
|
| 1955 |
+
</button>
|
| 1956 |
+
<button class="tab" onclick="switchTab('resources')">
|
| 1957 |
+
<span class="tab-icon"><svg><use href="#icon-resources"></use></svg></span>
|
| 1958 |
+
Resources
|
| 1959 |
+
</button>
|
| 1960 |
+
<button class="tab" onclick="switchTab('reports')">
|
| 1961 |
+
<span class="tab-icon"><svg><use href="#icon-reports"></use></svg></span>
|
| 1962 |
+
Reports
|
| 1963 |
+
</button>
|
| 1964 |
</div>
|
| 1965 |
</div>
|
| 1966 |
|
|
|
|
| 2064 |
<!-- Market Table -->
|
| 2065 |
<div class="market-section">
|
| 2066 |
<div class="section-header">
|
| 2067 |
+
<div class="section-title gradient-text">
|
| 2068 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-diamond"></use></svg></span>
|
| 2069 |
+
Live Market Data
|
| 2070 |
+
</div>
|
| 2071 |
+
<button class="refresh-btn ripple" onclick="loadMarketData()" data-tooltip="بهروزرسانی دادههای بازار">
|
| 2072 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2073 |
+
Refresh
|
| 2074 |
+
</button>
|
| 2075 |
</div>
|
| 2076 |
|
| 2077 |
<!-- Search Bar -->
|
| 2078 |
<div class="search-container">
|
| 2079 |
+
<span class="search-icon icon"><svg><use href="#icon-search"></use></svg></span>
|
| 2080 |
<input type="text" class="search-input" id="marketSearch" placeholder="جستجوی ارز دیجیتال (مثال: Bitcoin, BTC, Ethereum)..." oninput="filterMarketTable()">
|
| 2081 |
</div>
|
| 2082 |
|
|
|
|
| 2084 |
<div class="filter-chips">
|
| 2085 |
<button class="filter-chip active" onclick="filterByCategory('all')">همه</button>
|
| 2086 |
<button class="filter-chip" onclick="filterByCategory('top10')">Top 10</button>
|
| 2087 |
+
<button class="filter-chip" onclick="filterByCategory('gainers')">
|
| 2088 |
+
<span class="icon icon-sm status-icon-success"><svg><use href="#icon-trending-up"></use></svg></span>
|
| 2089 |
+
در حال رشد
|
| 2090 |
+
</button>
|
| 2091 |
+
<button class="filter-chip" onclick="filterByCategory('losers')">
|
| 2092 |
+
<span class="icon icon-sm status-icon-error"><svg><use href="#icon-trending-down"></use></svg></span>
|
| 2093 |
+
در حال سقوط
|
| 2094 |
+
</button>
|
| 2095 |
+
<button class="filter-chip" onclick="filterByCategory('volume')">
|
| 2096 |
+
<span class="icon icon-sm"><svg><use href="#icon-volume"></use></svg></span>
|
| 2097 |
+
حجم بالا
|
| 2098 |
+
</button>
|
| 2099 |
</div>
|
| 2100 |
<div style="overflow-x: auto;">
|
| 2101 |
<table id="marketTable">
|
|
|
|
| 2144 |
|
| 2145 |
<!-- Trending Section -->
|
| 2146 |
<div class="market-section">
|
| 2147 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2148 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-fire"></use></svg></span>
|
| 2149 |
+
Trending Now
|
| 2150 |
+
</div>
|
| 2151 |
<div id="trendingGrid"
|
| 2152 |
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
|
| 2153 |
<div class="loading">
|
|
|
|
| 2226 |
|
| 2227 |
<div class="market-section">
|
| 2228 |
<div class="section-header">
|
| 2229 |
+
<div class="section-title">
|
| 2230 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-monitor"></use></svg></span>
|
| 2231 |
+
API Providers Status
|
| 2232 |
+
</div>
|
| 2233 |
+
<button class="refresh-btn ripple" onclick="loadMonitorData()">
|
| 2234 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2235 |
+
Refresh
|
| 2236 |
+
</button>
|
| 2237 |
</div>
|
| 2238 |
<div style="overflow-x: auto;">
|
| 2239 |
<table>
|
|
|
|
| 2256 |
</div>
|
| 2257 |
|
| 2258 |
<div class="market-section">
|
| 2259 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2260 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-brain"></use></svg></span>
|
| 2261 |
+
HuggingFace Sentiment Analysis
|
| 2262 |
+
</div>
|
| 2263 |
<div class="form-group">
|
| 2264 |
<label class="form-label">Enter crypto-related text (one per line):</label>
|
| 2265 |
<textarea class="form-textarea" id="sentimentText" rows="5"
|
|
|
|
| 2267 |
ETH looks weak
|
| 2268 |
Market is bullish today</textarea>
|
| 2269 |
</div>
|
| 2270 |
+
<button class="refresh-btn ripple" onclick="runSentiment()">
|
| 2271 |
+
<span class="icon icon-sm"><svg><use href="#icon-brain"></use></svg></span>
|
| 2272 |
+
Analyze Sentiment
|
| 2273 |
+
</button>
|
| 2274 |
<div id="sentimentResult"
|
| 2275 |
style="margin-top: 20px; padding: 20px; background: rgba(17, 24, 39, 0.6); border-radius: 12px; text-align: center; font-size: 36px; font-weight: 900;">
|
| 2276 |
—</div>
|
|
|
|
| 2404 |
</div>
|
| 2405 |
|
| 2406 |
<div class="market-section">
|
| 2407 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2408 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-logs"></use></svg></span>
|
| 2409 |
+
Current API Sources
|
| 2410 |
+
</div>
|
| 2411 |
<div id="apisList">Loading...</div>
|
| 2412 |
</div>
|
| 2413 |
|
| 2414 |
<div class="market-section">
|
| 2415 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2416 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-settings"></use></svg></span>
|
| 2417 |
+
Settings
|
| 2418 |
+
</div>
|
| 2419 |
<div class="form-group">
|
| 2420 |
<label class="form-label">API Check Interval (seconds)</label>
|
| 2421 |
<input type="number" class="form-input" id="checkInterval" value="30" min="10" max="300">
|
|
|
|
| 2428 |
</div>
|
| 2429 |
|
| 2430 |
<div class="market-section">
|
| 2431 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2432 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-reports"></use></svg></span>
|
| 2433 |
+
Statistics
|
| 2434 |
+
</div>
|
| 2435 |
<div class="stats-grid">
|
| 2436 |
<div class="stat-card">
|
| 2437 |
<div class="stat-value" id="statTotal">0</div>
|
|
|
|
| 2453 |
<div id="tab-hf" class="tab-content">
|
| 2454 |
<div class="market-section">
|
| 2455 |
<div class="section-header">
|
| 2456 |
+
<div class="section-title">
|
| 2457 |
+
<span class="icon icon-md" style="margin-left: 8px;"><svg><use href="#icon-reports"></use></svg></span>
|
| 2458 |
+
Health Status
|
| 2459 |
+
</div>
|
| 2460 |
+
<button class="refresh-btn ripple" onclick="loadHFHealth()">
|
| 2461 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2462 |
+
Refresh
|
| 2463 |
+
</button>
|
| 2464 |
</div>
|
| 2465 |
<pre id="healthOutput"
|
| 2466 |
style="background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 8px; overflow-x: auto; font-size: 12px; max-height: 200px; overflow-y: auto;">Loading...</pre>
|
|
|
|
| 2505 |
</div>
|
| 2506 |
|
| 2507 |
<div class="market-section">
|
| 2508 |
+
<div class="section-title" style="margin-bottom: 20px;">
|
| 2509 |
+
<span class="icon icon-md"><svg><use href="#icon-brain"></use></svg></span>
|
| 2510 |
+
Sentiment Analysis
|
| 2511 |
+
</div>
|
| 2512 |
<div class="form-group">
|
| 2513 |
<label class="form-label">Enter text samples (one per line):</label>
|
| 2514 |
<textarea class="form-textarea" id="sentimentTexts" rows="5"
|
|
|
|
| 2516 |
ETH looks weak
|
| 2517 |
Crypto market is bullish today</textarea>
|
| 2518 |
</div>
|
| 2519 |
+
<button class="refresh-btn ripple" onclick="doSentiment()">
|
| 2520 |
+
<span class="icon icon-sm"><svg><use href="#icon-brain"></use></svg></span>
|
| 2521 |
+
Run Sentiment Analysis
|
| 2522 |
+
</button>
|
| 2523 |
<div id="voteDisplay"
|
| 2524 |
style="margin-top: 20px; padding: 20px; background: rgba(17, 24, 39, 0.6); border-radius: 12px; text-align: center; font-size: 36px; font-weight: 900;">
|
| 2525 |
—</div>
|
|
|
|
| 2532 |
<div id="tab-logs" class="tab-content">
|
| 2533 |
<div class="market-section">
|
| 2534 |
<div class="section-header">
|
| 2535 |
+
<div class="section-title">
|
| 2536 |
+
<span class="icon icon-md"><svg><use href="#icon-logs"></use></svg></span>
|
| 2537 |
+
Log Management
|
| 2538 |
+
</div>
|
| 2539 |
<div style="display: flex; gap: 10px;">
|
| 2540 |
+
<button class="refresh-btn ripple" onclick="loadLogs()">
|
| 2541 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2542 |
+
Refresh
|
| 2543 |
+
</button>
|
| 2544 |
+
<button class="refresh-btn ripple" onclick="exportLogsJSON()"
|
| 2545 |
+
style="background: rgba(16, 185, 129, 0.2); color: var(--accent-green);">
|
| 2546 |
+
<span class="icon icon-sm"><svg><use href="#icon-export"></use></svg></span>
|
| 2547 |
+
Export JSON
|
| 2548 |
+
</button>
|
| 2549 |
+
<button class="refresh-btn ripple" onclick="exportLogsCSV()"
|
| 2550 |
+
style="background: rgba(16, 185, 129, 0.2); color: var(--accent-green);">
|
| 2551 |
+
<span class="icon icon-sm"><svg><use href="#icon-reports"></use></svg></span>
|
| 2552 |
+
Export CSV
|
| 2553 |
+
</button>
|
| 2554 |
+
<button class="refresh-btn ripple" onclick="clearAllLogs()"
|
| 2555 |
+
style="background: rgba(239, 68, 68, 0.2); color: var(--accent-red);">
|
| 2556 |
+
<span class="icon icon-sm"><svg><use href="#icon-delete"></use></svg></span>
|
| 2557 |
+
Clear
|
| 2558 |
+
</button>
|
| 2559 |
</div>
|
| 2560 |
</div>
|
| 2561 |
|
|
|
|
| 2738 |
|
| 2739 |
<!-- Reports Tab -->
|
| 2740 |
<div id="tab-reports" class="tab-content">
|
| 2741 |
+
<!-- System Status Alerts -->
|
| 2742 |
+
<div class="market-section" id="systemAlertsSection" style="display: none;">
|
| 2743 |
+
<div class="section-header">
|
| 2744 |
+
<div class="section-title">
|
| 2745 |
+
<span class="icon icon-md status-icon-warning"><svg><use href="#icon-warning"></use></svg></span>
|
| 2746 |
+
System Status & Alerts
|
| 2747 |
+
</div>
|
| 2748 |
+
<button class="refresh-btn ripple" onclick="loadSystemAlerts()">
|
| 2749 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2750 |
+
Refresh
|
| 2751 |
+
</button>
|
| 2752 |
+
</div>
|
| 2753 |
+
<div id="systemAlertsContainer"></div>
|
| 2754 |
+
</div>
|
| 2755 |
+
|
| 2756 |
<div class="market-section">
|
| 2757 |
<div class="section-header">
|
| 2758 |
+
<div class="section-title">
|
| 2759 |
+
<span class="icon icon-md"><svg><use href="#icon-search"></use></svg></span>
|
| 2760 |
+
System Diagnostics
|
| 2761 |
+
</div>
|
| 2762 |
<div style="display: flex; gap: 10px;">
|
| 2763 |
+
<button class="refresh-btn ripple" onclick="runDiagnostics(false)"
|
| 2764 |
+
style="background: rgba(59, 130, 246, 0.2); color: var(--accent-blue);">
|
| 2765 |
+
<span class="icon icon-sm"><svg><use href="#icon-search"></use></svg></span>
|
| 2766 |
+
بررسی
|
| 2767 |
+
</button>
|
| 2768 |
+
<button class="refresh-btn ripple" onclick="runDiagnostics(true)"
|
| 2769 |
+
style="background: rgba(16, 185, 129, 0.2); color: var(--accent-green);">
|
| 2770 |
+
<span class="icon icon-sm"><svg><use href="#icon-settings"></use></svg></span>
|
| 2771 |
+
بررسی و تعمیر
|
| 2772 |
+
</button>
|
| 2773 |
+
<button class="refresh-btn ripple" onclick="loadReports()">
|
| 2774 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2775 |
+
بهروزرسانی
|
| 2776 |
+
</button>
|
| 2777 |
</div>
|
| 2778 |
</div>
|
| 2779 |
|
|
|
|
| 2787 |
|
| 2788 |
<div class="market-section">
|
| 2789 |
<div class="section-header">
|
| 2790 |
+
<div class="section-title">
|
| 2791 |
+
<span class="icon icon-md"><svg><use href="#icon-pools"></use></svg></span>
|
| 2792 |
+
Auto-Discovery Service Report
|
| 2793 |
+
</div>
|
| 2794 |
+
<button class="refresh-btn ripple" onclick="loadDiscoveryReport()">
|
| 2795 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2796 |
+
بهروزرسانی
|
| 2797 |
+
</button>
|
| 2798 |
</div>
|
| 2799 |
<div id="discoveryReport">
|
| 2800 |
<div class="loading">
|
|
|
|
| 2805 |
|
| 2806 |
<div class="market-section">
|
| 2807 |
<div class="section-header">
|
| 2808 |
+
<div class="section-title">
|
| 2809 |
+
<span class="icon icon-md"><svg><use href="#icon-brain"></use></svg></span>
|
| 2810 |
+
HuggingFace Models Status Report
|
| 2811 |
+
</div>
|
| 2812 |
+
<button class="refresh-btn ripple" onclick="loadModelsReport()">
|
| 2813 |
+
<span class="icon icon-sm"><svg><use href="#icon-refresh"></use></svg></span>
|
| 2814 |
+
بهروزرسانی
|
| 2815 |
+
</button>
|
| 2816 |
</div>
|
| 2817 |
<div id="modelsReport">
|
| 2818 |
<div class="loading">
|
|
|
|
| 3045 |
|
| 3046 |
// Call updateStats with validated data - double check before calling
|
| 3047 |
if (stats && stats.market && typeof stats.market === 'object' && !Array.isArray(stats.market)) {
|
| 3048 |
+
updateStats(stats, sentiment);
|
| 3049 |
} else {
|
| 3050 |
console.error('Failed final validation before updateStats:', { stats, sentiment });
|
| 3051 |
throw new Error('دادههای stats.market نامعتبر است');
|
|
|
|
| 3138 |
if (sentimentLabelEl) {
|
| 3139 |
sentimentLabelEl.innerHTML = `<span>${classification}</span>`;
|
| 3140 |
|
| 3141 |
+
if (fg < 25) {
|
| 3142 |
sentimentLabelEl.style.color = 'var(--accent-red)';
|
| 3143 |
+
} else if (fg < 45) {
|
| 3144 |
sentimentLabelEl.style.color = 'var(--accent-yellow)';
|
| 3145 |
+
} else if (fg < 55) {
|
| 3146 |
sentimentLabelEl.style.color = 'var(--text-secondary)';
|
| 3147 |
+
} else if (fg < 75) {
|
| 3148 |
sentimentLabelEl.style.color = 'var(--accent-blue)';
|
| 3149 |
+
} else {
|
| 3150 |
sentimentLabelEl.style.color = 'var(--accent-green)';
|
| 3151 |
}
|
| 3152 |
}
|
|
|
|
| 3160 |
function updateMarketTable(cryptos) {
|
| 3161 |
try {
|
| 3162 |
if (!cryptos || !Array.isArray(cryptos) || cryptos.length === 0) {
|
| 3163 |
+
const tbody = document.getElementById('marketTableBody');
|
| 3164 |
if (tbody) {
|
| 3165 |
tbody.innerHTML = '<tr><td colspan="6" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ دادهای یافت نشد</td></tr>';
|
| 3166 |
}
|
|
|
|
| 3185 |
|
| 3186 |
return `
|
| 3187 |
<tr data-name="${name.toLowerCase()}" data-symbol="${symbol.toLowerCase()}" data-change="${change24h}" data-rank="${crypto.rank || index + 1}">
|
| 3188 |
+
<td style="font-weight: 700; color: var(--text-secondary);">${crypto.rank || index + 1}</td>
|
| 3189 |
+
<td>
|
| 3190 |
+
<div class="crypto-name">
|
| 3191 |
${crypto.image ? `<img src="${crypto.image}" class="crypto-img" alt="${symbol}" onerror="this.style.display='none'">` :
|
| 3192 |
`<div class="crypto-img" style="background: linear-gradient(135deg, #3b82f6, #8b5cf6); display: flex; align-items: center; justify-content: center; font-weight: 700; color: white;">${symbol[0] || '?'}</div>`}
|
| 3193 |
+
<div>
|
| 3194 |
<div style="font-weight: 600;">${name}</div>
|
| 3195 |
<div class="crypto-symbol">${symbol}</div>
|
| 3196 |
+
</div>
|
| 3197 |
+
</div>
|
| 3198 |
+
</td>
|
| 3199 |
<td class="price number-counter">$${price.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 6 })}</td>
|
| 3200 |
<td><span class="change ${changeClass} pulse-data">${changeIcon} ${change24h >= 0 ? '+' : ''}${change24h.toFixed(2)}%</span></td>
|
| 3201 |
<td style="font-weight: 600;">$${(marketCap / 1e9).toFixed(2)}B</td>
|
| 3202 |
<td style="color: var(--text-secondary);">$${(volume24h / 1e9).toFixed(2)}B</td>
|
| 3203 |
+
</tr>
|
| 3204 |
`;
|
| 3205 |
}).join('');
|
| 3206 |
} catch (error) {
|
|
|
|
| 3214 |
|
| 3215 |
function updateTrending(trending) {
|
| 3216 |
try {
|
| 3217 |
+
const grid = document.getElementById('trendingGrid');
|
| 3218 |
if (!grid) return;
|
| 3219 |
|
| 3220 |
if (!trending || !Array.isArray(trending) || trending.length === 0) {
|
|
|
|
| 3226 |
const name = coin.name || 'نامشخص';
|
| 3227 |
const symbol = coin.symbol || 'N/A';
|
| 3228 |
return `
|
| 3229 |
+
<div style="background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.2); border-radius: 12px; padding: 15px; display: flex; align-items: center; gap: 12px;">
|
| 3230 |
+
<div style="font-size: 20px; font-weight: 900; color: var(--accent-yellow);">#${index + 1}</div>
|
| 3231 |
${coin.thumb ? `<img src="${coin.thumb}" style="width: 32px; height: 32px; border-radius: 8px;" onerror="this.style.display='none'">` : ''}
|
| 3232 |
+
<div>
|
| 3233 |
<div style="font-weight: 600;">${name}</div>
|
| 3234 |
<div style="font-size: 12px; color: var(--text-secondary);">${symbol}</div>
|
| 3235 |
+
</div>
|
| 3236 |
+
</div>
|
| 3237 |
`;
|
| 3238 |
}).join('');
|
| 3239 |
} catch (error) {
|
|
|
|
| 3247 |
|
| 3248 |
function updateDeFi(defi) {
|
| 3249 |
try {
|
| 3250 |
+
const list = document.getElementById('defiList');
|
| 3251 |
if (!list) return;
|
| 3252 |
|
| 3253 |
const protocols = defi && defi.protocols ? defi.protocols : [];
|
| 3254 |
const totalTvl = defi && defi.total_tvl ? defi.total_tvl : 0;
|
| 3255 |
|
| 3256 |
+
list.innerHTML = `
|
| 3257 |
<div class="stat-card" style="margin-bottom: 20px; text-align: center; background: linear-gradient(135deg, rgba(59, 130, 246, 0.2), rgba(139, 92, 246, 0.2));">
|
| 3258 |
<div class="stat-value gradient-text" style="font-size: 42px; margin-bottom: 8px;">$${(totalTvl / 1e9).toFixed(2)}B</div>
|
| 3259 |
<div class="stat-label" style="font-size: 16px;">Total Value Locked</div>
|
| 3260 |
+
</div>
|
| 3261 |
+
<div style="display: grid; gap: 12px;">
|
| 3262 |
${protocols.length > 0 ? protocols.map((p, i) => {
|
| 3263 |
const name = p.name || 'نامشخص';
|
| 3264 |
const chain = p.chain || 'N/A';
|
|
|
|
| 3268 |
return `
|
| 3269 |
<div class="stat-card" style="animation-delay: ${i * 0.05}s; cursor: pointer;" onclick="showToast('${name}: $${(tvl / 1e9).toFixed(2)}B TVL', 'info', 'DeFi Protocol')">
|
| 3270 |
<div style="display: flex; justify-content: space-between; align-items: center;">
|
| 3271 |
+
<div>
|
| 3272 |
<div style="font-weight: 700; font-size: 16px; margin-bottom: 4px;">${i + 1}. ${name}</div>
|
| 3273 |
<div style="font-size: 12px; color: var(--text-secondary); display: flex; align-items: center; gap: 6px;">
|
| 3274 |
<span>🔗</span> <span>${chain}</span>
|
| 3275 |
</div>
|
| 3276 |
+
</div>
|
| 3277 |
+
<div style="text-align: right;">
|
| 3278 |
<div class="stat-value" style="font-size: 18px; margin-bottom: 4px;">$${(tvl / 1e9).toFixed(2)}B</div>
|
| 3279 |
<div class="stat-change ${changeClass}" style="font-size: 13px;">
|
| 3280 |
${change24h >= 0 ? '📈' : '📉'} ${change24h >= 0 ? '+' : ''}${change24h.toFixed(2)}%
|
|
|
|
|
|
|
|
|
|
| 3281 |
</div>
|
| 3282 |
+
</div>
|
| 3283 |
+
</div>
|
| 3284 |
+
</div>
|
| 3285 |
+
`;
|
| 3286 |
}).join('') : '<div class="empty-state"><div class="empty-state-icon">📦</div><div>هیچ پروتکلی یافت نشد</div></div>'}
|
| 3287 |
</div>
|
| 3288 |
`;
|
|
|
|
| 3379 |
window.wsClient.on('stats_update', (message) => {
|
| 3380 |
console.log('📊 Stats update:', message.data);
|
| 3381 |
if (typeof updateOnlineStats === 'function') {
|
| 3382 |
+
updateOnlineStats(message.data);
|
| 3383 |
}
|
| 3384 |
});
|
| 3385 |
|
|
|
|
| 3407 |
// درخواست آمار هر 10 ثانیه (فقط یک بار تنظیم شود)
|
| 3408 |
if (!wsStatsInterval) {
|
| 3409 |
wsStatsInterval = setInterval(() => {
|
| 3410 |
+
if (window.wsClient && window.wsClient.isConnected) {
|
| 3411 |
+
window.wsClient.requestStats();
|
| 3412 |
+
}
|
| 3413 |
+
}, 10000);
|
| 3414 |
}
|
| 3415 |
} else {
|
| 3416 |
wsConnectAttempts++;
|
|
|
|
| 3419 |
if (wsConnectAttempts % 5 === 0 || wsConnectAttempts === 1) {
|
| 3420 |
console.log(`⏳ در انتظار WebSocket Client... (${wsConnectAttempts}/${MAX_WS_CONNECT_ATTEMPTS})`);
|
| 3421 |
}
|
| 3422 |
+
setTimeout(connectWebSocket, 1000);
|
| 3423 |
} else {
|
| 3424 |
console.warn('⚠️ WebSocket Client پس از ' + MAX_WS_CONNECT_ATTEMPTS + ' تلاش آماده نشد. ممکن است فایل websocket-client.js لود نشده باشد یا WebSocket پشتیبانی نشود.');
|
| 3425 |
console.warn('⚠️ بررسی کنید که فایل /static/js/websocket-client.js به درستی لود شده باشد.');
|
|
|
|
| 3513 |
if (providers.length === 0) {
|
| 3514 |
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ APIای یافت نشد</td></tr>';
|
| 3515 |
} else {
|
| 3516 |
+
tbody.innerHTML = providers.map(p => {
|
| 3517 |
+
let statusClass = 'badge-success';
|
| 3518 |
+
if (p.status === 'offline') statusClass = 'badge-danger';
|
| 3519 |
+
else if (p.status === 'degraded') statusClass = 'badge-warning';
|
| 3520 |
|
| 3521 |
+
return `
|
| 3522 |
+
<tr>
|
| 3523 |
<td><strong>${p.name || 'نامشخص'}</strong></td>
|
| 3524 |
<td><span class="badge badge-info">${p.category || 'نامشخص'}</span></td>
|
| 3525 |
<td><span class="badge ${statusClass}">${(p.status || 'unknown').toUpperCase()}</span></td>
|
| 3526 |
<td>${p.response_time_ms || p.avg_response_time_ms || 0}ms</td>
|
| 3527 |
<td style="color: var(--text-secondary); font-size: 13px;">${p.last_fetch ? new Date(p.last_fetch).toLocaleTimeString() : 'نامشخص'}</td>
|
| 3528 |
+
</tr>
|
| 3529 |
+
`;
|
| 3530 |
+
}).join('');
|
| 3531 |
}
|
| 3532 |
}
|
| 3533 |
} catch (error) {
|
|
|
|
| 4224 |
// Auto hide after 3 seconds
|
| 4225 |
setTimeout(() => {
|
| 4226 |
hideFeedback();
|
| 4227 |
+
}, 3000);
|
| 4228 |
}
|
| 4229 |
}
|
| 4230 |
|
|
|
|
| 4655 |
]);
|
| 4656 |
}
|
| 4657 |
|
| 4658 |
+
// Load System Alerts
|
| 4659 |
+
async function loadSystemAlerts() {
|
| 4660 |
+
try {
|
| 4661 |
+
const response = await fetch('/api/diagnostics/last');
|
| 4662 |
+
const report = await response.json();
|
| 4663 |
+
|
| 4664 |
+
if (report.message || !report.issues || report.issues.length === 0) {
|
| 4665 |
+
document.getElementById('systemAlertsSection').style.display = 'none';
|
| 4666 |
+
return;
|
| 4667 |
+
}
|
| 4668 |
+
|
| 4669 |
+
displaySystemAlerts(report.issues);
|
| 4670 |
+
document.getElementById('systemAlertsSection').style.display = 'block';
|
| 4671 |
+
} catch (error) {
|
| 4672 |
+
console.error('Error loading system alerts:', error);
|
| 4673 |
+
}
|
| 4674 |
+
}
|
| 4675 |
+
|
| 4676 |
+
function displaySystemAlerts(issues) {
|
| 4677 |
+
const container = document.getElementById('systemAlertsContainer');
|
| 4678 |
+
if (!container) return;
|
| 4679 |
+
|
| 4680 |
+
const severityConfig = {
|
| 4681 |
+
'critical': {
|
| 4682 |
+
icon: 'icon-error',
|
| 4683 |
+
color: 'var(--accent-red)',
|
| 4684 |
+
bg: 'rgba(239, 68, 68, 0.1)',
|
| 4685 |
+
border: 'rgba(239, 68, 68, 0.3)'
|
| 4686 |
+
},
|
| 4687 |
+
'warning': {
|
| 4688 |
+
icon: 'icon-warning',
|
| 4689 |
+
color: 'var(--accent-yellow)',
|
| 4690 |
+
bg: 'rgba(245, 158, 11, 0.1)',
|
| 4691 |
+
border: 'rgba(245, 158, 11, 0.3)'
|
| 4692 |
+
},
|
| 4693 |
+
'info': {
|
| 4694 |
+
icon: 'icon-info',
|
| 4695 |
+
color: 'var(--accent-blue)',
|
| 4696 |
+
bg: 'rgba(59, 130, 246, 0.1)',
|
| 4697 |
+
border: 'rgba(59, 130, 246, 0.3)'
|
| 4698 |
+
}
|
| 4699 |
+
};
|
| 4700 |
+
|
| 4701 |
+
const solutions = {
|
| 4702 |
+
'HF_API_TOKEN': {
|
| 4703 |
+
title: 'تنظیم متغیر محیطی HF_API_TOKEN',
|
| 4704 |
+
steps: [
|
| 4705 |
+
'1. یک توکن از HuggingFace دریافت کنید:',
|
| 4706 |
+
' - به https://huggingface.co/settings/tokens بروید',
|
| 4707 |
+
' - یک توکن جدید ایجاد کنید',
|
| 4708 |
+
'2. توکن را به متغیر محیطی اضافه کنید:',
|
| 4709 |
+
' Windows: set HF_API_TOKEN=your_token_here',
|
| 4710 |
+
' Linux/Mac: export HF_API_TOKEN=your_token_here',
|
| 4711 |
+
' یا در فایل .env: HF_API_TOKEN=your_token_here'
|
| 4712 |
+
]
|
| 4713 |
+
},
|
| 4714 |
+
'resources.json': {
|
| 4715 |
+
title: 'ایجاد فایل resources.json',
|
| 4716 |
+
steps: [
|
| 4717 |
+
'این فایل به صورت خودکار ساخته میشود.',
|
| 4718 |
+
'اگر نیاز به تنظیمات دستی دارید، میتوانید آن را ایجاد کنید:',
|
| 4719 |
+
'{',
|
| 4720 |
+
' "resources": []',
|
| 4721 |
+
'}'
|
| 4722 |
+
]
|
| 4723 |
+
},
|
| 4724 |
+
'config.json': {
|
| 4725 |
+
title: 'ایجاد فایل config.json',
|
| 4726 |
+
steps: [
|
| 4727 |
+
'این فایل به صورت خودکار ساخته میشود.',
|
| 4728 |
+
'اگر نیاز به تنظیمات دستی دارید، میتوانید آن را ایجاد کنید.'
|
| 4729 |
+
]
|
| 4730 |
+
},
|
| 4731 |
+
'HuggingFace API': {
|
| 4732 |
+
title: 'رفع مشکل اتصال به HuggingFace',
|
| 4733 |
+
steps: [
|
| 4734 |
+
'1. بررسی اتصال اینترنت',
|
| 4735 |
+
'2. بررسی فایروال و پروکسی',
|
| 4736 |
+
'3. بررسی DNS settings',
|
| 4737 |
+
'4. اگر از VPN استفاده میکنید، آن را غیرفعال کنید',
|
| 4738 |
+
'5. بررسی کنید که https://api.huggingface.co قابل دسترسی باشد'
|
| 4739 |
+
]
|
| 4740 |
+
},
|
| 4741 |
+
'Auto-Discovery': {
|
| 4742 |
+
title: 'فعالسازی Auto-Discovery Service',
|
| 4743 |
+
steps: [
|
| 4744 |
+
'برای فعالسازی سرویس Auto-Discovery:',
|
| 4745 |
+
'1. متغیر محیطی را تنظیم کنید:',
|
| 4746 |
+
' export ENABLE_AUTO_DISCOVERY=true',
|
| 4747 |
+
'2. یا در فایل .env اضافه کنید:',
|
| 4748 |
+
' ENABLE_AUTO_DISCOVERY=true',
|
| 4749 |
+
'3. سرور را restart کنید'
|
| 4750 |
+
]
|
| 4751 |
+
}
|
| 4752 |
+
};
|
| 4753 |
+
|
| 4754 |
+
let html = '';
|
| 4755 |
+
issues.forEach((issue, index) => {
|
| 4756 |
+
const config = severityConfig[issue.severity] || severityConfig['info'];
|
| 4757 |
+
const solutionKey = issue.title.includes('HF_API_TOKEN') ? 'HF_API_TOKEN' :
|
| 4758 |
+
issue.title.includes('resources.json') ? 'resources.json' :
|
| 4759 |
+
issue.title.includes('config.json') ? 'config.json' :
|
| 4760 |
+
issue.title.includes('HuggingFace') ? 'HuggingFace API' :
|
| 4761 |
+
issue.title.includes('Auto-Discovery') ? 'Auto-Discovery' : null;
|
| 4762 |
+
|
| 4763 |
+
const solution = solutionKey ? solutions[solutionKey] : null;
|
| 4764 |
+
|
| 4765 |
+
html += `
|
| 4766 |
+
<div class="stat-card" style="margin-bottom: 15px; border-left: 4px solid ${config.border}; background: ${config.bg}; animation-delay: ${index * 0.1}s;">
|
| 4767 |
+
<div style="display: flex; align-items: start; gap: 12px;">
|
| 4768 |
+
<div class="icon icon-md status-icon-${issue.severity}" style="flex-shrink: 0; margin-top: 2px;">
|
| 4769 |
+
<svg><use href="#${config.icon}"></use></svg>
|
| 4770 |
+
</div>
|
| 4771 |
+
<div style="flex: 1;">
|
| 4772 |
+
<div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 8px;">
|
| 4773 |
+
<div>
|
| 4774 |
+
<h3 style="font-size: 16px; font-weight: 700; margin-bottom: 4px; color: ${config.color};">
|
| 4775 |
+
${issue.title}
|
| 4776 |
+
</h3>
|
| 4777 |
+
<div style="font-size: 13px; color: var(--text-secondary); margin-bottom: 8px;">
|
| 4778 |
+
${issue.description}
|
| 4779 |
+
</div>
|
| 4780 |
+
</div>
|
| 4781 |
+
<span class="badge badge-${issue.severity === 'critical' ? 'danger' : issue.severity === 'warning' ? 'warning' : 'info'}" style="flex-shrink: 0;">
|
| 4782 |
+
${issue.category}
|
| 4783 |
+
</span>
|
| 4784 |
+
</div>
|
| 4785 |
+
|
| 4786 |
+
${solution ? `
|
| 4787 |
+
<div style="margin-top: 12px; padding: 12px; background: rgba(17, 24, 39, 0.6); border-radius: 8px; border: 1px solid var(--border);">
|
| 4788 |
+
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">
|
| 4789 |
+
<span class="icon icon-sm status-icon-info"><svg><use href="#icon-info"></use></svg></span>
|
| 4790 |
+
<strong style="font-size: 14px;">راهحل:</strong>
|
| 4791 |
+
</div>
|
| 4792 |
+
<div style="font-size: 12px; color: var(--text-secondary); font-family: 'Courier New', monospace; line-height: 1.8;">
|
| 4793 |
+
${solution.steps.map(step => `<div style="margin-bottom: 4px;">${step}</div>`).join('')}
|
| 4794 |
+
</div>
|
| 4795 |
+
</div>
|
| 4796 |
+
` : ''}
|
| 4797 |
+
|
| 4798 |
+
<div style="margin-top: 8px; font-size: 11px; color: var(--text-secondary);">
|
| 4799 |
+
${new Date(issue.timestamp).toLocaleString('fa-IR')}
|
| 4800 |
+
</div>
|
| 4801 |
+
</div>
|
| 4802 |
+
</div>
|
| 4803 |
+
</div>
|
| 4804 |
+
`;
|
| 4805 |
+
});
|
| 4806 |
+
|
| 4807 |
+
container.innerHTML = html || '<div style="text-align: center; padding: 40px; color: var(--text-secondary);">هیچ هشداری یافت نشد</div>';
|
| 4808 |
+
}
|
| 4809 |
+
|
| 4810 |
async function runDiagnostics(autoFix = false) {
|
| 4811 |
const resultsDiv = document.getElementById('diagnosticsResults');
|
| 4812 |
resultsDiv.innerHTML = '<div class="loading"><div class="spinner"></div></div>';
|
|
|
|
| 4818 |
const report = await response.json();
|
| 4819 |
|
| 4820 |
displayDiagnosticsReport(report);
|
| 4821 |
+
showToast(`اشکالیابی انجام شد (${report.total_issues} مشکل یافت شد)`, 'success', 'Diagnostics');
|
| 4822 |
+
|
| 4823 |
+
// Update system alerts
|
| 4824 |
+
if (report.issues && report.issues.length > 0) {
|
| 4825 |
+
displaySystemAlerts(report.issues);
|
| 4826 |
+
document.getElementById('systemAlertsSection').style.display = 'block';
|
| 4827 |
+
}
|
| 4828 |
} catch (error) {
|
| 4829 |
+
resultsDiv.innerHTML = `<div class="alert alert-error">
|
| 4830 |
+
<span class="icon icon-md status-icon-error"><svg><use href="#icon-error"></use></svg></span>
|
| 4831 |
+
خطا: ${error.message}
|
| 4832 |
+
</div>`;
|
| 4833 |
+
showToast('خطا در اجرای اشکالیابی', 'error', 'Error');
|
| 4834 |
}
|
| 4835 |
}
|
| 4836 |
|
|
|
|
| 4944 |
}
|
| 4945 |
|
| 4946 |
displayDiagnosticsReport(report);
|
| 4947 |
+
|
| 4948 |
+
// Load system alerts
|
| 4949 |
+
if (report.issues && report.issues.length > 0) {
|
| 4950 |
+
displaySystemAlerts(report.issues);
|
| 4951 |
+
document.getElementById('systemAlertsSection').style.display = 'block';
|
| 4952 |
+
}
|
| 4953 |
} catch (error) {
|
| 4954 |
console.error('Error loading last diagnostics:', error);
|
| 4955 |
}
|