diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1c36c5cc..7d56cfdf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -85,7 +85,7 @@ jobs: cd x-ui/bin # Download dependencies - Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.9.5/" + Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v25.9.11/" if [ "${{ matrix.platform }}" == "amd64" ]; then wget -q ${Xray_URL}Xray-linux-64.zip unzip Xray-linux-64.zip @@ -183,7 +183,7 @@ jobs: cd x-ui\bin # Download Xray for Windows - $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v25.6.8/" + $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v25.9.11/" Invoke-WebRequest -Uri "${Xray_URL}Xray-windows-64.zip" -OutFile "Xray-windows-64.zip" Expand-Archive -Path "Xray-windows-64.zip" -DestinationPath . Remove-Item "Xray-windows-64.zip" diff --git a/DockerInit.sh b/DockerInit.sh index d08eaf61..db391359 100755 --- a/DockerInit.sh +++ b/DockerInit.sh @@ -27,7 +27,7 @@ case $1 in esac mkdir -p build/bin cd build/bin -wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.9.5/Xray-linux-${ARCH}.zip" +wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.9.11/Xray-linux-${ARCH}.zip" unzip "Xray-linux-${ARCH}.zip" rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat mv xray "xray-linux-${FNAME}" diff --git a/config/config.go b/config/config.go index 32d83055..d5fe65ff 100644 --- a/config/config.go +++ b/config/config.go @@ -95,7 +95,7 @@ func GetLogFolder() string { return logFolderPath } if runtime.GOOS == "windows" { - return getBaseDir() + return filepath.Join(".", "log") } return "/var/log" } diff --git a/config/version b/config/version index 4484c2b2..6533b668 100644 --- a/config/version +++ b/config/version @@ -1 +1 @@ -2.6.8 \ No newline at end of file +2.8.0 \ No newline at end of file diff --git a/go.mod b/go.mod index 9277a466..78b6f09c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module x-ui -go 1.25.0 +go 1.25.1 require ( github.com/gin-contrib/gzip v1.2.3 @@ -15,15 +15,16 @@ require ( github.com/pelletier/go-toml/v2 v2.2.4 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil/v4 v4.25.8 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/valyala/fasthttp v1.65.0 github.com/xlzd/gotp v0.1.0 - github.com/xtls/xray-core v1.250905.0 + github.com/xtls/xray-core v1.250911.0 go.uber.org/atomic v1.11.0 - golang.org/x/crypto v0.41.0 - golang.org/x/text v0.28.0 - google.golang.org/grpc v1.75.0 + golang.org/x/crypto v0.42.0 + golang.org/x/text v0.29.0 + google.golang.org/grpc v1.75.1 gorm.io/driver/sqlite v1.6.0 - gorm.io/gorm v1.30.2 + gorm.io/gorm v1.30.5 ) require ( @@ -85,16 +86,16 @@ require ( go.uber.org/mock v0.6.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/arch v0.21.0 // indirect - golang.org/x/mod v0.27.0 // indirect - golang.org/x/net v0.43.0 // indirect + golang.org/x/mod v0.28.0 // indirect + golang.org/x/net v0.44.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.36.0 // indirect golang.org/x/time v0.13.0 // indirect golang.org/x/tools v0.36.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect - google.golang.org/protobuf v1.36.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/protobuf v1.36.9 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c // indirect lukechampine.com/blake3 v1.4.1 // indirect diff --git a/go.sum b/go.sum index d5ece387..7cf8d118 100644 --- a/go.sum +++ b/go.sum @@ -142,6 +142,8 @@ github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1 github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= github.com/shirou/gopsutil/v4 v4.25.8 h1:NnAsw9lN7587WHxjJA9ryDnqhJpFH6A+wagYWTOH970= github.com/shirou/gopsutil/v4 v4.25.8/go.mod h1:q9QdMmfAOVIw7a+eF86P7ISEU6ka+NLgkUxlopV4RwI= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -176,8 +178,8 @@ github.com/xlzd/gotp v0.1.0 h1:37blvlKCh38s+fkem+fFh7sMnceltoIEBYTVXyoa5Po= github.com/xlzd/gotp v0.1.0/go.mod h1:ndLJ3JKzi3xLmUProq4LLxCuECL93dG9WASNLpHz8qg= github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c h1:LHLhQY3mKXSpTcQAkjFR4/6ar3rXjQryNeM7khK3AHU= github.com/xtls/reality v0.0.0-20250904214705-431b6ff8c67c/go.mod h1:XxvnCCgBee4WWE0bc4E+a7wbk8gkJ/rS0vNVNtC5qp0= -github.com/xtls/xray-core v1.250905.0 h1:VNL3l/6fcwyeYXJTRbf+TYqPfJYkk0Wmmz7qoQNkxY8= -github.com/xtls/xray-core v1.250905.0/go.mod h1:WB/73DmN9Vs7lxtx4Xc/D0Ub1VUu06hAh1mMh8JN2uM= +github.com/xtls/xray-core v1.250911.0 h1:KMN8zVurAjHFixiUoFV/jwmzYohf27dQRntjV+8LQno= +github.com/xtls/xray-core v1.250911.0/go.mod h1:LkqA/BFVtPS2e5fRzg/bkYas9nQu4Uztlx+/fjlLM9k= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -202,12 +204,12 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -218,8 +220,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= @@ -230,12 +232,12 @@ golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+Z golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 h1:pmJpJEvT846VzausCQ5d7KreSROcDqmO388w5YbnltA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:/OQuEa4YWtDt7uQWHd3q3sUMb+QOLQUg1xa8CEsRv5w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -247,8 +249,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= -gorm.io/gorm v1.30.2 h1:f7bevlVoVe4Byu3pmbWPVHnPsLoWaMjEb7/clyr9Ivs= -gorm.io/gorm v1.30.2/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= +gorm.io/gorm v1.30.5 h1:dvEfYwxL+i+xgCNSGGBT1lDjCzfELK8fHZxL3Ee9X0s= +gorm.io/gorm v1.30.5/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c h1:m/r7OM+Y2Ty1sgBQ7Qb27VgIMBW8ZZhT4gLnUyDIhzI= gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c/go.mod h1:3r5CMtNQMKIvBlrmM9xWUNamjKBYPOWyXOjmg5Kts3g= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= diff --git a/sub/sub.go b/sub/sub.go index 4f8f5672..7931b24d 100644 --- a/sub/sub.go +++ b/sub/sub.go @@ -3,14 +3,19 @@ package sub import ( "context" "crypto/tls" + "html/template" "io" + "io/fs" "net" "net/http" + "os" + "path/filepath" "strconv" - "x-ui/config" "x-ui/logger" "x-ui/util/common" + webpkg "x-ui/web" + "x-ui/web/locale" "x-ui/web/middleware" "x-ui/web/network" "x-ui/web/service" @@ -18,6 +23,21 @@ import ( "github.com/gin-gonic/gin" ) +// setEmbeddedTemplates parses and sets embedded templates on the engine +func setEmbeddedTemplates(engine *gin.Engine) error { + t, err := template.New("").Funcs(engine.FuncMap).ParseFS( + webpkg.EmbeddedHTML(), + "html/common/page.html", + "html/component/aThemeSwitch.html", + "html/subscription.html", + ) + if err != nil { + return err + } + engine.SetHTMLTemplate(t) + return nil +} + type Server struct { httpServer *http.Server listener net.Listener @@ -38,13 +58,10 @@ func NewServer() *Server { } func (s *Server) initRouter() (*gin.Engine, error) { - if config.IsDebug() { - gin.SetMode(gin.DebugMode) - } else { - gin.DefaultWriter = io.Discard - gin.DefaultErrorWriter = io.Discard - gin.SetMode(gin.ReleaseMode) - } + // Always run in release mode for the subscription server + gin.DefaultWriter = io.Discard + gin.DefaultErrorWriter = io.Discard + gin.SetMode(gin.ReleaseMode) engine := gin.Default() @@ -57,6 +74,11 @@ func (s *Server) initRouter() (*gin.Engine, error) { engine.Use(middleware.DomainValidatorMiddleware(subDomain)) } + // Provide base_path in context for templates + engine.Use(func(c *gin.Context) { + c.Set("base_path", "/") + }) + LinksPath, err := s.settingService.GetSubPath() if err != nil { return nil, err @@ -112,6 +134,36 @@ func (s *Server) initRouter() (*gin.Engine, error) { SubTitle = "" } + // set per-request localizer from headers/cookies + engine.Use(locale.LocalizerMiddleware()) + + // register i18n function similar to web server + i18nWebFunc := func(key string, params ...string) string { + return locale.I18n(locale.Web, key, params...) + } + engine.SetFuncMap(map[string]any{"i18n": i18nWebFunc}) + + // Templates: prefer embedded; fallback to disk if necessary + if err := setEmbeddedTemplates(engine); err != nil { + logger.Warning("sub: failed to parse embedded templates:", err) + if files, derr := s.getHtmlFiles(); derr == nil { + engine.LoadHTMLFiles(files...) + } else { + logger.Error("sub: no templates available (embedded parse and disk load failed)", err, derr) + } + } + + // Assets: use disk if present, fallback to embedded + if _, err := os.Stat("web/assets"); err == nil { + engine.StaticFS("/assets", http.FS(os.DirFS("web/assets"))) + } else { + if subFS, err := fs.Sub(webpkg.EmbeddedAssets(), "assets"); err == nil { + engine.StaticFS("/assets", http.FS(subFS)) + } else { + logger.Error("sub: failed to mount embedded assets:", err) + } + } + g := engine.Group("/") s.sub = NewSUBController( @@ -121,6 +173,30 @@ func (s *Server) initRouter() (*gin.Engine, error) { return engine, nil } +// getHtmlFiles loads templates from local folder (used in debug mode) +func (s *Server) getHtmlFiles() ([]string, error) { + dir, _ := os.Getwd() + files := []string{} + // common layout + common := filepath.Join(dir, "web", "html", "common", "page.html") + if _, err := os.Stat(common); err == nil { + files = append(files, common) + } + // components used + theme := filepath.Join(dir, "web", "html", "component", "aThemeSwitch.html") + if _, err := os.Stat(theme); err == nil { + files = append(files, theme) + } + // page itself + page := filepath.Join(dir, "web", "html", "subscription.html") + if _, err := os.Stat(page); err == nil { + files = append(files, page) + } else { + return nil, err + } + return files, nil +} + func (s *Server) Start() (err error) { // This is an anonymous function, no function name defer func() { diff --git a/sub/subController.go b/sub/subController.go index 3f053740..c37ff5a9 100644 --- a/sub/subController.go +++ b/sub/subController.go @@ -2,8 +2,8 @@ package sub import ( "encoding/base64" - "net" "strings" + "x-ui/config" "github.com/gin-gonic/gin" ) @@ -58,21 +58,8 @@ func (a *SUBController) initRouter(g *gin.RouterGroup) { func (a *SUBController) subs(c *gin.Context) { subId := c.Param("subid") - var host string - if h, err := getHostFromXFH(c.GetHeader("X-Forwarded-Host")); err == nil { - host = h - } - if host == "" { - host = c.GetHeader("X-Real-IP") - } - if host == "" { - var err error - host, _, err = net.SplitHostPort(c.Request.Host) - if err != nil { - host = c.Request.Host - } - } - subs, header, err := a.subService.GetSubs(subId, host) + scheme, host, hostWithPort, hostHeader := a.subService.ResolveRequest(c) + subs, header, lastOnline, err := a.subService.GetSubs(subId, host) if err != nil || len(subs) == 0 { c.String(400, "Error!") } else { @@ -81,10 +68,38 @@ func (a *SUBController) subs(c *gin.Context) { result += sub + "\n" } + // If the request expects HTML (e.g., browser) or explicitly asked (?html=1 or ?view=html), render the info page here + accept := c.GetHeader("Accept") + if strings.Contains(strings.ToLower(accept), "text/html") || c.Query("html") == "1" || strings.EqualFold(c.Query("view"), "html") { + // Build page data in service + subURL, subJsonURL := a.subService.BuildURLs(scheme, hostWithPort, a.subPath, a.subJsonPath, subId) + page := a.subService.BuildPageData(subId, hostHeader, header, lastOnline, subs, subURL, subJsonURL) + c.HTML(200, "subscription.html", gin.H{ + "title": "subscription.title", + "cur_ver": config.GetVersion(), + "host": page.Host, + "base_path": page.BasePath, + "sId": page.SId, + "download": page.Download, + "upload": page.Upload, + "total": page.Total, + "used": page.Used, + "remained": page.Remained, + "expire": page.Expire, + "lastOnline": page.LastOnline, + "datepicker": page.Datepicker, + "downloadByte": page.DownloadByte, + "uploadByte": page.UploadByte, + "totalByte": page.TotalByte, + "subUrl": page.SubUrl, + "subJsonUrl": page.SubJsonUrl, + "result": page.Result, + }) + return + } + // Add headers - c.Writer.Header().Set("Subscription-Userinfo", header) - c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval) - c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(a.subTitle))) + a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle) if a.subEncrypt { c.String(200, base64.StdEncoding.EncodeToString([]byte(result))) @@ -96,41 +111,21 @@ func (a *SUBController) subs(c *gin.Context) { func (a *SUBController) subJsons(c *gin.Context) { subId := c.Param("subid") - var host string - if h, err := getHostFromXFH(c.GetHeader("X-Forwarded-Host")); err == nil { - host = h - } - if host == "" { - host = c.GetHeader("X-Real-IP") - } - if host == "" { - var err error - host, _, err = net.SplitHostPort(c.Request.Host) - if err != nil { - host = c.Request.Host - } - } + _, host, _, _ := a.subService.ResolveRequest(c) jsonSub, header, err := a.subJsonService.GetJson(subId, host) if err != nil || len(jsonSub) == 0 { c.String(400, "Error!") } else { // Add headers - c.Writer.Header().Set("Subscription-Userinfo", header) - c.Writer.Header().Set("Profile-Update-Interval", a.updateInterval) - c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(a.subTitle))) + a.ApplyCommonHeaders(c, header, a.updateInterval, a.subTitle) c.String(200, jsonSub) } } -func getHostFromXFH(s string) (string, error) { - if strings.Contains(s, ":") { - realHost, _, err := net.SplitHostPort(s) - if err != nil { - return "", err - } - return realHost, nil - } - return s, nil +func (a *SUBController) ApplyCommonHeaders(c *gin.Context, header, updateInterval, profileTitle string) { + c.Writer.Header().Set("Subscription-Userinfo", header) + c.Writer.Header().Set("Profile-Update-Interval", updateInterval) + c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileTitle))) } diff --git a/sub/subService.go b/sub/subService.go index e6e25e3a..a47cb6be 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -3,10 +3,15 @@ package sub import ( "encoding/base64" "fmt" + "net" "net/url" + "strconv" "strings" "time" + "github.com/gin-gonic/gin" + "github.com/goccy/go-json" + "x-ui/database" "x-ui/database/model" "x-ui/logger" @@ -14,8 +19,6 @@ import ( "x-ui/util/random" "x-ui/web/service" "x-ui/xray" - - "github.com/goccy/go-json" ) type SubService struct { @@ -34,19 +37,20 @@ func NewSubService(showInfo bool, remarkModel string) *SubService { } } -func (s *SubService) GetSubs(subId string, host string) ([]string, string, error) { +func (s *SubService) GetSubs(subId string, host string) ([]string, string, int64, error) { s.address = host var result []string var header string var traffic xray.ClientTraffic + var lastOnline int64 var clientTraffics []xray.ClientTraffic inbounds, err := s.getInboundsBySubId(subId) if err != nil { - return nil, "", err + return nil, "", 0, err } if len(inbounds) == 0 { - return nil, "", common.NewError("No inbounds found with ", subId) + return nil, "", 0, common.NewError("No inbounds found with ", subId) } s.datepicker, err = s.settingService.GetDatepicker() @@ -73,7 +77,11 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, string, error if client.Enable && client.SubID == subId { link := s.getLink(inbound, client.Email) result = append(result, link) - clientTraffics = append(clientTraffics, s.getClientTraffics(inbound.ClientStats, client.Email)) + ct := s.getClientTraffics(inbound.ClientStats, client.Email) + clientTraffics = append(clientTraffics, ct) + if ct.LastOnline > lastOnline { + lastOnline = ct.LastOnline + } } } } @@ -101,7 +109,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, string, error } } header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000) - return result, header, nil + return result, header, lastOnline, nil } func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) { @@ -1001,3 +1009,172 @@ func searchHost(headers any) string { return "" } + +// PageData is a view model for subscription.html +type PageData struct { + Host string + BasePath string + SId string + Download string + Upload string + Total string + Used string + Remained string + Expire int64 + LastOnline int64 + Datepicker string + DownloadByte int64 + UploadByte int64 + TotalByte int64 + SubUrl string + SubJsonUrl string + Result []string +} + +// ResolveRequest extracts scheme and host info from request/headers consistently. +func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string, hostWithPort string, hostHeader string) { + // scheme + scheme = "http" + if c.Request.TLS != nil || strings.EqualFold(c.GetHeader("X-Forwarded-Proto"), "https") { + scheme = "https" + } + + // base host (no port) + if h, err := getHostFromXFH(c.GetHeader("X-Forwarded-Host")); err == nil && h != "" { + host = h + } + if host == "" { + host = c.GetHeader("X-Real-IP") + } + if host == "" { + var err error + host, _, err = net.SplitHostPort(c.Request.Host) + if err != nil { + host = c.Request.Host + } + } + + // host:port for URLs + hostWithPort = c.GetHeader("X-Forwarded-Host") + if hostWithPort == "" { + hostWithPort = c.Request.Host + } + if hostWithPort == "" { + hostWithPort = host + } + + // header display host + hostHeader = c.GetHeader("X-Forwarded-Host") + if hostHeader == "" { + hostHeader = c.GetHeader("X-Real-IP") + } + if hostHeader == "" { + hostHeader = host + } + return +} + +// BuildURLs constructs absolute subscription and json URLs. +func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) { + if strings.HasSuffix(subPath, "/") { + subURL = scheme + "://" + hostWithPort + subPath + subId + } else { + subURL = scheme + "://" + hostWithPort + strings.TrimRight(subPath, "/") + "/" + subId + } + if strings.HasSuffix(subJsonPath, "/") { + subJsonURL = scheme + "://" + hostWithPort + subJsonPath + subId + } else { + subJsonURL = scheme + "://" + hostWithPort + strings.TrimRight(subJsonPath, "/") + "/" + subId + } + return +} + +// BuildPageData parses header and prepares the template view model. +func (s *SubService) BuildPageData(subId, hostHeader, header string, lastOnline int64, subs []string, subURL, subJsonURL string) PageData { + // Parse header values + var uploadByte, downloadByte, totalByte, expire int64 + parts := strings.Split(header, ";") + for _, p := range parts { + kv := strings.Split(strings.TrimSpace(p), "=") + if len(kv) != 2 { + continue + } + key := strings.ToLower(strings.TrimSpace(kv[0])) + val := strings.TrimSpace(kv[1]) + switch key { + case "upload": + if v, err := parseInt64(val); err == nil { + uploadByte = v + } + case "download": + if v, err := parseInt64(val); err == nil { + downloadByte = v + } + case "total": + if v, err := parseInt64(val); err == nil { + totalByte = v + } + case "expire": + if v, err := parseInt64(val); err == nil { + expire = v + } + } + } + + download := common.FormatTraffic(downloadByte) + upload := common.FormatTraffic(uploadByte) + total := "∞" + used := common.FormatTraffic(uploadByte + downloadByte) + remained := "" + if totalByte > 0 { + total = common.FormatTraffic(totalByte) + left := totalByte - (uploadByte + downloadByte) + if left < 0 { + left = 0 + } + remained = common.FormatTraffic(left) + } + + datepicker := s.datepicker + if datepicker == "" { + datepicker = "gregorian" + } + + return PageData{ + Host: hostHeader, + BasePath: "/", + SId: subId, + Download: download, + Upload: upload, + Total: total, + Used: used, + Remained: remained, + Expire: expire, + LastOnline: lastOnline, + Datepicker: datepicker, + DownloadByte: downloadByte, + UploadByte: uploadByte, + TotalByte: totalByte, + SubUrl: subURL, + SubJsonUrl: subJsonURL, + Result: subs, + } +} + +func getHostFromXFH(s string) (string, error) { + if strings.Contains(s, ":") { + realHost, _, err := net.SplitHostPort(s) + if err != nil { + return "", err + } + return realHost, nil + } + return s, nil +} + +func parseInt64(s string) (int64, error) { + // handle potential quotes + s = strings.Trim(s, "\"'") + n, err := strconv.ParseInt(s, 10, 64) + return n, err +} diff --git a/web/assets/css/custom.min.css b/web/assets/css/custom.min.css index 87dba544..126745e1 100644 --- a/web/assets/css/custom.min.css +++ b/web/assets/css/custom.min.css @@ -1 +1 @@ -:root{--color-primary-100:#008771;--dark-color-background:#0a1222;--dark-color-surface-100:#151f31;--dark-color-surface-200:#222d42;--dark-color-surface-300:#2c3950;--dark-color-surface-400:rgba(65, 85, 119, 0.5);--dark-color-surface-500:#2c3950;--dark-color-surface-600:#313f5a;--dark-color-surface-700:#111929;--dark-color-surface-700-rgb:17, 25, 41;--dark-color-table-hover:rgba(44, 57, 80, 0.2);--dark-color-text-primary:rgba(255, 255, 255, 0.75);--dark-color-stroke:#2c3950;--dark-color-btn-danger:#cd3838;--dark-color-btn-danger-border:transparent;--dark-color-btn-danger-hover:#e94b4b;--dark-color-tag-bg:rgba(255, 255, 255, 0.05);--dark-color-tag-border:rgba(255, 255, 255, 0.15);--dark-color-tag-color:rgba(255, 255, 255, 0.75);--dark-color-tag-green-bg:17, 36, 33;--dark-color-tag-green-border:25, 81, 65;--dark-color-tag-green-color:#3ad3ba;--dark-color-tag-purple-bg:#201425;--dark-color-tag-purple-border:#5a2969;--dark-color-tag-purple-color:#d988cd;--dark-color-tag-red-bg:#291515;--dark-color-tag-red-border:#5c2626;--dark-color-tag-red-color:#e04141;--dark-color-tag-orange-bg:#312313;--dark-color-tag-orange-border:#593914;--dark-color-tag-orange-color:#ffa031;--dark-color-tag-blue-bg:#111a2c;--dark-color-tag-blue-border:#1348ab;--dark-color-tag-blue-color:#529fff;--dark-color-codemirror-line-hover:rgba(0, 135, 113, 0.2);--dark-color-codemirror-line-selection:rgba(0, 135, 113, 0.3);--dark-color-login-background:var(--dark-color-background);--dark-color-login-wave:var(--dark-color-surface-200);--dark-color-tooltip:rgba(61, 76, 104, 0.9);--dark-color-back-top:rgba(61, 76, 104, 0.9);--dark-color-back-top-hover:rgba(61, 76, 104, 1);--dark-color-scrollbar:#313f5a;--dark-color-scrollbar-webkit:#7484a0;--dark-color-scrollbar-webkit-hover:#90a4c7;--dark-color-table-ring:rgb(38 52 77);--dark-color-spin-container:#151f31}html[data-theme-animations='off']{.ant-menu,.ant-layout-sider,.ant-card,.ant-tag,.ant-progress-circle>*,.ant-input,.ant-table-row-expand-icon,.ant-switch,.ant-table-thead>tr>th,.ant-select-selection,.ant-btn,.ant-input-number,.ant-input-group-addon,.ant-checkbox-inner,.ant-progress-bg,.ant-progress-success-bg,.ant-radio-button-wrapper:not(:first-child):before,.ant-radio-button-wrapper,#login,.cm-s-xq.CodeMirror{transition:border 0s,background 0s!important}.ant-menu.ant-menu-inline .ant-menu-item:not(.ant-menu-sub .ant-menu-item),.ant-layout-sider-trigger,.ant-alert-close-icon .anticon-close,.ant-tabs-nav .ant-tabs-tab,.ant-input-number-input,.ant-collapse>.ant-collapse-item>.ant-collapse-header,.Line-Hover,.ant-menu-theme-switch,.ant-menu-submenu-title{transition:color 0s!important}.wave-btn-bg{transition:width 0s!important}}html[data-theme='ultra-dark']{--dark-color-background:#21242a;--dark-color-surface-100:#0c0e12;--dark-color-surface-200:#222327;--dark-color-surface-300:#32353b;--dark-color-surface-400:rgba(255, 255, 255, 0.1);--dark-color-surface-500:#3b404b;--dark-color-surface-600:#505663;--dark-color-surface-700:#101113;--dark-color-surface-700-rgb:16, 17, 19;--dark-color-table-hover:rgba(89, 89, 89, 0.15);--dark-color-text-primary:rgb(255 255 255 / 85%);--dark-color-stroke:#202025;--dark-color-tag-green-bg:17, 36, 33;--dark-color-tag-green-border:29, 95, 77;--dark-color-tag-green-color:#59cbac;--dark-color-tag-purple-bg:#241121;--dark-color-tag-purple-border:#5a2969;--dark-color-tag-purple-color:#d686ca;--dark-color-tag-red-bg:#2a1215;--dark-color-tag-red-border:#58181c;--dark-color-tag-red-color:#e84749;--dark-color-tag-orange-bg:#2b1d11;--dark-color-tag-orange-border:#593815;--dark-color-tag-orange-color:#e89a3c;--dark-color-tag-blue-bg:#111a2c;--dark-color-tag-blue-border:#0f367e;--dark-color-tag-blue-color:#3c89e8;--dark-color-codemirror-line-hover:rgba(82, 84, 94, 0.2);--dark-color-codemirror-line-selection:rgba(82, 84, 94, 0.3);--dark-color-login-background:#0a2227;--dark-color-login-wave:#0f2d32;--dark-color-tooltip:rgba(88, 93, 100, 0.9);--dark-color-back-top:rgba(88, 93, 100, 0.9);--dark-color-back-top-hover:rgba(88, 93, 100, 1);--dark-color-scrollbar:rgb(107,107,107);--dark-color-scrollbar-webkit:#9f9f9f;--dark-color-scrollbar-webkit-hover:#d1d1d1;--dark-color-table-ring:rgb(37 39 42);--dark-color-spin-container:#1d1d1d;.ant-dropdown-menu-dark{background-color:var(--dark-color-surface-500)}.dark .ant-dropdown-menu-submenu-title:hover,.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled){background-color:rgb(0 93 78 / .3)}.dark .waves-header{background-color:#0a2227}.dark .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-decade:hover{background-color:var(--dark-color-surface-600)}}html,body{height:100vh;width:100vw;margin:0;padding:0;overflow:hidden}body{color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;background-color:#fff;font-feature-settings:"tnum"}html{--antd-wave-shadow-color:var(--color-primary-100);line-height:1.15;text-size-adjust:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-moz-tap-highlight-color:#fff0;-webkit-tap-highlight-color:#fff0}@supports (scrollbar-width:auto) and (not selector(::-webkit-scrollbar)){:not(.dark){scrollbar-color:#9a9a9a #fff0;scrollbar-width:thin}.dark *{scrollbar-color:var(--dark-color-scrollbar) #fff0;scrollbar-width:thin}}::-webkit-scrollbar{width:10px;height:10px;background-color:#fff0}::-webkit-scrollbar-track{background-color:#fff0;margin-block:.5em}.ant-modal-wrap::-webkit-scrollbar-track{background-color:#fff;margin-block:0}::-webkit-scrollbar-thumb{border-radius:9999px;background-color:#9a9a9a;border:2px solid #fff0;background-clip:content-box}::-webkit-scrollbar-thumb:hover,::-webkit-scrollbar-thumb:active{background-color:#828282}.dark .ant-modal-wrap::-webkit-scrollbar-track{background-color:var(--dark-color-background)}.dark ::-webkit-scrollbar-thumb{background-color:var(--dark-color-scrollbar-webkit)}.dark ::-webkit-scrollbar-thumb:hover,.dark ::-webkit-scrollbar-thumb:active{background-color:var(--dark-color-scrollbar-webkit-hover)}::-moz-selection{color:var(--color-primary-100);background-color:#cfe8e4}::selection{color:var(--color-primary-100);background-color:#cfe8e4}#app{height:100%;position:fixed;top:0;left:0;right:0;bottom:0;margin:0;padding:0;overflow:auto}.ant-layout,.ant-layout *{box-sizing:border-box}.ant-spin-container:after{border-radius:1.5rem}.dark .ant-spin-container:after{background:var(--dark-color-spin-container)}style attribute{text-align:center}.ant-table-thead>tr>th{padding:12px 8px}.ant-table-tbody>tr>td{padding:10px 8px}.ant-table-thead>tr>th{color:rgb(0 0 0 / .85);font-weight:500;text-align:left;border-bottom:1px solid #e8e8e8;transition:background 0.3s ease}.ant-table table{border-radius:1rem}.ant-table-bordered .ant-table-tbody:not(.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody)>tr:last-child>td:first-child{border-bottom-left-radius:1rem}.ant-table-bordered .ant-table-tbody:not(.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody)>tr:last-child>td:last-child{border-bottom-right-radius:1rem}.ant-table{box-sizing:border-box;margin:0;padding:0;color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;font-feature-settings:"tnum";position:relative;clear:both}.ant-table .ant-table-body:not(.ant-table-expanded-row .ant-table-body){overflow-x:auto!important}.ant-card-hoverable{cursor:auto;cursor:pointer}.ant-card{box-sizing:border-box;margin:0;padding:0;color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;position:relative;background-color:#fff;border-radius:2px;transition:all 0.3s}.ant-space{width:100%}.ant-layout-sider-zero-width-trigger{display:none}@media (max-width:768px){.ant-layout-sider{display:none}.ant-card,.ant-alert-error{margin:.5rem}.ant-tabs{margin:.5rem;padding:.5rem}.ant-modal-body{padding:20px}.ant-form-item-label{line-height:1.5;padding:8px 0 0}:not(.dark) ::-webkit-scrollbar{width:8px;height:8px;background-color:#fff0}.dark ::-webkit-scrollbar{width:8px;height:8px;background-color:#fff0}}.ant-layout-content{min-height:auto}.ant-card,.ant-tabs{border-radius:1.5rem}.ant-card-hoverable{cursor:auto}.ant-card+.ant-card{margin-top:20px}.drawer-handle{position:absolute;top:72px;width:41px;height:40px;cursor:pointer;z-index:0;text-align:center;line-height:40px;font-size:16px;display:flex;justify-content:center;align-items:center;background-color:#fff;right:-40px;box-shadow:2px 0 8px rgb(0 0 0 / .15);border-radius:0 4px 4px 0}.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color:#006655!important;background-image:linear-gradient(270deg,#fff0 30%,#009980,#fff0 100%);background-repeat:no-repeat;animation:ma-bg-move linear 6.6s infinite;color:#fff;border-radius:.5rem}.ant-layout-sider-collapsed .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{border-radius:0}@-webkit-keyframes ma-bg-move{0%{background-position:-500px 0}100%{background-position:1000px 0}}@keyframes ma-bg-move{0%{background-position:-500px 0}50%{background-position:1000px 0}100%{background-position:1000px 0}}.ant-menu-item-active,.ant-menu-item:hover,.ant-menu-submenu-title:hover,.ant-menu-item:active,.ant-menu-submenu-title:active{color:var(--color-primary-100);background-color:#e8f4f2}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title{border-radius:.5rem}.ant-menu-inline .ant-menu-item:after,.ant-menu{border-right-width:0}.ant-layout-sider-children,.ant-pagination ul{padding:.5rem}.ant-layout-sider-collapsed .ant-layout-sider-children{padding:.5rem 0}.ant-dropdown-menu,.ant-select-dropdown-menu{padding:.5rem}.ant-dropdown-menu-item,.ant-dropdown-menu-item:hover,.ant-select-dropdown-menu-item,.ant-select-dropdown-menu-item:hover,.ant-select-selection--multiple .ant-select-selection__choice{border-radius:.5rem}.ant-select-dropdown--multiple .ant-select-dropdown-menu .ant-select-dropdown-menu-item,.ant-select-dropdown--single .ant-select-dropdown-menu .ant-select-dropdown-menu-item-selected{margin-block:2px}@media (min-width:769px){.drawer-handle{display:none}.ant-tabs{padding:2rem}}.fade-in-enter,.fade-in-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.fade-in-enter-active,.fade-in-leave-active{-webkit-transition:all 0.3s cubic-bezier(.55,0,.1,1);transition:all 0.3s cubic-bezier(.55,0,.1,1)}.zoom-in-center-enter-active,.zoom-in-center-leave-active{-webkit-transition:all 0.3s cubic-bezier(.55,0,.1,1);transition:all 0.3s cubic-bezier(.55,0,.1,1)}.zoom-in-center-enter,.zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.zoom-in-top-enter-active,.zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.zoom-in-top-enter,.zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.zoom-in-bottom-enter-active,.zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.zoom-in-bottom-enter,.zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.zoom-in-left-enter-active,.zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1);transition:transform 0.3s cubic-bezier(.23,1,.32,1),opacity 0.3s cubic-bezier(.23,1,.32,1),-webkit-transform 0.3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.zoom-in-left-enter,.zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.list-enter-active,.list-leave-active{-webkit-transition:all 0.3s;transition:all 0.3s}.list-enter,.list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.ant-tooltip-inner{min-height:0;padding-inline:1rem}.ant-list-item-meta-title{font-size:14px}.ant-progress-inner{background-color:#ebeef5}.deactive-client .ant-collapse-header{color:#ffffff!important;background-color:#ff7f7f}.ant-table-expand-icon-th,.ant-table-row-expand-icon-cell{width:30px;min-width:30px}.ant-tabs{background-color:#fff}.ant-form-item{margin-bottom:0}.ant-setting-textarea{margin-top:1.5rem}.client-table-header{background-color:#f0f2f5}.client-table-odd-row{background-color:#fafafa}.ant-table-pagination.ant-pagination{float:left}.ant-tag{margin-right:0;margin-inline:2px;display:inline-flex;align-items:center;justify-content:space-evenly}.ant-tag:not(.qr-tag){column-gap:4px}#inbound-info-modal .ant-tag{margin-block:2px}.tr-info-table{display:inline-table;margin-block:10px;width:100%}#inbound-info-modal .tr-info-table .ant-tag{margin-block:0;margin-inline:0}.tr-info-row{display:flex;flex-direction:column;row-gap:2px;margin-block:10px}.tr-info-row a{margin-left:6px}.tr-info-row code{padding-inline:8px}.tr-info-tag{max-width:100%;text-wrap:balance;overflow:hidden;overflow-wrap:anywhere}.tr-info-title{display:inline-flex;align-items:center;justify-content:flex-start;column-gap:4px}.ant-tag-blue{background-color:#edf4fa;border-color:#a9c5e7;color:#0e49b5}.ant-tag-green{background-color:#eafff9;border-color:#76ccb4;color:#199270}.ant-tag-purple{background-color:#f2eaf1;border-color:#d5bed2;color:#7a316f}.ant-tag-orange,.ant-alert-warning{background-color:#ffeee1;border-color:#fec093;color:#f37b24}.ant-tag-red,.ant-alert-error{background-color:#ffe9e9;border-color:#ff9e9e;color:#cf3c3c}.ant-input::placeholder{opacity:.5}.ant-input:hover,.ant-input:focus{background-color:#e8f4f2}.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){background-color:#e8f4f2}.delete-icon:hover{color:#e04141}.normal-icon:hover{color:var(--color-primary-100)}.dark ::-moz-selection{color:#fff;background-color:var(--color-primary-100)}.dark ::selection{color:#fff;background-color:var(--color-primary-100)}.dark .normal-icon:hover{color:#fff}.dark .ant-layout-sider,.dark .ant-drawer-content,.ant-menu-dark,.ant-menu-dark .ant-menu-sub,.dark .ant-card,.dark .ant-table,.dark .ant-collapse-content,.dark .ant-tabs{background-color:var(--dark-color-surface-100);color:var(--dark-color-text-primary)}.dark .ant-card-hoverable:hover,.dark .ant-space-item>.ant-tabs:hover{box-shadow:0 2px 8px #fff0}.dark>.ant-layout,.dark .drawer-handle,.dark .ant-table-thead>tr>th,.dark .ant-table-expanded-row,.dark .ant-table-expanded-row:hover,.dark .ant-table-expanded-row .ant-table-tbody,.dark .ant-calendar{background-color:var(--dark-color-background);color:var(--dark-color-text-primary)}.dark .ant-table-expanded-row .ant-table-thead>tr:first-child>th{border-radius:0}.dark .ant-calendar,.dark .ant-card-bordered{border-color:var(--dark-color-background)}.dark .ant-table-bordered,.dark .ant-table-bordered.ant-table-empty .ant-table-placeholder,.dark .ant-table-bordered .ant-table-body>table,.dark .ant-table-bordered .ant-table-fixed-left table,.dark .ant-table-bordered .ant-table-fixed-right table,.dark .ant-table-bordered .ant-table-header>table,.dark .ant-table-bordered .ant-table-thead>tr:not(:last-child)>th,.dark .ant-table-bordered .ant-table-tbody>tr>td,.dark .ant-table-bordered .ant-table-thead>tr>th{border-color:var(--dark-color-surface-400)}.dark .ant-table-tbody>tr>td,.dark .ant-table-thead>tr>th,.dark .ant-card-head,.dark .ant-modal-header,.dark .ant-collapse>.ant-collapse-item,.dark .ant-tabs-bar,.dark .ant-list-split .ant-list-item,.dark .ant-popover-title,.dark .ant-calendar-header,.dark .ant-calendar-input-wrap{border-bottom-color:var(--dark-color-surface-400)}.dark .ant-modal-footer,.dark .ant-collapse-content,.dark .ant-calendar-footer,.dark .ant-divider-horizontal.ant-divider-with-text-left:before,.dark .ant-divider-horizontal.ant-divider-with-text-left:after,.dark .ant-divider-horizontal.ant-divider-with-text-center:before,.dark .ant-divider-horizontal.ant-divider-with-text-center:after{border-top-color:var(--dark-color-surface-300)}.ant-divider-horizontal.ant-divider-with-text-left:before{width:10%}.dark .ant-progress-text,.dark .ant-card-head,.dark .ant-form,.dark .ant-collapse>.ant-collapse-item>.ant-collapse-header,.dark .ant-modal-close-x,.dark .ant-form .anticon,.dark .ant-tabs-tab-arrow-show:not(.ant-tabs-tab-btn-disabled),.dark .anticon-close,.dark .ant-list-item-meta-title,.dark .ant-select-selection i,.dark .ant-modal-confirm-title,.dark .ant-modal-confirm-content,.dark .ant-popover-message,.dark .ant-modal,.dark .ant-divider-inner-text,.dark .ant-popover-title,.dark .ant-popover-inner-content,.dark h2,.dark .ant-modal-title,.dark .ant-form-item-label>label,.dark .ant-checkbox-wrapper,.dark .ant-form-item,.dark .ant-calendar-footer .ant-calendar-today-btn,.dark .ant-calendar-footer .ant-calendar-time-picker-btn,.dark .ant-calendar-day-select,.dark .ant-calendar-month-select,.dark .ant-calendar-year-select,.dark .ant-calendar-date,.dark .ant-calendar-year-panel-year,.dark .ant-calendar-month-panel-month,.dark .ant-calendar-decade-panel-decade{color:var(--dark-color-text-primary)}.dark .ant-pagination-options-size-changer .ant-select-arrow .anticon.anticon-down.ant-select-arrow-icon{color:rgb(255 255 255 / 35%)}.dark .ant-pagination-item a,.dark .ant-pagination-next a,.dark .ant-pagination-prev a{color:var(--dark-color-text-primary)}.dark .ant-pagination-item:focus a,.dark .ant-pagination-item:hover a,.dark .ant-pagination-item-active a,.dark .ant-pagination-next:hover .ant-pagination-item-link{color:var(--color-primary-100)}.dark .ant-pagination-item-active{background-color:#fff0}.dark .ant-list-item-meta-description{color:rgb(255 255 255 / .45)}.dark .ant-pagination-disabled i,.dark .ant-tabs-tab-btn-disabled{color:rgb(255 255 255 / .25)}.dark .ant-input,.dark .ant-input-group-addon,.dark .ant-collapse,.dark .ant-select-selection,.dark .ant-input-number,.dark .ant-input-number-handler-wrap,.dark .ant-table-placeholder,.dark .ant-empty-normal,.dark .ant-select-dropdown,.dark .ant-select-dropdown li,.dark .ant-select-dropdown-menu-item,.dark .client-table-header,.dark .ant-select-selection--multiple .ant-select-selection__choice{background-color:var(--dark-color-surface-200);border-color:var(--dark-color-surface-300);color:var(--dark-color-text-primary)}.dark .ant-select-dropdown--multiple .ant-select-dropdown-menu .ant-select-dropdown-menu-item.ant-select-dropdown-menu-item-selected :not(.ant-dropdown-menu-submenu-title:hover){background-color:var(--dark-color-surface-300)}.dark .ant-select-dropdown-menu-item.ant-select-dropdown-menu-item-selected{background-color:var(--dark-color-surface-300)}.dark .ant-calendar-time-picker-inner{background-color:var(--dark-color-background)}.dark .ant-select-selection:hover,.dark .ant-calendar-picker-clear,.dark .ant-input-number:hover,.dark .ant-input-number:focus,.dark .ant-input:hover,.dark .ant-input:focus{background-color:rgb(0 135 113 / .3);border-color:var(--color-primary-100)}.dark .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){border-color:var(--color-primary-100);background-color:rgb(0 135 113 / .3)}.dark .ant-btn:not(.ant-btn-primary):not(.ant-btn-danger){color:var(--dark-color-text-primary);background-color:rgb(10 117 87 / 30%);border:1px solid var(--color-primary-100)}.dark .ant-radio-button-wrapper,.dark .ant-radio-button-wrapper:before{color:var(--dark-color-text-primary);background-color:rgb(0 135 113 / .3);border-color:var(--color-primary-100)}.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){background-color:#e8f4f2}.dark .ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.dark .ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){color:#fff;background-color:rgb(10 117 87 / 50%);border-color:var(--color-primary-100)}.dark .ant-btn-primary[disabled],.dark .ant-btn-danger[disabled],.dark .ant-calendar-ok-btn-disabled{color:rgb(255 255 255 / 35%);background-color:var(--dark-color-surface-200);border-color:var(--dark-color-surface-300)}.dark .ant-table-tbody>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.dark .client-table-odd-row{background-color:var(--dark-color-table-hover)}.dark .ant-table-row-expand-icon{color:#fff;background-color:#fff0;border-color:rgb(255 255 255 / 20%)}.dark .ant-table-row-expand-icon:hover{color:var(--color-primary-100);background-color:#fff0;border-color:var(--color-primary-100)}.dark .ant-switch:not(.ant-switch-checked),.dark .ant-progress-line .ant-progress-inner{background-color:var(--dark-color-surface-500)}.dark .ant-progress-circle-trail{stroke:var(--dark-color-stroke)!important}.dark .ant-popover-inner{background-color:var(--dark-color-surface-500)}.dark>.ant-popover-content>.ant-popover-arrow{border-color:var(--dark-color-surface-500)}@media (max-width:768px){.dark .ant-popover-inner{background-color:var(--dark-color-surface-200)}.dark>.ant-popover-content>.ant-popover-arrow{border-color:var(--dark-color-surface-200)}}.ant-dropdown-menu-dark .ant-dropdown-menu-item:hover,.dark .ant-select-dropdown-menu-item-selected,.dark .ant-calendar-time-picker-select-option-selected{background-color:var(--dark-color-surface-600)}.ant-menu-dark .ant-menu-item:hover,.ant-menu-dark .ant-menu-submenu-title:hover{background-color:var(--dark-color-surface-300)}.dark .ant-menu-item:active,.dark .ant-menu-submenu-title:active{color:#fff;background-color:var(--dark-color-surface-300)}.dark .ant-alert-message{color:rgb(255 255 255 / .85)}.dark .ant-tag{color:var(--dark-color-tag-color);background-color:var(--dark-color-tag-bg);border-color:var(--dark-color-tag-border)}.dark .ant-tag-blue{background-color:var(--dark-color-tag-blue-bg);border-color:var(--dark-color-tag-blue-border);color:var(--dark-color-tag-blue-color)}.dark .ant-tag-red,.dark .ant-alert-error{background-color:var(--dark-color-tag-red-bg);border-color:var(--dark-color-tag-red-border);color:var(--dark-color-tag-red-color)}.dark .ant-tag-orange,.dark .ant-alert-warning{background-color:var(--dark-color-tag-orange-bg);border-color:var(--dark-color-tag-orange-border);color:var(--dark-color-tag-orange-color)}.dark .ant-tag-green{background-color:rgb(var(--dark-color-tag-green-bg));border-color:rgb(var(--dark-color-tag-green-border));color:var(--dark-color-tag-green-color)}.dark .ant-tag-purple{background-color:var(--dark-color-tag-purple-bg);border-color:var(--dark-color-tag-purple-border);color:var(--dark-color-tag-purple-color)}.dark .ant-modal-content,.dark .ant-modal-header{background-color:var(--dark-color-surface-700)}.dark .ant-calendar-next-month-btn-day .ant-calendar-date,.dark .ant-calendar-last-month-cell .ant-calendar-date{color:var(--dark-color-surface-300)}.dark .ant-calendar-selected-day .ant-calendar-date{background-color:var(--color-primary-100)!important;color:#fff}.dark .ant-calendar-date:hover,.dark .ant-calendar-time-picker-select li:hover{background-color:var(--dark-color-surface-600);color:#fff}.dark .ant-calendar-header a:hover,.dark .ant-calendar-header a:hover::before,.dark .ant-calendar-header a:hover::after{border-color:#fff}.dark .ant-calendar-time-picker-select{border-right-color:var(--dark-color-surface-300)}.has-warning .ant-select-selection,.has-warning .ant-select-selection:hover,.has-warning .ant-input,.has-warning .ant-input:hover{background-color:#ffeee1;border-color:#fec093}.has-warning .ant-input::placeholder{color:#f37b24}.has-warning .ant-input:not([disabled]):hover{border-color:#fec093}.dark .has-warning .ant-select-selection,.dark .has-warning .ant-select-selection:hover,.dark .has-warning .ant-input,.dark .has-warning .ant-input:hover{border-color:#784e1d;background:#312313}.dark .has-warning .ant-input::placeholder{color:rgb(255 160 49 / 70%)}.dark .has-warning .anticon{color:#ffa031}.dark .has-success .anticon{color:var(--color-primary-100);animation-name:diffZoomIn1!important}.dark .anticon-close-circle{color:#e04141}.dark .ant-spin-nested-loading>div>.ant-spin .ant-spin-text{text-shadow:0 1px 2px #0007}.dark .ant-spin{color:#fff}.dark .ant-spin-dot-item{background-color:#fff}.ant-checkbox-wrapper,.ant-input-group-addon,.ant-tabs-tab,.ant-input::placeholder,.ant-collapse-header,.ant-menu,.ant-radio-button-wrapper{-webkit-user-select:none;user-select:none}.ant-calendar-date,.ant-calendar-year-panel-year,.ant-calendar-decade-panel-decade,.ant-calendar-month-panel-month{border-radius:4px}.ant-checkbox-inner,.ant-checkbox-checked:after,.ant-table-row-expand-icon{border-radius:6px}.ant-calendar-date:hover{background-color:#e8f4f2}.ant-calendar-date:active{background-color:#e8f4f2;color:rgb(0 0 0 / .65)}.ant-calendar-today .ant-calendar-date{color:var(--color-primary-100);font-weight:400;border-color:var(--color-primary-100)}.dark .ant-calendar-today .ant-calendar-date{color:#fff;border-color:var(--color-primary-100)}.ant-calendar-selected-day .ant-calendar-date{background:var(--color-primary-100);color:#fff}li.ant-select-dropdown-menu-item:empty:after{content:"None";font-weight:400;color:rgb(0 0 0 / .25)}.dark li.ant-select-dropdown-menu-item:empty:after{content:"None";font-weight:400;color:rgb(255 255 255 / .3)}.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item:hover .ant-select-selected-icon{color:rgb(0 0 0 / .87)}.dark.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item:hover .ant-select-selected-icon{color:#fff}.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item-selected .ant-select-selected-icon,.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item-selected:hover .ant-select-selected-icon{color:var(--color-primary-100)}.ant-select-selection:hover,.ant-input-number-focused,.ant-input-number:hover{background-color:#e8f4f2}.dark .ant-input-number-handler:active{background-color:var(--color-primary-100)}.dark .ant-input-number-handler:hover .ant-input-number-handler-down-inner,.dark .ant-input-number-handler:hover .ant-input-number-handler-up-inner{color:#fff}.dark .ant-input-number-handler-down{border-top:1px solid rgb(217 217 217 / .3)}.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-century-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-decade-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-month-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-year-select .dark .ant-calendar-month-panel-header .ant-calendar-month-panel-century-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-decade-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-month-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-year-select{color:rgb(255 255 255 / .85)}.dark .ant-calendar-year-panel-header{border-bottom:1px solid var(--dark-color-surface-200)}.dark .ant-calendar-year-panel-last-decade-cell .ant-calendar-year-panel-year,.dark .ant-calendar-year-panel-next-decade-cell .ant-calendar-year-panel-year{color:rgb(255 255 255 / .35)}.dark .ant-divider:not(.ant-divider-with-text-center,.ant-divider-with-text-left,.ant-divider-with-text-right),.ant-dropdown-menu-dark,.dark .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-decade:hover{background-color:var(--dark-color-surface-200)}.dark .ant-calendar-header a:hover{color:#fff}.dark .ant-calendar-month-panel-header{background-color:var(--dark-color-background);border-bottom:1px solid var(--dark-color-surface-200)}.dark .ant-calendar-year-panel,.dark .ant-calendar table{background-color:var(--dark-color-background)}.dark .ant-calendar-year-panel-selected-cell .ant-calendar-year-panel-year,.dark .ant-calendar-year-panel-selected-cell .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-selected-cell .ant-calendar-month-panel-month,.dark .ant-calendar-month-panel-selected-cell .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-selected-cell .ant-calendar-decade-panel-decade,.dark .ant-calendar-decade-panel-selected-cell .ant-calendar-decade-panel-decade:hover{color:#fff;background-color:var(--color-primary-100)!important}.dark .ant-calendar-last-month-cell .ant-calendar-date,.dark .ant-calendar-last-month-cell .ant-calendar-date:hover,.dark .ant-calendar-next-month-btn-day .ant-calendar-date,.dark .ant-calendar-next-month-btn-day .ant-calendar-date:hover{color:rgb(255 255 255 / 25%);background:#fff0;border-color:#fff0}.dark .ant-calendar-today .ant-calendar-date:hover{color:#fff;border-color:var(--color-primary-100);background-color:var(--color-primary-100)}.dark .ant-calendar-decade-panel-last-century-cell .ant-calendar-decade-panel-decade,.dark .ant-calendar-decade-panel-next-century-cell .ant-calendar-decade-panel-decade{color:rgb(255 255 255 / 25%)}.dark .ant-calendar-decade-panel-header{border-bottom:1px solid var(--dark-color-surface-200);background-color:var(--dark-color-background)}.dark .ant-checkbox-inner{background-color:rgb(0 135 113 / .3);border-color:rgb(0 135 113 / .3)}.dark .ant-checkbox-checked .ant-checkbox-inner{background-color:var(--color-primary-100);border-color:var(--color-primary-100)}.dark .ant-calendar-input{background-color:var(--dark-color-background);color:var(--dark-color-text-primary)}.dark .ant-calendar-input::placeholder{color:rgb(255 255 255 / .25)}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child),.ant-input-number-handler,.ant-input-number-handler-wrap{border-radius:0}.ant-input-number{overflow:clip}.ant-modal-body,.ant-collapse-content>.ant-collapse-content-box{overflow-x:auto}.ant-modal-body{overflow-y:hidden}.ant-calendar-year-panel-year:hover,.ant-calendar-decade-panel-decade:hover,.ant-calendar-month-panel-month:hover,.ant-dropdown-menu-item:hover,.ant-dropdown-menu-submenu-title:hover,.ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled),.ant-table-tbody>tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-tbody>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-thead>tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-thead>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td{background-color:#e8f4f2}.dark .ant-dropdown-menu-submenu-title:hover,.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled){background-color:rgb(0 93 78 / .3)}.ant-select-dropdown,.ant-popover-inner{overflow-x:hidden}.ant-popover-inner-content{max-height:450px;overflow-y:auto}@media (max-height:900px){.ant-popover-inner-content{max-height:400px}}@media (max-height:768px){.ant-popover-inner-content{max-height:300px}}@media (max-width:768px){.ant-popover-inner-content{max-height:300px}}.qr-modal{display:flex;align-items:flex-end;gap:10px;flex-direction:column;flex-wrap:wrap;row-gap:24px}.qr-box{width:220px}.qr-cv{width:100%;height:100%}.dark .qr-cv{filter:invert(1)}.qr-bg{background-color:#fff;display:flex;justify-content:center;align-content:center;padding:.8rem;border-radius:1rem;border:solid 1px #e8e8e8;height:220px;width:220px;transition:all 0.1s}.qr-bg:hover{border-color:#76ccb4;background-color:#eafff9}.qr-bg:hover:active{border-color:#76ccb4;background-color:rgb(197 241 228 / 70%)}.dark .qr-bg{background-color:var(--dark-color-surface-700);border-color:var(--dark-color-surface-300)}.dark .qr-bg:hover{background-color:rgb(var(--dark-color-tag-green-bg));border-color:rgb(var(--dark-color-tag-green-border))}.dark .qr-bg:hover:active{background-color:#17322e}@property --tr-rotate{syntax:'';initial-value:45deg;inherits:false}.qr-bg-sub{background-image:linear-gradient(var(--tr-rotate),#76ccb4,transparent,#d5bed2);display:flex;justify-content:center;align-content:center;padding:1px;border-radius:1rem;height:220px;width:220px}.dark .qr-bg-sub{background-image:linear-gradient(var(--tr-rotate),#195141,transparent,#5a2969)}.qr-bg-sub:hover{animation:tr-rotate-gradient 3.5s linear infinite}@keyframes tr-rotate-gradient{from{--tr-rotate:45deg}to{--tr-rotate:405deg}}.qr-bg-sub-inner{background-color:#fff;padding:.8rem;border-radius:1rem;transition:all 0.1s}.qr-bg-sub-inner:hover{background-color:rgb(255 255 255 / 60%);backdrop-filter:blur(25px)}.qr-bg-sub-inner:hover:active{background-color:rgb(255 255 255 / 30%)}.dark .qr-bg-sub-inner{background-color:rgb(var(--dark-color-surface-700-rgb))}.dark .qr-bg-sub-inner:hover{background-color:rgba(var(--dark-color-surface-700-rgb),.5);backdrop-filter:blur(25px)}.dark .qr-bg-sub-inner:hover:active{background-color:rgba(var(--dark-color-surface-700-rgb),.2)}.qr-tag{text-align:center;margin-bottom:10px;width:100%;overflow:hidden;margin-inline:0}@media (min-width:769px){.qr-modal{flex-direction:row;max-width:680px}}.tr-marquee{justify-content:flex-start}.tr-marquee span{padding-right:25%;white-space:nowrap;transform-origin:center}@keyframes move-ltr{0%{transform:translateX(0)}100%{transform:translateX(-100%)}}.ant-input-group-addon:not(:first-child):not(:last-child){border-radius:0rem 1rem 1rem 0rem}b,strong{font-weight:500}.ant-collapse>.ant-collapse-item>.ant-collapse-header{padding:10px 16px 10px 40px}.dark .ant-message-notice-content{background-color:var(--dark-color-surface-200);border:1px solid var(--dark-color-surface-300);color:var(--dark-color-text-primary)}.ant-btn-danger{background-color:var(--dark-color-btn-danger);border-color:var(--dark-color-btn-danger-border)}.ant-btn-danger:focus,.ant-btn-danger:hover{background-color:var(--dark-color-btn-danger-hover);border-color:var(--dark-color-btn-danger-hover)}.dark .ant-alert-close-icon .anticon-close:hover{color:#fff}.ant-empty-small{margin:4px 0;background-color:transparent!important}.ant-empty-small .ant-empty-image{height:20px}.ant-menu-theme-switch,.ant-menu-theme-switch:hover{background-color:transparent!important;cursor:default!important}.dark .ant-tooltip-inner,.dark .ant-tooltip-arrow:before{background-color:var(--dark-color-tooltip)}.ant-select-sm .ant-select-selection__rendered{margin-left:10px}.ant-collapse{-moz-animation:collfade 0.3s ease;-webkit-animation:0.3s collfade 0.3s ease;animation:collfade 0.3s ease}@-webkit-keyframes collfade{0%{transform:scaleY(.8);transform-origin:0% 0%;opacity:0}100%{transform:scaleY(1);transform-origin:0% 0%;opacity:1}}@keyframes collfade{0%{transform:scaleY(.8);transform-origin:0% 0%;opacity:0}100%{transform:scaleY(1);transform-origin:0% 0%;opacity:1}}.ant-table-tbody>tr>td{border-color:#f0f0f0}.ant-table-row-expand-icon{vertical-align:middle;margin-inline-end:8px;position:relative;transform:scale(.9411764705882353)}.ant-table-row-collapsed::before{transform:rotate(-180deg);top:7px;inset-inline-end:3px;inset-inline-start:3px;height:1px;position:absolute;background:currentcolor;transition:transform 0.3s ease-out;content:""}.ant-table-row-collapsed::after{transform:rotate(0deg);top:3px;bottom:3px;inset-inline-start:7px;width:1px;position:absolute;background:currentcolor;transition:transform 0.3s ease-out;content:""}.ant-table-row-expanded::before{top:7px;inset-inline-end:3px;inset-inline-start:3px;height:1px;position:absolute;background:currentcolor;transition:transform 0.3s ease-out;content:""}.ant-table-row-expanded::after{top:3px;bottom:3px;inset-inline-start:7px;width:1px;transform:rotate(90deg);position:absolute;background:currentcolor;transition:transform 0.3s ease-out;content:""}.ant-menu-theme-switch.ant-menu-item .ant-switch:not(.ant-switch-disabled):active:after,.ant-switch:not(.ant-switch-disabled):active:before{width:16px}.dark .ant-select-disabled .ant-select-selection{background:var(--dark-color-surface-100);border-color:var(--dark-color-surface-200);color:rgb(255 255 255 / .25)}.dark .ant-select-disabled .anticon{color:rgb(255 255 255 / .25)}.dark .ant-input-number-handler-down-disabled,.dark .ant-input-number-handler-up-disabled{background-color:rgb(0 0 0 / .1)}.dark .ant-input-number-handler-down-disabled .anticon,.dark .ant-input-number-handler-up-disabled .anticon,.dark .ant-input-number-handler-down:hover.ant-input-number-handler-down-disabled .anticon,.dark .ant-input-number-handler-up:hover.ant-input-number-handler-up-disabled .anticon{color:rgb(255 255 255 / .25)}.dark .ant-input-number-handler-down:active.ant-input-number-handler-down-disabled,.dark .ant-input-number-handler-up:active.ant-input-number-handler-up-disabled{background-color:rgb(0 0 0 / .2)}.ant-menu-dark .ant-menu-inline.ant-menu-sub{background:var(--dark-color-surface-100);box-shadow:none}.dark .ant-layout-sider-trigger{background:var(--dark-color-surface-100);color:rgb(255 255 255 / 65%)}.ant-layout-sider{overflow:auto}.dark .ant-back-top-content{background-color:var(--dark-color-back-top)}.dark .ant-back-top-content:hover{background-color:var(--dark-color-back-top-hover)}.ant-calendar-time .ant-calendar-footer .ant-calendar-time-picker-btn{text-transform:capitalize}.ant-calendar{border-color:#fff0;border-width:0}.ant-calendar-time-picker-select li:focus,li.ant-calendar-time-picker-select-option-selected{color:rgb(0 0 0 / .65);font-weight:400;background-color:#e8f4f2}.dark li.ant-calendar-time-picker-select-option-selected{color:var(--dark-color-text-primary);font-weight:400}.dark .ant-calendar-time-picker-select li:focus{color:#fff;font-weight:400;background-color:var(--color-primary-100)}.ant-calendar-time-picker-select li:hover{background:#f5f5f5}.ant-calendar-date{transition:background .3s ease,color .3s ease}li.ant-calendar-time-picker-select-option-selected{margin-block:2px}.ant-calendar-time-picker-select{padding:4px}.ant-calendar-time-picker-select li{height:28px;line-height:28px;border-radius:4px} \ No newline at end of file +:root{--color-primary-100:#008771;--dark-color-background:#0a1222;--dark-color-surface-100:#151f31;--dark-color-surface-200:#222d42;--dark-color-surface-300:#2c3950;--dark-color-surface-400:rgba(65,85,119,.5);--dark-color-surface-500:#2c3950;--dark-color-surface-600:#313f5a;--dark-color-surface-700:#111929;--dark-color-surface-700-rgb:17,25,41;--dark-color-table-hover:rgba(44,57,80,.2);--dark-color-text-primary:rgba(255,255,255,.75);--dark-color-stroke:#2c3950;--dark-color-btn-danger:#cd3838;--dark-color-btn-danger-border:transparent;--dark-color-btn-danger-hover:#e94b4b;--dark-color-tag-bg:rgba(255,255,255,.05);--dark-color-tag-border:rgba(255,255,255,.15);--dark-color-tag-color:rgba(255,255,255,.75);--dark-color-tag-green-bg:17,36,33;--dark-color-tag-green-border:25,81,65;--dark-color-tag-green-color:#3ad3ba;--dark-color-tag-purple-bg:#201425;--dark-color-tag-purple-border:#5a2969;--dark-color-tag-purple-color:#d988cd;--dark-color-tag-red-bg:#291515;--dark-color-tag-red-border:#5c2626;--dark-color-tag-red-color:#e04141;--dark-color-tag-orange-bg:#312313;--dark-color-tag-orange-border:#593914;--dark-color-tag-orange-color:#ffa031;--dark-color-tag-blue-bg:#111a2c;--dark-color-tag-blue-border:#1348ab;--dark-color-tag-blue-color:#529fff;--dark-color-codemirror-line-hover:rgba(0,135,113,.2);--dark-color-codemirror-line-selection:rgba(0,135,113,.3);--dark-color-login-background:var(--dark-color-background);--dark-color-login-wave:var(--dark-color-surface-200);--dark-color-tooltip:rgba(61,76,104,.9);--dark-color-back-top:rgba(61,76,104,.9);--dark-color-back-top-hover:rgba(61,76,104,1);--dark-color-scrollbar:#313f5a;--dark-color-scrollbar-webkit:#7484a0;--dark-color-scrollbar-webkit-hover:#90a4c7;--dark-color-table-ring:rgb(38 52 77);--dark-color-spin-container:#151f31}html[data-theme-animations='off']{.ant-menu,.ant-layout-sider,.ant-card,.ant-tag,.ant-progress-circle>*,.ant-input,.ant-table-row-expand-icon,.ant-switch,.ant-table-thead>tr>th,.ant-select-selection,.ant-btn,.ant-input-number,.ant-input-group-addon,.ant-checkbox-inner,.ant-progress-bg,.ant-progress-success-bg,.ant-radio-button-wrapper:not(:first-child):before,.ant-radio-button-wrapper,#login,.cm-s-xq.CodeMirror{transition:border 0s,background 0s!important}.ant-menu.ant-menu-inline .ant-menu-item:not(.ant-menu-sub .ant-menu-item),.ant-layout-sider-trigger,.ant-alert-close-icon .anticon-close,.ant-tabs-nav .ant-tabs-tab,.ant-input-number-input,.ant-collapse>.ant-collapse-item>.ant-collapse-header,.Line-Hover,.ant-menu-theme-switch,.ant-menu-submenu-title{transition:color 0s!important}.wave-btn-bg{transition:width 0s!important}}html[data-theme='ultra-dark']{--dark-color-background:#21242a;--dark-color-surface-100:#0c0e12;--dark-color-surface-200:#222327;--dark-color-surface-300:#32353b;--dark-color-surface-400:rgba(255,255,255,.1);--dark-color-surface-500:#3b404b;--dark-color-surface-600:#505663;--dark-color-surface-700:#101113;--dark-color-surface-700-rgb:16,17,19;--dark-color-table-hover:rgba(89,89,89,.15);--dark-color-text-primary:rgb(255 255 255 / 85%);--dark-color-stroke:#202025;--dark-color-tag-green-bg:17,36,33;--dark-color-tag-green-border:29,95,77;--dark-color-tag-green-color:#59cbac;--dark-color-tag-purple-bg:#241121;--dark-color-tag-purple-border:#5a2969;--dark-color-tag-purple-color:#d686ca;--dark-color-tag-red-bg:#2a1215;--dark-color-tag-red-border:#58181c;--dark-color-tag-red-color:#e84749;--dark-color-tag-orange-bg:#2b1d11;--dark-color-tag-orange-border:#593815;--dark-color-tag-orange-color:#e89a3c;--dark-color-tag-blue-bg:#111a2c;--dark-color-tag-blue-border:#0f367e;--dark-color-tag-blue-color:#3c89e8;--dark-color-codemirror-line-hover:rgba(82,84,94,.2);--dark-color-codemirror-line-selection:rgba(82,84,94,.3);--dark-color-login-background:#0a2227;--dark-color-login-wave:#0f2d32;--dark-color-tooltip:rgba(88,93,100,.9);--dark-color-back-top:rgba(88,93,100,.9);--dark-color-back-top-hover:rgba(88,93,100,1);--dark-color-scrollbar:rgb(107,107,107);--dark-color-scrollbar-webkit:#9f9f9f;--dark-color-scrollbar-webkit-hover:#d1d1d1;--dark-color-table-ring:rgb(37 39 42);--dark-color-spin-container:#1d1d1d;.ant-dropdown-menu-dark{background-color:var(--dark-color-surface-500)}.dark .ant-dropdown-menu-submenu-title:hover,.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled){background-color:rgb(0 93 78 / .3)}.dark .waves-header{background-color:#0a2227}.dark .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-decade:hover{background-color:var(--dark-color-surface-600)}}html,body{height:100vh;width:100vw;margin:0;padding:0;overflow:hidden}body{color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;background-color:#fff;font-feature-settings:"tnum"}html{--antd-wave-shadow-color:var(--color-primary-100);line-height:1.15;text-size-adjust:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-moz-tap-highlight-color:#fff0;-webkit-tap-highlight-color:#fff0}@supports (scrollbar-width:auto) and (not selector(::-webkit-scrollbar)){:not(.dark){scrollbar-color:#9a9a9a #fff0;scrollbar-width:thin}.dark *{scrollbar-color:var(--dark-color-scrollbar) #fff0;scrollbar-width:thin}}::-webkit-scrollbar{width:10px;height:10px;background-color:#fff0}::-webkit-scrollbar-track{background-color:#fff0;margin-block:.5em}.ant-modal-wrap::-webkit-scrollbar-track{background-color:#fff;margin-block:0}::-webkit-scrollbar-thumb{border-radius:9999px;background-color:#9a9a9a;border:2px solid #fff0;background-clip:content-box}::-webkit-scrollbar-thumb:hover,::-webkit-scrollbar-thumb:active{background-color:#828282}.dark .ant-modal-wrap::-webkit-scrollbar-track{background-color:var(--dark-color-background)}.dark::-webkit-scrollbar-thumb{background-color:var(--dark-color-scrollbar-webkit)}.dark::-webkit-scrollbar-thumb:hover,.dark::-webkit-scrollbar-thumb:active{background-color:var(--dark-color-scrollbar-webkit-hover)}::-moz-selection{color:var(--color-primary-100);background-color:#cfe8e4}::selection{color:var(--color-primary-100);background-color:#cfe8e4}#app{height:100%;position:fixed;top:0;left:0;right:0;bottom:0;margin:0;padding:0;overflow:auto}.ant-layout,.ant-layout *{box-sizing:border-box}.ant-spin-container:after{border-radius:1.5rem}.dark .ant-spin-container:after{background:var(--dark-color-spin-container)}style attribute{text-align:center}.ant-table-thead>tr>th{padding:12px 8px}.ant-table-tbody>tr>td{padding:10px 8px}.ant-table-thead>tr>th{color:rgb(0 0 0 / .85);font-weight:500;text-align:left;border-bottom:1px solid #e8e8e8;transition:background .3s ease}.ant-table table{border-radius:1rem}.ant-table-bordered .ant-table-tbody:not(.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody)>tr:last-child>td:first-child{border-bottom-left-radius:1rem}.ant-table-bordered .ant-table-tbody:not(.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody)>tr:last-child>td:last-child{border-bottom-right-radius:1rem}.ant-table{box-sizing:border-box;margin:0;padding:0;color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;font-feature-settings:"tnum";position:relative;clear:both}.ant-table .ant-table-body:not(.ant-table-expanded-row .ant-table-body){overflow-x:auto!important}.ant-card-hoverable{cursor:auto;cursor:pointer}.ant-card{box-sizing:border-box;margin:0;padding:0;color:rgb(0 0 0 / .65);font-size:14px;font-variant:tabular-nums;line-height:1.5;list-style:none;position:relative;background-color:#fff;border-radius:2px;transition:all .3s}.ant-space{width:100%}.ant-layout-sider-zero-width-trigger{display:none}@media (max-width:768px){.ant-layout-sider{display:none}.ant-card,.ant-alert-error{margin:.5rem}.ant-tabs{margin:.5rem;padding:.5rem}.ant-modal-body{padding:20px}.ant-form-item-label{line-height:1.5;padding:8px 0 0}:not(.dark)::-webkit-scrollbar{width:8px;height:8px;background-color:#fff0}.dark::-webkit-scrollbar{width:8px;height:8px;background-color:#fff0}}.ant-layout-content{min-height:auto}.ant-card,.ant-tabs{border-radius:1.5rem}.ant-card-hoverable{cursor:auto}.ant-card+.ant-card{margin-top:20px}.drawer-handle{position:absolute;top:72px;width:41px;height:40px;cursor:pointer;z-index:0;text-align:center;line-height:40px;font-size:16px;display:flex;justify-content:center;align-items:center;background-color:#fff;right:-40px;box-shadow:2px 0 8px rgb(0 0 0 / .15);border-radius:0 4px 4px 0}.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{background-color:#006655!important;background-image:linear-gradient(270deg,#fff0 30%,#009980,#fff0 100%);background-repeat:no-repeat;animation:ma-bg-move linear 6.6s infinite;color:#fff;border-radius:.5rem}.ant-layout-sider-collapsed .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{border-radius:0}@-webkit-keyframes ma-bg-move{0%{background-position:-500px 0}100%{background-position:1000px 0}}@keyframes ma-bg-move{0%{background-position:-500px 0}50%{background-position:1000px 0}100%{background-position:1000px 0}}.ant-menu-item-active,.ant-menu-item:hover,.ant-menu-submenu-title:hover,.ant-menu-item:active,.ant-menu-submenu-title:active{color:var(--color-primary-100);background-color:#e8f4f2}.ant-menu-inline .ant-menu-item,.ant-menu-inline .ant-menu-submenu-title{border-radius:.5rem}.ant-menu-inline .ant-menu-item:after,.ant-menu{border-right-width:0}.ant-layout-sider-children,.ant-pagination ul{padding:.5rem}.ant-layout-sider-collapsed .ant-layout-sider-children{padding:.5rem 0}.ant-dropdown-menu,.ant-select-dropdown-menu{padding:.5rem}.ant-dropdown-menu-item,.ant-dropdown-menu-item:hover,.ant-select-dropdown-menu-item,.ant-select-dropdown-menu-item:hover,.ant-select-selection--multiple .ant-select-selection__choice{border-radius:.5rem}.ant-select-dropdown--multiple .ant-select-dropdown-menu .ant-select-dropdown-menu-item,.ant-select-dropdown--single .ant-select-dropdown-menu .ant-select-dropdown-menu-item-selected{margin-block:2px}@media (min-width:769px){.drawer-handle{display:none}.ant-tabs{padding:2rem}}.fade-in-enter,.fade-in-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.fade-in-enter-active,.fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.zoom-in-center-enter-active,.zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.zoom-in-center-enter,.zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.zoom-in-top-enter-active,.zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.zoom-in-top-enter,.zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.zoom-in-bottom-enter-active,.zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.zoom-in-bottom-enter,.zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.zoom-in-left-enter-active,.zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.zoom-in-left-enter,.zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.list-enter-active,.list-leave-active{-webkit-transition:all .3s;transition:all .3s}.list-enter,.list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.ant-tooltip-inner{min-height:0;padding-inline:1rem}.ant-list-item-meta-title{font-size:14px}.ant-progress-inner{background-color:#ebeef5}.deactive-client .ant-collapse-header{color:#ffffff!important;background-color:#ff7f7f}.ant-table-expand-icon-th,.ant-table-row-expand-icon-cell{width:30px;min-width:30px}.ant-tabs{background-color:#fff}.ant-form-item{margin-bottom:0}.ant-setting-textarea{margin-top:1.5rem}.client-table-header{background-color:#f0f2f5}.client-table-odd-row{background-color:#fafafa}.ant-table-pagination.ant-pagination{float:left}.ant-tag{margin-right:0;margin-inline:2px;display:inline-flex;align-items:center;justify-content:space-evenly}.ant-tag:not(.qr-tag){column-gap:4px}#inbound-info-modal .ant-tag{margin-block:2px}.tr-info-table{display:inline-table;margin-block:10px;width:100%}#inbound-info-modal .tr-info-table .ant-tag{margin-block:0;margin-inline:0}.tr-info-row{display:flex;flex-direction:column;row-gap:2px;margin-block:10px}.tr-info-row a{margin-left:6px}.tr-info-row code{padding-inline:8px}.tr-info-tag{max-width:100%;text-wrap:balance;overflow:hidden;overflow-wrap:anywhere}.tr-info-title{display:inline-flex;align-items:center;justify-content:flex-start;column-gap:4px}.ant-tag-blue{background-color:#edf4fa;border-color:#a9c5e7;color:#0e49b5}.ant-tag-green{background-color:#eafff9;border-color:#76ccb4;color:#199270}.ant-tag-purple{background-color:#f2eaf1;border-color:#d5bed2;color:#7a316f}.ant-tag-orange,.ant-alert-warning{background-color:#ffeee1;border-color:#fec093;color:#f37b24}.ant-tag-red,.ant-alert-error{background-color:#ffe9e9;border-color:#ff9e9e;color:#cf3c3c}.ant-input::placeholder{opacity:.5}.ant-input:hover,.ant-input:focus{background-color:#e8f4f2}.ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){background-color:#e8f4f2}.delete-icon:hover{color:#e04141}.normal-icon:hover{color:var(--color-primary-100)}.dark::-moz-selection{color:#fff;background-color:var(--color-primary-100)}.dark::selection{color:#fff;background-color:var(--color-primary-100)}.dark .normal-icon:hover{color:#fff}.dark .ant-layout-sider,.dark .ant-drawer-content,.ant-menu-dark,.ant-menu-dark .ant-menu-sub,.dark .ant-card,.dark .ant-table,.dark .ant-collapse-content,.dark .ant-tabs{background-color:var(--dark-color-surface-100);color:var(--dark-color-text-primary)}.dark .ant-card-hoverable:hover,.dark .ant-space-item>.ant-tabs:hover{box-shadow:0 2px 8px #fff0}.dark>.ant-layout,.dark .drawer-handle,.dark .ant-table-thead>tr>th,.dark .ant-table-expanded-row,.dark .ant-table-expanded-row:hover,.dark .ant-table-expanded-row .ant-table-tbody,.dark .ant-calendar{background-color:var(--dark-color-background);color:var(--dark-color-text-primary)}.dark .ant-table-expanded-row .ant-table-thead>tr:first-child>th{border-radius:0}.dark .ant-calendar,.dark .ant-card-bordered{border-color:var(--dark-color-background)}.dark .ant-table-bordered,.dark .ant-table-bordered.ant-table-empty .ant-table-placeholder,.dark .ant-table-bordered .ant-table-body>table,.dark .ant-table-bordered .ant-table-fixed-left table,.dark .ant-table-bordered .ant-table-fixed-right table,.dark .ant-table-bordered .ant-table-header>table,.dark .ant-table-bordered .ant-table-thead>tr:not(:last-child)>th,.dark .ant-table-bordered .ant-table-tbody>tr>td,.dark .ant-table-bordered .ant-table-thead>tr>th{border-color:var(--dark-color-surface-400)}.dark .ant-table-tbody>tr>td,.dark .ant-table-thead>tr>th,.dark .ant-card-head,.dark .ant-modal-header,.dark .ant-collapse>.ant-collapse-item,.dark .ant-tabs-bar,.dark .ant-list-split .ant-list-item,.dark .ant-popover-title,.dark .ant-calendar-header,.dark .ant-calendar-input-wrap{border-bottom-color:var(--dark-color-surface-400)}.dark .ant-modal-footer,.dark .ant-collapse-content,.dark .ant-calendar-footer,.dark .ant-divider-horizontal.ant-divider-with-text-left:before,.dark .ant-divider-horizontal.ant-divider-with-text-left:after,.dark .ant-divider-horizontal.ant-divider-with-text-center:before,.dark .ant-divider-horizontal.ant-divider-with-text-center:after{border-top-color:var(--dark-color-surface-300)}.ant-divider-horizontal.ant-divider-with-text-left:before{width:10%}.dark .ant-progress-text,.dark .ant-card-head,.dark .ant-form,.dark .ant-collapse>.ant-collapse-item>.ant-collapse-header,.dark .ant-modal-close-x,.dark .ant-form .anticon,.dark .ant-tabs-tab-arrow-show:not(.ant-tabs-tab-btn-disabled),.dark .anticon-close,.dark .ant-list-item-meta-title,.dark .ant-select-selection i,.dark .ant-modal-confirm-title,.dark .ant-modal-confirm-content,.dark .ant-popover-message,.dark .ant-modal,.dark .ant-divider-inner-text,.dark .ant-popover-title,.dark .ant-popover-inner-content,.dark h2,.dark .ant-modal-title,.dark .ant-form-item-label>label,.dark .ant-checkbox-wrapper,.dark .ant-form-item,.dark .ant-calendar-footer .ant-calendar-today-btn,.dark .ant-calendar-footer .ant-calendar-time-picker-btn,.dark .ant-calendar-day-select,.dark .ant-calendar-month-select,.dark .ant-calendar-year-select,.dark .ant-calendar-date,.dark .ant-calendar-year-panel-year,.dark .ant-calendar-month-panel-month,.dark .ant-calendar-decade-panel-decade{color:var(--dark-color-text-primary)}.dark .ant-pagination-options-size-changer .ant-select-arrow .anticon.anticon-down.ant-select-arrow-icon{color:rgb(255 255 255 / 35%)}.dark .ant-pagination-item a,.dark .ant-pagination-next a,.dark .ant-pagination-prev a{color:var(--dark-color-text-primary)}.dark .ant-pagination-item:focus a,.dark .ant-pagination-item:hover a,.dark .ant-pagination-item-active a,.dark .ant-pagination-next:hover .ant-pagination-item-link{color:var(--color-primary-100)}.dark .ant-pagination-item-active{background-color:#fff0}.dark .ant-list-item-meta-description{color:rgb(255 255 255 / .45)}.dark .ant-pagination-disabled i,.dark .ant-tabs-tab-btn-disabled{color:rgb(255 255 255 / .25)}.dark .ant-input,.dark .ant-input-group-addon,.dark .ant-collapse,.dark .ant-select-selection,.dark .ant-input-number,.dark .ant-input-number-handler-wrap,.dark .ant-table-placeholder,.dark .ant-empty-normal,.dark .ant-select-dropdown,.dark .ant-select-dropdown li,.dark .ant-select-dropdown-menu-item,.dark .client-table-header,.dark .ant-select-selection--multiple .ant-select-selection__choice{background-color:var(--dark-color-surface-200);border-color:var(--dark-color-surface-300);color:var(--dark-color-text-primary)}.dark .ant-select-dropdown--multiple .ant-select-dropdown-menu .ant-select-dropdown-menu-item.ant-select-dropdown-menu-item-selected:not(.ant-dropdown-menu-submenu-title:hover){background-color:var(--dark-color-surface-300)}.dark .ant-select-dropdown-menu-item.ant-select-dropdown-menu-item-selected{background-color:var(--dark-color-surface-300)}.dark .ant-calendar-time-picker-inner{background-color:var(--dark-color-background)}.dark .ant-select-selection:hover,.dark .ant-calendar-picker-clear,.dark .ant-input-number:hover,.dark .ant-input-number:focus,.dark .ant-input:hover,.dark .ant-input:focus{background-color:rgb(0 135 113 / .3);border-color:var(--color-primary-100)}.dark .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled){border-color:var(--color-primary-100);background-color:rgb(0 135 113 / .3)}.dark .ant-btn:not(.ant-btn-primary):not(.ant-btn-danger){color:var(--dark-color-text-primary);background-color:rgb(10 117 87 / 30%);border:1px solid var(--color-primary-100)}.dark .ant-radio-button-wrapper,.dark .ant-radio-button-wrapper:before{color:var(--dark-color-text-primary);background-color:rgb(0 135 113 / .3);border-color:var(--color-primary-100)}.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){background-color:#e8f4f2}.dark .ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.dark .ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger){color:#fff;background-color:rgb(10 117 87 / 50%);border-color:var(--color-primary-100)}.dark .ant-btn-primary[disabled],.dark .ant-btn-danger[disabled],.dark .ant-calendar-ok-btn-disabled{color:rgb(255 255 255 / 35%);background-color:var(--dark-color-surface-200);border-color:var(--dark-color-surface-300)}.dark .ant-table-tbody>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.dark .client-table-odd-row{background-color:var(--dark-color-table-hover)}.dark .ant-table-row-expand-icon{color:#fff;background-color:#fff0;border-color:rgb(255 255 255 / 20%)}.dark .ant-table-row-expand-icon:hover{color:var(--color-primary-100);background-color:#fff0;border-color:var(--color-primary-100)}.dark .ant-switch:not(.ant-switch-checked),.dark .ant-progress-line .ant-progress-inner{background-color:var(--dark-color-surface-500)}.dark .ant-progress-circle-trail{stroke:var(--dark-color-stroke)!important}.dark .ant-popover-inner{background-color:var(--dark-color-surface-500)}.dark>.ant-popover-content>.ant-popover-arrow{border-color:var(--dark-color-surface-500)}@media (max-width:768px){.dark .ant-popover-inner{background-color:var(--dark-color-surface-200)}.dark>.ant-popover-content>.ant-popover-arrow{border-color:var(--dark-color-surface-200)}}.ant-dropdown-menu-dark .ant-dropdown-menu-item:hover,.dark .ant-select-dropdown-menu-item-selected,.dark .ant-calendar-time-picker-select-option-selected{background-color:var(--dark-color-surface-600)}.ant-menu-dark .ant-menu-item:hover,.ant-menu-dark .ant-menu-submenu-title:hover{background-color:var(--dark-color-surface-300)}.dark .ant-menu-item:active,.dark .ant-menu-submenu-title:active{color:#fff;background-color:var(--dark-color-surface-300)}.dark .ant-alert-message{color:rgb(255 255 255 / .85)}.dark .ant-tag{color:var(--dark-color-tag-color);background-color:var(--dark-color-tag-bg);border-color:var(--dark-color-tag-border)}.dark .ant-tag-blue{background-color:var(--dark-color-tag-blue-bg);border-color:var(--dark-color-tag-blue-border);color:var(--dark-color-tag-blue-color)}.dark .ant-tag-red,.dark .ant-alert-error{background-color:var(--dark-color-tag-red-bg);border-color:var(--dark-color-tag-red-border);color:var(--dark-color-tag-red-color)}.dark .ant-tag-orange,.dark .ant-alert-warning{background-color:var(--dark-color-tag-orange-bg);border-color:var(--dark-color-tag-orange-border);color:var(--dark-color-tag-orange-color)}.dark .ant-tag-green{background-color:rgb(var(--dark-color-tag-green-bg));border-color:rgb(var(--dark-color-tag-green-border));color:var(--dark-color-tag-green-color)}.dark .ant-tag-purple{background-color:var(--dark-color-tag-purple-bg);border-color:var(--dark-color-tag-purple-border);color:var(--dark-color-tag-purple-color)}.dark .ant-modal-content,.dark .ant-modal-header{background-color:var(--dark-color-surface-700)}.dark .ant-calendar-next-month-btn-day .ant-calendar-date,.dark .ant-calendar-last-month-cell .ant-calendar-date{color:var(--dark-color-surface-300)}.dark .ant-calendar-selected-day .ant-calendar-date{background-color:var(--color-primary-100)!important;color:#fff}.dark .ant-calendar-date:hover,.dark .ant-calendar-time-picker-select li:hover{background-color:var(--dark-color-surface-600);color:#fff}.dark .ant-calendar-header a:hover,.dark .ant-calendar-header a:hover::before,.dark .ant-calendar-header a:hover::after{border-color:#fff}.dark .ant-calendar-time-picker-select{border-right-color:var(--dark-color-surface-300)}.has-warning .ant-select-selection,.has-warning .ant-select-selection:hover,.has-warning .ant-input,.has-warning .ant-input:hover{background-color:#ffeee1;border-color:#fec093}.has-warning .ant-input::placeholder{color:#f37b24}.has-warning .ant-input:not([disabled]):hover{border-color:#fec093}.dark .has-warning .ant-select-selection,.dark .has-warning .ant-select-selection:hover,.dark .has-warning .ant-input,.dark .has-warning .ant-input:hover{border-color:#784e1d;background:#312313}.dark .has-warning .ant-input::placeholder{color:rgb(255 160 49 / 70%)}.dark .has-warning .anticon{color:#ffa031}.dark .has-success .anticon{color:var(--color-primary-100);animation-name:diffZoomIn1!important}.dark .anticon-close-circle{color:#e04141}.dark .ant-spin-nested-loading>div>.ant-spin .ant-spin-text{text-shadow:0 1px 2px #0007}.dark .ant-spin{color:#fff}.dark .ant-spin-dot-item{background-color:#fff}.ant-checkbox-wrapper,.ant-input-group-addon,.ant-tabs-tab,.ant-input::placeholder,.ant-collapse-header,.ant-menu,.ant-radio-button-wrapper{-webkit-user-select:none;user-select:none}.ant-calendar-date,.ant-calendar-year-panel-year,.ant-calendar-decade-panel-decade,.ant-calendar-month-panel-month{border-radius:4px}.ant-checkbox-inner,.ant-checkbox-checked:after,.ant-table-row-expand-icon{border-radius:6px}.ant-calendar-date:hover{background-color:#e8f4f2}.ant-calendar-date:active{background-color:#e8f4f2;color:rgb(0 0 0 / .65)}.ant-calendar-today .ant-calendar-date{color:var(--color-primary-100);font-weight:400;border-color:var(--color-primary-100)}.dark .ant-calendar-today .ant-calendar-date{color:#fff;border-color:var(--color-primary-100)}.ant-calendar-selected-day .ant-calendar-date{background:var(--color-primary-100);color:#fff}li.ant-select-dropdown-menu-item:empty:after{content:"None";font-weight:400;color:rgb(0 0 0 / .25)}.dark li.ant-select-dropdown-menu-item:empty:after{content:"None";font-weight:400;color:rgb(255 255 255 / .3)}.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item:hover .ant-select-selected-icon{color:rgb(0 0 0 / .87)}.dark.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item:hover .ant-select-selected-icon{color:#fff}.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item-selected .ant-select-selected-icon,.ant-select-dropdown.ant-select-dropdown--multiple .ant-select-dropdown-menu-item-selected:hover .ant-select-selected-icon{color:var(--color-primary-100)}.ant-select-selection:hover,.ant-input-number-focused,.ant-input-number:hover{background-color:#e8f4f2}.dark .ant-input-number-handler:active{background-color:var(--color-primary-100)}.dark .ant-input-number-handler:hover .ant-input-number-handler-down-inner,.dark .ant-input-number-handler:hover .ant-input-number-handler-up-inner{color:#fff}.dark .ant-input-number-handler-down{border-top:1px solid rgb(217 217 217 / .3)}.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-century-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-decade-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-month-select,.dark .ant-calendar-year-panel-header .ant-calendar-year-panel-year-select .dark .ant-calendar-month-panel-header .ant-calendar-month-panel-century-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-decade-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-month-select,.dark .ant-calendar-month-panel-header .ant-calendar-month-panel-year-select{color:rgb(255 255 255 / .85)}.dark .ant-calendar-year-panel-header{border-bottom:1px solid var(--dark-color-surface-200)}.dark .ant-calendar-year-panel-last-decade-cell .ant-calendar-year-panel-year,.dark .ant-calendar-year-panel-next-decade-cell .ant-calendar-year-panel-year{color:rgb(255 255 255 / .35)}.dark .ant-divider:not(.ant-divider-with-text-center,.ant-divider-with-text-left,.ant-divider-with-text-right),.ant-dropdown-menu-dark,.dark .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-decade:hover{background-color:var(--dark-color-surface-200)}.dark .ant-calendar-header a:hover{color:#fff}.dark .ant-calendar-month-panel-header{background-color:var(--dark-color-background);border-bottom:1px solid var(--dark-color-surface-200)}.dark .ant-calendar-year-panel,.dark .ant-calendar table{background-color:var(--dark-color-background)}.dark .ant-calendar-year-panel-selected-cell .ant-calendar-year-panel-year,.dark .ant-calendar-year-panel-selected-cell .ant-calendar-year-panel-year:hover,.dark .ant-calendar-month-panel-selected-cell .ant-calendar-month-panel-month,.dark .ant-calendar-month-panel-selected-cell .ant-calendar-month-panel-month:hover,.dark .ant-calendar-decade-panel-selected-cell .ant-calendar-decade-panel-decade,.dark .ant-calendar-decade-panel-selected-cell .ant-calendar-decade-panel-decade:hover{color:#fff;background-color:var(--color-primary-100)!important}.dark .ant-calendar-last-month-cell .ant-calendar-date,.dark .ant-calendar-last-month-cell .ant-calendar-date:hover,.dark .ant-calendar-next-month-btn-day .ant-calendar-date,.dark .ant-calendar-next-month-btn-day .ant-calendar-date:hover{color:rgb(255 255 255 / 25%);background:#fff0;border-color:#fff0}.dark .ant-calendar-today .ant-calendar-date:hover{color:#fff;border-color:var(--color-primary-100);background-color:var(--color-primary-100)}.dark .ant-calendar-decade-panel-last-century-cell .ant-calendar-decade-panel-decade,.dark .ant-calendar-decade-panel-next-century-cell .ant-calendar-decade-panel-decade{color:rgb(255 255 255 / 25%)}.dark .ant-calendar-decade-panel-header{border-bottom:1px solid var(--dark-color-surface-200);background-color:var(--dark-color-background)}.dark .ant-checkbox-inner{background-color:rgb(0 135 113 / .3);border-color:rgb(0 135 113 / .3)}.dark .ant-checkbox-checked .ant-checkbox-inner{background-color:var(--color-primary-100);border-color:var(--color-primary-100)}.dark .ant-calendar-input{background-color:var(--dark-color-background);color:var(--dark-color-text-primary)}.dark .ant-calendar-input::placeholder{color:rgb(255 255 255 / .25)}.ant-input-group.ant-input-group-compact-addon:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact-wrap:not(:first-child):not(:last-child),.ant-input-group.ant-input-group-compact>.ant-input:not(:first-child):not(:last-child),.ant-input-number-handler,.ant-input-number-handler-wrap{border-radius:0}.ant-input-number{overflow:clip}.ant-modal-body,.ant-collapse-content>.ant-collapse-content-box{overflow-x:auto}.ant-modal-body{overflow-y:hidden}.ant-calendar-year-panel-year:hover,.ant-calendar-decade-panel-decade:hover,.ant-calendar-month-panel-month:hover,.ant-dropdown-menu-item:hover,.ant-dropdown-menu-submenu-title:hover,.ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled),.ant-table-tbody>tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-tbody>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-thead>tr.ant-table-row-hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td,.ant-table-thead>tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)>td{background-color:#e8f4f2}.dark .ant-dropdown-menu-submenu-title:hover,.dark .ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled),.dark .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled){background-color:rgb(0 93 78 / .3)}.ant-select-dropdown,.ant-popover-inner{overflow-x:hidden}.ant-popover-inner-content{max-height:450px;overflow-y:auto}@media (max-height:900px){.ant-popover-inner-content{max-height:400px}}@media (max-height:768px){.ant-popover-inner-content{max-height:300px}}@media (max-width:768px){.ant-popover-inner-content{max-height:300px}}.qr-modal{display:flex;align-items:flex-end;gap:10px;flex-direction:column;flex-wrap:wrap;row-gap:24px}.qr-box{width:220px}.qr-cv{width:100%;height:100%}.dark .qr-cv{filter:invert(1)}.qr-bg{background-color:#fff;display:flex;justify-content:center;align-content:center;padding:.8rem;border-radius:1rem;border:solid 1px #e8e8e8;height:220px;width:220px;transition:all .1s}.qr-bg:hover{border-color:#76ccb4;background-color:#eafff9}.qr-bg:hover:active{border-color:#76ccb4;background-color:rgb(197 241 228 / 70%)}.dark .qr-bg{background-color:var(--dark-color-surface-700);border-color:var(--dark-color-surface-300)}.dark .qr-bg:hover{background-color:rgb(var(--dark-color-tag-green-bg));border-color:rgb(var(--dark-color-tag-green-border))}.dark .qr-bg:hover:active{background-color:#17322e}@property --tr-rotate{syntax:'';initial-value:45deg;inherits:false}.qr-bg-sub{background-image:linear-gradient(var(--tr-rotate),#76ccb4,transparent,#d5bed2);display:flex;justify-content:center;align-content:center;padding:1px;border-radius:1rem;height:220px;width:220px}.dark .qr-bg-sub{background-image:linear-gradient(var(--tr-rotate),#195141,transparent,#5a2969)}.qr-bg-sub:hover{animation:tr-rotate-gradient 3.5s linear infinite}@keyframes tr-rotate-gradient{from{--tr-rotate:45deg}to{--tr-rotate:405deg}}.qr-bg-sub-inner{background-color:#fff;padding:.8rem;border-radius:1rem;transition:all .1s}.qr-bg-sub-inner:hover{background-color:rgb(255 255 255 / 60%);backdrop-filter:blur(25px)}.qr-bg-sub-inner:hover:active{background-color:rgb(255 255 255 / 30%)}.dark .qr-bg-sub-inner{background-color:rgb(var(--dark-color-surface-700-rgb))}.dark .qr-bg-sub-inner:hover{background-color:rgba(var(--dark-color-surface-700-rgb),.5);backdrop-filter:blur(25px)}.dark .qr-bg-sub-inner:hover:active{background-color:rgba(var(--dark-color-surface-700-rgb),.2)}.mono-link .ant-input{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important;direction:ltr!important;unicode-bidi:plaintext!important;white-space:nowrap!important;overflow-x:auto!important;text-overflow:clip!important}.mono-link.single-line .ant-input{height:38px}.qr-tag{text-align:center;margin-bottom:10px;width:100%;overflow:hidden;margin-inline:0}@media (min-width:769px){.qr-modal{flex-direction:row;max-width:680px}}.tr-marquee{justify-content:flex-start}.tr-marquee span{padding-right:25%;white-space:nowrap;transform-origin:center}@keyframes move-ltr{0%{transform:translateX(0)}100%{transform:translateX(-100%)}}.ant-input-group-addon:not(:first-child):not(:last-child){border-radius:0 1rem 1rem 0}b,strong{font-weight:500}.ant-collapse>.ant-collapse-item>.ant-collapse-header{padding:10px 16px 10px 40px}.dark .ant-message-notice-content{background-color:var(--dark-color-surface-200);border:1px solid var(--dark-color-surface-300);color:var(--dark-color-text-primary)}.ant-btn-danger{background-color:var(--dark-color-btn-danger);border-color:var(--dark-color-btn-danger-border)}.ant-btn-danger:focus,.ant-btn-danger:hover{background-color:var(--dark-color-btn-danger-hover);border-color:var(--dark-color-btn-danger-hover)}.dark .ant-alert-close-icon .anticon-close:hover{color:#fff}.ant-empty-small{margin:4px 0;background-color:transparent!important}.ant-empty-small .ant-empty-image{height:20px}.ant-menu-theme-switch,.ant-menu-theme-switch:hover{background-color:transparent!important;cursor:default!important}.dark .ant-tooltip-inner,.dark .ant-tooltip-arrow:before{background-color:var(--dark-color-tooltip)}.ant-select-sm .ant-select-selection__rendered{margin-left:10px}.ant-collapse{-moz-animation:collfade .3s ease;-webkit-animation:.3s collfade .3s ease;animation:collfade .3s ease}@-webkit-keyframes collfade{0%{transform:scaleY(.8);transform-origin:0 0%;opacity:0}100%{transform:scaleY(1);transform-origin:0 0%;opacity:1}}@keyframes collfade{0%{transform:scaleY(.8);transform-origin:0 0%;opacity:0}100%{transform:scaleY(1);transform-origin:0 0%;opacity:1}}.ant-table-tbody>tr>td{border-color:#f0f0f0}.ant-table-row-expand-icon{vertical-align:middle;margin-inline-end:8px;position:relative;transform:scale(.9411764705882353)}.ant-table-row-collapsed::before{transform:rotate(-180deg);top:7px;inset-inline-end:3px;inset-inline-start:3px;height:1px;position:absolute;background:currentcolor;transition:transform .3s ease-out;content:""}.ant-table-row-collapsed::after{transform:rotate(0deg);top:3px;bottom:3px;inset-inline-start:7px;width:1px;position:absolute;background:currentcolor;transition:transform .3s ease-out;content:""}.ant-table-row-expanded::before{top:7px;inset-inline-end:3px;inset-inline-start:3px;height:1px;position:absolute;background:currentcolor;transition:transform .3s ease-out;content:""}.ant-table-row-expanded::after{top:3px;bottom:3px;inset-inline-start:7px;width:1px;transform:rotate(90deg);position:absolute;background:currentcolor;transition:transform .3s ease-out;content:""}.ant-menu-theme-switch.ant-menu-item .ant-switch:not(.ant-switch-disabled):active:after,.ant-switch:not(.ant-switch-disabled):active:before{width:16px}.dark .ant-select-disabled .ant-select-selection{background:var(--dark-color-surface-100);border-color:var(--dark-color-surface-200);color:rgb(255 255 255 / .25)}.dark .ant-select-disabled .anticon{color:rgb(255 255 255 / .25)}.dark .ant-input-number-handler-down-disabled,.dark .ant-input-number-handler-up-disabled{background-color:rgb(0 0 0 / .1)}.dark .ant-input-number-handler-down-disabled .anticon,.dark .ant-input-number-handler-up-disabled .anticon,.dark .ant-input-number-handler-down:hover.ant-input-number-handler-down-disabled .anticon,.dark .ant-input-number-handler-up:hover.ant-input-number-handler-up-disabled .anticon{color:rgb(255 255 255 / .25)}.dark .ant-input-number-handler-down:active.ant-input-number-handler-down-disabled,.dark .ant-input-number-handler-up:active.ant-input-number-handler-up-disabled{background-color:rgb(0 0 0 / .2)}.ant-menu-dark .ant-menu-inline.ant-menu-sub{background:var(--dark-color-surface-100);box-shadow:none}.dark .ant-layout-sider-trigger{background:var(--dark-color-surface-100);color:rgb(255 255 255 / 65%)}.ant-layout-sider{overflow:auto}.dark .ant-back-top-content{background-color:var(--dark-color-back-top)}.dark .ant-back-top-content:hover{background-color:var(--dark-color-back-top-hover)}.ant-calendar-time .ant-calendar-footer .ant-calendar-time-picker-btn{text-transform:capitalize}.ant-calendar{border-color:#fff0;border-width:0}.ant-calendar-time-picker-select li:focus,li.ant-calendar-time-picker-select-option-selected{color:rgb(0 0 0 / .65);font-weight:400;background-color:#e8f4f2}.dark li.ant-calendar-time-picker-select-option-selected{color:var(--dark-color-text-primary);font-weight:400}.dark .ant-calendar-time-picker-select li:focus{color:#fff;font-weight:400;background-color:var(--color-primary-100)}.ant-calendar-time-picker-select li:hover{background:#f5f5f5}.ant-calendar-date{transition:background .3s ease,color .3s ease}li.ant-calendar-time-picker-select-option-selected{margin-block:2px}.ant-calendar-time-picker-select{padding:4px}.ant-calendar-time-picker-select li{height:28px;line-height:28px;border-radius:4px}@media (min-width:769px){.ant-layout-content{margin:24px 16px}}.ant-card-dark h2{color:var(--dark-color-text-primary)}.ant-backup-list-item{gap:10px}.ant-version-list-item{--padding:12px;padding:var(--padding)!important;gap:var(--padding)}.dark .ant-version-list-item svg{color:var(--dark-color-text-primary)}.dark .ant-backup-list-item svg,.dark .ant-badge-status-text,.dark .ant-card-extra{color:var(--dark-color-text-primary)}.dark .ant-card-actions>li{color:rgba(255,255,255,.55)}.dark .ant-radio-inner{background-color:var(--dark-color-surface-100);border-color:var(--dark-color-surface-600)}.dark .ant-radio-checked .ant-radio-inner{border-color:var(--color-primary-100)}.dark .ant-backup-list,.dark .ant-version-list,.dark .ant-card-actions,.dark .ant-card-actions>li:not(:last-child){border-color:var(--dark-color-stroke)}.ant-card-actions{background:transparent}.ip-hidden{-webkit-user-select:none;-moz-user-select:none;user-select:none;filter:blur(10px)}.running-animation .ant-badge-status-dot{animation:runningAnimation 1.2s linear infinite}.running-animation .ant-badge-status-processing:after{border-color:var(--color-primary-100)}@keyframes runningAnimation{0%,50%,100%{transform:scale(1);opacity:1}10%{transform:scale(1.5);opacity:.2}}.mb-10{margin-bottom:10px!important}.mb-12{margin-bottom:12px!important}.mt-5{margin-top:5px!important}.mr-8{margin-right:8px!important}.ml-10{margin-left:10px!important}.mr-05{margin-right:.5rem!important}.fs-1rem{font-size:1rem!important}.w-100{width:100%!important}.w-70{width:70px!important}.w-95{width:95px!important}.text-center{text-align:center!important}.cursor-pointer{cursor:pointer!important}.float-right{float:right!important}.va-middle{vertical-align:middle!important}.d-flex{display:flex!important}.justify-end{justify-content:flex-end!important}.log-container{height:auto;max-height:500px;overflow:auto;margin-top:.5rem}.max-w-400{max-width:400px;display:inline-block}.card-placeholder{text-align:center;padding:30px 0;margin-top:10px;background:transparent;border:none}.ant-space.jc-center{justify-content:center}#app.login-app{overflow:hidden;margin:0!important;padding:0!important;min-height:100vh;width:100vw}#app.login-app *{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app.login-app h1{text-align:center;height:110px}#app.login-app .ant-layout-content{margin:0!important;padding:0!important;width:100vw;max-width:100vw}#app.login-app.ant-layout,#app.login-app .ant-layout{margin:0!important;padding:0!important;width:100vw;max-width:100vw}.min-h-0{min-height:0!important}.min-h-100vh{min-height:100vh!important}.h-100{height:100%!important}.h-50px{height:50px!important}.overflow-auto{overflow:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-hidden-auto{overflow:hidden auto!important}.mt-1rem{margin-top:1rem!important}.my-3rem{margin-top:3rem!important;margin-bottom:3rem!important}#app.login-app #login{animation:charge .5s both;background-color:#fff;border-radius:2rem;padding:4rem 3rem;transition:all .3s;user-select:none;-webkit-user-select:none;-moz-user-select:none}#app.login-app #login:hover{box-shadow:0 2px 8px rgba(0,0,0,.09)}@keyframes charge{from{transform:translateY(5rem);opacity:0}to{transform:translateY(0);opacity:1}}#app.login-app .under{background-color:#c7ebe2;z-index:0}#app.login-app.dark .under{background-color:var(--dark-color-login-wave)}#app.login-app.dark #login{background-color:var(--dark-color-surface-100)}#app.login-app.dark h1{color:rgba(255,255,255)}#app.login-app #login .ant-form-item-children .ant-btn,#app.login-app #login .ant-input{height:50px;border-radius:30px}#app.login-app #login .ant-input-group-addon{border-radius:0 30px 30px 0;width:50px;font-size:18px}#app.login-app #login .ant-input-affix-wrapper .ant-input-prefix{left:23px}#app.login-app #login .ant-input-affix-wrapper .ant-input:not(:first-child){padding-left:50px}#app.login-app .centered{display:flex;text-align:center;align-items:center;justify-content:center;width:100%}#app.login-app .title{font-size:2rem;margin-block-end:2rem}#app.login-app .title b{font-weight:bold!important}.ant-btn-primary-login{width:100%}.ant-btn-primary-login:focus,.ant-btn-primary-login:hover{color:#fff;background-color:#006655;border-color:#006655;background-image:linear-gradient(270deg,rgba(123,199,77,0) 30%,#009980,rgba(123,199,77,0) 100%);background-repeat:no-repeat;animation:ma-bg-move ease-in-out 5s infinite;background-position-x:-500px;width:95%;animation-delay:-.5s;box-shadow:0 2px 0 rgba(0,0,0,.045)}.ant-btn-primary-login.active,.ant-btn-primary-login:active{color:#fff;background-color:#006655;border-color:#006655}.wave-btn-bg{position:relative;border-radius:25px;width:100%;transition:all .3s cubic-bezier(.645,.045,.355,1)}.dark .wave-btn-bg{color:#fff;position:relative;background-color:#0a7557;border:2px double transparent;background-origin:border-box;background-clip:padding-box,border-box;background-size:300%;width:100%;z-index:1}.dark .wave-btn-bg:hover{animation:wave-btn-tara 4s ease infinite}.dark .wave-btn-bg-cl{background-image:linear-gradient(rgba(13,14,33,0),rgba(13,14,33,0)),radial-gradient(circle at left top,#006655,#009980,#006655)!important;border-radius:3em}.dark .wave-btn-bg-cl:hover{width:95%}.dark .wave-btn-bg-cl:before{position:absolute;content:"";top:-5px;left:-5px;bottom:-5px;right:-5px;z-index:-1;background:inherit;background-size:inherit;border-radius:4em;opacity:0;transition:.5s}.dark .wave-btn-bg-cl:hover::before{opacity:1;filter:blur(20px);animation:wave-btn-tara 8s linear infinite}@keyframes wave-btn-tara{to{background-position:300%}}.waves-header{position:fixed;top:0;left:0;right:0;width:100%;text-align:center;background-color:#dbf5ed;color:white;z-index:-1}.dark .waves-header{background-color:var(--dark-color-login-background)}.waves-inner-header{height:50vh;width:100%;margin:0;padding:0}.waves{position:relative;width:100%;height:15vh;margin-bottom:-8px;min-height:100px;max-height:150px}.parallax>use{animation:move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite}.dark .parallax>use{fill:var(--dark-color-login-wave)}.parallax>use:nth-child(1){animation-delay:-2s;animation-duration:4s;opacity:.2}.parallax>use:nth-child(2){animation-delay:-3s;animation-duration:7s;opacity:.4}.parallax>use:nth-child(3){animation-delay:-4s;animation-duration:10s;opacity:.6}.parallax>use:nth-child(4){animation-delay:-5s;animation-duration:13s}@keyframes move-forever{0%{transform:translate3d(-90px,0,0)}100%{transform:translate3d(85px,0,0)}}@media (max-width:768px){#app.login-app .waves{height:40px;min-height:40px}}#app.login-app .words-wrapper{width:100%;display:inline-block;position:relative;text-align:center}#app.login-app .words-wrapper b{width:100%;display:inline-block;position:absolute;left:0;top:0}#app.login-app .words-wrapper b.is-visible{position:relative}#app.login-app .headline.zoom .words-wrapper{-webkit-perspective:300px;-moz-perspective:300px;perspective:300px}#app.login-app .headline{display:flex;justify-content:center;align-items:center}#app.login-app .headline.zoom b{opacity:0}#app.login-app .headline.zoom b.is-visible{opacity:1;-webkit-animation:zoom-in .8s;-moz-animation:zoom-in .8s;animation:cubic-bezier(.215,.61,.355,1) zoom-in .8s}#app.login-app .headline.zoom b.is-hidden{-webkit-animation:zoom-out .8s;-moz-animation:zoom-out .8s;animation:cubic-bezier(.215,.61,.355,1) zoom-out .4s}@-webkit-keyframes zoom-in{0%{opacity:0;-webkit-transform:translateZ(100px)}100%{opacity:1;-webkit-transform:translateZ(0)}}@-moz-keyframes zoom-in{0%{opacity:0;-moz-transform:translateZ(100px)}100%{opacity:1;-moz-transform:translateZ(0)}}@keyframes zoom-in{0%{opacity:0;-webkit-transform:translateZ(100px);-moz-transform:translateZ(100px);-ms-transform:translateZ(100px);-o-transform:translateZ(100px);transform:translateZ(100px)}100%{opacity:1;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}}.inbounds-page .ant-table:not(.ant-table-expanded-row .ant-table){outline:1px solid #f0f0f0;outline-offset:-1px;border-radius:1rem;overflow-x:hidden}.inbounds-page.dark .ant-table:not(.ant-table-expanded-row .ant-table){outline-color:var(--dark-color-table-ring)}.inbounds-page .ant-table .ant-table-content .ant-table-scroll .ant-table-body{overflow-y:hidden}.inbounds-page .ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper{margin:-10px 22px!important}.inbounds-page .ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper .ant-table{border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.inbounds-page .ant-table .ant-table-content .ant-table-tbody tr:last-child tr:last-child td{border-bottom-color:transparent}.inbounds-page .ant-table .ant-table-tbody tr:last-child.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody>tr:last-child>td:first-child{border-bottom-left-radius:6px}.inbounds-page .ant-table .ant-table-tbody tr:last-child.ant-table-expanded-row .ant-table-wrapper .ant-table-tbody>tr:last-child>td:last-child{border-bottom-right-radius:6px}@media (max-width:768px){.inbounds-page .ant-card-body{padding:.5rem}.inbounds-page .ant-table .ant-table-content .ant-table-tbody tr:last-child .ant-table-wrapper{margin:-10px 2px!important}}.inbounds-page.dark .ant-switch-small:not(.ant-switch-checked){background-color:var(--dark-color-surface-100)!important}.inbounds-page .ant-custom-popover-title{display:flex;align-items:center;gap:10px;margin:5px 0}.inbounds-page .ant-col-sm-24{margin:.5rem -2rem .5rem 2rem}.inbounds-page tr.hideExpandIcon .ant-table-row-expand-icon{display:none}.inbounds-page .infinite-tag{padding:0 5px;border-radius:2rem;min-width:50px;min-height:22px}.inbounds-page .infinite-bar .ant-progress-inner .ant-progress-bg{background-color:#F2EAF1;border:#D5BED2 solid 1px}.inbounds-page.dark .infinite-bar .ant-progress-inner .ant-progress-bg{background-color:#7a316f!important;border:#7a316f solid 1px}.inbounds-page .ant-collapse{margin:5px 0}.inbounds-page .info-large-tag{max-width:200px;overflow:hidden}.inbounds-page .client-comment{font-size:12px;opacity:.75;cursor:help}.inbounds-page .client-email{font-weight:500}.inbounds-page .client-popup-item{display:flex;align-items:center;gap:5px}.inbounds-page .online-animation .ant-badge-status-dot{animation:onlineAnimation 1.2s linear infinite}@keyframes onlineAnimation{0%,50%,100%{transform:scale(1);opacity:1}10%{transform:scale(1.5);opacity:.2}}.inbounds-page .tr-table-box{display:flex;gap:4px;justify-content:center;align-items:center}.inbounds-page .tr-table-rt{flex-basis:70px;min-width:70px;text-align:end}.inbounds-page .tr-table-lt{flex-basis:70px;min-width:70px;text-align:start}.inbounds-page .tr-table-bar{flex-basis:160px;min-width:60px}.inbounds-page .tr-infinity-ch{font-size:14pt;max-height:24px;display:inline-flex;align-items:center}.inbounds-page .ant-table-expanded-row .ant-table .ant-table-body{overflow-x:hidden}.inbounds-page .ant-table-expanded-row .ant-table-tbody>tr>td{padding:10px 2px}.inbounds-page .ant-table-expanded-row .ant-table-thead>tr>th{padding:12px 2px}@-webkit-keyframes zoom-out{0%{opacity:1;-webkit-transform:translateZ(0)}100%{opacity:0;-webkit-transform:translateZ(-100px)}}@-moz-keyframes zoom-out{0%{opacity:1;-moz-transform:translateZ(0)}100%{opacity:0;-moz-transform:translateZ(-100px)}}@keyframes zoom-out{0%{opacity:1;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}100%{opacity:0;-webkit-transform:translateZ(-100px);-moz-transform:translateZ(-100px);-ms-transform:translateZ(-100px);-o-transform:translateZ(-100px);transform:translateZ(-100px)}}.setting-section{position:absolute;top:0;right:0;padding:22px}.ant-space-item .ant-switch{margin:2px 0 4px}@media (min-width:769px){.settings-page .ant-layout-content{margin:24px 16px}}@media (max-width:768px){.settings-page .ant-tabs-nav .ant-tabs-tab{margin:0;padding:12px .5rem}}.settings-page .ant-tabs-bar{margin:0}.settings-page .ant-list-item{display:block}.settings-page .alert-msg{color:rgb(194,117,18);font-weight:normal;font-size:16px;padding:.5rem 1rem;text-align:center;background:rgb(255 145 0 / 15%);margin:1.5rem 2.5rem 0;border-radius:.5rem;transition:all .5s;animation:settings-signal 3s cubic-bezier(.18,.89,.32,1.28) infinite}.settings-page .alert-msg:hover{cursor:default;transition-duration:.3s;animation:settings-signal .9s ease infinite}@keyframes settings-signal{0%{box-shadow:0 0 0 0 rgba(194,118,18,.5)}50%{box-shadow:0 0 0 6px rgba(0,0,0,0)}100%{box-shadow:0 0 0 6px rgba(0,0,0,0)}}.settings-page .alert-msg>i{color:inherit;font-size:24px}.settings-page.dark .ant-input-password-icon{color:var(--dark-color-text-primary)}.settings-page .ant-collapse-content-box .ant-alert{margin-block-end:12px}@media (min-width:769px){.xray-page .ant-layout-content{margin:24px 16px}}@media (max-width:768px){.xray-page .ant-tabs-nav .ant-tabs-tab{margin:0;padding:12px .5rem}.xray-page .ant-table-thead>tr>th,.xray-page .ant-table-tbody>tr>td{padding:10px 0}}.xray-page .ant-tabs-bar{margin:0}.xray-page .ant-list-item{display:block}.xray-page .ant-list-item>li{padding:10px 20px!important}.xray-page .ant-collapse-content-box .ant-alert{margin-block-end:12px}#app.login-app.dark #login input.ant-input:-webkit-autofill,#app.login-app.dark #login input.ant-input:-webkit-autofill:hover,#app.login-app.dark #login input.ant-input:-webkit-autofill:focus,#app.login-app.dark #login .ant-input-password input:-webkit-autofill,#app.login-app.dark #login .ant-input-password input:-webkit-autofill:hover,#app.login-app.dark #login .ant-input-password input:-webkit-autofill:focus{-webkit-text-fill-color:var(--login-input-color,#d6dce6)!important;caret-color:var(--login-input-color,#d6dce6)!important;-webkit-box-shadow:0 0 0 1000px var(--login-input-bg,#1d2433) inset!important;box-shadow:0 0 0 1000px var(--login-input-bg,#1d2433) inset!important;transition:background-color 9999s ease-in-out 0s!important}#app.login-app.dark #login input.ant-input:-moz-autofill,#app.login-app.dark #login .ant-input-password input:-moz-autofill{-moz-text-fill-color:var(--login-input-color,#d6dce6)!important;caret-color:var(--login-input-color,#d6dce6)!important;box-shadow:0 0 0 1000px var(--login-input-bg,#1d2433) inset!important}#app.login-app.dark #login{--login-input-bg:var(--dark-color-surface-200);--login-input-color:var(--dark-color-text-primary)}.dark .ant-descriptions-bordered .ant-descriptions-view{background-color:transparent}.dark .ant-descriptions-bordered .ant-descriptions-item-label,.dark .ant-descriptions-bordered .ant-descriptions-item-content{background-color:transparent;border-color:var(--dark-color-surface-400)}.dark .ant-descriptions-bordered .ant-descriptions-item-label{color:#a9c2d6}.dark .ant-descriptions-bordered .ant-descriptions-item-content{color:var(--dark-color-text-primary)}.dark .ant-input[readonly],.dark .ant-input-textarea .ant-input[readonly]{background-color:var(--dark-color-surface-200);color:var(--dark-color-text-primary)} \ No newline at end of file diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index e798ddc1..2d5660fb 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -6,7 +6,7 @@ const Protocols = { VLESS: "vless", Trojan: "trojan", Shadowsocks: "shadowsocks", - Mixed: "mixed", + Socks: "socks", HTTP: "http", Wireguard: "wireguard" }; @@ -643,7 +643,7 @@ class Outbound extends CommonClass { Protocols.Trojan, Protocols.Shadowsocks, Protocols.HTTP, - Protocols.Mixed + Protocols.Socks ].includes(this.protocol); } @@ -652,7 +652,7 @@ class Outbound extends CommonClass { } hasServers() { - return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Mixed, Protocols.HTTP].includes(this.protocol); + return [Protocols.Trojan, Protocols.Shadowsocks, Protocols.Socks, Protocols.HTTP].includes(this.protocol); } hasAddressPort() { @@ -662,13 +662,13 @@ class Outbound extends CommonClass { Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks, - Protocols.Mixed, + Protocols.Socks, Protocols.HTTP ].includes(this.protocol); } hasUsername() { - return [Protocols.Mixed, Protocols.HTTP].includes(this.protocol); + return [Protocols.Socks, Protocols.HTTP].includes(this.protocol); } static fromJson(json = {}) { @@ -847,7 +847,7 @@ Outbound.Settings = class extends CommonClass { case Protocols.VLESS: return new Outbound.VLESSSettings(); case Protocols.Trojan: return new Outbound.TrojanSettings(); case Protocols.Shadowsocks: return new Outbound.ShadowsocksSettings(); - case Protocols.Mixed: return new Outbound.MixedSettings(); + case Protocols.Socks: return new Outbound.SocksSettings(); case Protocols.HTTP: return new Outbound.HttpSettings(); case Protocols.Wireguard: return new Outbound.WireguardSettings(); default: return null; @@ -863,7 +863,7 @@ Outbound.Settings = class extends CommonClass { case Protocols.VLESS: return Outbound.VLESSSettings.fromJson(json); case Protocols.Trojan: return Outbound.TrojanSettings.fromJson(json); case Protocols.Shadowsocks: return Outbound.ShadowsocksSettings.fromJson(json); - case Protocols.Mixed: return Outbound.MixedSettings.fromJson(json); + case Protocols.Socks: return Outbound.SocksSettings.fromJson(json); case Protocols.HTTP: return Outbound.HttpSettings.fromJson(json); case Protocols.Wireguard: return Outbound.WireguardSettings.fromJson(json); default: return null; @@ -1141,7 +1141,7 @@ Outbound.ShadowsocksSettings = class extends CommonClass { } }; -Outbound.MixedSettings = class extends CommonClass { +Outbound.SocksSettings = class extends CommonClass { constructor(address, port, user, pass) { super(); this.address = address; @@ -1153,7 +1153,7 @@ Outbound.MixedSettings = class extends CommonClass { static fromJson(json = {}) { let servers = json.servers; if (ObjectUtil.isArrEmpty(servers)) servers = [{ users: [{}] }]; - return new Outbound.MixedSettings( + return new Outbound.SocksSettings( servers[0].address, servers[0].port, ObjectUtil.isArrEmpty(servers[0].users) ? '' : servers[0].users[0].user, diff --git a/web/assets/js/subscription.js b/web/assets/js/subscription.js new file mode 100644 index 00000000..625d55b3 --- /dev/null +++ b/web/assets/js/subscription.js @@ -0,0 +1,125 @@ +(function () { + // Vue app for Subscription page + const el = document.getElementById('subscription-data'); + if (!el) return; + const textarea = document.getElementById('subscription-links'); + const rawLinks = (textarea?.value || '').split('\n').filter(Boolean); + + const data = { + sId: el.getAttribute('data-sid') || '', + subUrl: el.getAttribute('data-sub-url') || '', + subJsonUrl: el.getAttribute('data-subjson-url') || '', + download: el.getAttribute('data-download') || '', + upload: el.getAttribute('data-upload') || '', + used: el.getAttribute('data-used') || '', + total: el.getAttribute('data-total') || '', + remained: el.getAttribute('data-remained') || '', + expireMs: (parseInt(el.getAttribute('data-expire') || '0', 10) || 0) * 1000, + lastOnlineMs: (parseInt(el.getAttribute('data-lastonline') || '0', 10) || 0), + downloadByte: parseInt(el.getAttribute('data-downloadbyte') || '0', 10) || 0, + uploadByte: parseInt(el.getAttribute('data-uploadbyte') || '0', 10) || 0, + totalByte: parseInt(el.getAttribute('data-totalbyte') || '0', 10) || 0, + datepicker: el.getAttribute('data-datepicker') || 'gregorian', + }; + + // Normalize lastOnline to milliseconds if it looks like seconds + if (data.lastOnlineMs && data.lastOnlineMs < 10_000_000_000) { + data.lastOnlineMs *= 1000; + } + + function renderLink(item) { + return ( + Vue.h('a-list-item', {}, [ + Vue.h('a-space', { props: { size: 'small' } }, [ + Vue.h('a-button', { props: { size: 'small' }, on: { click: () => copy(item) } }, [Vue.h('a-icon', { props: { type: 'copy' } })]), + Vue.h('span', { class: 'break-all' }, item) + ]) + ]) + ); + } + + function copy(text) { + ClipboardManager.copyText(text).then(ok => { + const messageType = ok ? 'success' : 'error'; + Vue.prototype.$message[messageType](ok ? 'Copied' : 'Copy failed'); + }); + } + + function open(url) { + window.location.href = url; + } + + function drawQR(value) { + try { new QRious({ element: document.getElementById('qrcode'), value, size: 220 }); } catch (e) { console.warn(e); } + } + + // Try to extract a human label (email/ps) from different link types + function linkName(link, idx) { + try { + if (link.startsWith('vmess://')) { + const json = JSON.parse(atob(link.replace('vmess://', ''))); + if (json.ps) return json.ps; + if (json.add && json.id) return json.add; // fallback host + } else if (link.startsWith('vless://') || link.startsWith('trojan://')) { + // vless://@host:port?...#name + const hashIdx = link.indexOf('#'); + if (hashIdx !== -1) return decodeURIComponent(link.substring(hashIdx + 1)); + // email sometimes in query params like sni or remark + const qIdx = link.indexOf('?'); + if (qIdx !== -1) { + const qs = new URL('http://x/?' + link.substring(qIdx + 1, hashIdx !== -1 ? hashIdx : undefined)).searchParams; + if (qs.get('remark')) return qs.get('remark'); + if (qs.get('email')) return qs.get('email'); + } + // else take user@host + const at = link.indexOf('@'); + const protSep = link.indexOf('://'); + if (at !== -1 && protSep !== -1) return link.substring(protSep + 3, at); + } else if (link.startsWith('ss://')) { + // shadowsocks: label often after # + const hashIdx = link.indexOf('#'); + if (hashIdx !== -1) return decodeURIComponent(link.substring(hashIdx + 1)); + } + } catch (e) { /* ignore and fallback */ } + return 'Link ' + (idx + 1); + } + + const app = new Vue({ + delimiters: ['[[', ']]'], + el: '#app', + data: { + themeSwitcher, + app: data, + links: rawLinks, + lang: '', + viewportWidth: (typeof window !== 'undefined' ? window.innerWidth : 1024), + }, + async mounted() { + this.lang = LanguageManager.getLanguage(); + // Discover subJsonUrl if provided via template bootstrap + const tpl = document.getElementById('subscription-data'); + const sj = tpl ? tpl.getAttribute('data-subjson-url') : ''; + if (sj) this.app.subJsonUrl = sj; + drawQR(this.app.subUrl); + // Draw second QR if available + try { new QRious({ element: document.getElementById('qrcode-subjson'), value: this.app.subJsonUrl || '', size: 220 }); } catch (e) { /* ignore */ } + // Track viewport width for responsive behavior + this._onResize = () => { this.viewportWidth = window.innerWidth; }; + window.addEventListener('resize', this._onResize); + }, + beforeDestroy() { + if (this._onResize) window.removeEventListener('resize', this._onResize); + }, + computed: { + isMobile() { return this.viewportWidth < 576; }, + isUnlimited() { return !this.app.totalByte; }, + isActive() { + const now = Date.now(); + const expiryOk = !this.app.expireMs || this.app.expireMs >= now; + const trafficOk = !this.app.totalByte || (this.app.uploadByte + this.app.downloadByte) <= this.app.totalByte; + return expiryOk && trafficOk; + }, + }, + methods: { renderLink, copy, open, linkName, i18nLabel(key) { return '{{ i18n "' + key + '" }}'; } }, + }); +})(); diff --git a/web/assets/js/util/index.js b/web/assets/js/util/index.js index 4bf760d7..bb47f538 100644 --- a/web/assets/js/util/index.js +++ b/web/assets/js/util/index.js @@ -326,6 +326,14 @@ class ObjectUtil { return false; } } + for (const key in b) { + if (!b.hasOwnProperty(key)) { + continue; + } + if (!a.hasOwnProperty(key)) { + return false; + } + } return true; } } diff --git a/web/controller/inbound.go b/web/controller/inbound.go index 10a58daa..8d610e7d 100644 --- a/web/controller/inbound.go +++ b/web/controller/inbound.go @@ -46,6 +46,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) { g.POST("/onlines", a.onlines) g.POST("/lastOnline", a.lastOnline) g.POST("/updateClientTraffic/:email", a.updateClientTraffic) + g.POST("/:id/delClientByEmail/:email", a.delInboundClientByEmail) } func (a *InboundController) getInbounds(c *gin.Context) { @@ -374,3 +375,23 @@ func (a *InboundController) updateClientTraffic(c *gin.Context) { jsonMsg(c, I18nWeb(c, "pages.inbounds.toasts.inboundClientUpdateSuccess"), nil) } + +func (a *InboundController) delInboundClientByEmail(c *gin.Context) { + inboundId, err := strconv.Atoi(c.Param("id")) + if err != nil { + jsonMsg(c, "Invalid inbound ID", err) + return + } + + email := c.Param("email") + needRestart, err := a.inboundService.DelInboundClientByEmail(inboundId, email) + if err != nil { + jsonMsg(c, "Failed to delete client by email", err) + return + } + + jsonMsg(c, "Client deleted successfully", nil) + if needRestart { + a.xrayService.SetToNeedRestart() + } +} diff --git a/web/html/form/outbound.html b/web/html/form/outbound.html index 271dea83..d2149b6d 100644 --- a/web/html/form/outbound.html +++ b/web/html/form/outbound.html @@ -241,9 +241,9 @@ - + - + - 10 20 @@ -465,11 +394,11 @@ Blocked Proxy - + -
+
- + diff --git a/web/html/login.html b/web/html/login.html index 968aa0bc..b561b732 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -1,456 +1,10 @@ {{ template "page/head_start" .}} - {{ template "page/head_end" .}} {{ template "page/body_start" .}} - + - +
- - + + @@ -482,7 +35,7 @@ {{ i18n "pages.settings.language" }} - @@ -511,26 +64,24 @@ - + - + - + -
+