3x-ui/web/html/settings/xray/outbounds.html

165 lines
8.3 KiB
HTML
Raw Normal View History

{{define "settings/xray/outbounds"}}
<a-space direction="vertical" size="middle" class="outbounds-modern">
<a-row :gutter="[12, 12]" align="middle" justify="space-between">
<a-col :xs="24" :sm="14" :lg="14">
<a-space direction="horizontal" size="small" class="outbounds-toolbar">
feat: Real-time Outbound Traffic, UI Improvements & Fix (#3629) * Refactor HTML and JavaScript for improved UI and functionality - Cleaned up JavaScript methods in subscription.js for better readability. - Updated inbounds.html to clarify traffic update handling and removed unnecessary comments. - Enhanced xray.html by correcting casing in routingDomainStrategies. - Added mobile touch scrolling styles in page.html for better tab navigation on small screens. - Streamlined vless.html by removing redundant line breaks and improving form layout. - Refined subscription subpage.html for better structure and user experience. - Adjusted outbounds.html to improve button visibility and functionality. - Updated xray_traffic_job.go to ensure accurate traffic updates and real-time UI refresh. * Refactor client traffic handling in InboundService - Updated addClientTraffic method to initialize onlineClients as an empty slice instead of nil. - Improved clarity and consistency in handling empty onlineUsers scenario. * Add WebSocket support for outbounds traffic updates - Implemented WebSocket connection in xray.html to handle real-time updates for outbounds traffic. - Enhanced xray_traffic_job.go to retrieve and broadcast outbounds traffic updates. - Introduced MessageTypeOutbounds in hub.go for managing outbounds messages. - Added BroadcastOutbounds function in notifier.go to facilitate broadcasting outbounds updates to connected clients. --------- Co-authored-by: lolka1333 <test123@gmail.com>
2026-01-05 04:50:40 +00:00
<a-button type="primary" icon="plus" @click="addOutbound">
<span v-if="!isMobile">{{ i18n
"pages.xray.outbound.addOutbound" }}</span>
</a-button>
<a-button type="primary" icon="cloud"
@click="showWarp()">WARP</a-button>
<a-button type="primary" icon="api"
@click="showNord()">NordVPN</a-button>
</a-space>
</a-col>
<a-col :xs="24" :sm="10" :lg="10" class="outbounds-toolbar-right">
<a-button-group>
<a-button icon="sync" @click="refreshOutboundTraffic()"
:loading="refreshing"></a-button>
<a-popconfirm placement="topRight"
@confirm="resetOutboundTraffic(-1)"
2025-05-10 14:47:59 +00:00
title='{{ i18n "pages.inbounds.resetTrafficContent"}}'
:overlay-class-name="themeSwitcher.currentTheme"
ok-text='{{ i18n "reset"}}'
2025-05-10 14:47:59 +00:00
cancel-text='{{ i18n "cancel"}}'>
<a-icon slot="icon" type="question-circle-o"
:style="{ color: '#008771' }"></a-icon>
<a-button icon="retweet"></a-button>
</a-popconfirm>
</a-button-group>
</a-col>
</a-row>
<a-table :columns="outboundColumns" :row-key="r => r.key"
:data-source="outboundData"
:scroll="isMobile ? { x: 720 } : {}"
:pagination="false"
:indent-size="0"
class="outbounds-table"
2025-05-10 14:47:59 +00:00
:locale='{ filterConfirm: `{{ i18n "confirm" }}`, filterReset: `{{ i18n "reset" }}` }'>
<template slot="action" slot-scope="text, outbound, index">
<div class="outbound-action-cell">
<span class="outbound-index">[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-button shape="circle" size="small" class="outbound-action-btn"
@click="e => e.preventDefault()">
<a-icon type="more"></a-icon>
</a-button>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item v-if="index>0"
@click="setFirstOutbound(index)">
<a-icon type="vertical-align-top"></a-icon>
<span>{{ i18n "pages.xray.rules.first"}}</span>
</a-menu-item>
<a-menu-item @click="editOutbound(index)">
<a-icon type="edit"></a-icon>
<span>{{ i18n "edit" }}</span>
</a-menu-item>
<a-menu-item @click="resetOutboundTraffic(index)">
<a-icon type="retweet"></a-icon>
<span>{{ i18n "pages.inbounds.resetTraffic"}}</span>
</a-menu-item>
<a-menu-item @click="deleteOutbound(index)">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
</a-menu-item>
</a-menu>
</a-dropdown>
</div>
</template>
<template slot="identity" slot-scope="text, outbound">
<div class="outbound-identity-cell">
<a-tooltip :title="outbound.tag" :overlay-class-name="themeSwitcher.currentTheme">
<span class="outbound-tag">[[ outbound.tag ]]</span>
</a-tooltip>
<div class="outbound-protocol-cell">
<span class="outbound-pill"
:class="outboundProtocolTone(outbound.protocol)">
[[ outbound.protocol ]]
</span>
<template
v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)">
<span class="outbound-pill"
:class="outboundNetworkTone(outbound.streamSettings.network)">
[[ outbound.streamSettings.network ]]
</span>
<span class="outbound-pill"
:class="outboundSecurityTone(outbound.streamSettings.security)"
v-if="isOutboundSecurityVisible(outbound.streamSettings.security)">
[[ outbound.streamSettings.security ]]
</span>
</template>
</div>
</div>
</template>
<template slot="address" slot-scope="text, outbound">
<div class="outbound-address-list">
<a-tooltip
v-for="addr in outboundAddresses(outbound)"
:key="addr"
:title="addr"
:overlay-class-name="themeSwitcher.currentTheme">
<span class="outbound-address-pill">[[ addr ]]</span>
</a-tooltip>
<span class="outbound-address-empty"
v-if="outboundAddresses(outbound).length === 0">—</span>
</div>
</template>
<template slot="traffic" slot-scope="text, outbound">
<div class="outbound-traffic-cell">
<span class="outbound-traffic-up" :title='`{{ i18n "pages.inbounds.upload" }}`'>
<a-icon type="arrow-up"></a-icon>
[[ SizeFormatter.sizeFormat(findOutboundUp(outbound)) ]]
</span>
<span class="outbound-traffic-sep" aria-hidden="true"></span>
<span class="outbound-traffic-down" :title='`{{ i18n "pages.inbounds.download" }}`'>
<a-icon type="arrow-down"></a-icon>
[[ SizeFormatter.sizeFormat(findOutboundDown(outbound)) ]]
</span>
</div>
</template>
<template slot="test" slot-scope="text, outbound, index">
<a-tooltip>
<template slot="title">{{ i18n "pages.xray.outbound.test" }}</template>
<a-button
type="primary"
shape="circle"
icon="thunderbolt"
class="outbound-test-btn"
:loading="isOutboundTesting(index)"
@click="testOutbound(index)"
:disabled="isOutboundUntestable(outbound) || isOutboundTesting(index)">
</a-button>
</a-tooltip>
</template>
<template slot="testResult" slot-scope="text, outbound, index">
<div class="outbound-result-cell" v-if="outboundTestResult(index)">
<span v-if="outboundTestResult(index).success"
class="outbound-result-pill outbound-result-ok">
<a-icon type="check-circle" theme="filled"></a-icon>
[[ outboundTestResult(index).delay ]]&nbsp;ms
<span class="outbound-result-status"
v-if="outboundTestResult(index).statusCode">
· [[ outboundTestResult(index).statusCode ]]
</span>
</span>
<a-tooltip v-else
:title="outboundTestResult(index).error"
:overlay-class-name="themeSwitcher.currentTheme">
<span class="outbound-result-pill outbound-result-fail">
<a-icon type="close-circle" theme="filled"></a-icon>
{{ i18n "pages.xray.outbound.testFailed" }}
</span>
</a-tooltip>
</div>
<span class="outbound-result-loading" v-else-if="isOutboundTesting(index)">
<a-icon type="loading"></a-icon>
</span>
<span class="outbound-result-idle" v-else></span>
</template>
</a-table>
</a-space>
{{end}}