Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daab64d232 | ||
|
|
da8fb57268 | ||
|
|
fda0dad5f1 | ||
|
|
c6fb3196ea | ||
|
|
711d162a46 | ||
|
|
d667ce8afe | ||
|
|
6abc0fce51 | ||
|
|
b1d77a1d27 |
@@ -72,6 +72,7 @@ You can change the dashboard language in the settings page (`/setting`) after th
|
|||||||
<a href="https://github.com/acgpiano" title="Acgpiano"><img src="https://avatars.githubusercontent.com/u/15900800?v=4" width="50;" alt="Acgpiano"/></a>
|
<a href="https://github.com/acgpiano" title="Acgpiano"><img src="https://avatars.githubusercontent.com/u/15900800?v=4" width="50;" alt="Acgpiano"/></a>
|
||||||
<a href="https://github.com/eya46" title="eya46"><img src="https://avatars.githubusercontent.com/u/61458340?v=4" width="50;" alt="eya46"/></a>
|
<a href="https://github.com/eya46" title="eya46"><img src="https://avatars.githubusercontent.com/u/61458340?v=4" width="50;" alt="eya46"/></a>
|
||||||
<a href="https://github.com/guoyongchang" title="guoyongchang"><img src="https://avatars.githubusercontent.com/u/10484506?v=4" width="50;" alt="guoyongchang"/></a>
|
<a href="https://github.com/guoyongchang" title="guoyongchang"><img src="https://avatars.githubusercontent.com/u/10484506?v=4" width="50;" alt="guoyongchang"/></a>
|
||||||
|
<a href="https://github.com/hiDandelion" title="hiDandelion"><img src="https://avatars.githubusercontent.com/u/77157418?v=4" width="50;" alt="hiDandelion"/></a>
|
||||||
<a href="https://github.com/yuanweize" title="I"><img src="https://avatars.githubusercontent.com/u/30067203?v=4" width="50;" alt="I"/></a>
|
<a href="https://github.com/yuanweize" title="I"><img src="https://avatars.githubusercontent.com/u/30067203?v=4" width="50;" alt="I"/></a>
|
||||||
<a href="https://github.com/lvyaoting" title="lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50;" alt="lvyaoting"/></a>
|
<a href="https://github.com/lvyaoting" title="lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50;" alt="lvyaoting"/></a>
|
||||||
<a href="https://github.com/unclezs" title="unclezs"><img src="https://avatars.githubusercontent.com/u/42318775?v=4" width="50;" alt="unclezs"/></a>
|
<a href="https://github.com/unclezs" title="unclezs"><img src="https://avatars.githubusercontent.com/u/42318775?v=4" width="50;" alt="unclezs"/></a>
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ func (p *commonPage) service(c *gin.Context) {
|
|||||||
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
|
"Title": singleton.Localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "ServicesStatus"}),
|
||||||
"Services": res.([]interface{})[0],
|
"Services": res.([]interface{})[0],
|
||||||
"CycleTransferStats": res.([]interface{})[1],
|
"CycleTransferStats": res.([]interface{})[1],
|
||||||
"CustomCode": singleton.Conf.Site.CustomCode,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +203,6 @@ func (cp *commonPage) network(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, mygin.GetPreferredTheme(c, "/network"), mygin.CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, mygin.GetPreferredTheme(c, "/network"), mygin.CommonEnvironment(c, gin.H{
|
||||||
"Servers": string(serversBytes),
|
"Servers": string(serversBytes),
|
||||||
"MonitorInfos": string(monitorInfos),
|
"MonitorInfos": string(monitorInfos),
|
||||||
"CustomCode": singleton.Conf.Site.CustomCode,
|
|
||||||
"MaxTCPPingValue": singleton.Conf.MaxTCPPingValue,
|
"MaxTCPPingValue": singleton.Conf.MaxTCPPingValue,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -254,8 +252,7 @@ func (cp *commonPage) home(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.HTML(http.StatusOK, mygin.GetPreferredTheme(c, "/home"), mygin.CommonEnvironment(c, gin.H{
|
c.HTML(http.StatusOK, mygin.GetPreferredTheme(c, "/home"), mygin.CommonEnvironment(c, gin.H{
|
||||||
"Servers": string(stat),
|
"Servers": string(stat),
|
||||||
"CustomCode": singleton.Conf.Site.CustomCode,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,20 +35,27 @@ func ServeWeb(port uint) *http.Server {
|
|||||||
pprof.Register(r)
|
pprof.Register(r)
|
||||||
}
|
}
|
||||||
r.Use(natGateway)
|
r.Use(natGateway)
|
||||||
tmpl := template.New("").Funcs(funcMap)
|
if os.Getenv("NZ_LOCAL_TEMPLATE") == "true" {
|
||||||
var err error
|
r.SetFuncMap(funcMap)
|
||||||
tmpl, err = tmpl.ParseFS(resource.TemplateFS, "template/**/*.html")
|
r.Use(mygin.RecordPath)
|
||||||
if err != nil {
|
r.Static("/static", "resource/static")
|
||||||
panic(err)
|
r.LoadHTMLGlob("resource/template/**/*.html")
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
|
staticFs, err := fs.Sub(resource.StaticFS, "static")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
r.StaticFS("/static", http.FS(staticFs))
|
||||||
}
|
}
|
||||||
tmpl = loadThirdPartyTemplates(tmpl)
|
|
||||||
r.SetHTMLTemplate(tmpl)
|
|
||||||
r.Use(mygin.RecordPath)
|
|
||||||
staticFs, err := fs.Sub(resource.StaticFS, "static")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
r.StaticFS("/static", http.FS(staticFs))
|
|
||||||
r.Static("/static-custom", "resource/static/custom")
|
r.Static("/static-custom", "resource/static/custom")
|
||||||
routers(r)
|
routers(r)
|
||||||
page404 := func(c *gin.Context) {
|
page404 := func(c *gin.Context) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -384,6 +385,7 @@ func (ma *memberAPI) addOrEditServer(c *gin.Context) {
|
|||||||
} else {
|
} else {
|
||||||
s.Host = &model.Host{}
|
s.Host = &model.Host{}
|
||||||
s.State = &model.HostState{}
|
s.State = &model.HostState{}
|
||||||
|
s.TaskCloseLock = new(sync.Mutex)
|
||||||
singleton.ServerLock.Lock()
|
singleton.ServerLock.Lock()
|
||||||
singleton.SecretToID[s.Secret] = s.ID
|
singleton.SecretToID[s.Secret] = s.ID
|
||||||
singleton.ServerList[s.ID] = &s
|
singleton.ServerList[s.ID] = &s
|
||||||
@@ -906,6 +908,7 @@ type settingForm struct {
|
|||||||
Theme string
|
Theme string
|
||||||
DashboardTheme string
|
DashboardTheme string
|
||||||
CustomCode string
|
CustomCode string
|
||||||
|
CustomCodeDashboard string
|
||||||
ViewPassword string
|
ViewPassword string
|
||||||
IgnoredIPNotification string
|
IgnoredIPNotification string
|
||||||
IPChangeNotificationTag string // IP变更提醒的通知组
|
IPChangeNotificationTag string // IP变更提醒的通知组
|
||||||
@@ -971,6 +974,7 @@ func (ma *memberAPI) updateSetting(c *gin.Context) {
|
|||||||
singleton.Conf.Site.Theme = sf.Theme
|
singleton.Conf.Site.Theme = sf.Theme
|
||||||
singleton.Conf.Site.DashboardTheme = sf.DashboardTheme
|
singleton.Conf.Site.DashboardTheme = sf.DashboardTheme
|
||||||
singleton.Conf.Site.CustomCode = sf.CustomCode
|
singleton.Conf.Site.CustomCode = sf.CustomCode
|
||||||
|
singleton.Conf.Site.CustomCodeDashboard = sf.CustomCodeDashboard
|
||||||
singleton.Conf.Site.ViewPassword = sf.ViewPassword
|
singleton.Conf.Site.ViewPassword = sf.ViewPassword
|
||||||
singleton.Conf.Oauth2.Admin = sf.Admin
|
singleton.Conf.Oauth2.Admin = sf.Admin
|
||||||
// 保证NotificationTag不为空
|
// 保证NotificationTag不为空
|
||||||
|
|||||||
+7
-6
@@ -80,12 +80,13 @@ type Config struct {
|
|||||||
Debug bool // debug模式开关
|
Debug bool // debug模式开关
|
||||||
Language string // 系统语言,默认 zh-CN
|
Language string // 系统语言,默认 zh-CN
|
||||||
Site struct {
|
Site struct {
|
||||||
Brand string // 站点名称
|
Brand string // 站点名称
|
||||||
CookieName string // 浏览器 Cookie 名称
|
CookieName string // 浏览器 Cookie 名称
|
||||||
Theme string
|
Theme string
|
||||||
DashboardTheme string
|
DashboardTheme string
|
||||||
CustomCode string
|
CustomCode string
|
||||||
ViewPassword string // 前台查看密码
|
CustomCodeDashboard string
|
||||||
|
ViewPassword string // 前台查看密码
|
||||||
}
|
}
|
||||||
Oauth2 struct {
|
Oauth2 struct {
|
||||||
Type string
|
Type string
|
||||||
|
|||||||
@@ -170,14 +170,23 @@ func (ns *NotificationServerBundle) replaceParamsInString(str string, message st
|
|||||||
|
|
||||||
if ns.Server != nil {
|
if ns.Server != nil {
|
||||||
str = strings.ReplaceAll(str, "#SERVER.NAME#", mod(ns.Server.Name))
|
str = strings.ReplaceAll(str, "#SERVER.NAME#", mod(ns.Server.Name))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.ID#", mod(fmt.Sprintf("%d", ns.Server.ID)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.CPU#", mod(fmt.Sprintf("%f", ns.Server.State.CPU)))
|
str = strings.ReplaceAll(str, "#SERVER.CPU#", mod(fmt.Sprintf("%f", ns.Server.State.CPU)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.MEM#", mod(fmt.Sprintf("%d", ns.Server.State.MemUsed)))
|
str = strings.ReplaceAll(str, "#SERVER.MEM#", mod(fmt.Sprintf("%d", ns.Server.State.MemUsed)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.SWAP#", mod(fmt.Sprintf("%d", ns.Server.State.SwapUsed)))
|
str = strings.ReplaceAll(str, "#SERVER.SWAP#", mod(fmt.Sprintf("%d", ns.Server.State.SwapUsed)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.DISK#", mod(fmt.Sprintf("%d", ns.Server.State.DiskUsed)))
|
str = strings.ReplaceAll(str, "#SERVER.DISK#", mod(fmt.Sprintf("%d", ns.Server.State.DiskUsed)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.MEMUSED#", mod(fmt.Sprintf("%d", ns.Server.State.MemUsed)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.SWAPUSED#", mod(fmt.Sprintf("%d", ns.Server.State.SwapUsed)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.DISKUSED#", mod(fmt.Sprintf("%d", ns.Server.State.DiskUsed)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.MEMTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.MemTotal)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.SWAPTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.SwapTotal)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.DISKTOTAL#", mod(fmt.Sprintf("%d", ns.Server.Host.DiskTotal)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.NETINSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetInSpeed)))
|
str = strings.ReplaceAll(str, "#SERVER.NETINSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetInSpeed)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.NETOUTSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutSpeed)))
|
str = strings.ReplaceAll(str, "#SERVER.NETOUTSPEED#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutSpeed)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.TRANSFERIN#", mod(fmt.Sprintf("%d", ns.Server.State.NetInTransfer)))
|
str = strings.ReplaceAll(str, "#SERVER.TRANSFERIN#", mod(fmt.Sprintf("%d", ns.Server.State.NetInTransfer)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.TRANSFEROUT#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutTransfer)))
|
str = strings.ReplaceAll(str, "#SERVER.TRANSFEROUT#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutTransfer)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.NETINTRANSFER#", mod(fmt.Sprintf("%d", ns.Server.State.NetInTransfer)))
|
||||||
|
str = strings.ReplaceAll(str, "#SERVER.NETOUTTRANSFER#", mod(fmt.Sprintf("%d", ns.Server.State.NetOutTransfer)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.LOAD1#", mod(fmt.Sprintf("%f", ns.Server.State.Load1)))
|
str = strings.ReplaceAll(str, "#SERVER.LOAD1#", mod(fmt.Sprintf("%f", ns.Server.State.Load1)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.LOAD5#", mod(fmt.Sprintf("%f", ns.Server.State.Load5)))
|
str = strings.ReplaceAll(str, "#SERVER.LOAD5#", mod(fmt.Sprintf("%f", ns.Server.State.Load5)))
|
||||||
str = strings.ReplaceAll(str, "#SERVER.LOAD15#", mod(fmt.Sprintf("%f", ns.Server.State.Load15)))
|
str = strings.ReplaceAll(str, "#SERVER.LOAD15#", mod(fmt.Sprintf("%f", ns.Server.State.Load15)))
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ func execCase(t *testing.T, item testSt) {
|
|||||||
UdpConnCount: 0,
|
UdpConnCount: 0,
|
||||||
ProcessCount: 0,
|
ProcessCount: 0,
|
||||||
},
|
},
|
||||||
LastActive: time.Time{},
|
LastActive: time.Time{},
|
||||||
TaskClose: nil,
|
TaskClose: nil,
|
||||||
TaskStream: nil,
|
TaskStream: nil,
|
||||||
PrevHourlyTransferIn: 0,
|
PrevTransferInSnapshot: 0,
|
||||||
PrevHourlyTransferOut: 0,
|
PrevTransferOutSnapshot: 0,
|
||||||
}
|
}
|
||||||
ns := NotificationServerBundle{
|
ns := NotificationServerBundle{
|
||||||
Notification: &n,
|
Notification: &n,
|
||||||
|
|||||||
+5
-3
@@ -5,6 +5,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -103,21 +105,21 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
src = float64(server.LastActive.Unix())
|
src = float64(server.LastActive.Unix())
|
||||||
}
|
}
|
||||||
case "transfer_in_cycle":
|
case "transfer_in_cycle":
|
||||||
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(utils.Uint64SubInt64(server.State.NetInTransfer, server.PrevTransferInSnapshot))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
src += float64(res.N)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_out_cycle":
|
case "transfer_out_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
|
src = float64(utils.Uint64SubInt64(server.State.NetOutTransfer, server.PrevTransferOutSnapshot))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
src += float64(res.N)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_all_cycle":
|
case "transfer_all_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(utils.Uint64SubInt64(server.State.NetOutTransfer, server.PrevTransferOutSnapshot) + utils.Uint64SubInt64(server.State.NetInTransfer, server.PrevTransferInSnapshot))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
|
|||||||
+9
-6
@@ -3,6 +3,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/naiba/nezha/pkg/utils"
|
"github.com/naiba/nezha/pkg/utils"
|
||||||
@@ -27,11 +28,12 @@ type Server struct {
|
|||||||
State *HostState `gorm:"-"`
|
State *HostState `gorm:"-"`
|
||||||
LastActive time.Time `gorm:"-"`
|
LastActive time.Time `gorm:"-"`
|
||||||
|
|
||||||
TaskClose chan error `gorm:"-" json:"-"`
|
TaskClose chan error `gorm:"-" json:"-"`
|
||||||
TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
|
TaskCloseLock *sync.Mutex `gorm:"-" json:"-"`
|
||||||
|
TaskStream pb.NezhaService_RequestTaskServer `gorm:"-" json:"-"`
|
||||||
|
|
||||||
PrevHourlyTransferIn int64 `gorm:"-" json:"-"` // 上次数据点时的入站使用量
|
PrevTransferInSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的入站使用量
|
||||||
PrevHourlyTransferOut int64 `gorm:"-" json:"-"` // 上次数据点时的出站使用量
|
PrevTransferOutSnapshot int64 `gorm:"-" json:"-"` // 上次数据点时的出站使用量
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) CopyFromRunningServer(old *Server) {
|
func (s *Server) CopyFromRunningServer(old *Server) {
|
||||||
@@ -39,9 +41,10 @@ func (s *Server) CopyFromRunningServer(old *Server) {
|
|||||||
s.State = old.State
|
s.State = old.State
|
||||||
s.LastActive = old.LastActive
|
s.LastActive = old.LastActive
|
||||||
s.TaskClose = old.TaskClose
|
s.TaskClose = old.TaskClose
|
||||||
|
s.TaskCloseLock = old.TaskCloseLock
|
||||||
s.TaskStream = old.TaskStream
|
s.TaskStream = old.TaskStream
|
||||||
s.PrevHourlyTransferIn = old.PrevHourlyTransferIn
|
s.PrevTransferInSnapshot = old.PrevTransferInSnapshot
|
||||||
s.PrevHourlyTransferOut = old.PrevHourlyTransferOut
|
s.PrevTransferOutSnapshot = old.PrevTransferOutSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolToString(b bool) string {
|
func boolToString(b bool) string {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ func CommonEnvironment(c *gin.Context, data map[string]interface{}) gin.H {
|
|||||||
data["Version"] = singleton.Version
|
data["Version"] = singleton.Version
|
||||||
data["Conf"] = singleton.Conf
|
data["Conf"] = singleton.Conf
|
||||||
data["Themes"] = model.Themes
|
data["Themes"] = model.Themes
|
||||||
|
data["CustomCode"] = singleton.Conf.Site.CustomCode
|
||||||
|
data["CustomCodeDashboard"] = singleton.Conf.Site.CustomCodeDashboard
|
||||||
// 是否是管理页面
|
// 是否是管理页面
|
||||||
data["IsAdminPage"] = adminPage[data["MatchedPath"].(string)]
|
data["IsAdminPage"] = adminPage[data["MatchedPath"].(string)]
|
||||||
// 站点标题
|
// 站点标题
|
||||||
|
|||||||
@@ -37,8 +37,7 @@ func ValidateViewPassword(opt ValidateViewPasswordOption) gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
if opt.IsPage {
|
if opt.IsPage {
|
||||||
c.HTML(http.StatusOK, GetPreferredTheme(c, "/viewpassword"), CommonEnvironment(c, gin.H{
|
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"}),
|
||||||
"CustomCode": singleton.Conf.Site.CustomCode,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -76,3 +76,13 @@ func GenerateRandomString(n int) (string, error) {
|
|||||||
}
|
}
|
||||||
return string(ret), nil
|
return string(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Uint64SubInt64(a uint64, b int64) uint64 {
|
||||||
|
if b < 0 {
|
||||||
|
return a + uint64(-b)
|
||||||
|
}
|
||||||
|
if a < uint64(b) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return a - uint64(b)
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+3
@@ -331,6 +331,9 @@ other = "Frontend Theme"
|
|||||||
[CustomCodes]
|
[CustomCodes]
|
||||||
other = "Custom Codes (Style and Script)"
|
other = "Custom Codes (Style and Script)"
|
||||||
|
|
||||||
|
[CustomCodesDashboard]
|
||||||
|
other = "Custom Codes for Dashboard"
|
||||||
|
|
||||||
[AccessPassword]
|
[AccessPassword]
|
||||||
other = "Frontend Access Password"
|
other = "Frontend Access Password"
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -331,6 +331,9 @@ other = "Tema de Frontend"
|
|||||||
[CustomCodes]
|
[CustomCodes]
|
||||||
other = "Códigos Personalizados (Incluye style y script)"
|
other = "Códigos Personalizados (Incluye style y script)"
|
||||||
|
|
||||||
|
[CustomCodesDashboard]
|
||||||
|
other = "Custom Codes for Dashboard"
|
||||||
|
|
||||||
[AccessPassword]
|
[AccessPassword]
|
||||||
other = "Contraseña de Acceso al Frontend"
|
other = "Contraseña de Acceso al Frontend"
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -331,6 +331,9 @@ other = "前台界面主题"
|
|||||||
[CustomCodes]
|
[CustomCodes]
|
||||||
other = "自定义代码(包括 style 和 script)"
|
other = "自定义代码(包括 style 和 script)"
|
||||||
|
|
||||||
|
[CustomCodesDashboard]
|
||||||
|
other = "Custom Codes for Dashboard"
|
||||||
|
|
||||||
[AccessPassword]
|
[AccessPassword]
|
||||||
other = "前台访问密码"
|
other = "前台访问密码"
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -331,6 +331,9 @@ other = "前台界面主題"
|
|||||||
[CustomCodes]
|
[CustomCodes]
|
||||||
other = "自定義代碼(包括 style 和 script)"
|
other = "自定義代碼(包括 style 和 script)"
|
||||||
|
|
||||||
|
[CustomCodesDashboard]
|
||||||
|
other = "Custom Codes for Dashboard"
|
||||||
|
|
||||||
[AccessPassword]
|
[AccessPassword]
|
||||||
other = "前台訪問密碼"
|
other = "前台訪問密碼"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
.ui.container {
|
||||||
|
width: 95vw !important;
|
||||||
|
max-width: 1680px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[nz-theme='dark'] {
|
||||||
|
body {
|
||||||
|
background-color: #121212 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.menu {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.menu * {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion .title {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.card {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.popup {
|
||||||
|
background-color: #575757 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.table {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui thead th {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.buttons .button {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.modal {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.modal * {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
.dropdown {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.message {
|
||||||
|
background-color: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.dropdown .menu {
|
||||||
|
background-color: #575757 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.modal>.header {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.modal>.content {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.modal>.actions {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#alert {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.form .field>label {
|
||||||
|
color: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.segment {
|
||||||
|
background-color: #3f3f3f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.segment textarea,
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
.dropdown {
|
||||||
|
background-color: #575757 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
form label {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.inverted.segment {
|
||||||
|
background-color: #121212 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.inverted.segment * {
|
||||||
|
color: #8b8b8b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu .dropdown {
|
||||||
|
background-color: #282828 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui.menu .ui.dropdown .menu>.item {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login .ui.message{
|
||||||
|
color: #8b8b8b !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
-51
@@ -1,46 +1,54 @@
|
|||||||
/* 屏幕适配 */
|
/* 屏幕适配 */
|
||||||
@media only screen and (min-width:1200px) {
|
@media only screen and (min-width:1200px) {
|
||||||
.ui.container {
|
.ui.container {
|
||||||
width:95% !important;
|
width: 95% !important;
|
||||||
font-size: 90% !important;
|
font-size: 90% !important;
|
||||||
max-width: 1300px !important;
|
max-width: 1300px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width:767px) {
|
@media only screen and (max-width:767px) {
|
||||||
.ui.card>.content>.header:not(.ui),.ui.cards>.card>.content>.header:not(.ui) {
|
|
||||||
margin-top:0.4em !important;
|
.ui.card>.content>.header:not(.ui),
|
||||||
|
.ui.cards>.card>.content>.header:not(.ui) {
|
||||||
|
margin-top: 0.4em !important;
|
||||||
}
|
}
|
||||||
.ui.menu .item>img:not(.ui){
|
|
||||||
|
.ui.menu .item>img:not(.ui) {
|
||||||
width: 2.2rem;
|
width: 2.2rem;
|
||||||
}
|
}
|
||||||
.ui.menu .item:before{
|
|
||||||
width:0.5px;
|
.ui.menu .item:before {
|
||||||
|
width: 0.5px;
|
||||||
}
|
}
|
||||||
.ui.menu .item{
|
|
||||||
|
.ui.menu .item {
|
||||||
padding: 0.9rem 0.55rem;
|
padding: 0.9rem 0.55rem;
|
||||||
}
|
}
|
||||||
.ui.large.menu{
|
|
||||||
|
.ui.large.menu {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i.icon {
|
i.icon {
|
||||||
color:#000;
|
color: #000;
|
||||||
width:1.2em !important;
|
width: 1.2em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.fi {
|
i.fi {
|
||||||
width:0.9em;
|
width: 0.9em;
|
||||||
margin:0px 6px 0px 2px;
|
margin: 0px 6px 0px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
content:" " !important;
|
content: " " !important;
|
||||||
background:fixed !important;
|
background: fixed !important;
|
||||||
z-index:-1 !important;
|
z-index: -1 !important;
|
||||||
top:0 !important;
|
top: 0 !important;
|
||||||
right:0 !important;
|
right: 0 !important;
|
||||||
bottom:0 !important;
|
bottom: 0 !important;
|
||||||
left:0 !important;
|
left: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
@@ -65,79 +73,80 @@ td {
|
|||||||
padding-top: unset;
|
padding-top: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login.nb-container > .grid {
|
.login.nb-container>.grid {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login.nb-container > .grid .column {
|
.login.nb-container>.grid .column {
|
||||||
max-width: 450px;
|
max-width: 450px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.menu .item-right:before{
|
.ui.menu .item-right:before {
|
||||||
width:0px;
|
width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .flag {
|
.status.cards .flag {
|
||||||
margin-right: 0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .header > .info.icon {
|
.status.cards .header>.info.icon {
|
||||||
float: right;
|
float: right;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.grid {
|
.ui.grid {
|
||||||
margin-bottom:-0.5em
|
margin-bottom: -0.5em
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.card>.content>.header:not(.ui), .ui.cards>.card>.content>.header:not(.ui){
|
.ui.card>.content>.header:not(.ui),
|
||||||
|
.ui.cards>.card>.content>.header:not(.ui) {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .wide.column {
|
.status.cards .wide.column {
|
||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
height:2.3rem !important;
|
height: 2.3rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .wide.column:nth-child(1) {
|
.status.cards .wide.column:nth-child(1) {
|
||||||
margin-top:1.2rem !important;
|
margin-top: 1.2rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .wide.column:nth-child(2) {
|
.status.cards .wide.column:nth-child(2) {
|
||||||
margin-top:1.2rem !important;
|
margin-top: 1.2rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .three.wide.column {
|
.status.cards .three.wide.column {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 22%!important;
|
width: 22% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .thirteen.wide.column{
|
.status.cards .thirteen.wide.column {
|
||||||
width: 78%!important;
|
width: 78% !important;
|
||||||
padding-left:0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .description {
|
.status.cards .description {
|
||||||
padding-bottom:0 !important;
|
padding-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .flag {
|
.status.cards .flag {
|
||||||
margin-right:0.5rem !important;
|
margin-right: 0.5rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .header > .info.icon {
|
.status.cards .header>.info.icon {
|
||||||
float: right;
|
float: right;
|
||||||
margin-right:0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.popup:before {
|
.ui.popup:before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.closePopup{
|
.closePopup {
|
||||||
color:rgb(10, 148, 242) !important;
|
color: rgb(10, 148, 242) !important;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
@@ -150,26 +159,26 @@ td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ui.content {
|
.ui.content {
|
||||||
margin:0 !important;
|
margin: 0 !important;
|
||||||
padding:1em !important;
|
padding: 1em !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .ui.content.popup {
|
.status.cards .ui.content.popup {
|
||||||
min-width:calc(100%)!important;
|
min-width: calc(100%) !important;
|
||||||
line-height:2rem !important;
|
line-height: 2rem !important;
|
||||||
border-radius:5px !important;
|
border-radius: 5px !important;
|
||||||
border:1px solid transparent !important;
|
border: 1px solid transparent !important;
|
||||||
font-family:Arial,Helvetica,sans-serif !important;
|
font-family: Arial, Helvetica, sans-serif !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status.cards .outline.icon {
|
.status.cards .outline.icon {
|
||||||
margin-right:1px !important;
|
margin-right: 1px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui.progress .bar {
|
.ui.progress .bar {
|
||||||
min-width:1.8em !important;
|
min-width: 1.8em !important;
|
||||||
border-radius:5px !important;
|
border-radius: 5px !important;
|
||||||
line-height:1.65em !important;
|
line-height: 1.65em !important;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 0.4em;
|
padding-right: 0.4em;
|
||||||
color: rgba(255, 255, 255, 0.7);
|
color: rgba(255, 255, 255, 0.7);
|
||||||
@@ -182,7 +191,7 @@ td {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.service-status .delay-today > i {
|
.service-status .delay-today>i {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 1.2em;
|
width: 1.2em;
|
||||||
height: 1.2em;
|
height: 1.2em;
|
||||||
|
|||||||
Vendored
+1
@@ -17,5 +17,6 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
Vendored
+6
-1
@@ -11,7 +11,12 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/semantic.min.css">
|
<link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/dist/semantic.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/assets/font-logos.css">
|
<link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/assets/font-logos.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/main.css?v2022042314">
|
<link rel="stylesheet" type="text/css" href="/static/main.css?v20240813">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/darkmode.css?v20240813">
|
||||||
|
<script>
|
||||||
|
document.documentElement.setAttribute('nz-theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
{{if ts .CustomCodeDashboard}} {{.CustomCodeDashboard|safe}} {{end}}
|
||||||
<body>
|
<body>
|
||||||
{{end}}
|
{{end}}
|
||||||
Vendored
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class=" actions">
|
<div class="actions">
|
||||||
<div class="ui negative button">{{tr "Cancel"}}</div>
|
<div class="ui negative button">{{tr "Cancel"}}</div>
|
||||||
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
+1
-1
@@ -60,7 +60,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=" actions">
|
<div class="actions">
|
||||||
<div class="ui negative button">{{tr "Cancel"}}</div>
|
<div class="ui negative button">{{tr "Cancel"}}</div>
|
||||||
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class=" actions">
|
<div class="actions">
|
||||||
<div class="ui negative button">{{tr "Cancel"}}</div>
|
<div class="ui negative button">{{tr "Cancel"}}</div>
|
||||||
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
<button class="ui positive nezha-primary-btn right labeled icon button">{{tr "Confirm"}}<i class="checkmark icon"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{tr "Token"}}</th>
|
<th>{{tr "Token"}}</th>
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="ui very basic table">
|
<table class="ui basic table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th><button onclick="checkAllServer()" class="ui mini nezha-primary-btn button">{{tr "SelectAll"}}</button></th>
|
<th><button onclick="checkAllServer()" class="ui mini nezha-primary-btn button">{{tr "SelectAll"}}</button></th>
|
||||||
|
|||||||
+7
-3
@@ -41,6 +41,10 @@
|
|||||||
<label>{{tr "CustomCodes"}}</label>
|
<label>{{tr "CustomCodes"}}</label>
|
||||||
<textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
|
<textarea name="CustomCode">{{.Conf.Site.CustomCode}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>{{tr "CustomCodesDashboard"}}</label>
|
||||||
|
<textarea name="CustomCodeDashboard">{{.Conf.Site.CustomCodeDashboard}}</textarea>
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>{{tr "AccessPassword"}}</label>
|
<label>{{tr "AccessPassword"}}</label>
|
||||||
<input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
|
<input type="text" name="ViewPassword" placeholder="" value="{{.Conf.Site.ViewPassword}}">
|
||||||
@@ -128,13 +132,13 @@
|
|||||||
})
|
})
|
||||||
$('.checkbox').checkbox()
|
$('.checkbox').checkbox()
|
||||||
$('#settingForm').find("select[name=Cover]").val({{.Conf.Cover }});
|
$('#settingForm').find("select[name=Cover]").val({{.Conf.Cover }});
|
||||||
{{if .Conf.EnableIPChangeNotification}}
|
{{ if .Conf.EnableIPChangeNotification}}
|
||||||
$('.checkbox.ip-change').checkbox('set checked')
|
$('.checkbox.ip-change').checkbox('set checked')
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{if .Conf.EnablePlainIPInNotification}}
|
{{ if .Conf.EnablePlainIPInNotification}}
|
||||||
$('.checkbox.plain-ip').checkbox('set checked')
|
$('.checkbox.plain-ip').checkbox('set checked')
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{if .Conf.DisableSwitchTemplateInFrontend }}
|
{{ if .Conf.DisableSwitchTemplateInFrontend }}
|
||||||
$('.checkbox.disable-switch-template').checkbox('set checked')
|
$('.checkbox.disable-switch-template').checkbox('set checked')
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+11
-3
@@ -1,6 +1,7 @@
|
|||||||
{{define "dashboard-default/terminal"}}
|
{{define "dashboard-default/terminal"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Conf.Language}}">
|
<html lang="{{.Conf.Language}}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
@@ -23,16 +24,19 @@
|
|||||||
background-color: black;
|
background-color: black;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<body onresize="onResize()">
|
<body onresize="onResize()">
|
||||||
<div id="terminal-container"></div>
|
<div id="terminal-container"></div>
|
||||||
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
|
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
|
||||||
<script src="https://unpkg.com/@xterm/[email protected]/lib/addon-attach.js"></script>
|
|
||||||
<script src="https://unpkg.com/@xterm/[email protected]/lib/addon-fit.js"></script>
|
<script src="https://unpkg.com/@xterm/[email protected]/lib/addon-fit.js"></script>
|
||||||
|
<script src="https://unpkg.com/@xterm/[email protected]/lib/addon-web-links.js"></script>
|
||||||
|
<script src="https://unpkg.com/[email protected]/lib/trzsz.js"></script>
|
||||||
<script>
|
<script>
|
||||||
let sendResizing = false;
|
let sendResizing = false;
|
||||||
|
|
||||||
function doResize() {
|
function doResize() {
|
||||||
fitAddon.fit()
|
fitAddon.fit()
|
||||||
|
|
||||||
const w = fitAddon.proposeDimensions();
|
const w = fitAddon.proposeDimensions();
|
||||||
const prefix = new Int8Array([1]);
|
const prefix = new Int8Array([1]);
|
||||||
const resizeMessage = new TextEncoder().encode(JSON.stringify({
|
const resizeMessage = new TextEncoder().encode(JSON.stringify({
|
||||||
@@ -70,10 +74,13 @@
|
|||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
});
|
});
|
||||||
const socket = new WebSocket((window.location.protocol == 'https:' ? 'wss' : 'ws') + '://' + window.location.host + '/terminal/' + '{{.SessionID}}');
|
const socket = new WebSocket((window.location.protocol == 'https:' ? 'wss' : 'ws') + '://' + window.location.host + '/terminal/' + '{{.SessionID}}');
|
||||||
const attachAddon = new AttachAddon.AttachAddon(socket);
|
socket.binaryType = 'arraybuffer';
|
||||||
|
|
||||||
|
const trzszAddon = new TrzszAddon(socket);
|
||||||
|
term.loadAddon(trzszAddon);
|
||||||
const fitAddon = new FitAddon.FitAddon();
|
const fitAddon = new FitAddon.FitAddon();
|
||||||
term.loadAddon(attachAddon);
|
|
||||||
term.loadAddon(fitAddon);
|
term.loadAddon(fitAddon);
|
||||||
|
|
||||||
term.open(document.getElementById('terminal-container'));
|
term.open(document.getElementById('terminal-container'));
|
||||||
|
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
@@ -90,5 +97,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
+2
-2
@@ -10,8 +10,8 @@
|
|||||||
{{ if not .Conf.DisableSwitchTemplateInFrontend }}
|
{{ if not .Conf.DisableSwitchTemplateInFrontend }}
|
||||||
<script>
|
<script>
|
||||||
function showSwitchTemplate(list, currentBackendTheme) {
|
function showSwitchTemplate(list, currentBackendTheme) {
|
||||||
console.log(list, currentBackendTheme);
|
// console.log(list, currentBackendTheme);
|
||||||
console.log("currentBackendTheme:",currentBackendTheme);
|
// console.log("currentBackendTheme:",currentBackendTheme);
|
||||||
}
|
}
|
||||||
showSwitchTemplate({{ .Themes }}, {{ .Conf.Site.Theme }})
|
showSwitchTemplate({{ .Themes }}, {{ .Conf.Site.Theme }})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+7
-2
@@ -1,6 +1,7 @@
|
|||||||
{{define "theme-default/header"}}
|
{{define "theme-default/header"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{.Conf.Language}}">
|
<html lang="{{.Conf.Language}}">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
@@ -14,13 +15,17 @@
|
|||||||
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/flag-icons.min.css">
|
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/flag-icons.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
<link rel="stylesheet" type="text/css" href="/static/semantic-ui-alerts.min.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/theme-default/css/main.css?v20240616">
|
<link rel="stylesheet" type="text/css" href="/static/theme-default/css/main.css?v20240616">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/darkmode.css?v20240813">
|
||||||
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/jquery.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/dist/semantic.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/semantic.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
|
||||||
<script src="/static/semantic-ui-alerts.min.js"></script>
|
<script src="/static/semantic-ui-alerts.min.js"></script>
|
||||||
<script src="/static/theme-default/js/mixin.js?v20240302"></script>
|
<script src="/static/theme-default/js/mixin.js?v20240302"></script>
|
||||||
|
<script>
|
||||||
|
document.documentElement.setAttribute('nz-theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{{end}}
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<div ref="chartDom" style="border-radius: 28px; margin-top: 15px;height: 520px;max-width: 1400px;overflow: hidden"></div>
|
<div ref="chartDom" style="border-radius: 28px; margin-top: 15px;height: 520px;overflow: hidden"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
+16
-12
@@ -90,12 +90,14 @@ func (s *NezhaHandler) RequestTask(h *pb.Host, stream pb.NezhaService_RequestTas
|
|||||||
}
|
}
|
||||||
closeCh := make(chan error)
|
closeCh := make(chan error)
|
||||||
singleton.ServerLock.RLock()
|
singleton.ServerLock.RLock()
|
||||||
|
singleton.ServerList[clientID].TaskCloseLock.Lock()
|
||||||
// 修复不断的请求 task 但是没有 return 导致内存泄漏
|
// 修复不断的请求 task 但是没有 return 导致内存泄漏
|
||||||
if singleton.ServerList[clientID].TaskClose != nil {
|
if singleton.ServerList[clientID].TaskClose != nil {
|
||||||
close(singleton.ServerList[clientID].TaskClose)
|
close(singleton.ServerList[clientID].TaskClose)
|
||||||
}
|
}
|
||||||
singleton.ServerList[clientID].TaskStream = stream
|
singleton.ServerList[clientID].TaskStream = stream
|
||||||
singleton.ServerList[clientID].TaskClose = closeCh
|
singleton.ServerList[clientID].TaskClose = closeCh
|
||||||
|
singleton.ServerList[clientID].TaskCloseLock.Unlock()
|
||||||
singleton.ServerLock.RUnlock()
|
singleton.ServerLock.RUnlock()
|
||||||
return <-closeCh
|
return <-closeCh
|
||||||
}
|
}
|
||||||
@@ -112,10 +114,10 @@ func (s *NezhaHandler) ReportSystemState(c context.Context, r *pb.State) (*pb.Re
|
|||||||
singleton.ServerList[clientID].LastActive = time.Now()
|
singleton.ServerList[clientID].LastActive = time.Now()
|
||||||
singleton.ServerList[clientID].State = &state
|
singleton.ServerList[clientID].State = &state
|
||||||
|
|
||||||
// 如果从未记录过,先打点,等到小时时间点时入库
|
// 应对 dashboard 重启的情况,如果从未记录过,先打点,等到小时时间点时入库
|
||||||
if singleton.ServerList[clientID].PrevHourlyTransferIn == 0 || singleton.ServerList[clientID].PrevHourlyTransferOut == 0 {
|
if singleton.ServerList[clientID].PrevTransferInSnapshot == 0 || singleton.ServerList[clientID].PrevTransferOutSnapshot == 0 {
|
||||||
singleton.ServerList[clientID].PrevHourlyTransferIn = int64(state.NetInTransfer)
|
singleton.ServerList[clientID].PrevTransferInSnapshot = int64(state.NetInTransfer)
|
||||||
singleton.ServerList[clientID].PrevHourlyTransferOut = int64(state.NetOutTransfer)
|
singleton.ServerList[clientID].PrevTransferOutSnapshot = int64(state.NetOutTransfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &pb.Receipt{Proced: true}, nil
|
return &pb.Receipt{Proced: true}, nil
|
||||||
@@ -135,9 +137,8 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
|
|||||||
// 检查并更新DDNS
|
// 检查并更新DDNS
|
||||||
if singleton.Conf.DDNS.Enable &&
|
if singleton.Conf.DDNS.Enable &&
|
||||||
singleton.ServerList[clientID].EnableDDNS &&
|
singleton.ServerList[clientID].EnableDDNS &&
|
||||||
singleton.ServerList[clientID].Host != nil &&
|
|
||||||
host.IP != "" &&
|
host.IP != "" &&
|
||||||
singleton.ServerList[clientID].Host.IP != host.IP {
|
(singleton.ServerList[clientID].Host == nil || singleton.ServerList[clientID].Host.IP != host.IP) {
|
||||||
serverDomain := singleton.ServerList[clientID].DDNSDomain
|
serverDomain := singleton.ServerList[clientID].DDNSDomain
|
||||||
if singleton.Conf.DDNS.Provider == "" {
|
if singleton.Conf.DDNS.Provider == "" {
|
||||||
provider, err = singleton.GetDDNSProviderFromProfile(singleton.ServerList[clientID].DDNSProfile)
|
provider, err = singleton.GetDDNSProviderFromProfile(singleton.ServerList[clientID].DDNSProfile)
|
||||||
@@ -164,10 +165,9 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送IP变动通知
|
// 发送IP变动通知
|
||||||
if singleton.Conf.EnableIPChangeNotification &&
|
if singleton.ServerList[clientID].Host != nil && singleton.Conf.EnableIPChangeNotification &&
|
||||||
((singleton.Conf.Cover == model.ConfigCoverAll && !singleton.Conf.IgnoredIPNotificationServerIDs[clientID]) ||
|
((singleton.Conf.Cover == model.ConfigCoverAll && !singleton.Conf.IgnoredIPNotificationServerIDs[clientID]) ||
|
||||||
(singleton.Conf.Cover == model.ConfigCoverIgnoreAll && singleton.Conf.IgnoredIPNotificationServerIDs[clientID])) &&
|
(singleton.Conf.Cover == model.ConfigCoverIgnoreAll && singleton.Conf.IgnoredIPNotificationServerIDs[clientID])) &&
|
||||||
singleton.ServerList[clientID].Host != nil &&
|
|
||||||
singleton.ServerList[clientID].Host.IP != "" &&
|
singleton.ServerList[clientID].Host.IP != "" &&
|
||||||
host.IP != "" &&
|
host.IP != "" &&
|
||||||
singleton.ServerList[clientID].Host.IP != host.IP {
|
singleton.ServerList[clientID].Host.IP != host.IP {
|
||||||
@@ -184,10 +184,14 @@ func (s *NezhaHandler) ReportSystemInfo(c context.Context, r *pb.Host) (*pb.Rece
|
|||||||
nil)
|
nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否是机器重启,如果是机器重启要录入最后记录的流量里面
|
/**
|
||||||
if singleton.ServerList[clientID].Host.BootTime < host.BootTime {
|
* 这里的 singleton 中的数据都是关机前的旧数据
|
||||||
singleton.ServerList[clientID].PrevHourlyTransferIn = singleton.ServerList[clientID].PrevHourlyTransferIn - int64(singleton.ServerList[clientID].State.NetInTransfer)
|
* 当 agent 重启时,bootTime 变大,agent 端会先上报 host 信息,然后上报 state 信息
|
||||||
singleton.ServerList[clientID].PrevHourlyTransferOut = singleton.ServerList[clientID].PrevHourlyTransferOut - int64(singleton.ServerList[clientID].State.NetOutTransfer)
|
* 这是可以借助上报顺序的空档,将停机前的流量统计数据标记下来,加到下一个小时的数据点上
|
||||||
|
*/
|
||||||
|
if singleton.ServerList[clientID].Host != nil && singleton.ServerList[clientID].Host.BootTime < host.BootTime {
|
||||||
|
singleton.ServerList[clientID].PrevTransferInSnapshot = singleton.ServerList[clientID].PrevTransferInSnapshot - int64(singleton.ServerList[clientID].State.NetInTransfer)
|
||||||
|
singleton.ServerList[clientID].PrevTransferOutSnapshot = singleton.ServerList[clientID].PrevTransferOutSnapshot - int64(singleton.ServerList[clientID].State.NetOutTransfer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不要冲掉国家码
|
// 不要冲掉国家码
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ func loadServers() {
|
|||||||
innerS := s
|
innerS := s
|
||||||
innerS.Host = &model.Host{}
|
innerS.Host = &model.Host{}
|
||||||
innerS.State = &model.HostState{}
|
innerS.State = &model.HostState{}
|
||||||
|
innerS.TaskCloseLock = new(sync.Mutex)
|
||||||
ServerList[innerS.ID] = &innerS
|
ServerList[innerS.ID] = &innerS
|
||||||
SecretToID[innerS.Secret] = innerS.ID
|
SecretToID[innerS.Secret] = innerS.ID
|
||||||
ServerTagToIDList[innerS.Tag] = append(ServerTagToIDList[innerS.Tag], innerS.ID)
|
ServerTagToIDList[innerS.Tag] = append(ServerTagToIDList[innerS.Tag], innerS.ID)
|
||||||
|
|||||||
@@ -100,14 +100,14 @@ func RecordTransferHourlyUsage() {
|
|||||||
for id, server := range ServerList {
|
for id, server := range ServerList {
|
||||||
tx := model.Transfer{
|
tx := model.Transfer{
|
||||||
ServerID: id,
|
ServerID: id,
|
||||||
In: server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn),
|
In: utils.Uint64SubInt64(server.State.NetInTransfer, server.PrevTransferInSnapshot),
|
||||||
Out: server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut),
|
Out: utils.Uint64SubInt64(server.State.NetOutTransfer, server.PrevTransferOutSnapshot),
|
||||||
}
|
}
|
||||||
if tx.In == 0 && tx.Out == 0 {
|
if tx.In == 0 && tx.Out == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
server.PrevHourlyTransferIn = int64(server.State.NetInTransfer)
|
server.PrevTransferInSnapshot = int64(server.State.NetInTransfer)
|
||||||
server.PrevHourlyTransferOut = int64(server.State.NetOutTransfer)
|
server.PrevTransferOutSnapshot = int64(server.State.NetOutTransfer)
|
||||||
tx.CreatedAt = nowTrimSeconds
|
tx.CreatedAt = nowTrimSeconds
|
||||||
txs = append(txs, tx)
|
txs = append(txs, tx)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user