From 035ebd8d40cc71858c49475417a54b39031b1753 Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Sun, 5 Apr 2026 15:23:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=89=E8=A3=85=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 2 +- install.sh | 118 +++++++++++++++++++++++++++++++++++ public/index.html | 5 +- public/js/app.js | 32 ++++++++-- server/db-integrity-check.js | 14 ++++- server/index.js | 33 +++++----- 6 files changed, 181 insertions(+), 23 deletions(-) diff --git a/.env.example b/.env.example index a151907..6251c0f 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ HOST=0.0.0.0 -PORT=3000 +PORT=3051 REFRESH_INTERVAL=5000 # Valkey/Redis Cache Configuration diff --git a/install.sh b/install.sh index 662e2b3..fd01471 100644 --- a/install.sh +++ b/install.sh @@ -121,4 +121,122 @@ else echo -e "Check logs with: ${BLUE}journalctl -u data-wall -xe${NC}" fi +# 10. Reverse Proxy Configuration +echo -ne "${YELLOW}Do you want to configure a reverse proxy (Nginx/Caddy)? (y/n): ${NC}" +read -r CONF_PROXY +if [[ "$CONF_PROXY" =~ ^[Yy]$ ]]; then + echo -e "${BLUE}=== Reverse Proxy Configuration ===${NC}" + + # Get Domain + echo -ne "Enter your domain name (e.g., monitor.example.com): " + read -r DOMAIN + if [ -z "$DOMAIN" ]; then + echo -e "${RED}Error: Domain cannot be empty. Skipping proxy configuration.${NC}" + else + # Get Port from .env + PORT=$(grep "^PORT=" .env | cut -d'=' -f2) + PORT=${PORT:-3000} + + # Choose Proxy + echo -e "Select Proxy Type:" + echo -e " 1) Caddy (Automatic SSL, easy to use)" + echo -e " 2) Nginx (Advanced, manual SSL)" + echo -ne "Choose (1/2): " + read -r PROXY_TYPE + + # Enable HTTPS? + echo -ne "Enable HTTPS (SSL)? (y/n): " + read -r ENABLE_HTTPS + + if [ "$PROXY_TYPE" == "1" ]; then + # Caddy Config + CADDY_FILE="Caddyfile" + echo -e "${BLUE}Generating Caddyfile...${NC}" + + if [[ "$ENABLE_HTTPS" =~ ^[Yy]$ ]]; then + cat < "$CADDY_FILE" +$DOMAIN { + reverse_proxy localhost:$PORT +} +EOF + else + cat < "$CADDY_FILE" +http://$DOMAIN { + reverse_proxy localhost:$PORT +} +EOF + fi + chown "$REAL_USER":"$REAL_USER" "$CADDY_FILE" + echo -e "${GREEN}Caddyfile generated at $PROJECT_DIR/$CADDY_FILE${NC}" + echo -e "${YELLOW}Tip: Ensure Caddy is installed and pointing to this file.${NC}" + + elif [ "$PROXY_TYPE" == "2" ]; then + # Nginx Config + echo -ne "Enter Nginx configuration export path (default: ./${DOMAIN}.conf): " + read -r NGINX_PATH + NGINX_PATH=${NGINX_PATH:-"./${DOMAIN}.conf"} + + echo -e "${BLUE}Generating Nginx configuration...${NC}" + + if [[ "$ENABLE_HTTPS" =~ ^[Yy]$ ]]; then + echo -ne "Enter SSL Certificate Path: " + read -r SSL_CERT + echo -ne "Enter SSL Key Path: " + read -r SSL_KEY + + cat < "$NGINX_PATH" +server { + listen 80; + server_name $DOMAIN; + return 301 https://\$host\$request_uri; +} + +server { + listen 443 ssl http2; + server_name $DOMAIN; + + ssl_certificate $SSL_CERT; + ssl_certificate_key $SSL_KEY; + + location / { + proxy_pass http://localhost:$PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } +} +EOF + else + cat < "$NGINX_PATH" +server { + listen 80; + server_name $DOMAIN; + + location / { + proxy_pass http://localhost:$PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade \$http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto \$scheme; + } +} +EOF + fi + chown "$REAL_USER":"$REAL_USER" "$NGINX_PATH" + echo -e "${GREEN}Nginx config generated at $NGINX_PATH${NC}" + echo -e "${YELLOW}Tip: You can symlink this to /etc/nginx/sites-enabled/ to activate.${NC}" + else + echo -e "${YELLOW}Unknown proxy type selected. Skipping.${NC}" + fi + fi +fi + echo -e "${BLUE}================================================${NC}" +echo -e "${GREEN}Setup completed successfully!${NC}" diff --git a/public/index.html b/public/index.html index 026f5a1..e1a56c1 100644 --- a/public/index.html +++ b/public/index.html @@ -395,9 +395,12 @@ style="padding: 10px 14px; background: var(--bg-input); border: 1px solid var(--border-color); border-radius: var(--radius-sm); color: var(--text-primary);"> - +
+ + +
diff --git a/public/js/app.js b/public/js/app.js index a38ea0e..87f483a 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -48,6 +48,7 @@ logoText: document.getElementById('logoText'), logoIconContainer: document.getElementById('logoIconContainer'), defaultThemeInput: document.getElementById('defaultThemeInput'), + show95BandwidthInput: document.getElementById('show95BandwidthInput'), // Auth & Theme elements themeToggle: document.getElementById('themeToggle'), sunIcon: document.querySelector('.sun-icon'), @@ -218,6 +219,7 @@ dom.siteTitleInput.value = window.SITE_SETTINGS.title || ''; dom.logoUrlInput.value = window.SITE_SETTINGS.logo_url || ''; dom.defaultThemeInput.value = window.SITE_SETTINGS.default_theme || 'dark'; + dom.show95BandwidthInput.checked = !!window.SITE_SETTINGS.show_95_bandwidth; } loadSiteSettings(); @@ -903,9 +905,19 @@ // Update inputs dom.pageNameInput.value = settings.page_name || ''; - dom.siteTitleInput.value = settings.title || ''; - dom.logoUrlInput.value = settings.logo_url || ''; - dom.defaultThemeInput.value = settings.default_theme || 'dark'; + if (settings.title) dom.siteTitleInput.value = settings.title; + if (settings.logo_url) dom.logoUrlInput.value = settings.logo_url; + if (settings.default_theme) dom.defaultThemeInput.value = settings.default_theme; + if (settings.show_95_bandwidth !== undefined) { + dom.show95BandwidthInput.checked = !!settings.show_95_bandwidth; + if (networkChart) { + networkChart.showP95 = !!settings.show_95_bandwidth; + if (dom.legendP95) { + dom.legendP95.classList.toggle('disabled', !networkChart.showP95); + } + networkChart.draw(); + } + } // Apply to UI applySiteSettings(settings); @@ -957,6 +969,17 @@ `; } + + // P95 setting + if (settings.show_95_bandwidth !== undefined) { + if (networkChart) { + networkChart.showP95 = !!settings.show_95_bandwidth; + if (dom.legendP95) { + dom.legendP95.classList.toggle('disabled', !networkChart.showP95); + } + networkChart.draw(); + } + } } async function saveSiteSettings() { @@ -970,7 +993,8 @@ page_name: dom.pageNameInput.value.trim(), title: dom.siteTitleInput.value.trim(), logo_url: dom.logoUrlInput.value.trim(), - default_theme: dom.defaultThemeInput.value + default_theme: dom.defaultThemeInput.value, + show_95_bandwidth: dom.show95BandwidthInput.checked ? 1 : 0 }; dom.btnSaveSiteSettings.disabled = true; diff --git a/server/db-integrity-check.js b/server/db-integrity-check.js index a30f0c8..81c6a6d 100644 --- a/server/db-integrity-check.js +++ b/server/db-integrity-check.js @@ -36,6 +36,15 @@ async function checkAndFixDatabase() { } console.log(`[Database Integrity] ✅ Missing tables created.`); } + + // Check for new columns in site_settings + const [columns] = await db.query("SHOW COLUMNS FROM site_settings"); + const columnNames = columns.map(c => c.Field); + if (!columnNames.includes('show_95_bandwidth')) { + console.log(`[Database Integrity] ⚠️ Missing column 'show_95_bandwidth' in 'site_settings'. Adding it...`); + await db.query("ALTER TABLE site_settings ADD COLUMN show_95_bandwidth TINYINT(1) DEFAULT 0 AFTER default_theme"); + console.log(`[Database Integrity] ✅ Column 'show_95_bandwidth' added.`); + } } catch (err) { console.error('[Database Integrity] ❌ Error checking integrity:', err.message); } @@ -75,12 +84,13 @@ async function createTable(tableName) { title VARCHAR(255) DEFAULT '数据可视化展示大屏', logo_url TEXT, default_theme VARCHAR(20) DEFAULT 'dark', + show_95_bandwidth TINYINT(1) DEFAULT 0, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `); await db.query(` - INSERT IGNORE INTO site_settings (id, page_name, title, default_theme) - VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark') + INSERT IGNORE INTO site_settings (id, page_name, title, default_theme, show_95_bandwidth) + VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark', 0) `); break; case 'traffic_stats': diff --git a/server/index.js b/server/index.js index a5b6ac0..21bedf4 100644 --- a/server/index.js +++ b/server/index.js @@ -216,12 +216,13 @@ app.post('/api/setup/init', async (req, res) => { title VARCHAR(255) DEFAULT '数据可视化展示大屏', logo_url TEXT, default_theme VARCHAR(20) DEFAULT 'dark', + show_95_bandwidth TINYINT(1) DEFAULT 0, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `); await connection.query(` - INSERT IGNORE INTO site_settings (id, page_name, title, default_theme) - VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark') + INSERT IGNORE INTO site_settings (id, page_name, title, default_theme, show_95_bandwidth) + VALUES (1, '数据可视化展示大屏', '数据可视化展示大屏', 'dark', 0) `); await connection.end(); @@ -487,7 +488,8 @@ app.get('/api/settings', async (req, res) => { return res.json({ page_name: '数据可视化展示大屏', title: '数据可视化展示大屏', - logo_url: null + logo_url: null, + show_95_bandwidth: 0 }); } res.json(rows[0]); @@ -499,18 +501,19 @@ app.get('/api/settings', async (req, res) => { // Update site settings app.post('/api/settings', requireAuth, async (req, res) => { - const { page_name, title, logo_url, default_theme } = req.body; - try { - await db.query( - `INSERT INTO site_settings (id, page_name, title, logo_url, default_theme) - VALUES (1, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE - page_name = VALUES(page_name), - title = VALUES(title), - logo_url = VALUES(logo_url), - default_theme = VALUES(default_theme)`, - [page_name, title, logo_url, default_theme] - ); + const { page_name, title, logo_url, default_theme, show_95_bandwidth } = req.body; + try { + await db.query( + `INSERT INTO site_settings (id, page_name, title, logo_url, default_theme, show_95_bandwidth) + VALUES (1, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + page_name = VALUES(page_name), + title = VALUES(title), + logo_url = VALUES(logo_url), + default_theme = VALUES(default_theme), + show_95_bandwidth = VALUES(show_95_bandwidth)`, + [page_name, title, logo_url, default_theme, show_95_bandwidth ? 1 : 0] + ); res.json({ success: true }); } catch (err) { console.error('Error updating settings:', err);