diff options
Diffstat (limited to 'web/html/inbounds.html')
| -rw-r--r-- | web/html/inbounds.html | 121 |
1 files changed, 108 insertions, 13 deletions
diff --git a/web/html/inbounds.html b/web/html/inbounds.html index 86bde2c8..4e1149ae 100644 --- a/web/html/inbounds.html +++ b/web/html/inbounds.html @@ -1128,8 +1128,11 @@ }, openEditClient(dbInboundId, client) { dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; clients = this.getInboundClients(dbInbound); + if (!clients || !Array.isArray(clients)) return; index = this.findIndexOfClient(dbInbound.protocol, clients, client); + if (index < 0) return; clientModal.show({ title: '{{ i18n "pages.client.edit"}}', okText: '{{ i18n "pages.client.submitEdit"}}', @@ -1144,11 +1147,14 @@ }); }, findIndexOfClient(protocol, clients, client) { + if (!clients || !Array.isArray(clients) || !client) { + return -1; + } switch (protocol) { case Protocols.TROJAN: case Protocols.SHADOWSOCKS: - return clients.findIndex(item => item.password === client.password && item.email === client.email); - default: return clients.findIndex(item => item.id === client.id && item.email === client.email); + return clients.findIndex(item => item && item.password === client.password && item.email === client.email); + default: return clients.findIndex(item => item && item.id === client.id && item.email === client.email); } }, async addClient(clients, dbInboundId, modal) { @@ -1271,11 +1277,15 @@ }, showInfo(dbInboundId, client) { dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; index = 0; if (dbInbound.isMultiUser()) { inbound = dbInbound.toInbound(); - clients = inbound.clients; - index = this.findIndexOfClient(dbInbound.protocol, clients, client); + clients = inbound && inbound.clients ? inbound.clients : null; + if (clients && Array.isArray(clients)) { + index = this.findIndexOfClient(dbInbound.protocol, clients, client); + if (index < 0) index = 0; + } } newDbInbound = this.checkFallback(dbInbound); infoModal.show(newDbInbound, index); @@ -1288,9 +1298,12 @@ async switchEnableClient(dbInboundId, client) { this.loading() dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; inbound = dbInbound.toInbound(); - clients = inbound.clients; + clients = inbound && inbound.clients ? inbound.clients : null; + if (!clients || !Array.isArray(clients)) return; index = this.findIndexOfClient(dbInbound.protocol, clients, client); + if (index < 0 || !clients[index]) return; clients[index].enable = !clients[index].enable; clientId = this.getClientId(dbInbound.protocol, clients[index]); await this.updateClient(clients[index], dbInboundId, clientId); @@ -1303,7 +1316,9 @@ } }, getInboundClients(dbInbound) { - return dbInbound.toInbound().clients; + if (!dbInbound) return null; + const inbound = dbInbound.toInbound(); + return inbound && inbound.clients ? inbound.clients : null; }, resetClientTraffic(client, dbInboundId, confirmation = true) { if (confirmation) { @@ -1443,7 +1458,12 @@ formatLastOnline(email) { const ts = this.getLastOnline(email) if (!ts) return '-' - return IntlUtil.formatDate(ts) + // Check if IntlUtil is available (may not be loaded yet) + if (typeof IntlUtil !== 'undefined' && IntlUtil.formatDate) { + return IntlUtil.formatDate(ts) + } + // Fallback to simple date formatting if IntlUtil is not available + return new Date(ts).toLocaleString() }, isRemovable(dbInboundId) { return this.getInboundClients(this.dbInbounds.find(row => row.id === dbInboundId)).length > 1; @@ -1567,13 +1587,88 @@ } this.loading(); this.getDefaultSettings(); - if (this.isRefreshEnabled) { - this.startDataRefreshLoop(); - } - else { - this.getDBInbounds(); + + // Initial data fetch + this.getDBInbounds().then(() => { + this.loading(false); + }); + + // Setup WebSocket for real-time updates + if (window.wsClient) { + window.wsClient.connect(); + + // Listen for inbounds updates + window.wsClient.on('inbounds', (payload) => { + if (payload && Array.isArray(payload)) { + // Use setInbounds to properly convert to DBInbound objects with methods + this.setInbounds(payload); + this.searchInbounds(this.searchKey); + } + }); + + // Listen for traffic updates + window.wsClient.on('traffic', (payload) => { + if (payload && payload.clientTraffics && Array.isArray(payload.clientTraffics)) { + // Update client traffic statistics + payload.clientTraffics.forEach(clientTraffic => { + const dbInbound = this.dbInbounds.find(ib => { + if (!ib) return false; + const clients = this.getInboundClients(ib); + return clients && Array.isArray(clients) && clients.some(c => c && c.email === clientTraffic.email); + }); + if (dbInbound && dbInbound.clientStats && Array.isArray(dbInbound.clientStats)) { + const stats = dbInbound.clientStats.find(s => s && s.email === clientTraffic.email); + if (stats) { + stats.up = clientTraffic.up || stats.up; + stats.down = clientTraffic.down || stats.down; + stats.total = clientTraffic.total || stats.total; + } + } + }); + } + + // Update online clients list in real-time + if (payload && Array.isArray(payload.onlineClients)) { + this.onlineClients = payload.onlineClients; + // Recalculate client counts to update online status + this.dbInbounds.forEach(dbInbound => { + const inbound = this.inbounds.find(ib => ib.id === dbInbound.id); + if (inbound && this.clientCount[dbInbound.id]) { + this.clientCount[dbInbound.id] = this.getClientCounts(dbInbound, inbound); + } + }); + } + + // Update last online map in real-time + if (payload && payload.lastOnlineMap && typeof payload.lastOnlineMap === 'object') { + this.lastOnlineMap = { ...this.lastOnlineMap, ...payload.lastOnlineMap }; + } + }); + + // Notifications disabled - white notifications are not needed + + // Fallback to polling if WebSocket fails + window.wsClient.on('error', () => { + console.warn('WebSocket connection failed, falling back to polling'); + if (this.isRefreshEnabled) { + this.startDataRefreshLoop(); + } + }); + + window.wsClient.on('disconnected', () => { + if (window.wsClient.reconnectAttempts >= window.wsClient.maxReconnectAttempts) { + console.warn('WebSocket reconnection failed, falling back to polling'); + if (this.isRefreshEnabled) { + this.startDataRefreshLoop(); + } + } + }); + } else { + // Fallback to polling if WebSocket is not available + if (this.isRefreshEnabled) { + this.startDataRefreshLoop(); + } } - this.loading(false); }, computed: { total() { |
