diff options
| author | Vadim Iskuchekov <egregors@pm.me> | 2025-06-21 10:55:35 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-21 10:55:35 +0300 |
| commit | 5c10035bd964b41ce466ef16ca5ef8bb9a4507f6 (patch) | |
| tree | c2d44ab3ce65ab72e884c47b587c2efb1472de83 /web/html | |
| parent | 2e6faf69e62274a35611eb20b0e0a05251c4a8cd (diff) | |
feat: add comments under client id (#3131)
Diffstat (limited to 'web/html')
| -rw-r--r-- | web/html/component/aClientTable.html | 39 | ||||
| -rw-r--r-- | web/html/form/protocol/shadowsocks.html | 7 | ||||
| -rw-r--r-- | web/html/form/protocol/trojan.html | 7 | ||||
| -rw-r--r-- | web/html/form/protocol/vless.html | 7 | ||||
| -rw-r--r-- | web/html/form/protocol/vmess.html | 7 | ||||
| -rw-r--r-- | web/html/inbounds.html | 99 |
6 files changed, 146 insertions, 20 deletions
diff --git a/web/html/component/aClientTable.html b/web/html/component/aClientTable.html index 868112d9..8ab08679 100644 --- a/web/html/component/aClientTable.html +++ b/web/html/component/aClientTable.html @@ -41,14 +41,28 @@ </template> </template> <template slot="client" slot-scope="text, client"> - <a-tooltip> - <template slot="title"> - <template v-if="!isClientEnabled(record, client.email)">{{ i18n "depleted" }}</template> - <template v-else-if="!client.enable">{{ i18n "disabled" }}</template> - <template v-else-if="client.enable && isClientOnline(client.email)">{{ i18n "online" }}</template> - </template> - <a-badge :class="isClientOnline(client.email)? 'online-animation' : ''" :color="client.enable ? statsExpColor(record, client.email) : themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc'"></a-badge> - </a-tooltip> [[ client.email ]] + <div class="client-cell"> + <div class="client-info-row"> + <a-tooltip> + <template slot="title"> + <template v-if="!isClientEnabled(record, client.email)">{{ i18n "depleted" }}</template> + <template v-else-if="!client.enable">{{ i18n "disabled" }}</template> + <template v-else-if="client.enable && isClientOnline(client.email)">{{ i18n "online" }}</template> + </template> + <a-badge :class="isClientOnline(client.email)? 'online-animation' : ''" :color="client.enable ? statsExpColor(record, client.email) : themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc'"></a-badge> + </a-tooltip> + <span class="client-email">[[ client.email ]]</span> + </div> + <div v-if="client.comment && client.comment.trim()" style="margin-left: 18px;"> + <a-tooltip v-if="client.comment.length > 50" :overlay-class-name="themeSwitcher.currentTheme"> + <template slot="title"> + [[ client.comment ]] + </template> + <span class="client-comment">[[ client.comment.substring(0, 47) + '...' ]]</span> + </a-tooltip> + <span v-else class="client-comment">[[ client.comment ]]</span> + </div> + </div> </template> <template slot="traffic" slot-scope="text, client"> <a-popover :overlay-class-name="themeSwitcher.currentTheme"> @@ -168,6 +182,15 @@ <a-popover placement="bottomRight" :overlay-class-name="themeSwitcher.currentTheme" trigger="click"> <template slot="content"> <table> + <tr v-if="client.comment && client.comment.trim()"> + <td colspan="3" :style="{ textAlign: 'left', borderBottom: '1px solid #f0f0f0', paddingBottom: '8px', marginBottom: '8px' }"> + <div :style="{ fontSize: '0.9em', fontWeight: '500', marginBottom: '4px' }">[[ client.email ]]</div> + <div :style="{ fontSize: '0.85em', color: '#666', fontStyle: 'italic', wordBreak: 'break-word', maxWidth: '250px' }">[[ client.comment ]]</div> + </td> + </tr> + <tr v-else> + <td colspan="3" :style="{ textAlign: 'center', fontWeight: '500', paddingBottom: '8px' }">[[ client.email ]]</td> + </tr> <tr> <td colspan="3" :style="{ textAlign: 'center' }">{{ i18n "pages.inbounds.traffic" }}</td> </tr> diff --git a/web/html/form/protocol/shadowsocks.html b/web/html/form/protocol/shadowsocks.html index 06e12075..04cd9399 100644 --- a/web/html/form/protocol/shadowsocks.html +++ b/web/html/form/protocol/shadowsocks.html @@ -13,7 +13,12 @@ <th>Password</th> </tr> <tr v-for="(client, index) in inbound.settings.shadowsockses" :class="index % 2 == 1 ? 'client-table-odd-row' : ''"> - <td>[[ client.email ]]</td> + <td> + <div class="client-cell"> + <div class="client-email">[[ client.email ]]</div> + <div v-if="client.comment && client.comment.trim()" class="client-comment">[[ client.comment ]]</div> + </div> + </td> <td>[[ client.password ]]</td> </tr> </table> diff --git a/web/html/form/protocol/trojan.html b/web/html/form/protocol/trojan.html index fc327721..6c7b3773 100644 --- a/web/html/form/protocol/trojan.html +++ b/web/html/form/protocol/trojan.html @@ -12,7 +12,12 @@ <th>Password</th> </tr> <tr v-for="(client, index) in inbound.settings.trojans" :class="index % 2 == 1 ? 'client-table-odd-row' : ''"> - <td>[[ client.email ]]</td> + <td> + <div class="client-cell"> + <div class="client-email">[[ client.email ]]</div> + <div v-if="client.comment && client.comment.trim()" class="client-comment">[[ client.comment ]]</div> + </div> + </td> <td>[[ client.password ]]</td> </tr> </table> diff --git a/web/html/form/protocol/vless.html b/web/html/form/protocol/vless.html index 3cebda6e..88274f71 100644 --- a/web/html/form/protocol/vless.html +++ b/web/html/form/protocol/vless.html @@ -12,7 +12,12 @@ <th>ID</th> </tr> <tr v-for="(client, index) in inbound.settings.vlesses" :class="index % 2 == 1 ? 'client-table-odd-row' : ''"> - <td>[[ client.email ]]</td> + <td> + <div class="client-cell"> + <div class="client-email">[[ client.email ]]</div> + <div v-if="client.comment && client.comment.trim()" class="client-comment">[[ client.comment ]]</div> + </div> + </td> <td>[[ client.id ]]</td> </tr> </table> diff --git a/web/html/form/protocol/vmess.html b/web/html/form/protocol/vmess.html index 3c5200ac..94a0cc58 100644 --- a/web/html/form/protocol/vmess.html +++ b/web/html/form/protocol/vmess.html @@ -13,7 +13,12 @@ <th>{{ i18n "security" }}</th> </tr> <tr v-for="(client, index) in inbound.settings.vmesses" :class="index % 2 == 1 ? 'client-table-odd-row' : ''"> - <td>[[ client.email ]]</td> + <td> + <div class="client-cell"> + <div class="client-email">[[ client.email ]]</div> + <div v-if="client.comment && client.comment.trim()" class="client-comment">[[ client.comment ]]</div> + </div> + </td> <td>[[ client.id ]]</td> <td>[[ client.security ]]</td> </tr> diff --git a/web/html/inbounds.html b/web/html/inbounds.html index 29e6b00f..1750aa44 100644 --- a/web/html/inbounds.html +++ b/web/html/inbounds.html @@ -79,6 +79,54 @@ max-width: 200px; overflow: hidden; } + .client-comment { + font-size: 12px; + color: #888; + font-style: italic; + line-height: 1.2; + } + .dark .client-comment { + color: #bbb; + } + .client-email { + font-weight: 500; + } + .client-cell { + display: flex; + flex-direction: column; + gap: 2px; + } + .client-info-row { + display: flex; + align-items: center; + gap: 6px; + } + .client-popup-item { + margin-bottom: 8px; + padding: 4px 0; + border-bottom: 1px solid #f0f0f0; + } + .dark .client-popup-item { + border-bottom: 1px solid #333; + } + .client-popup-item:last-child { + border-bottom: none; + margin-bottom: 0; + } + .client-popup-email { + font-weight: 500; + margin-bottom: 2px; + } + .client-popup-comment { + font-size: 11px; + color: #666; + font-style: italic; + max-width: 200px; + word-break: break-word; + } + .dark .client-popup-comment { + color: #aaa; + } .online-animation .ant-badge-status-dot { animation: onlineAnimation 1.2s linear infinite; } @@ -382,25 +430,37 @@ <a-tag :style="{ margin: '0' }" color="green">[[ clientCount[dbInbound.id].clients ]]</a-tag> <a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <div v-for="clientEmail in clientCount[dbInbound.id].deactive"><span>[[ clientEmail ]]</span></div> + <div v-for="clientEmail in clientCount[dbInbound.id].deactive" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <div v-for="clientEmail in clientCount[dbInbound.id].depleted"><span>[[ clientEmail ]]</span></div> + <div v-for="clientEmail in clientCount[dbInbound.id].depleted" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <div v-for="clientEmail in clientCount[dbInbound.id].expiring"><span>[[ clientEmail ]]</span></div> + <div v-for="clientEmail in clientCount[dbInbound.id].expiring" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "online" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <div v-for="clientEmail in clientCount[dbInbound.id].online"><span>[[ clientEmail ]]</span></div> + <div v-for="clientEmail in clientCount[dbInbound.id].online" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="blue" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag> </a-popover> @@ -479,25 +539,37 @@ <a-tag :style="{ margin: '0' }" color="blue">[[ clientCount[dbInbound.id].clients ]]</a-tag> <a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <p v-for="clientEmail in clientCount[dbInbound.id].deactive">[[ clientEmail ]]</p> + <div v-for="clientEmail in clientCount[dbInbound.id].deactive" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <p v-for="clientEmail in clientCount[dbInbound.id].depleted">[[ clientEmail ]]</p> + <div v-for="clientEmail in clientCount[dbInbound.id].depleted" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <p v-for="clientEmail in clientCount[dbInbound.id].expiring">[[ clientEmail ]]</p> + <div v-for="clientEmail in clientCount[dbInbound.id].expiring" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag> </a-popover> <a-popover title='{{ i18n "online" }}' :overlay-class-name="themeSwitcher.currentTheme"> <template slot="content"> - <p v-for="clientEmail in clientCount[dbInbound.id].online">[[ clientEmail ]]</p> + <div v-for="clientEmail in clientCount[dbInbound.id].online" :key="clientEmail" class="client-popup-item"> + <div class="client-popup-email">[[ clientEmail ]]</div> + <div v-if="getClientWithComment(clientEmail, dbInbound.id).comment" class="client-popup-comment">[[ getClientWithComment(clientEmail, dbInbound.id).comment ]]</div> + </div> </template> <a-tag :style="{ margin: '0', padding: '0 2px' }" color="green" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag> </a-popover> @@ -716,6 +788,17 @@ loading(spinning = true) { this.spinning = spinning; }, + getClientWithComment(email, inboundId) { + const dbInbound = this.dbInbounds.find(inbound => inbound.id === inboundId); + if (!dbInbound) return { email, comment: '' }; + + const inboundSettings = JSON.parse(dbInbound.settings); + if (inboundSettings.clients) { + const client = inboundSettings.clients.find(c => c.email === email); + return client ? { email: client.email, comment: client.comment || '' } : { email, comment: '' }; + } + return { email, comment: '' }; + }, async getDBInbounds() { this.refreshing = true; const msg = await HttpUtil.post('/panel/inbound/list'); |
