mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-10-27 18:32:52 +00:00
Compare commits
No commits in common. "f60682a6b7cb749fee403c84e2587c3ad7e7ced0" and "7447cec17ed6735c3faf44e88d47dd71a81e9643" have entirely different histories.
f60682a6b7
...
7447cec17e
13 changed files with 64 additions and 89 deletions
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — لوحة تحكم متقدمة مفتوحة المصدر تعتمد على الويب مصممة لإدارة خادم Xray-core. توفر واجهة سهلة الاستخدام لتكوين ومراقبة بروتوكولات VPN والوكيل المختلفة.
|
**3X-UI** — لوحة تحكم متقدمة مفتوحة المصدر تعتمد على الويب مصممة لإدارة خادم Xray-core. توفر واجهة سهلة الاستخدام لتكوين ومراقبة بروتوكولات VPN والوكيل المختلفة.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — panel de control avanzado basado en web de código abierto diseñado para gestionar el servidor Xray-core. Ofrece una interfaz fácil de usar para configurar y monitorear varios protocolos VPN y proxy.
|
**3X-UI** — panel de control avanzado basado en web de código abierto diseñado para gestionar el servidor Xray-core. Ofrece una interfaz fácil de usar para configurar y monitorear varios protocolos VPN y proxy.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — یک پنل کنترل پیشرفته مبتنی بر وب با کد باز که برای مدیریت سرور Xray-core طراحی شده است. این پنل یک رابط کاربری آسان برای پیکربندی و نظارت بر پروتکلهای مختلف VPN و پراکسی ارائه میدهد.
|
**3X-UI** — یک پنل کنترل پیشرفته مبتنی بر وب با کد باز که برای مدیریت سرور Xray-core طراحی شده است. این پنل یک رابط کاربری آسان برای پیکربندی و نظارت بر پروتکلهای مختلف VPN و پراکسی ارائه میدهد.
|
||||||
|
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — advanced, open-source web-based control panel designed for managing Xray-core server. It offers a user-friendly interface for configuring and monitoring various VPN and proxy protocols.
|
**3X-UI** — advanced, open-source web-based control panel designed for managing Xray-core server. It offers a user-friendly interface for configuring and monitoring various VPN and proxy protocols.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — продвинутая панель управления с открытым исходным кодом на основе веб-интерфейса, разработанная для управления сервером Xray-core. Предоставляет удобный интерфейс для настройки и мониторинга различных VPN и прокси-протоколов.
|
**3X-UI** — продвинутая панель управления с открытым исходным кодом на основе веб-интерфейса, разработанная для управления сервером Xray-core. Предоставляет удобный интерфейс для настройки и мониторинга различных VPN и прокси-протоколов.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,11 @@
|
||||||
</picture>
|
</picture>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||||
[](#)
|
[](#)
|
||||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2)
|
|
||||||
|
|
||||||
**3X-UI** — 一个基于网页的高级开源控制面板,专为管理 Xray-core 服务器而设计。它提供了用户友好的界面,用于配置和监控各种 VPN 和代理协议。
|
**3X-UI** — 一个基于网页的高级开源控制面板,专为管理 Xray-core 服务器而设计。它提供了用户友好的界面,用于配置和监控各种 VPN 和代理协议。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,8 @@ func (a *InboundController) addInbound(c *gin.Context) {
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
inbound, needRestart, err := a.inboundService.AddInbound(inbound)
|
needRestart := false
|
||||||
|
inbound, needRestart, err = a.inboundService.AddInbound(inbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
@ -125,7 +126,8 @@ func (a *InboundController) delInbound(c *gin.Context) {
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundDeleteSuccess"), err)
|
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundDeleteSuccess"), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
needRestart, err := a.inboundService.DelInbound(id)
|
needRestart := true
|
||||||
|
needRestart, err = a.inboundService.DelInbound(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
@ -150,7 +152,8 @@ func (a *InboundController) updateInbound(c *gin.Context) {
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundUpdateSuccess"), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inbound, needRestart, err := a.inboundService.UpdateInbound(inbound)
|
needRestart := true
|
||||||
|
inbound, needRestart, err = a.inboundService.UpdateInbound(inbound)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
@ -192,7 +195,9 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needRestart, err := a.inboundService.AddInboundClient(data)
|
needRestart := true
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.AddInboundClient(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
@ -211,7 +216,9 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
|
||||||
}
|
}
|
||||||
clientId := c.Param("clientId")
|
clientId := c.Param("clientId")
|
||||||
|
|
||||||
needRestart, err := a.inboundService.DelInboundClient(id, clientId)
|
needRestart := true
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.DelInboundClient(id, clientId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
@ -232,7 +239,9 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
needRestart, err := a.inboundService.UpdateInboundClient(inbound, clientId)
|
needRestart := true
|
||||||
|
|
||||||
|
needRestart, err = a.inboundService.UpdateInboundClient(inbound, clientId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,22 @@
|
||||||
:mask-closable="false" :footer="null" :class="themeSwitcher.currentTheme">
|
:mask-closable="false" :footer="null" :class="themeSwitcher.currentTheme">
|
||||||
<a-list class="ant-dns-presets-list" bordered :style="{ width: '100%' }">
|
<a-list class="ant-dns-presets-list" bordered :style="{ width: '100%' }">
|
||||||
<a-list-item v-for="dns in dnsPresetsDatabase" :style="{ padding: '12px 16px' }">
|
<a-list-item v-for="dns in dnsPresetsDatabase" :style="{ padding: '12px 16px' }">
|
||||||
<div class="ant-dns-presets-line">
|
<a-row justify="space-between" align="middle">
|
||||||
<a-space direction="horizontal" size="small" align="center">
|
<a-col :span="12">
|
||||||
<a-tag :color="dns.family ? 'purple' : 'green'">[[ dns.family ? '{{ i18n "pages.xray.dns.dnsPresetFamily" }}' : 'DNS' ]]</a-tag>
|
<a-space direction="vertical" size="small">
|
||||||
<span class="ant-dns-presets-list-name">[[ dns.name ]]</span>
|
<span class="ant-dns-presets-list-name">[[ dns.name ]]</span>
|
||||||
</a-space>
|
<a-tag :color="dns.family ? 'purple' : 'green'">[[ dns.family ? '{{ i18n "pages.xray.dns.dnsPresetFamily" }}' : 'DNS' ]]</a-tag>
|
||||||
<a-button class="ant-dns-presets-install" type="primary" @click="dnsPresetsModal.install(dns.data)">{{ i18n "install" }}</a-button>
|
</a-space>
|
||||||
</div>
|
</a-col>
|
||||||
|
<a-col :span="12" :style="{ textAlign: 'right' }">
|
||||||
|
<a-button type="primary" @click="dnsPresetsModal.install(dns.data)">{{ i18n "install" }}</a-button>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</a-list-item>
|
</a-list-item>
|
||||||
</a-list>
|
</a-list>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.ant-dns-presets-line {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-dns-presets-install {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .ant-dns-presets-list {
|
.dark .ant-dns-presets-list {
|
||||||
border-color: var(--dark-color-stroke)
|
border-color: var(--dark-color-stroke)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,7 @@
|
||||||
<template #title>{{ i18n "pages.settings.subPath"}}</template>
|
<template #title>{{ i18n "pages.settings.subPath"}}</template>
|
||||||
<template #description>{{ i18n "pages.settings.subPathDesc"}}</template>
|
<template #description>{{ i18n "pages.settings.subPathDesc"}}</template>
|
||||||
<template #control>
|
<template #control>
|
||||||
<a-input
|
<a-input type="text" v-model="allSetting.subPath"></a-input>
|
||||||
type="text"
|
|
||||||
v-model="allSetting.subPath"
|
|
||||||
@input="allSetting.subPath = ((typeof $event === 'string' ? $event : ($event && $event.target ? $event.target.value : '')) || '').replace(/[:*]/g, '')"
|
|
||||||
@blur="allSetting.subPath = (p => { p = p || '/'; if (!p.startsWith('/')) p='/' + p; if (!p.endsWith('/')) p += '/'; return p.replace(/\/+/g,'/'); })(allSetting.subPath)"
|
|
||||||
placeholder="/sub/"
|
|
||||||
></a-input>
|
|
||||||
</template>
|
</template>
|
||||||
</a-setting-list-item>
|
</a-setting-list-item>
|
||||||
<a-setting-list-item paddings="small">
|
<a-setting-list-item paddings="small">
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,7 @@
|
||||||
<template #title>{{ i18n "pages.settings.subPath"}}</template>
|
<template #title>{{ i18n "pages.settings.subPath"}}</template>
|
||||||
<template #description>{{ i18n "pages.settings.subPathDesc"}}</template>
|
<template #description>{{ i18n "pages.settings.subPathDesc"}}</template>
|
||||||
<template #control>
|
<template #control>
|
||||||
<a-input
|
<a-input type="text" v-model="allSetting.subJsonPath"></a-input>
|
||||||
type="text"
|
|
||||||
v-model="allSetting.subJsonPath"
|
|
||||||
@input="allSetting.subJsonPath = ((typeof $event === 'string' ? $event : ($event && $event.target ? $event.target.value : '')) || '').replace(/[:*]/g, '')"
|
|
||||||
@blur="allSetting.subJsonPath = (p => { p = p || '/'; if (!p.startsWith('/')) p='/' + p; if (!p.endsWith('/')) p += '/'; return p.replace(/\/+/g,'/'); })(allSetting.subJsonPath)"
|
|
||||||
placeholder="/json/"
|
|
||||||
></a-input>
|
|
||||||
</template>
|
</template>
|
||||||
</a-setting-list-item>
|
</a-setting-list-item>
|
||||||
<a-setting-list-item paddings="small">
|
<a-setting-list-item paddings="small">
|
||||||
|
|
|
||||||
|
|
@ -49,10 +49,10 @@ func InitLocalizer(i18nFS embed.FS, settingService SettingService) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTemplateData(params []string, separator ...string) map[string]any {
|
func createTemplateData(params []string, seperator ...string) map[string]any {
|
||||||
var sep string = "=="
|
var sep string = "=="
|
||||||
if len(separator) > 0 {
|
if len(seperator) > 0 {
|
||||||
sep = separator[0]
|
sep = seperator[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
templateData := make(map[string]any)
|
templateData := make(map[string]any)
|
||||||
|
|
|
||||||
|
|
@ -2091,9 +2091,6 @@ func (s *InboundService) MigrationRequirements() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
if dbErr := db.Exec(`VACUUM "main"`).Error; dbErr != nil {
|
|
||||||
logger.Warningf("VACUUM failed: %v", dbErr)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -856,7 +856,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
|
||||||
if len(dataArray) == 3 {
|
if len(dataArray) == 3 {
|
||||||
days, err := strconv.Atoi(dataArray[2])
|
days, err := strconv.Atoi(dataArray[2])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var date int64
|
var date int64 = 0
|
||||||
if days > 0 {
|
if days > 0 {
|
||||||
traffic, err := t.inboundService.GetClientTrafficByEmail(email)
|
traffic, err := t.inboundService.GetClientTrafficByEmail(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -960,7 +960,7 @@ func (t *Tgbot) answerCallback(callbackQuery *telego.CallbackQuery, isAdmin bool
|
||||||
case "add_client_reset_exp_c":
|
case "add_client_reset_exp_c":
|
||||||
client_ExpiryTime = 0
|
client_ExpiryTime = 0
|
||||||
days, _ := strconv.Atoi(dataArray[1])
|
days, _ := strconv.Atoi(dataArray[1])
|
||||||
var date int64
|
var date int64 = 0
|
||||||
if client_ExpiryTime > 0 {
|
if client_ExpiryTime > 0 {
|
||||||
if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
|
if client_ExpiryTime-time.Now().Unix()*1000 < 0 {
|
||||||
date = -int64(days * 24 * 60 * 60000)
|
date = -int64(days * 24 * 60 * 60000)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue