This commit is contained in:
naiba 2024-10-20 00:09:16 +08:00
parent 6cd243ea40
commit 843ecdaa33
528 changed files with 281 additions and 19449 deletions

View File

@ -1,7 +1,6 @@
package controller
import (
"errors"
"fmt"
"net/http"
"strconv"
@ -11,7 +10,6 @@ import (
"github.com/gorilla/websocket"
"github.com/hashicorp/go-uuid"
"github.com/jinzhu/copier"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/crypto/bcrypt"
"golang.org/x/sync/singleflight"
@ -68,7 +66,7 @@ func (p *commonPage) issueViewPassword(c *gin.Context) {
err := c.ShouldBind(&vpf)
var hash []byte
if err == nil && vpf.Password != singleton.Conf.Site.ViewPassword {
err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
// err = errors.New(singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "WrongAccessPassword"}))
}
if err == nil {
hash, err = bcrypt.GenerateFromPassword([]byte(vpf.Password), bcrypt.DefaultCost)
@ -76,9 +74,9 @@ func (p *commonPage) issueViewPassword(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusOK,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "AnErrorEccurred",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "AnErrorEccurred",
// }),
Msg: err.Error(),
}, true)
c.Abort()
@ -107,7 +105,7 @@ func (p *commonPage) service(c *gin.Context) {
}, nil
})
c.HTML(http.StatusOK, mygin.GetPreferredTheme(c, "/service"), mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
"Services": res.([]interface{})[0],
"CycleTransferStats": res.([]interface{})[1],
}))
@ -255,9 +253,9 @@ func (cp *commonPage) home(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SystemError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "SystemError",
// }),
Msg: "服务器状态获取失败",
Link: "/",
Btn: "返回首页",
@ -284,9 +282,9 @@ func (cp *commonPage) ws(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "NetworkError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "NetworkError",
// }),
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
@ -332,9 +330,9 @@ func (cp *commonPage) terminal(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "NetworkError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "NetworkError",
// }),
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
@ -394,9 +392,9 @@ func (cp *commonPage) createTerminal(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SystemError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "SystemError",
// }),
Msg: "生成会话ID失败",
Link: "/server",
Btn: "返回重试",
@ -462,9 +460,9 @@ func (cp *commonPage) fm(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "NetworkError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "NetworkError",
// }),
Msg: "Websocket协议切换失败",
Link: "/",
Btn: "返回首页",
@ -508,9 +506,9 @@ func (cp *commonPage) createFM(c *gin.Context) {
if err != nil {
mygin.ShowErrorPage(c, mygin.ErrInfo{
Code: http.StatusInternalServerError,
Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SystemError",
}),
// Title: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{
// MessageID: "SystemError",
// }),
Msg: "生成会话ID失败",
Link: "/server",
Btn: "返回重试",

View File

@ -2,20 +2,14 @@ package controller
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"code.cloudfoundry.org/bytefmt"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/hashicorp/go-uuid"
"github.com/nicksnyder/go-i18n/v2/i18n"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
@ -24,11 +18,29 @@ import (
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/pkg/utils"
"github.com/naiba/nezha/proto"
"github.com/naiba/nezha/resource"
"github.com/naiba/nezha/service/rpc"
"github.com/naiba/nezha/service/singleton"
)
// @title Swagger Example API
// @version 1.0
// @description This is a sample server celler server.
// @termsOfService http://swagger.io/terms/
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
// @securityDefinitions.basic BasicAuth
// @externalDocs.description OpenAPI
// @externalDocs.url https://swagger.io/resources/open-api/
func ServeWeb(port uint) *http.Server {
gin.SetMode(gin.ReleaseMode)
r := gin.Default()
@ -39,16 +51,7 @@ func ServeWeb(port uint) *http.Server {
}
r.Use(natGateway)
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
tmpl := template.New("").Funcs(funcMap)
var err error
tmpl, err = tmpl.ParseFS(resource.TemplateFS, "template/**/*.html")
if err != nil {
panic(err)
}
tmpl = loadThirdPartyTemplates(tmpl)
r.SetHTMLTemplate(tmpl)
r.Use(mygin.RecordPath)
r.StaticFS("/static", http.FS(resource.StaticFS))
routers(r)
page404 := func(c *gin.Context) {
mygin.ShowErrorPage(c, mygin.ErrInfo{
@ -71,6 +74,19 @@ func ServeWeb(port uint) *http.Server {
}
func routers(r *gin.Engine) {
authMiddleware, err := jwt.New(initParams())
if err != nil {
log.Fatal("JWT Error:" + err.Error())
}
// register middleware
r.Use(handlerMiddleWare(authMiddleware))
r.POST("/login", authMiddleware.LoginHandler)
auth := r.Group("/auth", authMiddleware.MiddlewareFunc())
auth.GET("/refresh_token", authMiddleware.RefreshHandler)
// 通用页面
cp := commonPage{r: r}
cp.serve()
@ -88,206 +104,6 @@ func routers(r *gin.Engine) {
}
}
func loadThirdPartyTemplates(tmpl *template.Template) *template.Template {
ret := tmpl
themes, err := os.ReadDir("resource/template")
if err != nil {
log.Printf("NEZHA>> Error reading themes folder: %v", err)
return ret
}
for _, theme := range themes {
if !theme.IsDir() {
continue
}
themeDir := theme.Name()
if themeDir == "theme-custom" {
// for backward compatibility
// note: will remove this in future versions
ret = loadTemplates(ret, themeDir)
continue
}
if strings.HasPrefix(themeDir, "dashboard-") {
// load dashboard templates, ignore desc file
ret = loadTemplates(ret, themeDir)
continue
}
if !strings.HasPrefix(themeDir, "theme-") {
log.Printf("NEZHA>> Invalid theme name: %s", themeDir)
continue
}
descPath := filepath.Join("resource", "template", themeDir, "theme.json")
desc, err := os.ReadFile(filepath.Clean(descPath))
if err != nil {
log.Printf("NEZHA>> Error opening %s config: %v", themeDir, err)
continue
}
themeName, err := utils.GjsonGet(desc, "name")
if err != nil {
log.Printf("NEZHA>> Error opening %s config: not a valid description file", theme.Name())
continue
}
// load templates
ret = loadTemplates(ret, themeDir)
themeKey := strings.TrimPrefix(themeDir, "theme-")
model.Themes[themeKey] = themeName.String()
}
return ret
}
func loadTemplates(tmpl *template.Template, themeDir string) *template.Template {
// load templates
templatePath := filepath.Join("resource", "template", themeDir, "*.html")
t, err := tmpl.ParseGlob(templatePath)
if err != nil {
log.Printf("NEZHA>> Error parsing templates %s: %v", themeDir, err)
return tmpl
}
return t
}
var funcMap = template.FuncMap{
"tr": func(id string, dataAndCount ...interface{}) string {
conf := i18n.LocalizeConfig{
MessageID: id,
}
if len(dataAndCount) > 0 {
conf.TemplateData = dataAndCount[0]
}
if len(dataAndCount) > 1 {
conf.PluralCount = dataAndCount[1]
}
return singleton.Localizer.MustLocalize(&conf)
},
"toValMap": func(val interface{}) map[string]interface{} {
return map[string]interface{}{
"Value": val,
}
},
"tf": func(t time.Time) string {
return t.In(singleton.Loc).Format("01/02/2006 15:04:05")
},
"len": func(slice []interface{}) string {
return strconv.Itoa(len(slice))
},
"safe": func(s string) template.HTML {
return template.HTML(s) // #nosec
},
"tag": func(s string) template.HTML {
return template.HTML(`<` + s + `>`) // #nosec
},
"stf": func(s uint64) string {
return time.Unix(int64(s), 0).In(singleton.Loc).Format("01/02/2006 15:04")
},
"sf": func(duration uint64) string {
return time.Duration(time.Duration(duration) * time.Second).String()
},
"sft": func(future time.Time) string {
return time.Until(future).Round(time.Second).String()
},
"bf": func(b uint64) string {
return bytefmt.ByteSize(b)
},
"ts": func(s string) string {
return strings.TrimSpace(s)
},
"float32f": func(f float32) string {
return fmt.Sprintf("%.3f", f)
},
"divU64": func(a, b uint64) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"div": func(a, b int) float32 {
if b == 0 {
if a > 0 {
return 100
}
return 0
}
if a == 0 {
// 这是从未在线的情况
return 0.00001 / float32(b) * 100
}
return float32(a) / float32(b) * 100
},
"addU64": func(a, b uint64) uint64 {
return a + b
},
"add": func(a, b int) int {
return a + b
},
"TransLeftPercent": func(a, b float64) (n float64) {
n, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (100-(a/b)*100)), 64)
if n < 0 {
n = 0
}
return
},
"TransLeft": func(a, b uint64) string {
if a < b {
return "0B"
}
return bytefmt.ByteSize(a - b)
},
"TransClassName": func(a float64) string {
if a == 0 {
return "offline"
}
if a > 50 {
return "fine"
}
if a > 20 {
return "warning"
}
if a > 0 {
return "error"
}
return "offline"
},
"UintToFloat": func(a uint64) (n float64) {
n, _ = strconv.ParseFloat((strconv.FormatUint(a, 10)), 64)
return
},
"dayBefore": func(i int) string {
year, month, day := time.Now().Date()
today := time.Date(year, month, day, 0, 0, 0, 0, singleton.Loc)
return today.AddDate(0, 0, i-29).Format("01/02")
},
"className": func(percent float32) string {
if percent == 0 {
return ""
}
if percent > 95 {
return "good"
}
if percent > 80 {
return "warning"
}
return "danger"
},
"statusName": func(val float32) string {
return singleton.StatusCodeToString(singleton.GetStatusCode(val))
},
}
func natGateway(c *gin.Context) {
natConfig := singleton.GetNATConfigByDomain(c.Request.Host)
if natConfig == nil {

View File

@ -5,7 +5,6 @@ import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
@ -56,7 +55,7 @@ func (gp *guestPage) login(c *gin.Context) {
RegistrationLink = singleton.Conf.Oauth2.OidcRegisterURL
}
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/login", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
"LoginType": LoginType,
"RegistrationLink": RegistrationLink,
}))

View File

@ -0,0 +1,96 @@
package controller
import (
"log"
"time"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin"
"github.com/naiba/nezha/model"
)
func initParams() *jwt.GinJWTMiddleware {
return &jwt.GinJWTMiddleware{
Realm: "test zone",
Key: []byte("secret key"),
Timeout: time.Hour,
MaxRefresh: time.Hour,
IdentityKey: model.CtxKeyAuthorizedUser,
PayloadFunc: payloadFunc(),
IdentityHandler: identityHandler(),
Authenticator: authenticator(),
Authorizator: authorizator(),
Unauthorized: unauthorized(),
TokenLookup: "header: Authorization, query: token, cookie: jwt",
TokenHeadName: "Bearer",
TimeFunc: time.Now,
}
}
func handlerMiddleWare(authMiddleware *jwt.GinJWTMiddleware) gin.HandlerFunc {
return func(context *gin.Context) {
errInit := authMiddleware.MiddlewareInit()
if errInit != nil {
log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
}
}
}
func payloadFunc() func(data interface{}) jwt.MapClaims {
return func(data interface{}) jwt.MapClaims {
if v, ok := data.(*model.User); ok {
return jwt.MapClaims{
model.CtxKeyAuthorizedUser: v.Username,
}
}
return jwt.MapClaims{}
}
}
func identityHandler() func(c *gin.Context) interface{} {
return func(c *gin.Context) interface{} {
claims := jwt.ExtractClaims(c)
return &model.User{
Username: claims[model.CtxKeyAuthorizedUser].(string),
}
}
}
func authenticator() func(c *gin.Context) (interface{}, error) {
return func(c *gin.Context) (interface{}, error) {
var loginVals model.LoginRequest
if err := c.ShouldBind(&loginVals); err != nil {
return "", jwt.ErrMissingLoginValues
}
userID := loginVals.Username
password := loginVals.Password
if (userID == "admin" && password == "admin") || (userID == "test" && password == "test") {
return &model.User{
Username: userID,
}, nil
}
return nil, jwt.ErrFailedAuthentication
}
}
func authorizator() func(data interface{}, c *gin.Context) bool {
return func(data interface{}, c *gin.Context) bool {
if v, ok := data.(*model.User); ok && v.Username == "admin" {
return true
}
return false
}
}
func unauthorized() func(c *gin.Context, code int, message string) {
return func(c *gin.Context, code int, message string) {
c.JSON(code, model.CommonResponse{
Success: false,
Error: model.CommonError{
Code: model.ApiErrorUnauthorized,
},
})
}
}

View File

@ -19,7 +19,6 @@ import (
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/pkg/utils"
"github.com/naiba/nezha/proto"
"github.com/naiba/nezha/resource"
"github.com/naiba/nezha/service/singleton"
)
@ -1050,22 +1049,6 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
return
}
if !utils.IsFileExists("resource/template/theme-"+sf.Theme+"/home.html") && !resource.IsTemplateFileExist("template/theme-"+sf.Theme+"/home.html") {
c.JSON(http.StatusOK, model.Response{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("前台主题文件异常:%s", sf.Theme),
})
return
}
if !utils.IsFileExists("resource/template/dashboard-"+sf.DashboardTheme+"/setting.html") && !resource.IsTemplateFileExist("template/dashboard-"+sf.DashboardTheme+"/setting.html") {
c.JSON(http.StatusOK, model.Response{
Code: http.StatusBadRequest,
Message: fmt.Sprintf("后台主题文件异常:%s", sf.DashboardTheme),
})
return
}
singleton.Conf.Language = sf.Language
singleton.Conf.EnableIPChangeNotification = sf.EnableIPChangeNotification == "on"
singleton.Conf.EnablePlainIPInNotification = sf.EnablePlainIPInNotification == "on"
@ -1093,8 +1076,6 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
})
return
}
// 更新系统语言
singleton.InitLocalizer()
// 更新DNS服务器
singleton.OnNameserverUpdate()
c.JSON(http.StatusOK, model.Response{

View File

@ -7,7 +7,6 @@ import (
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/pkg/mygin"
"github.com/naiba/nezha/service/singleton"
"github.com/nicksnyder/go-i18n/v2/i18n"
)
type memberPage struct {
@ -19,8 +18,8 @@ func (mp *memberPage) serve() {
mr.Use(mygin.Authorize(mygin.AuthorizeOption{
MemberOnly: true,
IsPage: true,
Msg: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "YouAreNotAuthorized"}),
Btn: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
// Msg: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "YouAreNotAuthorized"}),
// Btn: singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Login"}),
Redirect: "/login",
}))
mr.GET("/server", mp.server)
@ -37,7 +36,7 @@ func (mp *memberPage) api(c *gin.Context) {
singleton.ApiLock.RLock()
defer singleton.ApiLock.RUnlock()
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/api", mygin.CommonEnvironment(c, gin.H{
"title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ApiManagement"}),
// "title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ApiManagement"}),
"Tokens": singleton.ApiTokenList,
}))
}
@ -46,14 +45,14 @@ func (mp *memberPage) server(c *gin.Context) {
singleton.SortedServerLock.RLock()
defer singleton.SortedServerLock.RUnlock()
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/server", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServersManagement"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServersManagement"}),
"Servers": singleton.SortedServerList,
}))
}
func (mp *memberPage) monitor(c *gin.Context) {
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/monitor", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
"Monitors": singleton.ServiceSentinelShared.Monitors(),
}))
}
@ -62,7 +61,7 @@ func (mp *memberPage) cron(c *gin.Context) {
var crons []model.Cron
singleton.DB.Find(&crons)
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/cron", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
"Crons": crons,
}))
}
@ -73,7 +72,7 @@ func (mp *memberPage) notification(c *gin.Context) {
var ar []model.AlertRule
singleton.DB.Find(&ar)
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/notification", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Notification"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Notification"}),
"Notifications": nf,
"AlertRules": ar,
}))
@ -83,7 +82,7 @@ func (mp *memberPage) ddns(c *gin.Context) {
var data []model.DDNSProfile
singleton.DB.Find(&data)
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/ddns", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "DDNS"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "DDNS"}),
"DDNS": data,
"ProviderMap": model.ProviderMap,
"ProviderList": model.ProviderList,
@ -94,14 +93,14 @@ func (mp *memberPage) nat(c *gin.Context) {
var data []model.NAT
singleton.DB.Find(&data)
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/nat", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NAT"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NAT"}),
"NAT": data,
}))
}
func (mp *memberPage) setting(c *gin.Context) {
c.HTML(http.StatusOK, "dashboard-"+singleton.Conf.Site.DashboardTheme+"/setting", mygin.CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Settings"}),
"Languages": model.Languages,
"DashboardThemes": model.DashboardThemes,
}))

View File

@ -39,7 +39,6 @@ func init() {
singleton.InitConfigFromPath(dashboardCliParam.ConfigFile)
singleton.InitTimezoneAndCache()
singleton.InitDBFromPath(dashboardCliParam.DatebaseLocation)
singleton.InitLocalizer()
initSystem()
}

43
go.mod
View File

@ -1,12 +1,13 @@
module github.com/naiba/nezha
go 1.21
go 1.21.0
toolchain go1.23.1
require (
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea
github.com/BurntSushi/toml v1.3.2
github.com/appleboy/gin-jwt/v2 v2.10.0
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.9.1
github.com/gin-gonic/gin v1.10.0
github.com/gorilla/websocket v1.5.1
github.com/hashicorp/go-uuid v1.0.3
github.com/jinzhu/copier v0.4.0
@ -15,7 +16,6 @@ require (
github.com/libdns/libdns v0.2.2
github.com/libdns/tencentcloud v1.0.0
github.com/miekg/dns v1.1.62
github.com/nicksnyder/go-i18n/v2 v2.4.0
github.com/ory/graceful v0.1.3
github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.0+incompatible
@ -26,10 +26,9 @@ require (
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.4
github.com/tidwall/gjson v1.18.0
golang.org/x/crypto v0.25.0
golang.org/x/net v0.27.0
golang.org/x/sync v0.7.0
golang.org/x/text v0.16.0
golang.org/x/crypto v0.26.0
golang.org/x/net v0.28.0
golang.org/x/sync v0.8.0
google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.34.2
gorm.io/driver/sqlite v1.5.5
@ -41,10 +40,12 @@ require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/bytedance/sonic v1.12.2 // indirect
github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
@ -52,14 +53,15 @@ require (
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/go-playground/validator/v10 v10.22.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -67,7 +69,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@ -79,13 +81,14 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/arch v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/tools v0.22.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
gopkg.in/ini.v1 v1.67.0 // indirect

100
go.sum
View File

@ -1,19 +1,22 @@
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea h1:1tgMNDgo8PjpsHhlaxdibj28C0WyLeOW2SPJ7GGdc9A=
code.cloudfoundry.org/bytefmt v0.0.0-20240425163905-bcdc1ad063ea/go.mod h1:3+xXJBOD8PsGHDqHedtCLalbaVJ+yi1OW+mXx9IcNxI=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/appleboy/gin-jwt/v2 v2.10.0 h1:vOlGSly8oIGQiT8AcEh1nYMLYI1K9YvsZNVWM612xN0=
github.com/appleboy/gin-jwt/v2 v2.10.0/go.mod h1:DvCh3V1Ma32/7kAsAHYQVyjsQMwG+wMXGpyCYLfHOJU=
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4=
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg=
github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -23,8 +26,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
@ -32,10 +35,8 @@ github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxt
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@ -56,21 +57,19 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
@ -88,8 +87,9 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@ -100,8 +100,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/libdns/cloudflare v0.1.1 h1:FVPfWwP8zZCqj268LZjmkDleXlHPlFU9KC4OJ3yn054=
github.com/libdns/cloudflare v0.1.1/go.mod h1:9VK91idpOjg6v7/WbjkEW49bSCxj00ALesIFDhJ8PBU=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
@ -128,13 +128,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=
github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=
github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc=
github.com/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
@ -142,8 +136,8 @@ github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -180,8 +174,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
@ -204,21 +196,20 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k=
golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@ -229,12 +220,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -242,12 +233,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -256,8 +246,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@ -293,6 +283,6 @@ gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -1,5 +1,9 @@
package model
const (
ApiErrorUnauthorized = 10001
)
type ServiceItemResponse struct {
Monitor *Monitor
CurrentUp uint64
@ -17,3 +21,19 @@ func (r ServiceItemResponse) TotalUptime() float32 {
}
return float32(r.TotalUp) / (float32(r.TotalUp + r.TotalDown)) * 100
}
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type CommonError struct {
Code int `json:"code"`
Args map[string]string `json:"args"`
}
type CommonResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data"`
Error CommonError `json:"error"`
}

View File

@ -5,7 +5,6 @@ import (
"strings"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
@ -41,15 +40,6 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
if ok {
data["Admin"] = u
}
data["LANG"] = map[string]string{
"Add": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Add"}),
"Edit": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Edit"}),
"AlarmRule": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "AlarmRule"}),
"Notification": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "NotificationMethod"}),
"Server": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "Server"}),
"Monitor": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesManagement"}),
"Cron": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ScheduledTasks"}),
}
return data
}

View File

@ -6,7 +6,6 @@ import (
"github.com/gin-gonic/gin"
"github.com/naiba/nezha/model"
"github.com/naiba/nezha/service/singleton"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/crypto/bcrypt"
)
@ -37,7 +36,7 @@ func ValidateViewPassword(opt ValidateViewPasswordOption) gin.HandlerFunc {
}
if opt.IsPage {
c.HTML(http.StatusOK, GetPreferredTheme(c, "/viewpassword"), CommonEnvironment(c, gin.H{
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "VerifyPassword"}),
// "Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "VerifyPassword"}),
}))
} else {

View File

@ -1,752 +0,0 @@
[NezhaMonitoring]
other = "Nezha Monitoring"
[Server]
other = "Servers"
[Services]
other = "Services"
[Task]
other = "Tasks"
[Notification]
other = "Notifications"
[Settings]
other = "Settings"
[Home]
other = "Home"
[BackToHomepage]
other = "Back to Homepage"
[AdminPanel]
other = "Dashboard"
[Logout]
other = "Log out"
[Login]
other = "Log in"
[ConfirmLogout]
other = "Confirm Logging Out?"
[AfterLoggingOutYouHaveToLoginAgain]
other = "You will need to log in again to continue"
[Cancel]
other = "Cancel"
[Confirm]
other = "Confirm"
[AddScheduledTasks]
other = "Add Schedule Task"
[Name]
other = "Name"
[Scheduler]
other = "Cron Expression"
[BackUp]
other = "Backup"
[3amDaily]
other = "(At 3 AM)"
[Command]
other = "Command"
[Coverage]
other = "Coverage"
[IgnoreAllAndExecuteOnlyThroughSpecificServers]
other = "Ignore All, Execute Only on Specific Servers"
[AllIncludedOnlySpecificServersAreNotExecuted]
other = "Cover All, Except Specific Servers"
[ExecuteByTriggerServer]
other = "Execute on Alarmed Servers"
[SpecificServers]
other = "Specific Servers"
[EnterIdAndNameToSearch]
other = "Enter ID/Name to search"
[NotificationMethodGroup]
other = "Notification Method Group"
[PushSuccessMessages]
other = "Send Success Messages"
[TaskType]
other = "Task Type"
[CronTask]
other = "Cron Task"
[TriggerTask]
other = "Trigger Task"
[TheFormaOfTheScheduleIs]
other = "The Cron Expression format is:"
[SecondsMinutesHoursDaysMonthsWeeksSeeDetails]
other = "Sec Min Hour Day Month Week, see details in "
[ScheduleExpressionFormat]
other = "CRON Expression Format"
[IntroductionOfCommands]
other = "Note on writing commands: It is similar to shell/bat scripts. but it's advised not to start a newline, and connect multiple commands with <code>&&</code> or <code>;</code>. If a command cannot be found, it is possibly due to <code>PATH</code> environment variable issues. On <code>Linux</code> servers, you can add <code>source ~/.bashrc</code> at the beginning of the command, or just use the absolute path."
[AddMonitor]
other = "Add Service Monitor"
[Blog]
other = "Blog"
[Target]
other = "Target"
[Type]
other = "Type"
[SslExpirationOrChange]
other = "(Certificate Expiration and Changes)"
[Duration]
other = "Interval"
[Seconds]
other = "Seconds"
[EnableFailureNotification]
other = "Enable Failure Notification"
[FailureNotification]
other = "Failure Notification"
[MaxLatency]
other = "Maximum Latency (ms)"
[MinLatency]
other = "Minimum Latency (ms)"
[EnableLatencyNotification]
other = "Enable Latency Notification"
[LatencyNotification]
other = "Latency Notification"
[IntroductionOfMonitor]
other = """
For type <b>HTTP-GET</b>, enter URL (with http/https scheme, HTTPS protocol will also monitor SSL certificate);<br>
For type <b>ICMP-Ping</b>, enter domain/IP without port: example.com;<br>
For type <b>TCP-Ping</b>, enter domain/IP + port number: example.com:22"""
[AddNotificationMethod]
other = "Add Notification Method"
[Tag]
other = "Notification Group"
[DoNotSendTestMessages]
other = "Do Not Send Test Message"
[RequestMethod]
other = "Request Method"
[RequestType]
other = "Request Type"
[VerifySSL]
other = "Verify SSL"
[AddNotificationRule]
other = "Add Notification Rule"
[Rules]
other = "Rules"
[NotificationTriggerMode]
other = "Notification Trigger Mode"
[ModeAlwaysTrigger]
other = "Always Trigger"
[ModeOnetimeTrigger]
other = "Trigger Once"
[EnableTriggerTask]
other = "Enable Trigger Task"
[FailTriggerTasks]
other = "Tasks to trigger on an alarm"
[RecoverTriggerTasks]
other = "Tasks to trigger after recovery"
[Enable]
other = "Enable"
[AddServer]
other = "Add Server"
[BatchEditServerGroup]
other = "Batch Edit Server Group"
[BatchDeleteServer]
other = "Batch Delete Server"
[InputServerGroupName]
other = "Input Server Group Name"
[ServerGroup]
other = "Server Group"
[EinsteinLightspeed1]
other = "Einstein Lightspeed 1"
[DisplayIndex]
other = "Display Index"
[TheLargerTheNumberTheHigherThePriority]
other = "Greater Number, Higher Priority"
[Secret]
other = "Secret"
[Note]
other = "Note"
[PublicNote]
other = "Public Note"
[LinuxOneKeyInstall]
other = "Linux Installation Command"
[NoDomainAlert]
other = "Please set the IP (or a domain pointed to it) of the original server in settings"
[PushSuccessfully]
other = "Send Success Notification"
[LastExecution]
other = "Last Execution"
[LastResult]
other = "Last Result"
[Administration]
other = "Manage"
[CoverAll]
other = "Cover All"
[IgnoreAll]
other = "Ignore All"
[ByTrigger]
other = "Alarmed Servers"
[DeleteScheduledTask]
other = "Delete Scheduled Task"
[ConfirmToDeleteThisScheduledTask]
other = "Confirm deletion?"
[AccessDenied]
other = "Access Denied"
[Use]
other = "Use"
[AccountToLogin]
other = "Account Login"
[SignUp]
other = "Sign up"
[DontHaveAnAccount]
other = "Don't Have an Account?"
[SSLCertificate]
other = "HTTP(S)/SSL Certificate"
[TCPPort]
other = "TCPing"
[DeleteService]
other = "Remove Service Monitor"
[ConfirmToDeleteThisService]
other = "Confirm Deleting This Service?"
[DeleteNotificationMethod]
other = "Delete Notification Method"
[ConfirmToDeleteThisNotificationMethod]
other = "Confirm Deleting This Notification Method?"
[ForceUpdate]
other = "Trigger Agent Update"
[SelectAll]
other = "Select All"
[VersionNumber]
other = "Version"
[OneKeyInstall]
other = "Installation commands"
[ClickToCopy]
other = "Click To Copy"
[DeleteServer]
other = "Delete Server"
[ConfirmToDeleteServer]
other = "Confirm Deleting This Server?"
[NoServerSelected]
other = "No Server Selected"
[ExecutionResults]
other = "Execute Results"
[SiteTitle]
other = "Site Title"
[AdministratorList]
other = "Administrator List"
[Theme]
other = "Frontend Theme"
[CustomCodes]
other = "Custom Codes (Style and Script)"
[CustomCodesDashboard]
other = "Custom Codes for Dashboard"
[AccessPassword]
other = "Frontend Access Password"
[PanelServerDomainAndIP]
other = "Dashboard Server Domain/IP without CDN"
[IPChangeAlert]
other = "IP Change Notification"
[AllIncludedOnlySpecificServersAreNotAlerted]
other = "Cover All, Only ignore Specific Servers"
[IgnoreAllOnlyAlertSpecificServers]
other = "Ignore All, Cover only Specific Servers"
[IgnoreAllRequestOnlyThroughSpecificServers]
other = "Ignore All, Request Only Through Specific Servers"
[AllIncludedOnlySpecificServersAreNotRequest]
other = "Cover All, Only Specific Servers do not request."
[ServerIDSeparatedByCommas]
other = "Server IDs Separated by Commas"
[IPChangeNotificationTag]
other = "Send Notification To Specific Notification Group"
[NotificationMessagesDoNotHideIP]
other = "Show Full IP Address in Notification Messages"
[Save]
other = "Save"
[ModifiedSuccessfully]
other = "Modified successfully"
[TerminalConnectionTimeOutOrSessionEnded]
other = "Terminal Connection Timeout or Session Ended"
[TerminalConnectionFailed]
other = "The terminal connection failed. Please check the WebSocket reverse proxy configuration for /terminal/*."
[Default]
other = "Default"
[Offline]
other = "Offline"
[Platform]
other = "System"
[DiskUsed]
other = "Disk"
[MemUsed]
other = "RAM"
[CpuUsed]
other = "CPU"
[Virtualization]
other = "Virtualization"
[SwapUsed]
other = "Swap"
[NetTransfer]
other = "Usage"
[Load]
other = "Load"
[ProcessCount]
other = "Process Count"
[ConnCount]
other = "Connection Count"
[BootTime]
other = "Boot Time"
[LastActive]
other = "Last Active"
[Version]
other = "Version"
[NetSpeed]
other = "NIC"
[Uptime]
other = "Uptime"
[ServerIsOffline]
other = "Server is Offline"
[Day]
other = "Days"
[RealtimeChannelEstablished]
other = "Realtime Channel Established"
[GetTheLatestMonitoringDataInRealTime]
other = "You Can Get the Latest Monitoring Data in Real Time!"
[RealtimeChannelDisconnect]
other = "Realtime Channel Disconnect"
[CanNotGetTheLatestMonitoringDataInRealTime]
other = "Cannot Get the Latest Monitoring Data in Real Time!"
[30DaysOnline]
other = "30-Day Availability"
[Details]
other = "Details"
[Status]
other = "Status"
[Availability]
other = "Availability"
[AverageLatency]
other = "Average Latency"
[CycleTransferStats]
other = "Periodic Transfer Stats"
[From]
other = "From"
[To]
other = "To"
[NextCheck]
other = "Next check"
[CurrentUsage]
other = "Current Usage"
[VerifyPassword]
other = "Please enter your password"
[LightMode]
other = "Light Mode"
[DarkMode]
other = "Dark Mode"
[FollowSystem]
other = "System Auto"
[GridLayout]
other = "Grid Layout"
[ListLayout]
other = "List Layout"
[EnterPassword]
other = "Enter Password"
[Location]
other = "Location"
[Running]
other = "Running"
[UpNetTransfer]
other = "Outbound"
[DownNetTransfer]
other = "Inbound"
[TotalUpNetTransfer]
other = "Total Outbound"
[TotalDownNetTransfer]
other = "Total Inbound"
[WrongPassword]
other = "Incorrect Password"
[AnErrorEccurred]
other = "An Error Occurred"
[SystemError]
other = "System Error"
[NetworkError]
other = "Network Error"
[ServicesStatus]
other = "Services Status"
[ServersManagement]
other = "Servers"
[ServicesManagement]
other = "Services"
[ScheduledTasks]
other = "Scheduled Tasks"
[ApiManagement]
other = "API Management"
[IssueNewApiToken]
other = "Generate New API Token"
[Token]
other = "Token"
[DeleteToken]
other = "Delete Token"
[ConfirmToDeleteThisToken]
other = "Confirm Deleting This Token?"
[YouAreNotAuthorized]
other = "This Page needs Authorization"
[WrongAccessPassword]
other = "Wrong Access Password"
[Add]
other = "Add"
[Edit]
other = "Edit"
[AlarmRule]
other = "Alarm Rule"
[NotificationMethod]
other = "Notification Method"
[Incident]
other = "Incident"
[Resolved]
other = "Resolved"
[StatusDown]
other = "Down"
[StatusNoData]
other = "No Data"
[StatusGood]
other = "Good"
[StatusLowAvailability]
other = "Low Availability"
[ScheduledTaskExecutedSuccessfully]
other = "Scheduled Task Executed Successfully"
[ScheduledTaskExecutedFailed]
other = "Scheduled Task Execution Failed"
[IPChanged]
other = "IP Changed"
[Transleft]
other = "Remaining Data"
[DashboardTheme]
other = "Dashboard Theme"
[Info]
other = "Info"
[HideForGuest]
other = "Hide from Guest"
[Menu]
other = "Menu"
[NetworkSpiter]
other = "Network"
[EnableShowInService]
other = "Enable Show in Service"
[DDNS]
other = "Dynamic DNS"
[DDNSProfiles]
other = "DDNS Profiles"
[AddDDNSProfile]
other = "New Profile"
[EnableDDNS]
other = "Enable DDNS"
[EnableIPv4]
other = "IPv4 Enabled"
[EnableIPv6]
other = "IPv6 Enabled"
[DDNSDomain]
other = "Domains"
[DDNSDomains]
other = "Domains (separate with comma)"
[DDNSProvider]
other = "DDNS Provider"
[MaxRetries]
other = "Maximum retry attempts"
[DDNSAccessID]
other = "Credential 1"
[DDNSAccessSecret]
other = "Credential 2"
[DDNSTokenID]
other = "Token ID"
[DDNSTokenSecret]
other = "Token Secret"
[WebhookURL]
other = "Webhook URL"
[WebhookMethod]
other = "Webhook Request Method"
[WebhookRequestType]
other = "Webhook Request Type"
[WebhookHeaders]
other = "Webhook Request Headers"
[WebhookRequestBody]
other = "Webhook Request Body"
[Feature]
other = "Feature"
[Template]
other = "Template"
[Stat]
other = "Asset"
[Temperature]
other = "Temperature"
[DisableSwitchTemplateInFrontend]
other = "Disable Switch Template in Frontend"
[ServersOnWorldMap]
other = "Servers On World Map"
[NAT]
other = "NAT Traversal"
[LocalService]
other = "Local service"
[LocalServicePlaceholder]
other = "192.168.1.1:80 (with port)"
[BindHostname]
other = "Bind hostname"
[NetworkSpiterList]
other = "Network Monitor"
[Refresh]
other = "Refresh"
[CopyPath]
other = "Copy Path"
[Goto]
other = "Go to"
[GotoHeadline]
other = "Go to a Folder"
[GotoGo]
other = "Go"
[GotoClose]
other = "Cancel"
[FMError]
other = "Agent returned an error, please view the console for details. To open a new connection, reopen the FM again."
[Remaining]
other = "Remaining"
[Lifetime]
other = "Lifetime"
[Price]
other = "Price"
[Expired]
other = "Expired"
[Days]
other = "d"
[CustomNameservers]
other = "Custom Public DNS Nameservers for DDNS (separate with comma)"

View File

@ -1,752 +0,0 @@
[NezhaMonitoring]
other = "Nezha Monitoring"
[Server]
other = "Servidores"
[Services]
other = "Servicios"
[Task]
other = "Tareas"
[Notification]
other = "Notificaciones"
[Settings]
other = "Configuraciones"
[Home]
other = "Inicio"
[BackToHomepage]
other = "Volver al Inicio"
[AdminPanel]
other = "Panel de Administración"
[Logout]
other = "Cerrar Sesión"
[Login]
other = "Iniciar Sesión"
[ConfirmLogout]
other = "¿Confirmar Cierre de Sesión?"
[AfterLoggingOutYouHaveToLoginAgain]
other = "Después de cerrar sesión, debe iniciar sesión nuevamente para continuar"
[Cancel]
other = "Cancelar"
[Confirm]
other = "Confirmar"
[AddScheduledTasks]
other = "Agregar Tareas Programadas"
[Name]
other = "Nombre"
[Scheduler]
other = "Plan"
[BackUp]
other = "Respaldo"
[3amDaily]
other = "(Diariamente a las 3 a.m.)"
[Command]
other = "Comandos"
[Coverage]
other = "Cobertura"
[IgnoreAllAndExecuteOnlyThroughSpecificServers]
other = "Ignorar todo, ejecutar solo a través de servidores específicos"
[AllIncludedOnlySpecificServersAreNotExecuted]
other = "Incluir todo, excepto servidores específicos"
[ExecuteByTriggerServer]
other = "Ejecutar en servidores con alarma"
[SpecificServers]
other = "Servidores Específicos"
[EnterIdAndNameToSearch]
other = "Ingrese ID/Nombre para buscar"
[NotificationMethodGroup]
other = "Grupo de Métodos de Notificación"
[PushSuccessMessages]
other = "Enviar el mensaje de éxito"
[TaskType]
other = "Tipo de Tarea"
[CronTask]
other = "Tarea Cron"
[TriggerTask]
other = "Tarea Disparadora"
[TheFormaOfTheScheduleIs]
other = "El formato del plan es:"
[SecondsMinutesHoursDaysMonthsWeeksSeeDetails]
other = "Segundos, Minutos, Horas, Días, Meses, Semanas - Ver detalles a"
[ScheduleExpressionFormat]
other = "Formato de Expresión de Cron"
[IntroductionOfCommands]
other = "Introducción de Comandos: Escriba comandos como en scripts shell/bat. Evite saltos de línea; conecte múltiples comandos con <code>&&</code> o <code>;</code>. Si no se encuentra un comando, verifique la variable de entorno <code>PATH</code>. En servidores <code>Linux</code>, antepóngale <code>source ~/.bashrc</code> a los comandos, o use rutas absolutas."
[AddMonitor]
other = "Agregar Monitor de Servicio"
[Blog]
other = "Blog"
[Target]
other = "Objetivo"
[Type]
other = "Tipo"
[SslExpirationOrChange]
other = "(Expiración o Cambio de SSL)"
[Duration]
other = "Intervalo de Solicitud"
[Seconds]
other = "Segundos"
[EnableFailureNotification]
other = "Habilitar Notificación de Fallo"
[FailureNotification]
other = "Notificación de Fallo"
[MaxLatency]
other = "Máxima Latencia (ms)"
[MinLatency]
other = "Mínima Latencia (ms)"
[EnableLatencyNotification]
other = "Habilitar Notificación de Latencia"
[LatencyNotification]
other = "Notificación de Latencia"
[IntroductionOfMonitor]
other = """
Para tipo <b>HTTP-GET</b>, ingrese URL (http/https, HTTPS también monitorea el certificado SSL);<br>
Para tipo <b>ICMP-Ping</b>, ingrese dominio/IP sin puerto;<br>
Para tipo <b>TCP-Ping</b>, ingrese dominio/IP + puerto: ejemplo.com:22"""
[AddNotificationMethod]
other = "Agregar Método de Notificación"
[Tag]
other = "Grupo de servidores"
[DoNotSendTestMessages]
other = "No Enviar Mensajes de Prueba"
[RequestMethod]
other = "Método de Solicitud"
[RequestType]
other = "Tipo de Solicitud"
[VerifySSL]
other = "Validar SSL"
[AddNotificationRule]
other = "Agregar Regla de Notificación"
[Rules]
other = "Reglas"
[NotificationTriggerMode]
other = "Modo de Disparo de Notificación"
[ModeAlwaysTrigger]
other = "Siempre Activar"
[ModeOnetimeTrigger]
other = "Activación Única"
[EnableTriggerTask]
other = "Habilitar Tarea Disparadora"
[FailTriggerTasks]
other = "Tareas Disparadas por Fallo"
[RecoverTriggerTasks]
other = "Tareas Disparadas por Recuperación"
[Enable]
other = "Habilitar"
[AddServer]
other = "Agregar Servidor"
[BatchEditServerGroup]
other = "Editar Grupo de Servidores en Lote"
[BatchDeleteServer]
other = "Eliminar Servidores en Lote"
[InputServerGroupName]
other = "Ingrese Nombre del Grupo de Servidores"
[ServerGroup]
other = "Grupos de Servidores"
[EinsteinLightspeed1]
other = "Einstein - Velocidad de luz 1"
[DisplayIndex]
other = "Índice de Visualización"
[TheLargerTheNumberTheHigherThePriority]
other = "A mayor número, mayor prioridad"
[Secret]
other = "Secreto"
[Note]
other = "Nota"
[PublicNote]
other = "Nota Pública"
[LinuxOneKeyInstall]
other = "Instalación Linux con Un Solo Clic"
[NoDomainAlert]
other = "Por favor, configure el dominio o IP del servidor del panel que no está conectado a la CDN en la página de configuración"
[PushSuccessfully]
other = "Envío Exitoso"
[LastExecution]
other = "Última Ejecución en"
[LastResult]
other = "Último Resultado"
[Administration]
other = "Administración"
[CoverAll]
other = "Cubrir Todo"
[IgnoreAll]
other = "Ignorar Todo"
[ByTrigger]
other = "Servidores con alarma"
[DeleteScheduledTask]
other = "Eliminar Tarea Programada"
[ConfirmToDeleteThisScheduledTask]
other = "¿Confirmar para eliminar esta Tarea Programada?"
[AccessDenied]
other = "Acceso Denegado"
[Use]
other = "Usar"
[AccountToLogin]
other = "Iniciar Sesión con Cuenta"
[SignUp]
other = "Registrarse"
[DontHaveAnAccount]
other = "¿No tiene una cuenta?"
[SSLCertificate]
other = "Certificados HTTP(S)/SSL"
[TCPPort]
other = "TCPing"
[DeleteService]
other = "Eliminar Servicio"
[ConfirmToDeleteThisService]
other = "¿Confirmar para eliminar este Servicio?"
[DeleteNotificationMethod]
other = "Eliminar Método de Notificación"
[ConfirmToDeleteThisNotificationMethod]
other = "¿Confirmar para eliminar este Método de Notificación?"
[ForceUpdate]
other = "Actualizar Ahora"
[SelectAll]
other = "Seleccionar Todo"
[VersionNumber]
other = "Número de Versión"
[OneKeyInstall]
other = "Instalación con Un Solo Clic"
[ClickToCopy]
other = "Hacer Clic para Copiar"
[DeleteServer]
other = "Eliminar Servidor"
[ConfirmToDeleteServer]
other = "¿Confirmar para eliminar este Servidor?"
[NoServerSelected]
other = "No hay Servidores Seleccionados"
[ExecutionResults]
other = "Resultados de Ejecución"
[SiteTitle]
other = "Título del Sitio"
[AdministratorList]
other = "Lista de Administradores"
[Theme]
other = "Tema de Frontend"
[CustomCodes]
other = "Códigos Personalizados (Incluye style y script)"
[CustomCodesDashboard]
other = "Custom Codes for Dashboard"
[AccessPassword]
other = "Contraseña de Acceso al Frontend"
[PanelServerDomainAndIP]
other = "Dominio/IP del Servidor del Panel sin CDN"
[IPChangeAlert]
other = "Notificación de Cambio de IP"
[AllIncludedOnlySpecificServersAreNotAlerted]
other = "Incluir Todo, Excepto Servidores Específicos"
[IgnoreAllOnlyAlertSpecificServers]
other = "Ignorar Todo, Alertar Solo Servidores Específicos"
[IgnoreAllRequestOnlyThroughSpecificServers]
other = "Ignorar Todo, Solicitar Solo a Través de Servidores Específicos"
[AllIncludedOnlySpecificServersAreNotRequest]
other = "Incluir Todo, Solo Los Servidores Específicos No Solicitan"
[ServerIDSeparatedByCommas]
other = "IDs de Servidores Separados por Comas"
[IPChangeNotificationTag]
other = "Enviar Alerta a Grupo de Notificación Específico"
[NotificationMessagesDoNotHideIP]
other = "Mostrar Dirección IP Completa en Mensajes de Notificación"
[Save]
other = "Guardar"
[ModifiedSuccessfully]
other = "Modificado con Éxito"
[TerminalConnectionTimeOutOrSessionEnded]
other = "Tiempo de Conexión del Terminal Agotado o Sesión Finalizada"
[TerminalConnectionFailed]
other = "Fallo en la Conexión del Terminal, Verifique la Configuración de Proxy Inverso de WebSocket en /terminal/*"
[Default]
other = "Predeterminado"
[Offline]
other = "Desconectado"
[Platform]
other = "Sistema"
[DiskUsed]
other = "Disco"
[MemUsed]
other = "Memoria"
[CpuUsed]
other = "CPU"
[Virtualization]
other = "Virtualización"
[SwapUsed]
other = "Swap"
[NetTransfer]
other = "Transferencia de Red"
[Load]
other = "Carga"
[ProcessCount]
other = "Cantidad de Procesos"
[ConnCount]
other = "Cantidad de Conexiones"
[BootTime]
other = "Tiempo de Arranque"
[LastActive]
other = "Última Actividad"
[Version]
other = "Versión"
[NetSpeed]
other = "Red"
[Uptime]
other = "Uptime"
[ServerIsOffline]
other = "El Servidor está Desconectado"
[Day]
other = "Días"
[RealtimeChannelEstablished]
other = "Canal en Tiempo Real Establecido"
[GetTheLatestMonitoringDataInRealTime]
other = "¡Ahora Puede Obtener los Últimos Datos de Monitoreo en Tiempo Real!"
[RealtimeChannelDisconnect]
other = "Canal en Tiempo Real Desconectado"
[CanNotGetTheLatestMonitoringDataInRealTime]
other = "¡No se Pueden Obtener los Últimos Datos de Monitoreo en Tiempo Real!"
[30DaysOnline]
other = "Disponibilidad de 30 Días"
[Details]
other = "Detalles"
[Status]
other = "Estado"
[Availability]
other = "Disponibilidad"
[AverageLatency]
other = "Latencia Promedio"
[CycleTransferStats]
other = "Estadísticas de Transferencia Periódica"
[From]
other = "Desde"
[To]
other = "Hasta"
[NextCheck]
other = "Próxima Verificación"
[CurrentUsage]
other = "Uso Actual"
[VerifyPassword]
other = "Verificar Contraseña"
[LightMode]
other = "Modo Claro"
[DarkMode]
other = "Modo Oscuro"
[FollowSystem]
other = "Seguir al Sistema"
[GridLayout]
other = "Diseño de Cuadrícula"
[ListLayout]
other = "Diseño de Lista"
[EnterPassword]
other = "Ingrese Contraseña"
[Location]
other = "Ubicación"
[Running]
other = "En Funcionamiento"
[UpNetTransfer]
other = "Red Ascendente"
[DownNetTransfer]
other = "Red Descendente"
[TotalUpNetTransfer]
other = "Total Ascendente"
[TotalDownNetTransfer]
other = "Total Descendente"
[WrongPassword]
other = "Contraseña Incorrecta"
[AnErrorEccurred]
other = "Ocurrió un Error"
[SystemError]
other = "Error del Sistema"
[NetworkError]
other = "Error de Red"
[ServicesStatus]
other = "Estado de los Servicios"
[ServersManagement]
other = "Gestión de Servidores"
[ServicesManagement]
other = "Gestión de Servicios"
[ScheduledTasks]
other = "Tareas Programadas"
[ApiManagement]
other = "Gestión de API"
[IssueNewApiToken]
other = "Emitir Nuevo Token"
[Token]
other = "Token"
[DeleteToken]
other = "Eliminar Token"
[ConfirmToDeleteThisToken]
other = "¿Confirmar para Eliminar este Token?"
[YouAreNotAuthorized]
other = "No Autorizado para esta Página"
[WrongAccessPassword]
other = "Contraseña de Acceso Incorrecta"
[Add]
other = "Agregar"
[Edit]
other = "Editar"
[AlarmRule]
other = "Reglas de Alarma"
[NotificationMethod]
other = "Método de notificación"
[Incident]
other = "Incidente"
[Resolved]
other = "Resuelto"
[StatusDown]
other = "Caído"
[StatusNoData]
other = "Sin Datos"
[StatusGood]
other = "Bueno"
[StatusLowAvailability]
other = "Baja Disponibilidad"
[ScheduledTaskExecutedSuccessfully]
other = "Tarea Programada Ejecutada con Éxito"
[ScheduledTaskExecutedFailed]
other = "Fallo en la Ejecución de la Tarea Programada"
[IPChanged]
other = "Cambio de IP"
[Transleft]
other = "Transferencia Restante"
[DashboardTheme]
other = "Tema del Panel de Administración"
[Info]
other = "Información"
[HideForGuest]
other = "Ocultar para Invitados"
[Menu]
other = "Menú"
[NetworkSpiter]
other = "Red"
[EnableShowInService]
other = "Mostrar en servicio"
[DDNS]
other = "DNS Dinámico"
[DDNSProfiles]
other = "Perfiles DDNS"
[AddDDNSProfile]
other = "Nuevo Perfil"
[EnableDDNS]
other = "Habilitar DDNS"
[EnableIPv4]
other = "IPv4 Activado"
[EnableIPv6]
other = "IPv6 Activado"
[DDNSDomain]
other = "Dominios"
[DDNSDomains]
other = "Dominios (separados por comas)"
[DDNSProvider]
other = "Proveedor DDNS"
[MaxRetries]
other = "Número máximo de intentos de reintento"
[DDNSAccessID]
other = "Credencial 1"
[DDNSAccessSecret]
other = "Credencial 2"
[DDNSTokenID]
other = "ID del Token"
[DDNSTokenSecret]
other = "Secreto del Token"
[WebhookURL]
other = "URL del Webhook"
[WebhookMethod]
other = "Método de Solicitud del Webhook"
[WebhookRequestType]
other = "Tipo de solicitud del Webhook"
[WebhookHeaders]
other = "Encabezados de Solicitud del Webhook"
[WebhookRequestBody]
other = "Cuerpo de Solicitud del Webhook"
[Feature]
other = "Característica"
[Template]
other = "Plantilla"
[Stat]
other = "Stat"
[Temperature]
other = "Temperatura"
[DisableSwitchTemplateInFrontend]
other = "Deshabilitar Cambio de Plantilla en Frontend"
[ServersOnWorldMap]
other = "Servidores en el mapa mundial"
[NAT]
other = "NAT traversal"
[LocalService]
other = "Servicio de red local"
[LocalServicePlaceholder]
other = "192.168.1.1:80 (con puerto)"
[BindHostname]
other = "Vincular nombre de host"
[NetworkSpiterList]
other = "Monitor de red"
[Refresh]
other = "Actualizar"
[CopyPath]
other = "Copiar ruta"
[Goto]
other = "Ir a"
[GotoHeadline]
other = "Ir a una carpeta"
[GotoGo]
other = "Ir"
[GotoClose]
other = "Cancelar"
[FMError]
other = "Agent devolvió un error, consulte la consola para obtener más detalles. Para abrir una nueva conexión, vuelva a abrir el FM."
[Remaining]
other = "Remaining"
[Lifetime]
other = "Lifetime"
[Price]
other = "Price"
[Expired]
other = "Expired"
[Days]
other = "d"
[CustomNameservers]
other = "Servidores DNS públicos personalizados para DDNS (separar con coma)"

View File

@ -1,752 +0,0 @@
[NezhaMonitoring]
other = "哪吒监控"
[Server]
other = "服务器"
[Services]
other = "服务"
[Task]
other = "任务"
[Notification]
other = "告警"
[Settings]
other = "设置"
[Home]
other = "首页"
[BackToHomepage]
other = "返回前台"
[AdminPanel]
other = "管理后台"
[Logout]
other = "注销登录"
[Login]
other = "登录"
[ConfirmLogout]
other = "确定要注销吗?"
[AfterLoggingOutYouHaveToLoginAgain]
other = "注销后需重新登录以继续使用"
[Cancel]
other = "取消"
[Confirm]
other = "确认"
[AddScheduledTasks]
other = "新增计划任务"
[Name]
other = "名称"
[Scheduler]
other = "计划"
[BackUp]
other = "备份"
[3amDaily]
other = "(每天3点)"
[Command]
other = "命令"
[Coverage]
other = "覆盖范围"
[IgnoreAllAndExecuteOnlyThroughSpecificServers]
other = "忽略所有,仅通过特定服务器执行"
[AllIncludedOnlySpecificServersAreNotExecuted]
other = "覆盖所有,仅特定服务器不执行"
[ExecuteByTriggerServer]
other = "由触发告警的服务器执行"
[SpecificServers]
other = "特定服务器"
[EnterIdAndNameToSearch]
other = "输入ID/名称以搜索"
[NotificationMethodGroup]
other = "通知方式组"
[PushSuccessMessages]
other = "推送成功的消息"
[TaskType]
other = "任务类型"
[CronTask]
other = "计划任务"
[TriggerTask]
other = "触发任务"
[TheFormaOfTheScheduleIs]
other = "计划的格式为:"
[SecondsMinutesHoursDaysMonthsWeeksSeeDetails]
other = "秒 分 时 天 月 星期,详情见"
[ScheduleExpressionFormat]
other = "计划表达式格式"
[IntroductionOfCommands]
other = "命令说明:编写命令时类似于 shell/bat 脚本。建议不要换行,多个命令可用 <code>&&</code> 或 <code>;</code> 连接,若出现命令无法找到的情况,可能是由于 <code>PATH</code> 环境变量配置问题。在 <code>Linux</code> 服务器上,可在命令开头加入 <code>source ~/.bashrc</code>,或使用命令的绝对路径执行。"
[AddMonitor]
other = "新增监控"
[Blog]
other = "博客"
[Target]
other = "目标"
[Type]
other = "类型"
[SslExpirationOrChange]
other = "(SSL到期、变更)"
[Duration]
other = "请求间隔"
[Seconds]
other = "秒"
[EnableFailureNotification]
other = "启用故障通知"
[FailureNotification]
other = "故障通知"
[MaxLatency]
other = "最大延迟(ms)"
[MinLatency]
other = "最小延迟(ms)"
[EnableLatencyNotification]
other = "启用延迟通知"
[LatencyNotification]
other = "延迟通知"
[IntroductionOfMonitor]
other = """
<b>HTTP-GET</b> URL( http/https, HTTPSSSL)<br>
<b>ICMP-Ping</b> /IP<br>
<b>TCP-Ping</b> /IP + example.com:22"""
[AddNotificationMethod]
other = "新增通知方式"
[Tag]
other = "分组"
[DoNotSendTestMessages]
other = "不发送测试信息"
[RequestMethod]
other = "请求方式"
[RequestType]
other = "请求类型"
[VerifySSL]
other = "验证SSL"
[AddNotificationRule]
other = "新增告警规则"
[Rules]
other = "规则"
[NotificationTriggerMode]
other = "通知触发模式"
[ModeAlwaysTrigger]
other = "始终触发"
[ModeOnetimeTrigger]
other = "单次触发"
[EnableTriggerTask]
other = "启用触发任务"
[FailTriggerTasks]
other = "告警时触发任务"
[RecoverTriggerTasks]
other = "恢复时触发任务"
[Enable]
other = "启用"
[AddServer]
other = "新增服务器"
[BatchEditServerGroup]
other = "批量修改分组"
[BatchDeleteServer]
other = "批量删除服务器"
[InputServerGroupName]
other = "输入分组名称"
[ServerGroup]
other = "服务器分组"
[EinsteinLightspeed1]
other = "爱因斯坦-光速1号"
[DisplayIndex]
other = "排序"
[TheLargerTheNumberTheHigherThePriority]
other = "越大越靠前"
[Secret]
other = "密钥"
[Note]
other = "备注"
[PublicNote]
other = "公开备注"
[LinuxOneKeyInstall]
other = "Linux 一键安装"
[NoDomainAlert]
other = "请先在设置页面配置 未接入CDN的面板服务器域名/IP"
[PushSuccessfully]
other = "推送成功"
[LastExecution]
other = "最近执行"
[LastResult]
other = "最后结果"
[Administration]
other = "管理"
[CoverAll]
other = "覆盖所有"
[IgnoreAll]
other = "忽略所有"
[ByTrigger]
other = "触发告警的服务器"
[DeleteScheduledTask]
other = "删除计划任务"
[ConfirmToDeleteThisScheduledTask]
other = "确认删除此计划任务?"
[AccessDenied]
other = "访问被拒绝"
[Use]
other = "使用"
[AccountToLogin]
other = "账号登录"
[SignUp]
other = "注册"
[DontHaveAnAccount]
other = "没有账号?"
[SSLCertificate]
other = "HTTP(S)/SSL证书"
[TCPPort]
other = "TCPing"
[DeleteService]
other = "移除服务"
[ConfirmToDeleteThisService]
other = "确认删除此服务?"
[DeleteNotificationMethod]
other = "删除通知方式"
[ConfirmToDeleteThisNotificationMethod]
other = "确认删除此通知方式?"
[ForceUpdate]
other = "立即更新"
[SelectAll]
other = "全选"
[VersionNumber]
other = "版本号"
[OneKeyInstall]
other = "一键安装"
[ClickToCopy]
other = "点击复制"
[DeleteServer]
other = "删除服务器"
[ConfirmToDeleteServer]
other = "确认删除服务器?"
[NoServerSelected]
other = "当前没有选中的服务器"
[ExecutionResults]
other = "执行结果"
[SiteTitle]
other = "网站标题"
[AdministratorList]
other = "管理员列表"
[Theme]
other = "前台界面主题"
[CustomCodes]
other = "自定义代码(包括 style 和 script"
[CustomCodesDashboard]
other = "Custom Codes for Dashboard"
[AccessPassword]
other = "前台访问密码"
[PanelServerDomainAndIP]
other = "未接入CDN的面板服务器域名/IP"
[IPChangeAlert]
other = "IP 变动通知"
[AllIncludedOnlySpecificServersAreNotAlerted]
other = "覆盖所有,仅特定服务器不提醒"
[IgnoreAllOnlyAlertSpecificServers]
other = "忽略所有,仅提醒特定服务器"
[IgnoreAllRequestOnlyThroughSpecificServers]
other = "忽略所有,仅通过特定服务器请求"
[AllIncludedOnlySpecificServersAreNotRequest]
other = "覆盖所有,仅特定服务器不请求"
[ServerIDSeparatedByCommas]
other = "服务器ID 以逗号隔开"
[IPChangeNotificationTag]
other = "将提醒发送至指定通知分组"
[NotificationMessagesDoNotHideIP]
other = "通知信息中显示完整IP地址"
[Save]
other = "保存"
[ModifiedSuccessfully]
other = "修改成功"
[TerminalConnectionTimeOutOrSessionEnded]
other = "Terminal 连接超时或会话已结束"
[TerminalConnectionFailed]
other = "Terminal 连接失败,请检查 /terminal/* 的 WebSocket 反向代理配置"
[Default]
other = "默认"
[Offline]
other = "已离线"
[Platform]
other = "系统"
[DiskUsed]
other = "硬盘"
[MemUsed]
other = "内存"
[CpuUsed]
other = "核心"
[Virtualization]
other = "虚拟化"
[SwapUsed]
other = "交换"
[NetTransfer]
other = "流量"
[Load]
other = "负载"
[ProcessCount]
other = "进程数"
[ConnCount]
other = "连接数"
[BootTime]
other = "启动"
[LastActive]
other = "活动"
[Version]
other = "版本"
[NetSpeed]
other = "网速"
[Uptime]
other = "在线"
[ServerIsOffline]
other = "服务器已离线"
[Day]
other = "天"
[RealtimeChannelEstablished]
other = "实时通道已建立"
[GetTheLatestMonitoringDataInRealTime]
other = "可以实时获取最新监控数据啦"
[RealtimeChannelDisconnect]
other = "实时通道已断开"
[CanNotGetTheLatestMonitoringDataInRealTime]
other = "无法实时获取最新监控数据咯"
[30DaysOnline]
other = "近30天可用性"
[Details]
other = "详情"
[Status]
other = "状态"
[Availability]
other = "可用性"
[AverageLatency]
other = "平均响应时间"
[CycleTransferStats]
other = "周期性流量统计"
[From]
other = "起始"
[To]
other = "结束"
[NextCheck]
other = "下一次检测"
[CurrentUsage]
other = "当前用量"
[VerifyPassword]
other = "验证查看密码"
[LightMode]
other = "亮色模式"
[DarkMode]
other = "暗色模式"
[FollowSystem]
other = "跟随系统"
[GridLayout]
other = "网格布局"
[ListLayout]
other = "列表布局"
[EnterPassword]
other = "请输入密码"
[Location]
other = "位置"
[Running]
other = "运行中"
[UpNetTransfer]
other = "上行"
[DownNetTransfer]
other = "下行"
[TotalUpNetTransfer]
other = "总上行"
[TotalDownNetTransfer]
other = "总下行"
[WrongPassword]
other = "输入的密码错误"
[AnErrorEccurred]
other = "发生错误"
[SystemError]
other = "系统错误"
[NetworkError]
other = "网络错误"
[ServicesStatus]
other = "服务状态"
[ServersManagement]
other = "服务器管理"
[ServicesManagement]
other = "服务监控"
[ScheduledTasks]
other = "计划任务"
[ApiManagement]
other = "API 管理"
[IssueNewApiToken]
other = "生成Token"
[Token]
other = "Token"
[DeleteToken]
other = "删除Token"
[ConfirmToDeleteThisToken]
other = "确认删除Token"
[YouAreNotAuthorized]
other = "此页面需要登录"
[WrongAccessPassword]
other = "访问密码错误"
[Add]
other = "新增"
[Edit]
other = "修改"
[AlarmRule]
other = "告警规则"
[NotificationMethod]
other = "通知方式"
[Incident]
other = "事件"
[Resolved]
other = "恢复"
[StatusDown]
other = "故障"
[StatusNoData]
other = "无数据"
[StatusGood]
other = "正常"
[StatusLowAvailability]
other = "低可用"
[ScheduledTaskExecutedSuccessfully]
other = "任务执行成功"
[ScheduledTaskExecutedFailed]
other = "任务执行失败"
[IPChanged]
other = "IP变更"
[Transleft]
other = "剩余流量"
[DashboardTheme]
other = "后台界面主题"
[Info]
other = "信息"
[HideForGuest]
other = "对游客隐藏"
[Menu]
other = "菜单"
[NetworkSpiter]
other = "网络"
[EnableShowInService]
other = "在服务中显示"
[DDNS]
other = "动态 DNS"
[DDNSProfiles]
other = "DDNS配置"
[AddDDNSProfile]
other = "新配置"
[EnableDDNS]
other = "启用 DDNS"
[EnableIPv4]
other = "启用 DDNS IPv4"
[EnableIPv6]
other = "启用 DDNS IPv6"
[DDNSDomain]
other = "DDNS 域名"
[DDNSDomains]
other = "域名(逗号分隔)"
[DDNSProvider]
other = "DDNS 供应商"
[MaxRetries]
other = "最大重试次数"
[DDNSAccessID]
other = "DDNS 凭据 1"
[DDNSAccessSecret]
other = "DDNS 凭据 2"
[DDNSTokenID]
other = "令牌 ID"
[DDNSTokenSecret]
other = "令牌 Secret"
[WebhookURL]
other = "Webhook 地址"
[WebhookMethod]
other = "Webhook 请求方式"
[WebhookRequestType]
other = "Webhook 请求类型"
[WebhookHeaders]
other = "Webhook 请求头"
[WebhookRequestBody]
other = "Webhook 请求体"
[Feature]
other = "功能"
[Template]
other = "主题"
[Stat]
other = "信息"
[Temperature]
other = "温度"
[DisableSwitchTemplateInFrontend]
other = "禁止前台切换模板"
[ServersOnWorldMap]
other = "服务器世界分布图"
[NAT]
other = "内网穿透"
[LocalService]
other = "内网服务"
[LocalServicePlaceholder]
other = "192.168.1.1:80(带端口)"
[BindHostname]
other = "绑定域名"
[NetworkSpiterList]
other = "网络监控"
[Refresh]
other = "刷新"
[CopyPath]
other = "复制路径"
[Goto]
other = "跳往"
[GotoHeadline]
other = "跳往文件夹"
[GotoGo]
other = "确认"
[GotoClose]
other = "取消"
[FMError]
other = "Agent 返回了错误,请查看控制台获取详细信息。要建立新连接,请重新打开 FM。"
[Remaining]
other = "剩余"
[Lifetime]
other = "永续"
[Price]
other = "价格"
[Expired]
other = "已到期"
[Days]
other = "天"
[CustomNameservers]
other = "自定义DDNS使用的公共DNS服务器逗号分隔"

View File

@ -1,752 +0,0 @@
[NezhaMonitoring]
other = "哪吒監控"
[Server]
other = "伺服器"
[Services]
other = "服務"
[Task]
other = "任務"
[Notification]
other = "告警"
[Settings]
other = "設置"
[Home]
other = "首頁"
[BackToHomepage]
other = "返回前台"
[AdminPanel]
other = "管理後台"
[Logout]
other = "登出"
[Login]
other = "登入"
[ConfirmLogout]
other = "確定要登出嗎?"
[AfterLoggingOutYouHaveToLoginAgain]
other = "登出後需重新登入以繼續使用"
[Cancel]
other = "取消"
[Confirm]
other = "確認"
[AddScheduledTasks]
other = "新增計劃任務"
[Name]
other = "名稱"
[Scheduler]
other = "排程"
[BackUp]
other = "備份"
[3amDaily]
other = "(每天3點)"
[Command]
other = "命令"
[Coverage]
other = "覆蓋範圍"
[IgnoreAllAndExecuteOnlyThroughSpecificServers]
other = "忽略所有,僅通過特定伺服器執行"
[AllIncludedOnlySpecificServersAreNotExecuted]
other = "覆蓋所有,僅特定伺服器不執行"
[ExecuteByTriggerServer]
other = "由觸發告警的伺服器執行"
[SpecificServers]
other = "特定伺服器"
[EnterIdAndNameToSearch]
other = "輸入ID/名稱以搜尋"
[NotificationMethodGroup]
other = "通知群組"
[PushSuccessMessages]
other = "推送成功的訊息"
[TaskType]
other = "任務類型"
[CronTask]
other = "排程任務"
[TriggerTask]
other = "觸發任務"
[TheFormaOfTheScheduleIs]
other = "排程的格式為:"
[SecondsMinutesHoursDaysMonthsWeeksSeeDetails]
other = "秒 分 時 天 月 星期,詳情見"
[ScheduleExpressionFormat]
other = "排程表達式格式"
[IntroductionOfCommands]
other = "命令說明:編寫命令時類似於 shell/bat 腳本。建議不要換行,多個命令可用 <code>&&</code> 或 <code>;</code> 連接,若出現命令無法找到的情況,可能是由於 <code>PATH</code> 環境變數配置問題。在 <code>Linux</code> 伺服器上,可在命令開頭加入 <code>source ~/.bashrc</code>,或使用命令的絕對路徑執行。"
[AddMonitor]
other = "新增監控"
[Blog]
other = "部落格"
[Target]
other = "目標"
[Type]
other = "類型"
[SslExpirationOrChange]
other = "(SSL到期、變更)"
[Duration]
other = "請求間隔"
[Seconds]
other = "秒"
[EnableFailureNotification]
other = "啟用故障通知"
[FailureNotification]
other = "故障通知"
[MaxLatency]
other = "最大延遲(ms)"
[MinLatency]
other = "最小延遲(ms)"
[EnableLatencyNotification]
other = "啟用延遲通知"
[LatencyNotification]
other = "延遲通知"
[IntroductionOfMonitor]
other = """
<b>HTTP-GET</b> URL( http/https, HTTPSSSL)<br>
<b>ICMP-Ping</b> /IP<br>
<b>TCP-Ping</b> /IP + example.com:22"""
[AddNotificationMethod]
other = "新增通知方式"
[Tag]
other = "分組"
[DoNotSendTestMessages]
other = "不發送測試訊息"
[RequestMethod]
other = "請求方式"
[RequestType]
other = "請求類型"
[VerifySSL]
other = "驗證SSL"
[AddNotificationRule]
other = "新增告警規則"
[Rules]
other = "規則"
[NotificationTriggerMode]
other = "通知觸發模式"
[ModeAlwaysTrigger]
other = "始終觸發"
[ModeOnetimeTrigger]
other = "單次觸發"
[EnableTriggerTask]
other = "啟用觸發任務"
[FailTriggerTasks]
other = "告警時觸發任務"
[RecoverTriggerTasks]
other = "恢復時觸發任務"
[Enable]
other = "啟用"
[AddServer]
other = "新增伺服器"
[BatchEditServerGroup]
other = "批量修改分組"
[BatchDeleteServer]
other = "批量刪除伺服器"
[InputServerGroupName]
other = "輸入分組名稱"
[ServerGroup]
other = "伺服器分組"
[EinsteinLightspeed1]
other = "愛因斯坦-光速1號"
[DisplayIndex]
other = "排序"
[TheLargerTheNumberTheHigherThePriority]
other = "越大越靠前"
[Secret]
other = "金鑰"
[Note]
other = "備註"
[PublicNote]
other = "公開備註"
[LinuxOneKeyInstall]
other = "Linux 一鍵安裝"
[NoDomainAlert]
other = "請先在設置頁面配置 未接入CDN的面板伺服器域名/IP"
[PushSuccessfully]
other = "推送成功"
[LastExecution]
other = "最近執行"
[LastResult]
other = "最後結果"
[Administration]
other = "管理"
[CoverAll]
other = "覆蓋所有"
[IgnoreAll]
other = "忽略所有"
[ByTrigger]
other = "觸發告警的伺服器"
[DeleteScheduledTask]
other = "刪除排程任務"
[ConfirmToDeleteThisScheduledTask]
other = "確認刪除此排程任務?"
[AccessDenied]
other = "訪問被拒絕"
[Use]
other = "使用"
[AccountToLogin]
other = "帳號登入"
[SignUp]
other = "註冊"
[DontHaveAnAccount]
other = "沒有帳號?"
[SSLCertificate]
other = "HTTP(S)/SSL證書"
[TCPPort]
other = "TCPing"
[DeleteService]
other = "移除服務"
[ConfirmToDeleteThisService]
other = "確認刪除此服務?"
[DeleteNotificationMethod]
other = "刪除通知方式"
[ConfirmToDeleteThisNotificationMethod]
other = "確認刪除此通知方式?"
[ForceUpdate]
other = "立即更新"
[SelectAll]
other = "全選"
[VersionNumber]
other = "版本號"
[OneKeyInstall]
other = "一鍵安裝"
[ClickToCopy]
other = "點擊複製"
[DeleteServer]
other = "刪除伺服器"
[ConfirmToDeleteServer]
other = "確認刪除伺服器?"
[NoServerSelected]
other = "當前沒有選中的伺服器"
[ExecutionResults]
other = "執行結果"
[SiteTitle]
other = "網站標題"
[AdministratorList]
other = "管理員列表"
[Theme]
other = "前台界面主題"
[CustomCodes]
other = "自定義代碼(包括 style 和 script"
[CustomCodesDashboard]
other = "Custom Codes for Dashboard"
[AccessPassword]
other = "前台訪問密碼"
[PanelServerDomainAndIP]
other = "未接入CDN的面板伺服器域名/IP"
[IPChangeAlert]
other = "IP 變動通知"
[AllIncludedOnlySpecificServersAreNotAlerted]
other = "覆蓋所有,僅特定伺服器不提醒"
[IgnoreAllOnlyAlertSpecificServers]
other = "忽略所有,僅提醒特定伺服器"
[IgnoreAllRequestOnlyThroughSpecificServers]
other = "忽略所有,僅通過特定伺服器請求"
[AllIncludedOnlySpecificServersAreNotRequest]
other = "覆蓋所有,僅特定伺服器不請求"
[ServerIDSeparatedByCommas]
other = "伺服器ID 以逗號隔開"
[IPChangeNotificationTag]
other = "將提醒發送至指定通知分組"
[NotificationMessagesDoNotHideIP]
other = "通知信息中顯示完整IP地址"
[Save]
other = "保存"
[ModifiedSuccessfully]
other = "修改成功"
[TerminalConnectionTimeOutOrSessionEnded]
other = "Terminal 連接超時或會話已結束"
[TerminalConnectionFailed]
other = "Terminal 連接失敗,請檢查 /terminal/* 的 WebSocket 反向代理配置"
[Default]
other = "默認"
[Offline]
other = "已離線"
[Platform]
other = "系統"
[DiskUsed]
other = "硬碟"
[MemUsed]
other = "記憶體"
[CpuUsed]
other = "核心"
[Virtualization]
other = "虛擬化"
[SwapUsed]
other = "交換"
[NetTransfer]
other = "流量"
[Load]
other = "負載"
[ProcessCount]
other = "行程數"
[ConnCount]
other = "連接數"
[BootTime]
other = "啟動"
[LastActive]
other = "活動"
[Version]
other = "版本"
[NetSpeed]
other = "網速"
[Uptime]
other = "在線"
[ServerIsOffline]
other = "伺服器已離線"
[Day]
other = "天"
[RealtimeChannelEstablished]
other = "實時通道已建立"
[GetTheLatestMonitoringDataInRealTime]
other = "可以實時獲取最新監控數據啦"
[RealtimeChannelDisconnect]
other = "實時通道已斷開"
[CanNotGetTheLatestMonitoringDataInRealTime]
other = "無法實時獲取最新監控數據咯"
[30DaysOnline]
other = "近30天可用性"
[Details]
other = "詳情"
[Status]
other = "狀態"
[Availability]
other = "可用性"
[AverageLatency]
other = "平均回應時間"
[CycleTransferStats]
other = "周期性流量統計"
[From]
other = "起始"
[To]
other = "結束"
[NextCheck]
other = "下一次檢測"
[CurrentUsage]
other = "當前用量"
[VerifyPassword]
other = "驗證查看密碼"
[LightMode]
other = "亮色模式"
[DarkMode]
other = "暗色模式"
[FollowSystem]
other = "跟隨系統"
[GridLayout]
other = "網格佈局"
[ListLayout]
other = "列表佈局"
[EnterPassword]
other = "請輸入密碼"
[Location]
other = "位置"
[Running]
other = "運行中"
[UpNetTransfer]
other = "上行"
[DownNetTransfer]
other = "下行"
[TotalUpNetTransfer]
other = "總上行"
[TotalDownNetTransfer]
other = "總下行"
[WrongPassword]
other = "輸入的密碼錯誤"
[AnErrorEccurred]
other = "發生錯誤"
[SystemError]
other = "系統錯誤"
[NetworkError]
other = "網路錯誤"
[ServicesStatus]
other = "服務狀態"
[ServersManagement]
other = "伺服器管理"
[ServicesManagement]
other = "服務監控"
[ScheduledTasks]
other = "排程任務"
[ApiManagement]
other = "API 管理"
[IssueNewApiToken]
other = "生成Token"
[Token]
other = "Token"
[DeleteToken]
other = "刪除Token"
[ConfirmToDeleteThisToken]
other = "確認刪除Token"
[YouAreNotAuthorized]
other = "此頁面需要登入"
[WrongAccessPassword]
other = "訪問密碼錯誤"
[Add]
other = "新增"
[Edit]
other = "修改"
[AlarmRule]
other = "告警規則"
[NotificationMethod]
other = "通知方式"
[Incident]
other = "事件"
[Resolved]
other = "恢復"
[StatusDown]
other = "故障"
[StatusNoData]
other = "無數據"
[StatusGood]
other = "正常"
[StatusLowAvailability]
other = "低可用"
[ScheduledTaskExecutedSuccessfully]
other = "任務執行成功"
[ScheduledTaskExecutedFailed]
other = "任務執行失敗"
[IPChanged]
other = "IP變更"
[Transleft]
other = "剩餘流量"
[DashboardTheme]
other = "後台界面主題"
[Info]
other = "信息"
[HideForGuest]
other = "對遊客隱藏"
[Menu]
other = "菜單"
[NetworkSpiter]
other = "網路"
[EnableShowInService]
other = "在服務中顯示"
[DDNS]
other = "動態 DNS"
[DDNSProfiles]
other = "DDNS配置"
[AddDDNSProfile]
other = "新增配置"
[EnableDDNS]
other = "啟用 DDNS"
[EnableIPv4]
other = "啟用 DDNS IPv4"
[EnableIPv6]
other = "啟用 DDNS IPv6"
[DDNSDomain]
other = "DDNS 域名"
[DDNSDomains]
other = "域名(逗號分隔)"
[DDNSProvider]
other = "DDN S供應商"
[MaxRetries]
other = "最大重試次數"
[DDNSAccessID]
other = "DDNS 憑據 1"
[DDNSAccessSecret]
other = "DDNS 憑據 2"
[DDNSTokenID]
other = "令牌 ID"
[DDNSTokenSecret]
other = "令牌 Secret"
[WebhookURL]
other = "Webhook 地址"
[WebhookMethod]
other = "Webhook 請求方式"
[WebhookRequestType]
other = "Webhook 請求類型"
[WebhookHeaders]
other = "Webhook 請求頭"
[WebhookRequestBody]
other = "Webhook 請求體"
[Feature]
other = "功能"
[Template]
other = "主題"
[Stat]
other = "信息"
[Temperature]
other = "溫度"
[DisableSwitchTemplateInFrontend]
other = "禁止前台切換主題"
[ServersOnWorldMap]
other = "伺服器世界分布圖"
[NAT]
other = "NAT穿透"
[LocalService]
other = "內網服務"
[LocalServicePlaceholder]
other = "192.168.1.1:80(帶埠號)"
[BindHostname]
other = "綁定網域"
[NetworkSpiterList]
other = "網路監控"
[Refresh]
other = "重新整理"
[CopyPath]
other = "複製路徑"
[Goto]
other = "跳至"
[GotoHeadline]
other = "跳至資料夾"
[GotoGo]
other = "確定"
[GotoClose]
other = "取消"
[FMError]
other = "Agent 回傳了錯誤,請查看主控台獲取詳細資訊。要建立新連線,請重新開啟 FM。"
[Remaining]
other = "剩餘"
[Lifetime]
other = "永續"
[Price]
other = "價格"
[Expired]
other = "已到期"
[Days]
other = "天"
[CustomNameservers]
other = "自訂DDNS使用的公共DNS伺服器逗號分隔"

31
resource/resource.go vendored
View File

@ -1,31 +0,0 @@
package resource
import (
"embed"
"github.com/naiba/nezha/pkg/utils"
)
var StaticFS *utils.HybridFS
//go:embed static
var staticFS embed.FS
//go:embed template
var TemplateFS embed.FS
//go:embed l10n
var I18nFS embed.FS
func init() {
var err error
StaticFS, err = utils.NewHybridFS(staticFS, "static", "resource/static/custom")
if err != nil {
panic(err)
}
}
func IsTemplateFileExist(name string) bool {
_, err := TemplateFS.Open(name)
return err == nil
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,141 +0,0 @@
html[nz-theme='dark'] body {
background-color: #121212 !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.menu {
background-color: #282828 !important;
}
html[nz-theme='dark'] .ui.menu * {
color: #fff !important;
}
html[nz-theme='dark'] .accordion {
background-color: #282828 !important;
}
html[nz-theme='dark'] .accordion .title {
color: #fff !important;
}
html[nz-theme='dark'] .ui.card {
background-color: #3f3f3f !important;
border: none !important;
box-shadow: none !important;
}
html[nz-theme='dark'] .header {
color: #fff !important;
}
html[nz-theme='dark'] .description {
color: #fff !important;
}
html[nz-theme='dark'] .icon {
color: #fff !important;
}
html[nz-theme='dark'] .ui.popup {
background-color: #575757 !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.table {
background-color: #282828 !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui thead th {
background-color: #3f3f3f !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.buttons .button {
background-color: #3f3f3f !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.modal {
background-color: #282828 !important;
}
html[nz-theme='dark'] .ui.modal * {
color: #fff !important;
}
html[nz-theme='dark'] textarea,
html[nz-theme='dark'] input,
html[nz-theme='dark'] select,
html[nz-theme='dark'] .dropdown {
background-color: #3f3f3f !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.message {
background-color: unset !important;
}
html[nz-theme='dark'] .ui.dropdown .menu {
background-color: #575757 !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.modal>.header {
background-color: #3f3f3f !important;
}
html[nz-theme='dark'] .ui.modal>.content {
background-color: #282828 !important;
}
html[nz-theme='dark'] .ui.modal>.actions {
background-color: #3f3f3f !important;
}
html[nz-theme='dark'] #alert {
background-color: #3f3f3f !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.form .field>label {
color: unset !important;
}
html[nz-theme='dark'] .ui.segment {
background-color: #3f3f3f !important;
}
html[nz-theme='dark'] .ui.segment textarea,
html[nz-theme='dark'] input,
html[nz-theme='dark'] select,
html[nz-theme='dark'] .dropdown {
background-color: #575757 !important;
color: #fff !important;
}
html[nz-theme='dark'] form label {
color: #fff !important;
}
html[nz-theme='dark'] .ui.inverted.segment {
background-color: #121212 !important;
}
html[nz-theme='dark'] .ui.inverted.segment * {
color: #8b8b8b !important;
}
html[nz-theme='dark'] .menu .dropdown {
background-color: #282828 !important;
color: #fff !important;
}
html[nz-theme='dark'] .ui.menu .ui.dropdown .menu>.item {
color: #fff !important;
}
html[nz-theme='dark'] .login .ui.message{
color: #8b8b8b !important;
}

View File

@ -1,70 +0,0 @@
let receivedLength = 0;
let expectedLength = 0;
let root;
let draftHandle;
let accessHandle;
const Operation = Object.freeze({
WriteHeader: 1,
WriteChunks: 2,
DeleteFiles: 3
});
onmessage = async function (event) {
try {
const { operation, arrayBuffer, fileName } = event.data;
switch (operation) {
case Operation.WriteHeader: {
const dataView = new DataView(arrayBuffer);
expectedLength = Number(dataView.getBigUint64(4, false));
receivedLength = 0;
// Create a new temporary file
root = await navigator.storage.getDirectory();
draftHandle = await root.getFileHandle(fileName, { create: true });
accessHandle = await draftHandle.createSyncAccessHandle();
// Inform that file handle is created
const dataChunk = arrayBuffer.slice(12);
receivedLength += dataChunk.byteLength;
accessHandle.write(dataChunk, { at: 0 });
const progress = 'got handle';
postMessage({ type: 'progress', progress: progress });
break;
}
case Operation.WriteChunks: {
if (!accessHandle) {
throw new Error('accessHandle is undefined');
}
const dataChunk = arrayBuffer;
accessHandle.write(dataChunk, { at: receivedLength });
receivedLength += dataChunk.byteLength;
if (receivedLength === expectedLength) {
accessHandle.flush();
accessHandle.close();
const fileBlob = await draftHandle.getFile();
const blob = new Blob([fileBlob], { type: 'application/octet-stream' });
postMessage({ type: 'result', blob: blob, fileName: fileName });
}
break;
}
case Operation.DeleteFiles: {
for await (const [name, handle] of root.entries()) {
if (handle.kind === 'file') {
await root.removeEntry(name);
} else if (handle.kind === 'directory') {
await root.removeEntry(name, { recursive: true });
}
}
break;
}
}
} catch (error) {
postMessage({ error: error.message });
}
};

View File

@ -1 +0,0 @@
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path fill="#0A94F2" d="M30 17v61.84L73.588 106 177 43.082l-7.336-.542V17z"/><path fill="#0338D6" d="M77.42 139.845L30 109.943v42.6L99.585 187l69.582-34.457V75.38L186 48z"/></g></svg>

Before

Width:  |  Height:  |  Size: 283 B

View File

@ -1,129 +0,0 @@
@media only screen and (min-width: 1200px) {
.ui.container {
width: 77%;
}
}
td {
word-wrap: break-word;
word-break: break-all;
}
.ui.container{
width: 95vw !important;
max-width: 1680px !important;
}
.nb-container {
padding-top: 75px;
min-height: 100vh;
padding-bottom: 65px;
margin-bottom: -47px;
}
#app .ui.fluid.accordion {
margin-bottom: 1rem;
}
.login.nb-container {
display: flex;
align-items: center;
padding-top: unset;
}
.login.nb-container > .grid {
width: 100%;
margin: 0 auto;
}
.login.nb-container > .grid .column {
max-width: 450px;
}
.status.cards .flag {
margin-right: 0 !important;
}
.status.cards .header > .info.icon {
float: right;
margin-right: 0;
}
.status.cards .wide.column {
padding-top: 0 !important;
padding-bottom: 0 !important;
height: 2rem !important;
}
.status.cards .three.wide.column {
padding-right: 0 !important;
}
.status.cards .wide.column:nth-child(1) {
margin-top: 1rem !important;
}
.status.cards .wide.column:nth-child(2) {
margin-top: 1rem !important;
}
.status.cards .description {
padding-bottom: 1rem !important;
}
.status.cards .ui.content.popup {
min-width: 250px;
}
.status.cards .outline.icon {
margin-right: 0 !important;
}
.ui.progress .bar {
min-width: 1.26em !important;
text-align: right;
padding-right: 0.4em;
line-height: 1.75em;
color: rgba(255, 255, 255, 0.7);
font-weight: 700;
max-width: 100% !important;
}
.service-status .delay-today {
display: flex;
align-items: center;
}
.service-status .delay-today > i {
display: inline-block;
width: 1.2em;
height: 1.2em;
border-radius: 0.6em;
background-color: grey;
margin-right: 0.3em;
}
.service-status .danger {
background-color: crimson !important;
}
.service-status .good {
background-color: rgb(10, 148, 242) !important;
}
.service-status .warning {
background-color: orange !important;
}
.nezha-primary-btn {
background-color: #0338d6 !important;
color: white !important;
}
.nezha-primary-font {
color: #0338d6 !important;
}
.nezha-secondary-font {
color: rgb(10, 148, 242) !important;
}

