2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 17:17:13 +08:00

feat: home page

This commit is contained in:
耗子
2023-06-22 23:00:33 +08:00
parent 43a44b08b8
commit 674586b844
16 changed files with 298 additions and 315 deletions

View File

@@ -44,14 +44,9 @@ func (receiver *Monitoring) Handle(ctx console.Context) error {
return nil
}
info, err := helpers.GetMonitoringInfo()
if err != nil {
facades.Log().Errorf("[面板] 系统监控失败: %s", err.Error())
color.Redf("[面板] 系统监控失败: %s", err.Error())
return nil
}
info := helpers.GetMonitoringInfo()
err = facades.Orm().Query().Create(&models.Monitor{
err := facades.Orm().Query().Create(&models.Monitor{
Info: info,
})
if err != nil {

View File

@@ -97,12 +97,14 @@ func (receiver *Panel) Handle(ctx console.Context) error {
return nil
}
color.Greenln("用户名: " + user.Username)
color.Greenln("密码: " + password)
nginxConf, err := os.ReadFile("/www/server/nginx/conf/nginx.conf")
if err != nil {
color.Redln("获取面板端口失败请检查Nginx主配置文件")
return nil
}
match := regexp.MustCompile(`listen\s+(\d+)`).FindStringSubmatch(string(nginxConf))
if len(match) < 2 {
color.Redln("获取面板端口失败请检查Nginx主配置文件")
@@ -110,8 +112,6 @@ func (receiver *Panel) Handle(ctx console.Context) error {
}
port := match[1]
color.Greenln("用户名: " + user.Username)
color.Greenln("密码: " + password)
color.Greenln("面板端口: " + port)
case "getPort":

View File

@@ -2,7 +2,7 @@ package controllers
import "github.com/goravel/framework/contracts/http"
func Success(ctx http.Context, data http.Json) {
func Success(ctx http.Context, data any) {
ctx.Response().Success().Json(http.Json{
"code": 0,
"message": "success",

View File

@@ -1,12 +1,22 @@
package controllers
import (
"fmt"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"panel/app/models"
"panel/packages/helpers"
)
type MenuItem struct {
Name string `json:"name"`
Title string `json:"title"`
Icon string `json:"icon"`
Jump string `json:"jump"`
}
type InfoController struct {
//Dependent services
}
@@ -30,3 +40,42 @@ func (r *InfoController) Name(ctx http.Context) {
"name": setting.Value,
})
}
func (r *InfoController) Menu(ctx http.Context) {
Success(ctx, []MenuItem{
{Name: "home", Title: "主页", Icon: "layui-icon-home", Jump: "/"},
{Name: "website", Title: "网站管理", Icon: "layui-icon-website", Jump: "website/list"},
{Name: "monitor", Title: "资源监控", Icon: "layui-icon-chart-screen", Jump: "monitor"},
{Name: "safe", Title: "系统安全", Icon: "layui-icon-auz", Jump: "safe"},
{Name: "file", Title: "文件管理", Icon: "layui-icon-file", Jump: "file"},
{Name: "cron", Title: "计划任务", Icon: "layui-icon-date", Jump: "cron"},
{Name: "plugin", Title: "插件中心", Icon: "layui-icon-app", Jump: "plugin"},
{Name: "setting", Title: "面板设置", Icon: "layui-icon-set", Jump: "setting"},
})
}
func (r *InfoController) HomePlugins(ctx http.Context) {
var plugins []models.Plugin
err := facades.Orm().Query().Where("show", 1).Find(&plugins)
if err != nil {
facades.Log().Error("[面板][InfoController] 查询首页插件失败 ", err)
Error(ctx, http.StatusInternalServerError, "系统内部错误")
return
}
Success(ctx, plugins)
}
func (r *InfoController) NowMonitor(ctx http.Context) {
Success(ctx, helpers.GetMonitoringInfo())
}
func (r *InfoController) SystemInfo(ctx http.Context) {
monitorInfo := helpers.GetMonitoringInfo()
Success(ctx, http.Json{
"os_name": monitorInfo.Host.Platform + " " + monitorInfo.Host.PlatformVersion,
"uptime": fmt.Sprintf("%.2f", float64(monitorInfo.Host.Uptime)/86400),
"panel_version": facades.Config().GetString("panel.version"),
})
}

View File

@@ -0,0 +1,32 @@
package controllers
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"panel/app/models"
)
type TaskController struct {
//Dependent services
}
func NewTaskController() *TaskController {
return &TaskController{
//Inject services
}
}
func (r *TaskController) Status(ctx http.Context) {
var task models.Task
err := facades.Orm().Query().Where("status", models.TaskStatusWaiting).OrWhere("status", models.TaskStatusRunning).FirstOrFail(&task)
if err == nil {
Success(ctx, http.Json{
"task": true,
})
return
}
Success(ctx, http.Json{
"task": false,
})
}

View File

@@ -13,7 +13,7 @@ import (
// Jwt 确保通过 JWT 鉴权
func Jwt() http.Middleware {
return func(ctx http.Context) {
token := ctx.Request().Header("Authorization", "")
token := ctx.Request().Input("access_token", "")
if len(token) == 0 {
ctx.Request().AbortWithStatusJson(http.StatusUnauthorized, http.Json{
"code": 401,

13
config/panel.go Normal file
View File

@@ -0,0 +1,13 @@
package config
import (
"github.com/goravel/framework/facades"
)
func init() {
config := facades.Config()
config.Add("panel", map[string]any{
"name": "耗子Linux面板",
"version": "2.0.0",
})
}

25
go.mod
View File

@@ -3,8 +3,14 @@ module panel
go 1.18
require (
github.com/goravel/framework v1.12.3-0.20230622070736-f7260a71f319
google.golang.org/grpc v1.56.0
github.com/gertd/go-pluralize v0.2.1
github.com/gin-contrib/static v0.0.1
github.com/gookit/color v1.5.3
github.com/goravel/framework v1.12.3
github.com/iancoleman/strcase v0.2.0
github.com/mojocn/base64Captcha v1.3.5
github.com/spf13/cast v1.5.1
github.com/stretchr/testify v1.8.4
)
require (
@@ -39,12 +45,11 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gertd/go-pluralize v0.2.1 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-contrib/static v0.0.1 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/glebarez/go-sqlite v1.21.1 // indirect
github.com/glebarez/sqlite v1.8.0 // indirect
github.com/go-ole/go-ole v1.2.6 // 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.1 // indirect
@@ -71,7 +76,6 @@ require (
github.com/google/wire v0.5.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
github.com/gookit/color v1.5.3 // indirect
github.com/gookit/filter v1.1.4 // indirect
github.com/gookit/goutil v0.5.15 // indirect
github.com/gookit/validate v1.4.6 // indirect
@@ -81,7 +85,6 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
@@ -104,7 +107,6 @@ require (
github.com/moby/term v0.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/mojocn/base64Captcha v1.3.5 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
@@ -117,21 +119,20 @@ require (
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/rs/cors v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/streadway/amqp v1.0.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/unrolled/secure v1.13.0 // indirect
github.com/urfave/cli/v2 v2.25.6 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
@@ -142,6 +143,7 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.mongodb.org/mongo-driver v1.7.5 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
@@ -160,6 +162,7 @@ require (
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.56.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect

22
go.sum
View File

@@ -172,6 +172,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
@@ -181,8 +183,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
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.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
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-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
@@ -346,10 +346,8 @@ github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c h1:obhFK91
github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c/go.mod h1:YSWsLXlG16u5CWFaXNZHhEQD10+NwF3xfgDV816OwLE=
github.com/goravel/file-rotatelogs/v2 v2.4.1 h1:ogkeIFcTHSBRUBpZYiyJbpul8hkVXxHPuDbOaP78O1M=
github.com/goravel/file-rotatelogs/v2 v2.4.1/go.mod h1:euk9qr52WrzM8ICs1hecFcR4CZ/ZZOPdacHfvHgbOf0=
github.com/goravel/framework v1.12.2 h1:2d+RQEVzcky6ff6LxlcPvnAj0tZPc0Y4yQAXQk88+nA=
github.com/goravel/framework v1.12.2/go.mod h1:96GRS8270PKLfJU9zrrLE7XKlp20S2TJ9RB337jBMy4=
github.com/goravel/framework v1.12.3-0.20230622070736-f7260a71f319 h1:xs7YlSAXdSJs0olT59PBwwj+3Rn5nTKASgNc+GUqsV8=
github.com/goravel/framework v1.12.3-0.20230622070736-f7260a71f319/go.mod h1:96GRS8270PKLfJU9zrrLE7XKlp20S2TJ9RB337jBMy4=
github.com/goravel/framework v1.12.3 h1:gGP+7fV7qAoBVh6zz8C4caQX9Vs8XTmqSJdMa/S9BsI=
github.com/goravel/framework v1.12.3/go.mod h1:96GRS8270PKLfJU9zrrLE7XKlp20S2TJ9RB337jBMy4=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@@ -522,11 +520,12 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -574,6 +573,10 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG
github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@@ -581,7 +584,6 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY
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/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFsk=
github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.25.6 h1:yuSkgDSZfH3L1CjF2/5fNNg2KbM47pY2EvjBq4ESQnU=
@@ -617,6 +619,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc=
go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI=
go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
@@ -791,6 +795,7 @@ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -839,6 +844,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -2,21 +2,23 @@
package helpers
import (
"bufio"
"bytes"
"crypto/md5"
"crypto/rand"
"fmt"
"io"
"os"
"os/exec"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
"github.com/shirou/gopsutil/process"
)
// Empty 类似于 PHP 的 empty() 函数
@@ -104,182 +106,43 @@ func Cut(begin, end, str string) string {
return string([]rune(str)[b : b+e])
}
// GetNetInfo 获取网络统计信息
func GetNetInfo() (uint64, uint64) {
file, err := os.Open("/proc/net/dev")
if err != nil {
panic(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
allRs := make(map[string][]string)
lineNumber := 0
for scanner.Scan() {
lineNumber++
if lineNumber < 3 {
continue
}
line := strings.TrimSpace(scanner.Text())
line = strings.Replace(line, ":", " ", -1)
re := regexp.MustCompile("[ ]+")
line = re.ReplaceAllString(line, " ")
arr := strings.Split(line, " ")
if len(arr) > 0 && arr[0] != "" {
allRs[arr[0]+strconv.Itoa(lineNumber)] = []string{arr[0], arr[1], arr[9]}
}
}
var keys []string
for key := range allRs {
keys = append(keys, key)
}
sort.Strings(keys)
tx := uint64(0)
rx := uint64(0)
for _, key := range keys {
if strings.Contains(key, "lo") {
continue
}
val := allRs[key]
txValue, err := strconv.ParseUint(val[2], 10, 64)
if err == nil {
tx += txValue
}
rxValue, err := strconv.ParseUint(val[1], 10, 64)
if err == nil {
rx += rxValue
}
}
return tx, rx
}
// MonitoringInfo 监控信息
type MonitoringInfo struct {
CpuUse float64 `json:"cpu_use"`
Uptime float64 `json:"uptime"`
UptimePercent float64 `json:"uptime_percent"`
MemTotal float64 `json:"mem_total"`
MemUse float64 `json:"mem_use"`
MemUsePercent float64 `json:"mem_use_percent"`
SwapTotal float64 `json:"swap_total"`
SwapUse float64 `json:"swap_use"`
SwapUsePercent float64 `json:"swap_use_percent"`
NetTx uint64 `json:"net_tx"`
NetRx uint64 `json:"net_rx"`
Cpus []cpu.InfoStat `json:"cpus"`
Percent []float64 `json:"percent"`
Load *load.AvgStat `json:"load"`
Host *host.InfoStat `json:"host"`
Mem *mem.VirtualMemoryStat `json:"mem"`
Swap *mem.SwapMemoryStat `json:"swap"`
Net []net.IOCountersStat `json:"net"`
Disk map[string]disk.IOCountersStat `json:"disk"`
Process []*process.Process `json:"process"`
}
// GetMonitoringInfo 获取监控数据
func GetMonitoringInfo() (MonitoringInfo, error) {
func GetMonitoringInfo() MonitoringInfo {
var res MonitoringInfo
res.Cpus, _ = cpu.Info()
res.Percent, _ = cpu.Percent(time.Second, false)
res.Load, _ = load.Avg()
res.Host, _ = host.Info()
res.Mem, _ = mem.VirtualMemory()
res.Swap, _ = mem.SwapMemory()
res.Net, _ = net.IOCounters(true)
res.Disk, _ = disk.IOCounters()
res.Process, _ = process.Processes()
// 网络流量
netTx1, netRx1 := GetNetInfo()
time.Sleep(time.Second)
netTx2, netRx2 := GetNetInfo()
res.NetTx = netTx2 - netTx1
res.NetRx = netRx2 - netRx1
// CPU 信息
cpuInfoRaw, err := os.ReadFile("/proc/cpuinfo")
if err != nil {
return MonitoringInfo{}, err
}
physicalArr := make(map[string]struct{})
var siblingsSum float64
var re = regexp.MustCompile(`\d+\.\d+`)
uptimeOutput, err := exec.Command("uptime").Output()
if err != nil {
return MonitoringInfo{}, err
}
uptimeValues := re.FindAllString(string(uptimeOutput), -1)
uptime1, _ := strconv.ParseFloat(uptimeValues[0], 64)
res.Uptime = uptime1
processors := bytes.Split(cpuInfoRaw, []byte("\nprocessor"))
rePhysical := regexp.MustCompile(`physical id\s*:\s(.*)`)
reSiblings := regexp.MustCompile(`siblings\s*:\s(.*)`)
for _, v := range processors {
physical := rePhysical.FindSubmatch(v)
siblings := reSiblings.FindSubmatch(v)
if len(physical) > 1 {
pid := string(physical[1])
if _, found := physicalArr[pid]; !found {
if len(siblings) > 1 {
siblingsValue, _ := strconv.ParseFloat(string(siblings[1]), 64)
siblingsSum += siblingsValue
}
physicalArr[pid] = struct{}{}
}
}
}
// CPU 使用率
cpuUse := 0.1
psOutput, err := exec.Command("ps", "aux").Output()
if err != nil {
return MonitoringInfo{}, err
}
cpuRaw := strings.Split(string(psOutput), "\n")
pid := os.Getpid()
for _, v := range cpuRaw {
v = strings.TrimSpace(v)
v = regexp.MustCompile(`\s+`).ReplaceAllString(v, " ")
values := strings.Split(v, " ")
if len(values) > 2 {
p, _ := strconv.Atoi(values[1])
if p == pid {
continue
}
cpu, _ := strconv.ParseFloat(values[2], 64)
cpuUse += cpu
}
}
cpuUse = cpuUse / siblingsSum
if cpuUse > 100 {
cpuUse = 100
}
res.CpuUse = cpuUse
// 内存使用率
freeOutput, err := exec.Command("free", "-m").Output()
if err != nil {
return MonitoringInfo{}, err
}
memRaw := strings.Split(string(freeOutput), "\n")
var memList, swapList string
for _, v := range memRaw {
if strings.Contains(v, "Mem") {
memList = regexp.MustCompile(`\s+`).ReplaceAllString(v, " ")
} else if strings.Contains(v, "Swap") {
swapList = regexp.MustCompile(`\s+`).ReplaceAllString(v, " ")
}
}
memArr := strings.Split(memList, " ")
swapArr := strings.Split(swapList, " ")
memTotal, _ := strconv.ParseFloat(memArr[1], 64)
swapTotal, _ := strconv.ParseFloat(swapArr[1], 64)
memUse, _ := strconv.ParseFloat(memArr[2], 64)
swapUse, _ := strconv.ParseFloat(swapArr[2], 64)
memUseP := (memUse / memTotal) * 100
swapUseP := (swapUse / swapTotal) * 100
uptime1P := uptime1 * 10
if uptime1P > 100 {
uptime1P = 100
}
res.MemTotal = memTotal
res.MemUse = memUse
res.MemUsePercent = memUseP
res.SwapTotal = swapTotal
res.SwapUse = swapUse
res.SwapUsePercent = swapUseP
res.UptimePercent = uptime1P
return res, nil
return res
}
// IsDebian 判断是否是 Debian 系统
func IsDebian() bool {
_, err := os.Stat("/etc/debian_version")
return err == nil
}
// IsRHEL 判断是否是 RHEL 系统
func IsRHEL() bool {
_, err := os.Stat("/etc/redhat-release")
return err == nil
}

View File

@@ -30,3 +30,12 @@ func Camel(s string) string {
func LowerCamel(s string) string {
return strcase.ToLowerCamel(s)
}
func ContainsString(arr []string, str string) bool {
for _, s := range arr {
if s == str {
return true
}
}
return false
}

View File

@@ -40,19 +40,19 @@
<script src="https://cdnjs.cdn.haozi.net/ace/1.6.1/ace.js"></script>
<script src="https://cdnjs.cdn.haozi.net/echarts/5.4.2/echarts.min.js"></script>
<script>
var panel_name = '耗子Linux面板'
layui.config({
base: 'res/', // 静态资源所在路径
version: new Date().getTime()
}).use('index', function () {
}).use(['index', 'setter'], function () {
var admin = layui.admin
var setter = layui.setter
admin.req({
url: '/api/panel/info/name',
type: 'get',
success: function (res) {
if (res.code === 0) {
panel_name = res.data.name
document.title = panel_name
setter.name = res.data.name
document.title = setter.name
}
}
})

View File

@@ -5,30 +5,25 @@ Date: 2022-11-30
-->
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div id="address1" class="layui-col-md12">
<div class="layui-collapse">
<div style="background: #fff;" class="layui-colla-content layui-show">
<div class="text" style="overflow: hidden;height: 22px;">
<div class="layui-carousel" id="home_ad" lay-filter="home_ad">
<div carousel-item="">
<a style="background: #fff;" href="https://hzbk.net"
title="耗子博客" target="_blank"><i class="layui-icon layui-icon-release"></i> 耗子博客</a>
<a style="background: #fff;" href="https://weavatar.com"
title="WeAvatar" target="_blank"><i class="layui-icon layui-icon-release"></i>
WeAvatar - 互联网公共头像服务</a>
<a style="background: #fff;" href="https://wepublish.cn"
title="WePublish" target="_blank"><i class="layui-icon layui-icon-release"></i>
WePublish - WordPress的本土化版本</a>
</div>
</div>
<div id="ad1" class="layui-col-md12">
<div style="background: #fff;" class="layui-colla-content layui-show">
<div id="ad1-carousel" class="layui-carousel"
style="overflow: hidden;background: #fff;">
<div carousel-item>
<a style="background: #fff;" href="https://hzbk.net"
title="耗子博客" target="_blank"><i class="layui-icon layui-icon-release"></i> 耗子博客</a>
<a style="background: #fff;" href="https://weavatar.com"
title="WeAvatar" target="_blank"><i class="layui-icon layui-icon-release"></i>
WeAvatar - 互联网公共头像服务</a>
<a style="background: #fff;" href="https://wepublish.cn"
title="WePublish" target="_blank"><i class="layui-icon layui-icon-release"></i>
WePublish - WordPress的本土化版本</a>
</div>
</div>
</div>
</div>
</div>
<div id="monitor1" class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">资源使用</div>
<div class="layui-card-body layadmin-takerates">
@@ -44,7 +39,6 @@ Date: 2022-11-30
</div>
</div>
<div id="monitor2" class="layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">系统负载</div>
<div class="layui-card-body layadmin-takerates">
@@ -84,18 +78,18 @@ Date: 2022-11-30
<div class="layui-carousel layadmin-carousel layadmin-shortcut" lay-anim="">
<div carousel-item="">
<ul class="layui-row layui-col-space10 layui-this">
<script type="text/html" template lay-url="/api/panel/info/getHomePlugins">
@{{# layui.each(d.data, function(index, item){ }}
<script type="text/html" template lay-url="/api/panel/info/homePlugins">
{{# layui.each(d.data, function(index, item){ }}
<li class="layui-col-xs4 layui-col-md2 layui-col-sm4">
<a lay-href="/plugin/@{{ item.slug }}">
<a lay-href="/plugin/{{ item.slug }}">
<i class="layui-icon layui-icon-engine"></i>
<cite>@{{ item.name }}</cite>
<cite>{{ item.name }}</cite>
</a>
</li>
@{{# }); }}
@{{# if(d.data.length === 0){ }}
{{# }); }}
{{# if(d.data.length === 0){ }}
这里好像啥也没有...
@{{# } }}
{{# } }}
</script>
</ul>
@@ -162,119 +156,134 @@ Date: 2022-11-30
</div>
<script>
var home_timer;
var uptime_1 = '获取中', uptime_5 = '获取中', uptime_15 = '获取中';
var home_timer
var uptime_1 = '获取中', uptime_5 = '获取中', uptime_15 = '获取中'
function refresh_home_info() {
function formatBytes (size) {
size = Number(size)
var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
var i = 0
while (size >= 1024 && i < units.length) {
size /= 1024
i++
}
return size.toFixed(2) + ' ' + units[i]
}
function formatPercentage (num) {
num = Number(num)
return num.toFixed(2) + '%'
}
function refresh_home_info () {
layui.use(['index', 'jquery', 'admin'], function () {
let $ = layui.jquery
, admin = layui.admin
, element = layui.element;
, element = layui.element
let device = layui.device();
let cpu_info;
let device = layui.device()
let cpu_info
admin.req({
url: "/api/panel/info/getNowMonitor"
url: '/api/panel/info/nowMonitor'
, method: 'get'
, success: function (result) {
if (result.code !== 0) {
console.log('耗子Linux面板系统资源信息获取失败接口返回' + result);
layer.msg('系统资源获取失败,请刷新重试!')
return false;
return false
}
element.progress('home_cpu', result.data.cpu_use);
element.progress('home_mem', result.data.mem_use_p);
element.progress('uptime_1', result.data.uptime_1_p);
element.progress('uptime_5', result.data.uptime_5_p);
uptime_1 = result.data.uptime_1;
uptime_5 = result.data.uptime_5;
uptime_15 = result.data.uptime_15;
// 判断一下移动设备不显示CPU型号放不下。。。
if (device.mobile) {
cpu_info = result.data.cpu_info.physical + 'CPU ' + result.data.cpu_info.cores + '核心 ' + result.data.cpu_info.siblings + '线程';
} else {
cpu_info = result.data.cpu_info.name + ' ' + result.data.cpu_info.physical + 'CPU ' + result.data.cpu_info.cores + '核心 ' + result.data.cpu_info.siblings + '线程';
element.progress('home_cpu', formatPercentage(result.data.percent[0]))
element.progress('home_mem', formatPercentage(result.data.mem.usedPercent))
// 计算核心数
let cores = 0
for (let i = 0; i < result.data.cpus.length; i++) {
cores += result.data.cpus[i].cores
}
$('#home_net_total').html(result.data.tx_total + ' / ' + result.data.rx_total);
$('#home_net_now').html(result.data.tx_now + '/s / ' + result.data.rx_now + '/s');
$('#home_cpu').text(cpu_info);
$('#home_mem').text('使用' + result.data.mem_use + 'MB / ' + '总计' + result.data.mem_total + 'MB');
element.render('progress');
// 计算负载百分比
uptime_1 = formatPercentage(result.data.load.load1 / cores * 100)
uptime_5 = formatPercentage(result.data.load.load5 / cores * 100)
uptime_15 = formatPercentage(result.data.load.load15 / cores * 100)
element.progress('uptime_1', uptime_1)
element.progress('uptime_5', uptime_5)
cpu_info = result.data.cpus[0].modelName + ' ' + cores + '线程'
//$('#home_net_total').html(result.data.tx_total + ' / ' + result.data.rx_total)
//$('#home_net_now').html(result.data.tx_now + '/s / ' + result.data.rx_now + '/s')
$('#home_cpu').text(cpu_info)
$('#home_mem').text('使用 ' + formatBytes(result.data.mem.used) + ' / ' + '总计 ' + formatBytes(result.data.mem.total))
element.render('progress')
}
, error: function (xhr, status, error) {
console.log('耗子Linux面板ajax请求出错错误' + error);
}
});
});
})
})
}
// 先执行一次
refresh_home_info();
refresh_home_info()
// 然后设置个定时器3s一次刷新
clearInterval(home_timer);
home_timer = setInterval(refresh_home_info, 3000);
clearInterval(home_timer)
home_timer = setInterval(refresh_home_info, 3000)
// 获取系统信息,这部分信息无需更新。
layui.use(['index', 'jquery', 'admin', 'carousel'], function () {
let $ = layui.jquery
, admin = layui.admin
, element = layui.element
, carousel = layui.carousel;
, carousel = layui.carousel
carousel.render({
elem: '#home_ad'
elem: '#ad1-carousel'
, width: '100%'
, height: '200px'
, height: '22px'
, anim: 'fade'
, arrow: 'none'
, indicator: 'none'
});
})
admin.req({
url: "/api/panel/info/getSystemInfo"
url: '/api/panel/info/systemInfo'
, method: 'get'
, success: function (result) {
if (result.code !== 0) {
console.log('耗子Linux面板系统信息获取失败接口返回' + result);
console.log('耗子Linux面板系统信息获取失败接口返回' + result)
layer.msg('系统信息获取失败,请刷新重试!')
return false;
return false
}
$('#home_os_name').text(result.data.os_name);
$('#home_panel_version').text(result.data.panel_version);
$('#home_uptime').text('已不间断运行 ' + result.data.uptime + ' 天');
$('#home_os_name').text(result.data.os_name)
$('#home_panel_version').text(result.data.panel_version)
$('#home_uptime').text('已不间断运行 ' + result.data.uptime + ' 天')
}
, error: function (xhr, status, error) {
console.log('耗子Linux面板ajax请求出错错误' + error);
}
});
});
})
})
// 监听鼠标悬停到uptime上的事件
// 用于显示1分钟、5分钟、15分钟的负载
layui.use(['jquery', 'layer'], function () {
let $ = layui.jquery
, layer = layui.layer
, admin = layui.admin;
, admin = layui.admin
// 监听鼠标悬停到uptime上的事件
// 用于显示1分钟、5分钟、15分钟的负载
$('#monitor2').hover(function () {
layer.tips('1分钟负载' + uptime_1 + '<br>5分钟负载' + uptime_5 + '<br>15分钟负载' + uptime_15, '#monitor2', {
tips: 1,
time: 0
});
})
}, function () {
layer.closeAll('tips');
});
layer.closeAll('tips')
})
// 监听更新按钮点击事件
$('#update_panel').click(function () {
index = layer.msg('正在获取版本信息...', {
icon: 16
, time: 0
});
})
admin.req(
{
url: '/api/panel/info/checkUpdate'
, method: 'get'
, success: function (result) {
layer.close(index);
layer.close(index)
if (result.code !== 0) {
layer.msg('获取版本信息失败,请刷新重试!')
return false;
return false
}
if (result.data.version) {
admin.popup({
@@ -291,17 +300,13 @@ Date: 2022-11-30
skin: 'layui-anim layui-anim-upbit'
,
content: '最新版本:' + result.data.version + '<br><br>更新日志:' + result.data.describe + '<br><br>请在SSH执行<span class="layui-badge-rim">panel update</span>以更新面板!'
});
})
} else {
layer.msg('当前已是最新版本!')
}
}
, error: function (xhr, status, error) {
layer.close(index);
layer.msg('获取版本信息失败,请刷新重试!')
}
}
);
});
});
)
})
})
</script>

View File

@@ -4,7 +4,7 @@
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item layadmin-flexible" lay-unselect>
<a href="javascript:;" layadmin-event="flexible" title="侧边伸缩">
<i class="layui-icon layui-icon-shrink-right" id="LAY_app_flexible"></i>
<i class="layui-icon layui-icon-shrink-right" id="Panel_app_flexible"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect>
@@ -17,8 +17,8 @@
<li class="layui-nav-item" lay-unselect>
<a lay-href="task" layadmin-event="message">
<script type="text/html" template lay-url="/api/panel/task/getStatus">
{{# if(d.data){ }}
<script type="text/html" template lay-url="/api/panel/task/status">
{{# if(d.data.task){ }}
<i class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>
{{# } else { }}
<i class="layui-icon layui-icon-component"></i>
@@ -43,7 +43,7 @@
</a>
</li>
<li style="margin-right: 15px;" class="layui-nav-item" lay-unselect>
<script type="text/html" template lay-url="/api/panel/user/getInfo"
<script type="text/html" template lay-url="/api/panel/user/info"
lay-done="layui.element.render('nav', 'layadmin-layout-right');">
<a href="javascript:;">
<cite>{{= d.data.username }}</cite>
@@ -61,11 +61,11 @@
<!-- 侧边菜单 -->
<div class="layui-side layui-side-menu">
<div class="layui-side-scroll">
<script type="text/html" template lay-url="/api/panel/info/getMenu?v={{ layui.cache.version }}"
<script type="text/html" template lay-url="/api/panel/info/menu?v={{ layui.cache.version }}"
lay-done="layui.element.render('nav', 'layadmin-system-side-menu');" id="TPL_layout">
<div class="layui-logo" lay-href="">
{{ config('panel.name') }}
<span>{{ layui.setter.name }}</span>
</div>
<ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
@@ -141,7 +141,7 @@
<!-- 页面标签 -->
<script type="text/html" template lay-done="layui.element.render('nav', 'layadmin-pagetabs-nav')">
{{# if(layui.setter.pageTabs){ }}
<div class="layadmin-pagetabs" id="LAY_app_tabs">
<div class="layadmin-pagetabs" id="Panel_app_tabs">
<div class="layui-icon layadmin-tabs-control layui-icon-prev" layadmin-event="leftPage"></div>
<div class="layui-icon layadmin-tabs-control layui-icon-next" layadmin-event="rightPage"></div>
<div class="layui-icon layadmin-tabs-control layui-icon-down">
@@ -157,7 +157,7 @@
</ul>
</div>
<div class="layui-tab" lay-unauto lay-allowClose="true" lay-filter="layadmin-layout-tabs">
<ul class="layui-tab-title" id="LAY_app_tabsheader">
<ul class="layui-tab-title" id="Panel_app_tabsheader">
<li lay-id="/"><i class="layui-icon layui-icon-home"></i></li>
</ul>
</div>
@@ -167,7 +167,7 @@
<!-- 主体内容 -->
<div class="layui-body" id="LAY_app_body">
<div class="layui-body" id="Panel_app_body">
<div class="layadmin-tabsbody-item layui-show"></div>
</div>

View File

@@ -50,7 +50,7 @@
, search = router.search;
// 设置面板名称
$('#panel-login-name').text(panel_name);
$('#panel-login-name').text(setter.name);
// 判断并清除定时器
if (typeof home_timer !== 'undefined') {

View File

@@ -14,12 +14,20 @@ func Web() {
r.Prefix("info").Group(func(r route.Route) {
infoController := controllers.NewInfoController()
r.Get("name", infoController.Name)
r.Middleware(middleware.Jwt()).Get("menu", infoController.Menu)
r.Middleware(middleware.Jwt()).Get("homePlugins", infoController.HomePlugins)
r.Middleware(middleware.Jwt()).Get("nowMonitor", infoController.NowMonitor)
r.Middleware(middleware.Jwt()).Get("systemInfo", infoController.SystemInfo)
})
r.Prefix("user").Group(func(r route.Route) {
userController := controllers.NewUserController()
r.Post("login", userController.Login)
r.Middleware(middleware.Jwt()).Get("info", userController.Info)
})
r.Prefix("task").Middleware(middleware.Jwt()).Group(func(r route.Route) {
taskController := controllers.NewTaskController()
r.Get("status", taskController.Status)
})
})
facades.Route().Fallback(func(ctx http.Context) {