View File

@ -1,717 +0,0 @@
let LANG = {
Add: "添加",
Edit: "修改",
AlarmRule: "报警规则",
Notification: "通知方式",
Server: "服务器",
Monitor: "监控",
Cron: "计划任务",
}
function updateLang(newLang) {
if (newLang) {
LANG = newLang;
}
}
function readableBytes(bytes) {
if (!bytes) {
return '0B'
}
var i = Math.floor(Math.log(bytes) / Math.log(1024)),
sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
}
const confirmBtn = $(".mini.confirm.modal .nezha-primary-btn.button");
function showConfirm(title, content, callFn, extData) {
const modal = $(".mini.confirm.modal");
modal.children(".header").text(title);
modal.children(".content").text(content);
if (confirmBtn.hasClass("loading")) {
return false;
}
modal
.modal({
closable: true,
onApprove: function () {
confirmBtn.toggleClass("loading");
callFn(extData);
return false;
},
})
.modal("show");
}
function postJson(url, data) {
return $.ajax({
url: url,
type: "POST",
contentType: "application/json",
data: JSON.stringify(data),
}).done((resp) => {
if (resp.code == 200) {
if (resp.message) {
alert(resp.message);
} else {
alert("删除成功");
}
window.location.reload();
} else {
alert("删除失败 " + resp.code + "" + resp.message);
confirmBtn.toggleClass("loading");
}
})
.fail((err) => {
alert("网络错误:" + err.responseText);
});
}
function showFormModal(modelSelector, formID, URL, getData) {
$(modelSelector)
.modal({
closable: true,
onApprove: function () {
let success = false;
const btn = $(modelSelector + " .nezha-primary-btn.button");
const form = $(modelSelector + " form");
if (btn.hasClass("loading")) {
return success;
}
form.children(".message").remove();
btn.toggleClass("loading");
const data = getData
? getData()
: $(formID)
.serializeArray()
.reduce(function (obj, item) {
// ID 类的数据
if (
item.name.endsWith("_id") ||
item.name === "id" ||
item.name === "ID" ||
item.name === "ServerID" ||
item.name === "RequestType" ||
item.name === "RequestMethod" ||
item.name === "TriggerMode" ||
item.name === "TaskType" ||
item.name === "DisplayIndex" ||
item.name === "Type" ||
item.name === "Cover" ||
item.name === "Duration" ||
item.name === "MaxRetries" ||
item.name === "Provider" ||
item.name === "WebhookMethod" ||
item.name === "WebhookRequestType"
) {
obj[item.name] = parseInt(item.value);
} else if (item.name.endsWith("Latency")) {
obj[item.name] = parseFloat(item.value);
} else {
obj[item.name] = item.value;
}
if (item.name.endsWith("ServersRaw")) {
if (item.value.length > 2) {
obj[item.name] = JSON.stringify(
[...item.value.matchAll(/\d+/gm)].map((k) =>
parseInt(k[0])
)
);
}
}
if (item.name.endsWith("TasksRaw")) {
if (item.value.length > 2) {
obj[item.name] = JSON.stringify(
[...item.value.matchAll(/\d+/gm)].map((k) =>
parseInt(k[0])
)
);
}
}
if (item.name.endsWith("DDNSProfilesRaw")) {
if (item.value.length > 2) {
obj[item.name] = JSON.stringify(
[...item.value.matchAll(/\d+/gm)].map((k) =>
parseInt(k[0])
)
);
}
}
return obj;
}, {});
$.post(URL, JSON.stringify(data))
.done(function (resp) {
if (resp.code == 200) {
window.location.reload()
} else {
form.append(
`<div class="ui negative message"><div class="header">操作失败</div><p>` +
resp.message +
`</p></div>`
);
}
})
.fail(function (err) {
form.append(
`<div class="ui negative message"><div class="header">网络错误</div><p>` +
err.responseText +
`</p></div>`
);
})
.always(function () {
btn.toggleClass("loading");
});
return success;
},
})
.modal("show");
}
function addOrEditAlertRule(rule) {
const modal = $(".rule.modal");
modal.children(".header").text((rule ? LANG.Edit : LANG.Add) + ' ' + LANG.AlarmRule);
modal
.find(".nezha-primary-btn.button")
.html(
rule ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(rule ? rule.ID : null);
modal.find("input[name=Name]").val(rule ? rule.Name : null);
modal.find("textarea[name=RulesRaw]").val(rule ? rule.RulesRaw : null);
modal.find("select[name=TriggerMode]").val(rule ? rule.TriggerMode : 0);
modal.find("input[name=NotificationTag]").val(rule ? rule.NotificationTag : null);
if (rule && rule.Enable) {
modal.find(".ui.rule-enable.checkbox").checkbox("set checked");
} else {
modal.find(".ui.rule-enable.checkbox").checkbox("set unchecked");
}
modal.find("a.ui.label.visible").each((i, el) => {
el.remove();
});
var failTriggerTasks;
var recoverTriggerTasks;
if (rule) {
failTriggerTasks = rule.FailTriggerTasksRaw;
recoverTriggerTasks = rule.RecoverTriggerTasksRaw;
const failTriggerTasksList = JSON.parse(failTriggerTasks || "[]");
const recoverTriggerTasksList = JSON.parse(recoverTriggerTasks || "[]");
const node1 = modal.find("i.dropdown.icon.1");
const node2 = modal.find("i.dropdown.icon.2");
for (let i = 0; i < failTriggerTasksList.length; i++) {
node1.after(
'<a class="ui label transition visible" data-value="' +
failTriggerTasksList[i] +
'" style="display: inline-block !important;">ID:' +
failTriggerTasksList[i] +
'<i class="delete icon"></i></a>'
);
}
for (let i = 0; i < recoverTriggerTasksList.length; i++) {
node2.after(
'<a class="ui label transition visible" data-value="' +
recoverTriggerTasksList[i] +
'" style="display: inline-block !important;">ID:' +
recoverTriggerTasksList[i] +
'<i class="delete icon"></i></a>'
);
}
}
// 需要在 showFormModal 进一步拼接数组
modal
.find("input[name=FailTriggerTasksRaw]")
.val(rule ? "[]," + failTriggerTasks.substr(1, failTriggerTasks.length - 2) : "[]");
modal
.find("input[name=RecoverTriggerTasksRaw]")
.val(rule ? "[]," + recoverTriggerTasks.substr(1, recoverTriggerTasks.length - 2) : "[]");
showFormModal(".rule.modal", "#ruleForm", "/api/alert-rule");
}
function addOrEditNotification(notification) {
const modal = $(".notification.modal");
modal.children(".header").text((notification ? LANG.Edit : LANG.Add) + ' ' + LANG.Notification);
modal
.find(".nezha-primary-btn.button")
.html(
notification
? LANG.Edit + '<i class="edit icon"></i>'
: LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(notification ? notification.ID : null);
modal.find("input[name=Name]").val(notification ? notification.Name : null);
modal.find("input[name=Tag]").val(notification ? notification.Tag : null);
modal.find("input[name=URL]").val(notification ? notification.URL : null);
modal
.find("textarea[name=RequestHeader]")
.val(notification ? notification.RequestHeader : null);
modal
.find("textarea[name=RequestBody]")
.val(notification ? notification.RequestBody : null);
modal
.find("select[name=RequestMethod]")
.val(notification ? notification.RequestMethod : 1);
modal
.find("select[name=RequestType]")
.val(notification ? notification.RequestType : 1);
if (notification && notification.VerifySSL) {
modal.find(".ui.nf-ssl.checkbox").checkbox("set checked");
} else {
modal.find(".ui.nf-ssl.checkbox").checkbox("set unchecked");
}
modal.find(".ui.nf-skip-check.checkbox").checkbox("set unchecked");
showFormModal(
".notification.modal",
"#notificationForm",
"/api/notification"
);
}
function addOrEditDDNS(ddns) {
const modal = $(".ddns.modal");
modal.children(".header").text((ddns ? LANG.Edit : LANG.Add));
modal
.find(".nezha-primary-btn.button")
.html(
ddns
? LANG.Edit + '<i class="edit icon"></i>'
: LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(ddns ? ddns.ID : null);
modal.find("input[name=Name]").val(ddns ? ddns.Name : null);
modal.find("input[name=DomainsRaw]").val(ddns ? ddns.DomainsRaw : null);
modal.find("input[name=AccessID]").val(ddns ? ddns.AccessID : null);
modal.find("input[name=AccessSecret]").val(ddns ? ddns.AccessSecret : null);
modal.find("input[name=MaxRetries]").val(ddns ? ddns.MaxRetries : 3);
modal.find("input[name=WebhookURL]").val(ddns ? ddns.WebhookURL : null);
modal
.find("textarea[name=WebhookHeaders]")
.val(ddns ? ddns.WebhookHeaders : null);
modal
.find("textarea[name=WebhookRequestBody]")
.val(ddns ? ddns.WebhookRequestBody : null);
modal
.find("select[name=Provider]")
.val(ddns ? ddns.Provider : 0);
modal
.find("select[name=WebhookMethod]")
.val(ddns ? ddns.WebhookMethod : 1);
modal
.find("select[name=WebhookRequestType]")
.val(ddns ? ddns.WebhookRequestType : 1);
if (ddns && ddns.EnableIPv4) {
modal.find(".ui.enableipv4.checkbox").checkbox("set checked");
} else {
modal.find(".ui.enableipv4.checkbox").checkbox("set unchecked");
}
if (ddns && ddns.EnableIPv6) {
modal.find(".ui.enableipv6.checkbox").checkbox("set checked");
} else {
modal.find(".ui.enableipv6.checkbox").checkbox("set unchecked");
}
showFormModal(
".ddns.modal",
"#ddnsForm",
"/api/ddns"
);
}
function addOrEditNAT(nat) {
const modal = $(".nat.modal");
modal.children(".header").text((nat ? LANG.Edit : LANG.Add));
modal
.find(".nezha-primary-btn.button")
.html(
nat
? LANG.Edit + '<i class="edit icon"></i>'
: LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(nat ? nat.ID : null);
modal.find("input[name=ServerID]").val(nat ? nat.ServerID : null);
modal.find("input[name=Name]").val(nat ? nat.Name : null);
modal.find("input[name=Host]").val(nat ? nat.Host : null);
modal.find("input[name=Domain]").val(nat ? nat.Domain : null);
showFormModal(
".nat.modal",
"#natForm",
"/api/nat"
);
}
function connectToServer(id) {
post('/terminal', { Host: window.location.host, Protocol: window.location.protocol, ID: id })
}
function post(path, params, method = 'post') {
const form = document.createElement('form');
form.method = method;
form.action = path;
form.target = "_blank";
for (const key in params) {
if (params.hasOwnProperty(key)) {
const hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.name = key;
hiddenField.value = params[key];
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
function issueNewApiToken(apiToken) {
const modal = $(".api.modal");
modal.children(".header").text((apiToken ? LANG.Edit : LANG.Add) + ' ' + "API Token");
modal
.find(".nezha-primary-btn.button")
.html(
apiToken ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("textarea[name=Note]").val(apiToken ? apiToken.Note : null);
showFormModal(".api.modal", "#apiForm", "/api/token");
}
function addOrEditServer(server, conf) {
const modal = $(".server.modal");
modal.children(".header").text((server ? LANG.Edit : LANG.Add) + ' ' + LANG.Server);
modal
.find(".nezha-primary-btn.button")
.html(
server ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=id]").val(server ? server.ID : null);
modal.find("input[name=name]").val(server ? server.Name : null);
modal.find("input[name=Tag]").val(server ? server.Tag : null);
modal.find("a.ui.label.visible").each((i, el) => {
el.remove();
});
var ddns;
if (server) {
ddns = server.DDNSProfilesRaw;
let serverList;
try {
serverList = JSON.parse(ddns);
} catch (error) {
serverList = "[]";
}
const node = modal.find("i.dropdown.icon.ddnsProfiles");
for (let i = 0; i < serverList.length; i++) {
node.after(
'<a class="ui label transition visible" data-value="' +
serverList[i] +
'" style="display: inline-block !important;">ID:' +
serverList[i] +
'<i class="delete icon"></i></a>'
);
}
}
// 需要在 showFormModal 进一步拼接数组
modal
.find("input[name=DDNSProfilesRaw]")
.val(server ? "[]," + ddns.substr(1, ddns.length - 2) : "[]");
modal
.find("input[name=DisplayIndex]")
.val(server ? server.DisplayIndex : null);
modal.find("textarea[name=Note]").val(server ? server.Note : null);
modal.find("textarea[name=PublicNote]").val(server ? server.PublicNote : null);
if (server) {
modal.find(".secret.field").attr("style", "");
modal.find(".command.field").attr("style", "");
modal.find(".command.hostSecret").text(server.Secret);
modal.find("input[name=secret]").val(server.Secret);
} else {
modal.find(".secret.field").attr("style", "display:none");
modal.find(".command.field").attr("style", "display:none");
modal.find("input[name=secret]").val("");
}
if (server && server.EnableDDNS) {
modal.find(".ui.enableddns.checkbox").checkbox("set checked");
} else {
modal.find(".ui.enableddns.checkbox").checkbox("set unchecked");
}
if (server && server.HideForGuest) {
modal.find(".ui.hideforguest.checkbox").checkbox("set checked");
} else {
modal.find(".ui.hideforguest.checkbox").checkbox("set unchecked");
}
showFormModal(".server.modal", "#serverForm", "/api/server");
}
function addOrEditMonitor(monitor) {
const modal = $(".monitor.modal");
modal.children(".header").text((monitor ? LANG.Edit : LANG.Add) + ' ' + LANG.Monitor);
modal
.find(".nezha-primary-btn.button")
.html(
monitor ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(monitor ? monitor.ID : null);
modal.find("input[name=Name]").val(monitor ? monitor.Name : null);
modal.find("input[name=Target]").val(monitor ? monitor.Target : null);
modal.find("input[name=Duration]").val(monitor && monitor.Duration ? monitor.Duration : 30);
modal.find("select[name=Type]").val(monitor ? monitor.Type : 1);
modal.find("select[name=Cover]").val(monitor ? monitor.Cover : 0);
modal.find("input[name=NotificationTag]").val(monitor ? monitor.NotificationTag : null);
if (monitor && monitor.EnableShowInService) {
modal.find(".ui.nb-show-in-service.checkbox").checkbox("set checked")
} else {
modal.find(".ui.nb-show-in-service.checkbox").checkbox("set unchecked")
}
if (monitor && monitor.Notify) {
modal.find(".ui.nb-notify.checkbox").checkbox("set checked");
} else {
modal.find(".ui.nb-notify.checkbox").checkbox("set unchecked");
}
modal.find("input[name=MaxLatency]").val(monitor ? monitor.MaxLatency : null);
modal.find("input[name=MinLatency]").val(monitor ? monitor.MinLatency : null);
if (monitor && monitor.LatencyNotify) {
modal.find(".ui.nb-lt-notify.checkbox").checkbox("set checked");
} else {
modal.find(".ui.nb-lt-notify.checkbox").checkbox("set unchecked");
}
modal.find("a.ui.label.visible").each((i, el) => {
el.remove();
});
if (monitor && monitor.EnableTriggerTask) {
modal.find(".ui.nb-EnableTriggerTask.checkbox").checkbox("set checked");
} else {
modal.find(".ui.nb-EnableTriggerTask.checkbox").checkbox("set unchecked");
}
var servers;
var failTriggerTasks;
var recoverTriggerTasks;
if (monitor) {
servers = monitor.SkipServersRaw;
const serverList = JSON.parse(servers || "[]");
const node = modal.find("i.dropdown.icon.specificServer");
for (let i = 0; i < serverList.length; i++) {
node.after(
'<a class="ui label transition visible" data-value="' +
serverList[i] +
'" style="display: inline-block !important;">ID:' +
serverList[i] +
'<i class="delete icon"></i></a>'
);
}
failTriggerTasks = monitor.FailTriggerTasksRaw;
recoverTriggerTasks = monitor.RecoverTriggerTasksRaw;
const failTriggerTasksList = JSON.parse(failTriggerTasks || "[]");
const recoverTriggerTasksList = JSON.parse(recoverTriggerTasks || "[]");
const node1 = modal.find("i.dropdown.icon.failTask");
const node2 = modal.find("i.dropdown.icon.recoverTask");
for (let i = 0; i < failTriggerTasksList.length; i++) {
node1.after(
'<a class="ui label transition visible" data-value="' +
failTriggerTasksList[i] +
'" style="display: inline-block !important;">ID:' +
failTriggerTasksList[i] +
'<i class="delete icon"></i></a>'
);
}
for (let i = 0; i < recoverTriggerTasksList.length; i++) {
node2.after(
'<a class="ui label transition visible" data-value="' +
recoverTriggerTasksList[i] +
'" style="display: inline-block !important;">ID:' +
recoverTriggerTasksList[i] +
'<i class="delete icon"></i></a>'
);
}
}
// 需要在 showFormModal 进一步拼接数组
modal
.find("input[name=FailTriggerTasksRaw]")
.val(monitor ? "[]," + failTriggerTasks.substr(1, failTriggerTasks.length - 2) : "[]");
modal
.find("input[name=RecoverTriggerTasksRaw]")
.val(monitor ? "[]," + recoverTriggerTasks.substr(1, recoverTriggerTasks.length - 2) : "[]");
modal
.find("input[name=SkipServersRaw]")
.val(monitor ? "[]," + servers.substr(1, servers.length - 2) : "[]");
showFormModal(".monitor.modal", "#monitorForm", "/api/monitor");
}
function addOrEditCron(cron) {
const modal = $(".cron.modal");
modal.children(".header").text((cron ? LANG.Edit : LANG.Add) + ' ' + LANG.Cron);
modal
.find(".nezha-primary-btn.button")
.html(
cron ? LANG.Edit + '<i class="edit icon"></i>' : LANG.Add + '<i class="add icon"></i>'
);
modal.find("input[name=ID]").val(cron ? cron.ID : null);
modal.find("input[name=Name]").val(cron ? cron.Name : null);
modal.find("select[name=TaskType]").val(cron ? cron.TaskType : 0);
modal.find("select[name=Cover]").val(cron ? cron.Cover : 0);
modal.find("input[name=NotificationTag]").val(cron ? cron.NotificationTag : null);
modal.find("input[name=Scheduler]").val(cron ? cron.Scheduler : null);
modal.find("a.ui.label.visible").each((i, el) => {
el.remove();
});
var servers;
if (cron) {
servers = cron.ServersRaw;
const serverList = JSON.parse(servers || "[]");
const node = modal.find("i.dropdown.icon");
for (let i = 0; i < serverList.length; i++) {
node.after(
'<a class="ui label transition visible" data-value="' +
serverList[i] +
'" style="display: inline-block !important;">ID:' +
serverList[i] +
'<i class="delete icon"></i></a>'
);
}
}
// 需要在 showFormModal 进一步拼接数组
modal
.find("input[name=ServersRaw]")
.val(cron ? "[]," + servers.substr(1, servers.length - 2) : "[]");
modal.find("textarea[name=Command]").val(cron ? cron.Command : null);
if (cron && cron.PushSuccessful) {
modal.find(".ui.push-successful.checkbox").checkbox("set checked");
} else {
modal.find(".ui.push-successful.checkbox").checkbox("set unchecked");
}
showFormModal(".cron.modal", "#cronForm", "/api/cron");
}
function deleteRequest(api) {
$.ajax({
url: api,
type: "DELETE",
})
.done((resp) => {
if (resp.code == 200) {
if (resp.message) {
alert(resp.message);
} else {
alert("删除成功");
}
window.location.reload();
} else {
alert("删除失败 " + resp.code + "" + resp.message);
confirmBtn.toggleClass("loading");
}
})
.fail((err) => {
alert("网络错误:" + err.responseText);
});
}
function manualTrigger(btn, cronId) {
$(btn).toggleClass("loading");
$.ajax({
url: "/api/cron/" + cronId + "/manual",
type: "GET",
})
.done((resp) => {
$(btn).toggleClass("loading");
if (resp.code == 200) {
$.suiAlert({
title: "触发成功,等待执行结果",
type: "success",
description: resp.message,
time: "3",
position: "top-center",
});
} else {
$.suiAlert({
title: "触发失败 ",
type: "error",
description: resp.code + "" + resp.message,
time: "3",
position: "top-center",
});
}
})
.fail((err) => {
$(btn).toggleClass("loading");
$.suiAlert({
title: "触发失败 ",
type: "error",
description: "网络错误:" + err.responseText,
time: "3",
position: "top-center",
});
});
}
function logout(id) {
$.post("/api/logout", JSON.stringify({ id: id }))
.done(function (resp) {
if (resp.code == 200) {
$.suiAlert({
title: "注销成功",
type: "success",
description: "如需继续访问请使用 GitHub 再次登录",
time: "3",
position: "top-center",
});
window.location.reload();
} else {
$.suiAlert({
title: "注销失败",
description: resp.code + "" + resp.message,
type: "error",
time: "3",
position: "top-center",
});
}
})
.fail(function (err) {
$.suiAlert({
title: "网络错误",
description: err.responseText,
type: "error",
time: "3",
position: "top-center",
});
});
}
$(document).ready(() => {
try {
$(".ui.servers.search.dropdown").dropdown({
clearable: true,
apiSettings: {
url: "/api/search-server?word={query}",
cache: false,
},
});
} catch (error) { }
});
$(document).ready(() => {
try {
$(".ui.tasks.search.dropdown").dropdown({
clearable: true,
apiSettings: {
url: "/api/search-tasks?word={query}",
cache: false,
},
});
} catch (error) { }
});
$(document).ready(() => {
try {
$(".ui.ddns.search.dropdown").dropdown({
clearable: true,
apiSettings: {
url: "/api/search-ddns?word={query}",
cache: false,
},
});
} catch (error) { }
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,36 +0,0 @@
{
"name": "Nezha",
"short_name": "Nezha",
"icons": [
{
"src": "/static/manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/static/manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/static/manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/static/manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#000000",
"lang": "eu-US",
"dir": "auto"
}

View File

@ -1,36 +0,0 @@
{
"name": "哪吒监控",
"short_name": "哪吒监控",
"icons": [
{
"src": "/static/manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "/static/manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/static/manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "/static/manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#000000",
"lang": "zh-CN",
"dir": "auto"
}

View File

@ -1 +0,0 @@
.ui-alerts{position:fixed;z-index:2060;padding:23px}.ui-alerts.center{top:50%;left:50%;margin-top:-100px;margin-left:-222px}.ui-alerts.top-right{top:20px;right:20px}.ui-alerts.top-center{top:20px;margin-left:-222px;left:50%}.ui-alerts.top-left{top:20px;left:20px}.ui-alerts.bottom-right{bottom:0;right:20px}.ui-alerts.bottom-center{bottom:0;margin-left:-222px;left:50%}.ui-alerts.bottom-left{bottom:0;left:20px}.ui-alerts.ui-alerts>.message>.content>.header{padding-right:13px}@media (min-width:320px){.ui-alerts.top-center{margin-left:-163px}}

View File

@ -1 +0,0 @@
$.suiAlert=function(i){function t(){l=setTimeout(function(){c.transition({animation:e,duration:"2s",onComplete:function(){c.remove()}})},1e3*o.time)}var o=$.extend({title:"Semantic UI Alerts",description:"semantic ui alerts library",type:"error",time:5,position:"top-right",icon:!1},i);o.icon===!1&&("info"==o.type?o.icon="announcement":"success"==o.type?o.icon="checkmark":"error"==o.type?o.icon="remove":"warning"==o.type&&(o.icon="warning circle"));var e="drop";"top-right"==o.position?e="fly left":"top-center"==o.position?e="fly down":"top-left"==o.position?e="fly right":"bottom-right"==o.position?e="fly left":"bottom-center"==o.position?e="fly up":"bottom-left"==o.position&&(e="fly right");var n="",r=$(window).width();r<425&&(n="mini");var s="ui-alerts."+o.position;$("body > ."+s).length||$("body").append('<div class="ui-alerts '+o.position+'"></div>');var c=$('<div class="ui icon floating '+n+" message "+o.type+'" id="alert"> <i class="'+o.icon+' icon"></i> <i class="close icon" id="alertclose"></i> <div class="content"> <div class="header">'+o.title+"</div> <p>"+o.description+"</p> </div> </div>");$("."+s).prepend(c),c.transition("pulse"),$("#alertclose").on("click",function(){$(this).closest("#alert").transition({animation:e,onComplete:function(){c.remove()}})});var l=0;$(c).mouseenter(function(){clearTimeout(l)}).mouseleave(function(){t()}),t()};

Binary file not shown.

View File

@ -1,379 +0,0 @@
@font-face {
font-family: HarmonyOS;
font-style: normal;
font-display: swap;
src: url(./HarmonyOS_Sans_SC_Medium.subset.woff2) format('woff2')
}
@font-face {
font-weight: 900;
font-family: dianzhenzt;
src: url(./ailmm.woff2)
}
body {
background: #e6eef4;
font-family: dianzhenzt !important
}
.header {
font-family: harmonyos, dianzhenzt !important
}
.container {
font-family: harmonyos, dianzhenzt !important
}
#app {
font-family: harmonyos, dianzhenzt !important
}
.ui.inverted.segment {
background: #e6eef4
}
.ui.menu {
background: #e6eef4;
border: none !important;
box-shadow: 0 0 0 #e6eef4 !important;
-webkit-box-shadow: 0 0 0 #e6eef4 !important
}
.ui.menu .active {
border: none !important;
border-radius: 10px !important;
background: #e6eef4 !important;
box-shadow: inset 5px 5px 16px #d6dde3, inset -5px -5px 16px #f6ffff !important
}
.ui.menu .item:before {
width: 0 !important
}
.ui.menu:not(.secondary):not(.text):not(.tabular):not(.borderless)>.container>.item:not(.right):not(.borderless):first-child {
border-left: none !important
}
.ui.menu.fixed {
position: static
}
.nb-container {
padding-top: 40px !important
}
.ui.menu {
margin-top: 20px !important
}
#app .styled {
box-shadow: 0 0 0 #e6eef4;
-webkit-box-shadow: 0 0 0 #e6eef4
}
#app .accordion {
background: #e6eef4;
border-style: none
}
#app .accordion .content .card {
border-radius: 20px;
background: #e6eef4;
box-shadow: -6px -6px 12px #b8bec3, 6px 6px 12px #fff
}
.ui.fine.progress>.bar {
background-image: linear-gradient(312deg, #57693b, #638b43, #6daf4a, #76d450)
}
.ui.progress.fine .bar {
background-image: linear-gradient(312deg, #57693b, #638b43, #6daf4a, #76d450)
}
.ui.progress>.bar {
background-color: #000 !important
}
.ui.progress.warning .bar {
background-image: linear-gradient(269deg, #de4723, #de6425, #dd7d26, #db9428) !important
}
.ui.progress.error .bar {
background-image: linear-gradient(287deg, #12032a, #480e2a, #7c1028, #b20d24) !important
}
.ui.progress.offline .bar {
background-color: #000 !important
}
.ui.progress .bar {
min-width: 1.8em !important;
border-radius: 15px !important;
line-height: 1.65em !important;
text-shadow: 1px 0 1px #eee, -1px 0 1px #000
}
.ui.progress {
border-radius: 50px;
background: #d9e1e8;
box-shadow: inset 3px 3px 6px #b8bfc5, inset -3px -3px 6px #faffff
}
.service-status .good {
border-radius: 7px !important;
background: linear-gradient(145deg, #23c74a, #1ea73e) !important;
box-shadow: 0 0 0 #20b342 !important
}
.service-status .danger {
border-radius: 7px !important;
background: linear-gradient(145deg, #c71e1e, #a71919) !important;
box-shadow: 0 0 0 #20b342 !important
}
.service-status .warning {
border-radius: 7px !important;
background: linear-gradient(145deg, #ffa51a, #de8b16) !important;
box-shadow: 0 0 0 #ed9417 !important
}
.service-status .table {
border: none !important;
border-radius: 7px;
background: #e6eef4;
box-shadow: -13px -13px 25px #d4dbe0, 13px 13px 25px #f8ffff
}
.service-status .table td .button {
border: none !important;
border-radius: 7px;
background: #e6eef4;
box-shadow: inset -3px -3px 6px #c4cacf, inset 3px 3px 6px #fff
}
.service-status table thead .center {
border: none !important;
background: #e6eef4 !important
}
.service-status .table td {
border: none !important
}
.ui.right.center.popup {
margin: -3px 0 0 .914286em !important;
-webkit-transform-origin: left 50% !important;
transform-origin: left 50% !important
}
.ui.bottom.left.popup {
margin-top: 3px !important;
margin-left: 1px !important
}
.ui.top.left.popup {
margin-bottom: 10px !important;
margin-left: 0 !important
}
.ui.top.right.popup {
margin-right: 0 !important;
margin-bottom: 8px !important
}
.ui.left.center.popup {
margin: -3px .91428571em 0 0 !important;
-webkit-transform-origin: right 50% !important;
transform-origin: right 50% !important
}
.ui.left.center.popup:before,
.ui.right.center.popup:before {
border: 0 solid #fafafaeb !important;
background: #fafafaeb !important
}
.ui.top.popup:before {
border-color: #fafafaeb transparent transparent !important
}
.ui.popup:before {
border-color: #fafafaeb transparent transparent !important
}
.ui.bottom.left.popup:before {
border: 1px solid transparent !important;
border-color: #fafafaeb transparent transparent !important;
border-radius: 0 !important;
background: #fafafaeb !important;
-webkit-box-shadow: 0 0 0 0 #fafafaeb !important;
box-shadow: 0 0 0 0 #fafafaeb !important;
-webkit-tap-highlight-color: transparent !important
}
.ui.bottom.right.popup:before {
border: 1px solid transparent !important;
border-color: #fafafaeb transparent transparent !important;
border-radius: 0 !important;
background: #fafafaeb !important -webkit-box-shadow:0 0 0 0 #fafafaeb !important;
box-shadow: 0 0 0 0 #fafafaeb !important;
-webkit-tap-highlight-color: transparent !important
}
.ui.top.left.popup:before {
border: 1px solid transparent !important;
border-color: #fafafaeb transparent transparent !important;
border-radius: 0 !important;
background: #fafafaeb !important;
-webkit-box-shadow: 0 0 0 0 #fafafaeb !important;
box-shadow: 0 0 0 0 #fafafaeb !important;
-webkit-tap-highlight-color: transparent !important
}
.ui.top.right.popup:before {
border: 1px solid transparent !important;
border-color: #fafafaeb transparent transparent !important;
border-radius: 0 !important;
background: #fafafaeb !important;
-webkit-box-shadow: 0 0 0 0 #fafafaeb !important;
box-shadow: 0 0 0 0 #fafafaeb !important;
-webkit-tap-highlight-color: transparent !important
}
.ui.left.center.popup:before {
border: 1px solid transparent !important;
border-color: #fafafaeb transparent transparent !important;
border-radius: 0 !important;
background: #fafafaeb !important;
-webkit-box-shadow: 0 0 0 0 #fafafaeb !important;
box-shadow: 0 0 0 0 #fafafaeb !important;
-webkit-tap-highlight-color: transparent !important
}
.status.cards .ui.content.popup {
min-width: 20rem !important;
border: 1px solid transparent !important;
border-radius: 5px !important;
background-color: #fafafaeb !important;
font-family: Arial, Helvetica, sans-serif !important;
line-height: 2rem !important
}
#app .accordion .title {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 900 !important
}
#app .accordion .content {
padding-top: 1.5em !important
}
.description .wide {
margin-top: 1em
}
.description .wide:nth-child(odd) {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.description .wide:nth-child(8) {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.description .wide:nth-child(10) {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.description .wide:nth-child(14) {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.description .wide:nth-child(16) {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.stackable .card .content .header {
text-align: center;
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #525151 !important;
font-weight: 500
}
.stackable .card .content .header .popup {
text-align: left;
color: #000 !important;
text-shadow: 0 0 0 #333 !important;
font-weight: 100 !important
}
.ui.menu .item>img:not(.ui) {
display: none
}
#app .accordion .content .card:not(:first-child) {
margin-left: 10px
}
.ui.menu .container .item {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.right.menu .positive {
background: #e6eef4 !important;
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.service-status .table {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff;
color: #787878 !important;
font-weight: 500
}
.celled .aligned .thirteen .fine {
width: 95% !important
}
.celled .aligned .thirteen .fine small {
color: #eee !important;
text-shadow: 0 0 #fff
}
.service-status>h2 {
text-shadow: 2px 2px 3px #c4cacf, -2px -2px 3px #fff
}
.ui.success.message {
border-radius: 11px !important;
background: #e6eef4 !important;
box-shadow: 7px 7px 15px #cfd6dc, -7px -7px 15px #fdffff !important;
color: #1a531b !important
}
.ui.error.message {
border-radius: 11px !important;
background: #e6eef4 !important;
box-shadow: 7px 7px 15px #cfd6dc, -7px -7px 15px #fdffff !important;
color: red !important
}
.ui.warning.message {
border-radius: 11px !important;
background: #e6eef4 !important;
box-shadow: 7px 7px 15px #cfd6dc, -7px -7px 15px #fdffff !important;
color: #f7c709 !important
}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
footer{background-color:#2f2f2f;color:#f2f2f2;font-size:14px}footer .footer-container{display:flex;justify-content:center;flex-direction:column;text-align:center;padding:1rem}footer .footer-container p{width:100%;margin-top:1rem}footer .footer-container a{color:#f2f2f2}footer .footer-container div{width:100%}*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;text-decoration:none}body{font-family:Microsoft Yahei,Avenir,Segoe UI,Hiragino Sans GB,STHeiti,Microsoft Sans Serif,WenQuanYi Micro Hei,sans-serif;overflow-x:hidden;min-height:100vh;display:grid;grid-template-rows:1fr auto;background-color:#334561;color:#e1e1e1}article{display:flex;justify-content:center;align-items:center}.passwd-container{display:grid;min-height:320px;background-color:#e5e5e5;color:#121212;border-radius:5px;padding:1em 1.2em;box-shadow:0 2px 5px rgba(0,0,0,.3);width:100%;max-width:400px;width:calc(100% - 2em);margin:0 auto}.passwd-container input[type=password]{border:1px solid #a6a6a6;border-radius:4px;font-size:1em;padding-left:2em;min-width:100px;height:3em}.passwd-container input[type=password]::placeholder{text-align:right}.passwd-container button{margin-top:1em;margin-bottom:2em;border:none;background:none;border:1px solid #a6a6a6;border-radius:4px;background-color:#1670c5;color:#f2f2f2;font-size:1em;font-weight:bold;letter-spacing:1px;cursor:pointer;padding:.5em 0}.passwd-container button:hover{background-color:#1e85e6}h2{font-size:2em;text-align:center;color:#3c3c3c}h4{text-align:left;font-size:1em;font-weight:normal;letter-spacing:1px;height:1.5em}form{display:grid;position:relative}.passwd-icon{height:1em;width:1.34em;position:absolute;top:42px;left:10px}.passwd-icon g{fill:#494949}.logo{display:flex;align-items:center;justify-content:center;font-size:1.2em}.logo a{color:#3c3c3c;font-weight:bold}.logo a+a{margin-left:.8em}/*# sourceMappingURL=passwd.css.map */

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Some files were not shown because too many files have changed in this diff Show More