mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: 增加分组、快速命令等接口
This commit is contained in:
parent
c5b2eddd3f
commit
89432bc1b8
@ -37,6 +37,7 @@ sqlite:
|
|||||||
|
|
||||||
log:
|
log:
|
||||||
level: info
|
level: info
|
||||||
|
time_zone: Asia/Shanghai
|
||||||
path: /opt/1Panel/log
|
path: /opt/1Panel/log
|
||||||
log_name: 1Panel
|
log_name: 1Panel
|
||||||
log_suffix: .log
|
log_suffix: .log
|
||||||
|
98
backend/app/api/v1/command.go
Normal file
98
backend/app/api/v1/command.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseApi) CreateCommand(c *gin.Context) {
|
||||||
|
var req dto.CommandCreate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := commandService.Create(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) SearchCommand(c *gin.Context) {
|
||||||
|
var req dto.SearchWithPage
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := commandService.SearchWithPage(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) ListCommand(c *gin.Context) {
|
||||||
|
list, err := commandService.Search()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) DeleteCommand(c *gin.Context) {
|
||||||
|
var req dto.DeleteByName
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := commandService.Delete(req.Name); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) UpdateCommand(c *gin.Context) {
|
||||||
|
var req dto.CommandUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := helper.GetParamID(c)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upMap := make(map[string]interface{})
|
||||||
|
upMap["name"] = req.Name
|
||||||
|
if err := commandService.Update(id, upMap); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
@ -11,5 +11,7 @@ var ApiGroupApp = new(ApiGroup)
|
|||||||
var (
|
var (
|
||||||
userService = service.ServiceGroupApp.UserService
|
userService = service.ServiceGroupApp.UserService
|
||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.ServiceGroupApp.HostService
|
||||||
|
groupService = service.ServiceGroupApp.GroupService
|
||||||
|
commandService = service.ServiceGroupApp.CommandService
|
||||||
operationService = service.ServiceGroupApp.OperationService
|
operationService = service.ServiceGroupApp.OperationService
|
||||||
)
|
)
|
||||||
|
79
backend/app/api/v1/group.go
Normal file
79
backend/app/api/v1/group.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BaseApi) CreateGroup(c *gin.Context) {
|
||||||
|
var req dto.GroupCreate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := groupService.Create(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) DeleteGroup(c *gin.Context) {
|
||||||
|
var req dto.DeleteByName
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := groupService.Delete(req.Name); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) UpdateGroup(c *gin.Context) {
|
||||||
|
var req dto.GroupUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := helper.GetParamID(c)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upMap := make(map[string]interface{})
|
||||||
|
upMap["name"] = req.Name
|
||||||
|
if err := groupService.Update(id, upMap); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) ListGroup(c *gin.Context) {
|
||||||
|
list, err := groupService.Search()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *BaseApi) Create(c *gin.Context) {
|
func (b *BaseApi) CreateHost(c *gin.Context) {
|
||||||
var req dto.HostCreate
|
var req dto.HostCreate
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
@ -26,23 +26,20 @@ func (b *BaseApi) Create(c *gin.Context) {
|
|||||||
helper.SuccessWithData(c, host)
|
helper.SuccessWithData(c, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) PageHosts(c *gin.Context) {
|
func (b *BaseApi) HostTree(c *gin.Context) {
|
||||||
var req dto.SearchWithPage
|
var req dto.SearchForTree
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
total, list, err := hostService.Search(req)
|
data, err := hostService.SearchForTree(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.SuccessWithData(c, dto.PageResult{
|
helper.SuccessWithData(c, data)
|
||||||
Items: list,
|
|
||||||
Total: total,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) DeleteHost(c *gin.Context) {
|
func (b *BaseApi) DeleteHost(c *gin.Context) {
|
||||||
@ -81,6 +78,7 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
|||||||
|
|
||||||
upMap := make(map[string]interface{})
|
upMap := make(map[string]interface{})
|
||||||
upMap["name"] = req.Name
|
upMap["name"] = req.Name
|
||||||
|
upMap["group"] = req.Group
|
||||||
upMap["addr"] = req.Addr
|
upMap["addr"] = req.Addr
|
||||||
upMap["port"] = req.Port
|
upMap["port"] = req.Port
|
||||||
upMap["user"] = req.User
|
upMap["user"] = req.User
|
||||||
|
@ -68,7 +68,7 @@ func (b *BaseApi) Register(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseApi) PageUsers(c *gin.Context) {
|
func (b *BaseApi) PageUsers(c *gin.Context) {
|
||||||
var req dto.UserPage
|
var req dto.SearchWithPage
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
|
15
backend/app/dto/command.go
Normal file
15
backend/app/dto/command.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type CommandCreate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Command string `json:"command" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandUpdate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
}
|
@ -1,5 +1,10 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
|
type SearchWithPage struct {
|
||||||
|
PageInfo
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type PageInfo struct {
|
type PageInfo struct {
|
||||||
Page int `json:"page" validate:"required,number"`
|
Page int `json:"page" validate:"required,number"`
|
||||||
PageSize int `json:"pageSize" validate:"required,number"`
|
PageSize int `json:"pageSize" validate:"required,number"`
|
||||||
@ -13,6 +18,10 @@ type BatchDeleteReq struct {
|
|||||||
Ids []uint `json:"ids" validate:"required"`
|
Ids []uint `json:"ids" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeleteByName struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type OperationWithNameAndType struct {
|
type OperationWithNameAndType struct {
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Type string `json:"type" validate:"required"`
|
Type string `json:"type" validate:"required"`
|
||||||
|
10
backend/app/dto/group.go
Normal file
10
backend/app/dto/group.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type GroupCreate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GroupUpdate struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type HostCreate struct {
|
type HostCreate struct {
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Addr string `json:"addr" validate:"required,ip"`
|
Addr string `json:"addr" validate:"required,ip"`
|
||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
@ -14,14 +17,14 @@ type HostCreate struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchWithPage struct {
|
type SearchForTree struct {
|
||||||
PageInfo
|
|
||||||
Info string `json:"info"`
|
Info string `json:"info"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HostInfo struct {
|
type HostInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
Group string `json:"group"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr"`
|
||||||
Port uint `json:"port"`
|
Port uint `json:"port"`
|
||||||
@ -31,7 +34,17 @@ type HostInfo struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HostTree struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
Children []TreeChild `json:"children"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeChild struct {
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
type HostUpdate struct {
|
type HostUpdate struct {
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
Name string `json:"name" validate:"required"`
|
Name string `json:"name" validate:"required"`
|
||||||
Addr string `json:"addr" validate:"required,ip"`
|
Addr string `json:"addr" validate:"required,ip"`
|
||||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||||
|
@ -10,11 +10,6 @@ type UserCreate struct {
|
|||||||
Email string `json:"email" validate:"required,email"`
|
Email string `json:"email" validate:"required,email"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserPage struct {
|
|
||||||
PageInfo
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CaptchaResponse struct {
|
type CaptchaResponse struct {
|
||||||
CaptchaID string `json:"captchaID"`
|
CaptchaID string `json:"captchaID"`
|
||||||
ImagePath string `json:"imagePath"`
|
ImagePath string `json:"imagePath"`
|
||||||
|
9
backend/app/model/command.go
Normal file
9
backend/app/model/command.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `gorm:"type:varchar(64));unique;not null" json:"name"`
|
||||||
|
Command string `gorm:"type:varchar(256);unique;not null" json:"command"`
|
||||||
|
}
|
9
backend/app/model/group.go
Normal file
9
backend/app/model/group.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
type Group struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||||
|
Type string `gorm:"type:varchar(16);unique;not null" json:"type"`
|
||||||
|
}
|
@ -4,6 +4,7 @@ import "gorm.io/gorm"
|
|||||||
|
|
||||||
type Host struct {
|
type Host struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
Group string `gorm:"type:varchar(64);not null" json:"group"`
|
||||||
Name string `gorm:"type:varchar(64);unique;not null" json:"name"`
|
Name string `gorm:"type:varchar(64);unique;not null" json:"name"`
|
||||||
Addr string `gorm:"type:varchar(16);unique;not null" json:"addr"`
|
Addr string `gorm:"type:varchar(16);unique;not null" json:"addr"`
|
||||||
Port int `gorm:"type:varchar(5);not null" json:"port"`
|
Port int `gorm:"type:varchar(5);not null" json:"port"`
|
||||||
|
80
backend/app/repo/command.go
Normal file
80
backend/app/repo/command.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandRepo struct{}
|
||||||
|
|
||||||
|
type ICommandRepo interface {
|
||||||
|
GetList(opts ...DBOption) ([]model.Command, error)
|
||||||
|
Page(limit, offset int, opts ...DBOption) (int64, []model.Command, error)
|
||||||
|
WithByInfo(info string) DBOption
|
||||||
|
Create(command *model.Command) error
|
||||||
|
Update(id uint, vars map[string]interface{}) error
|
||||||
|
Delete(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewICommandService() ICommandRepo {
|
||||||
|
return &CommandRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) Get(opts ...DBOption) (model.Command, error) {
|
||||||
|
var command model.Command
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.First(&command).Error
|
||||||
|
return command, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) Page(page, size int, opts ...DBOption) (int64, []model.Command, error) {
|
||||||
|
var users []model.Command
|
||||||
|
db := global.DB.Model(&model.Command{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
count := int64(0)
|
||||||
|
db = db.Count(&count)
|
||||||
|
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error
|
||||||
|
return count, users, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) GetList(opts ...DBOption) ([]model.Command, error) {
|
||||||
|
var commands []model.Command
|
||||||
|
db := global.DB.Model(&model.Command{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.Find(&commands).Error
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandRepo) WithByInfo(info string) DBOption {
|
||||||
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
if len(info) == 0 {
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
infoStr := "%" + info + "%"
|
||||||
|
return g.Where("name LIKE ? OR addr LIKE ?", infoStr, infoStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) Create(command *model.Command) error {
|
||||||
|
return global.DB.Create(command).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
|
return global.DB.Model(&model.Command{}).Where("id = ?", id).Updates(vars).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandRepo) Delete(opts ...DBOption) error {
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
return db.Delete(&model.Command{}).Error
|
||||||
|
}
|
@ -3,6 +3,8 @@ package repo
|
|||||||
type RepoGroup struct {
|
type RepoGroup struct {
|
||||||
UserRepo
|
UserRepo
|
||||||
HostRepo
|
HostRepo
|
||||||
|
GroupRepo
|
||||||
|
CommandRepo
|
||||||
OperationRepo
|
OperationRepo
|
||||||
CommonRepo
|
CommonRepo
|
||||||
}
|
}
|
||||||
|
56
backend/app/repo/group.go
Normal file
56
backend/app/repo/group.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupRepo struct{}
|
||||||
|
|
||||||
|
type IGroupRepo interface {
|
||||||
|
Get(opts ...DBOption) (model.Group, error)
|
||||||
|
GetList(opts ...DBOption) ([]model.Group, error)
|
||||||
|
Create(group *model.Group) error
|
||||||
|
Update(id uint, vars map[string]interface{}) error
|
||||||
|
Delete(opts ...DBOption) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIGroupService() IGroupRepo {
|
||||||
|
return &GroupRepo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) Get(opts ...DBOption) (model.Group, error) {
|
||||||
|
var group model.Group
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.First(&group).Error
|
||||||
|
return group, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) GetList(opts ...DBOption) ([]model.Group, error) {
|
||||||
|
var groups []model.Group
|
||||||
|
db := global.DB.Model(&model.Group{})
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
err := db.Find(&groups).Error
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) Create(group *model.Group) error {
|
||||||
|
return global.DB.Create(group).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
|
return global.DB.Model(&model.Group{}).Where("id = ?", id).Updates(vars).Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupRepo) Delete(opts ...DBOption) error {
|
||||||
|
db := global.DB
|
||||||
|
for _, opt := range opts {
|
||||||
|
db = opt(db)
|
||||||
|
}
|
||||||
|
return db.Delete(&model.Group{}).Error
|
||||||
|
}
|
@ -10,7 +10,7 @@ type HostRepo struct{}
|
|||||||
|
|
||||||
type IHostRepo interface {
|
type IHostRepo interface {
|
||||||
Get(opts ...DBOption) (model.Host, error)
|
Get(opts ...DBOption) (model.Host, error)
|
||||||
Page(limit, offset int, opts ...DBOption) (int64, []model.Host, error)
|
GetList(opts ...DBOption) ([]model.Host, error)
|
||||||
WithByInfo(info string) DBOption
|
WithByInfo(info string) DBOption
|
||||||
Create(host *model.Host) error
|
Create(host *model.Host) error
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
@ -31,20 +31,21 @@ func (u *HostRepo) Get(opts ...DBOption) (model.Host, error) {
|
|||||||
return host, err
|
return host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostRepo) Page(page, size int, opts ...DBOption) (int64, []model.Host, error) {
|
func (u *HostRepo) GetList(opts ...DBOption) ([]model.Host, error) {
|
||||||
var hosts []model.Host
|
var hosts []model.Host
|
||||||
db := global.DB.Model(&model.Host{})
|
db := global.DB.Model(&model.Host{})
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
db = opt(db)
|
db = opt(db)
|
||||||
}
|
}
|
||||||
count := int64(0)
|
err := db.Find(&hosts).Error
|
||||||
db = db.Count(&count)
|
return hosts, err
|
||||||
err := db.Limit(size).Offset(size * (page - 1)).Find(&hosts).Error
|
|
||||||
return count, hosts, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *HostRepo) WithByInfo(info string) DBOption {
|
func (c *HostRepo) WithByInfo(info string) DBOption {
|
||||||
return func(g *gorm.DB) *gorm.DB {
|
return func(g *gorm.DB) *gorm.DB {
|
||||||
|
if len(info) == 0 {
|
||||||
|
return g
|
||||||
|
}
|
||||||
infoStr := "%" + info + "%"
|
infoStr := "%" + info + "%"
|
||||||
return g.Where("name LIKE ? OR addr LIKE ?", infoStr, infoStr)
|
return g.Where("name LIKE ? OR addr LIKE ?", infoStr, infoStr)
|
||||||
}
|
}
|
||||||
|
70
backend/app/service/command.go
Normal file
70
backend/app/service/command.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandService struct{}
|
||||||
|
|
||||||
|
type ICommandService interface {
|
||||||
|
Search() ([]model.Command, error)
|
||||||
|
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
|
||||||
|
Create(commandDto dto.CommandCreate) error
|
||||||
|
Update(id uint, upMap map[string]interface{}) error
|
||||||
|
Delete(name string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewICommandService() ICommandService {
|
||||||
|
return &CommandService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandService) Search() ([]model.Command, error) {
|
||||||
|
commands, err := commandRepo.GetList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
return commands, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
|
||||||
|
total, commands, err := commandRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Name))
|
||||||
|
var dtoCommands []dto.CommandInfo
|
||||||
|
for _, command := range commands {
|
||||||
|
var item dto.CommandInfo
|
||||||
|
if err := copier.Copy(&item, &command); err != nil {
|
||||||
|
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
dtoCommands = append(dtoCommands, item)
|
||||||
|
}
|
||||||
|
return total, dtoCommands, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandService) Create(commandDto dto.CommandCreate) error {
|
||||||
|
command, _ := commandRepo.Get(commonRepo.WithByName(commandDto.Name))
|
||||||
|
if command.ID != 0 {
|
||||||
|
return constant.ErrRecordExist
|
||||||
|
}
|
||||||
|
if err := copier.Copy(&command, &commandDto); err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
if err := commandRepo.Create(&command); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandService) Delete(name string) error {
|
||||||
|
command, _ := commandRepo.Get(commonRepo.WithByName(name))
|
||||||
|
if command.ID == 0 {
|
||||||
|
return constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
return commandRepo.Delete(commonRepo.WithByID(command.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *CommandService) Update(id uint, upMap map[string]interface{}) error {
|
||||||
|
return commandRepo.Update(id, upMap)
|
||||||
|
}
|
@ -5,6 +5,8 @@ import "github.com/1Panel-dev/1Panel/app/repo"
|
|||||||
type ServiceGroup struct {
|
type ServiceGroup struct {
|
||||||
UserService
|
UserService
|
||||||
HostService
|
HostService
|
||||||
|
GroupService
|
||||||
|
CommandService
|
||||||
OperationService
|
OperationService
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,6 +15,8 @@ var ServiceGroupApp = new(ServiceGroup)
|
|||||||
var (
|
var (
|
||||||
userRepo = repo.RepoGroupApp.UserRepo
|
userRepo = repo.RepoGroupApp.UserRepo
|
||||||
hostRepo = repo.RepoGroupApp.HostRepo
|
hostRepo = repo.RepoGroupApp.HostRepo
|
||||||
|
groupRepo = repo.RepoGroupApp.GroupRepo
|
||||||
|
commandRepo = repo.RepoGroupApp.CommandRepo
|
||||||
operationRepo = repo.RepoGroupApp.OperationRepo
|
operationRepo = repo.RepoGroupApp.OperationRepo
|
||||||
commonRepo = repo.RepoGroupApp.CommonRepo
|
commonRepo = repo.RepoGroupApp.CommonRepo
|
||||||
)
|
)
|
||||||
|
56
backend/app/service/group.go
Normal file
56
backend/app/service/group.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupService struct{}
|
||||||
|
|
||||||
|
type IGroupService interface {
|
||||||
|
Search() ([]model.Group, error)
|
||||||
|
Create(groupDto dto.GroupCreate) error
|
||||||
|
Update(id uint, upMap map[string]interface{}) error
|
||||||
|
Delete(name string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIGroupService() IGroupService {
|
||||||
|
return &GroupService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupService) Search() ([]model.Group, error) {
|
||||||
|
groups, err := groupRepo.GetList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
return groups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupService) Create(groupDto dto.GroupCreate) error {
|
||||||
|
group, _ := groupRepo.Get(commonRepo.WithByName(groupDto.Name), commonRepo.WithByName(groupDto.Name))
|
||||||
|
if group.ID != 0 {
|
||||||
|
return constant.ErrRecordExist
|
||||||
|
}
|
||||||
|
if err := copier.Copy(&group, &groupDto); err != nil {
|
||||||
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||||
|
}
|
||||||
|
if err := groupRepo.Create(&group); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupService) Delete(name string) error {
|
||||||
|
group, _ := groupRepo.Get(commonRepo.WithByName(name))
|
||||||
|
if group.ID == 0 {
|
||||||
|
return constant.ErrRecordNotFound
|
||||||
|
}
|
||||||
|
return groupRepo.Delete(commonRepo.WithByID(group.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *GroupService) Update(id uint, upMap map[string]interface{}) error {
|
||||||
|
return groupRepo.Update(id, upMap)
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/app/dto"
|
"github.com/1Panel-dev/1Panel/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/app/model"
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/constant"
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
@ -12,7 +14,7 @@ type HostService struct{}
|
|||||||
|
|
||||||
type IHostService interface {
|
type IHostService interface {
|
||||||
GetConnInfo(id uint) (*model.Host, error)
|
GetConnInfo(id uint) (*model.Host, error)
|
||||||
Search(search dto.SearchWithPage) (int64, interface{}, error)
|
SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error)
|
||||||
Create(hostDto dto.HostCreate) (*dto.HostInfo, error)
|
Create(hostDto dto.HostCreate) (*dto.HostInfo, error)
|
||||||
Update(id uint, upMap map[string]interface{}) error
|
Update(id uint, upMap map[string]interface{}) error
|
||||||
BatchDelete(ids []uint) error
|
BatchDelete(ids []uint) error
|
||||||
@ -30,17 +32,25 @@ func (u *HostService) GetConnInfo(id uint) (*model.Host, error) {
|
|||||||
return &host, err
|
return &host, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostService) Search(search dto.SearchWithPage) (int64, interface{}, error) {
|
func (u *HostService) SearchForTree(search dto.SearchForTree) ([]dto.HostTree, error) {
|
||||||
total, hosts, err := hostRepo.Page(search.Page, search.PageSize, hostRepo.WithByInfo(search.Info))
|
hosts, err := hostRepo.GetList(hostRepo.WithByInfo(search.Info))
|
||||||
var dtoHosts []dto.HostInfo
|
distinctMap := make(map[string][]string)
|
||||||
for _, host := range hosts {
|
for _, host := range hosts {
|
||||||
var item dto.HostInfo
|
if _, ok := distinctMap[host.Group]; !ok {
|
||||||
if err := copier.Copy(&item, &host); err != nil {
|
distinctMap[host.Group] = []string{fmt.Sprintf("%s@%s:%d", host.User, host.Addr, host.Port)}
|
||||||
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
} else {
|
||||||
|
distinctMap[host.Group] = append(distinctMap[host.Group], fmt.Sprintf("%s@%s:%d", host.User, host.Addr, host.Port))
|
||||||
}
|
}
|
||||||
dtoHosts = append(dtoHosts, item)
|
|
||||||
}
|
}
|
||||||
return total, dtoHosts, err
|
var data []dto.HostTree
|
||||||
|
for key, value := range distinctMap {
|
||||||
|
var children []dto.TreeChild
|
||||||
|
for _, label := range value {
|
||||||
|
children = append(children, dto.TreeChild{Label: label})
|
||||||
|
}
|
||||||
|
data = append(data, dto.HostTree{Label: key, Children: children})
|
||||||
|
}
|
||||||
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *HostService) Create(hostDto dto.HostCreate) (*dto.HostInfo, error) {
|
func (u *HostService) Create(hostDto dto.HostCreate) (*dto.HostInfo, error) {
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/app/model"
|
"github.com/1Panel-dev/1Panel/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/constant"
|
"github.com/1Panel-dev/1Panel/constant"
|
||||||
"github.com/1Panel-dev/1Panel/global"
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
"github.com/1Panel-dev/1Panel/init/session/psession"
|
|
||||||
"github.com/1Panel-dev/1Panel/utils/encrypt"
|
"github.com/1Panel-dev/1Panel/utils/encrypt"
|
||||||
"github.com/1Panel-dev/1Panel/utils/jwt"
|
"github.com/1Panel-dev/1Panel/utils/jwt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -18,7 +17,7 @@ type UserService struct{}
|
|||||||
|
|
||||||
type IUserService interface {
|
type IUserService interface {
|
||||||
Get(id uint) (*dto.UserInfo, error)
|
Get(id uint) (*dto.UserInfo, error)
|
||||||
Page(search dto.UserPage) (int64, interface{}, error)
|
Page(search dto.SearchWithPage) (int64, interface{}, error)
|
||||||
Register(userDto dto.UserCreate) error
|
Register(userDto dto.UserCreate) error
|
||||||
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error)
|
||||||
LogOut(c *gin.Context) error
|
LogOut(c *gin.Context) error
|
||||||
@ -44,7 +43,7 @@ func (u *UserService) Get(id uint) (*dto.UserInfo, error) {
|
|||||||
return &dtoUser, err
|
return &dtoUser, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserService) Page(search dto.UserPage) (int64, interface{}, error) {
|
func (u *UserService) Page(search dto.SearchWithPage) (int64, interface{}, error) {
|
||||||
total, users, err := userRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Name))
|
total, users, err := userRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Name))
|
||||||
var dtoUsers []dto.UserInfo
|
var dtoUsers []dto.UserInfo
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
@ -92,13 +91,9 @@ func (u *UserService) Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo,
|
|||||||
}
|
}
|
||||||
return &dto.UserLoginInfo{Name: user.Name, Token: token}, err
|
return &dto.UserLoginInfo{Name: user.Name, Token: token}, err
|
||||||
}
|
}
|
||||||
sessionUser := psession.SessionUser{
|
|
||||||
ID: user.ID,
|
|
||||||
Name: user.Name,
|
|
||||||
}
|
|
||||||
lifeTime := global.CONF.Session.ExpiresTime
|
lifeTime := global.CONF.Session.ExpiresTime
|
||||||
sID, _ := c.Cookie(global.CONF.Session.SessionName)
|
sID, _ := c.Cookie(global.CONF.Session.SessionName)
|
||||||
sessionUser, err = global.SESSION.Get(sID)
|
sessionUser, err := global.SESSION.Get(sID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sID = uuid.NewV4().String()
|
sID = uuid.NewV4().String()
|
||||||
c.SetCookie(global.CONF.Session.SessionName, sID, lifeTime, "", "", false, false)
|
c.SetCookie(global.CONF.Session.SessionName, sID, lifeTime, "", "", false, false)
|
||||||
|
Binary file not shown.
@ -2,6 +2,7 @@ package configs
|
|||||||
|
|
||||||
type LogConfig struct {
|
type LogConfig struct {
|
||||||
Level string `mapstructure:"level"`
|
Level string `mapstructure:"level"`
|
||||||
|
TimeZone string `mapstructure:"timeZone"`
|
||||||
Path string `mapstructure:"path"`
|
Path string `mapstructure:"path"`
|
||||||
LogName string `mapstructure:"log_name"`
|
LogName string `mapstructure:"log_name"`
|
||||||
LogSuffix string `mapstructure:"log_suffix"`
|
LogSuffix string `mapstructure:"log_suffix"`
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/configs"
|
"github.com/1Panel-dev/1Panel/configs"
|
||||||
"github.com/1Panel-dev/1Panel/global"
|
"github.com/1Panel-dev/1Panel/global"
|
||||||
@ -20,10 +23,10 @@ func setOutput(log *logrus.Logger, config configs.LogConfig) {
|
|||||||
filePath := path.Join(config.Path, config.LogName+config.LogSuffix)
|
filePath := path.Join(config.Path, config.LogName+config.LogSuffix)
|
||||||
logPrint := &lumberjack.Logger{
|
logPrint := &lumberjack.Logger{
|
||||||
Filename: filePath,
|
Filename: filePath,
|
||||||
MaxSize: config.LogSize, // 日志文件大小,单位是 MB
|
MaxSize: config.LogSize,
|
||||||
MaxBackups: config.LogBackup, // 最大过期日志保留个数
|
MaxBackups: config.LogBackup,
|
||||||
MaxAge: config.LogData, // 保留过期文件最大时间,单位 天
|
MaxAge: config.LogData,
|
||||||
Compress: true, // 是否压缩日志,默认是不压缩。这里设置为true,压缩日志
|
Compress: true,
|
||||||
}
|
}
|
||||||
level, err := logrus.ParseLevel(config.Level)
|
level, err := logrus.ParseLevel(config.Level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -31,4 +34,24 @@ func setOutput(log *logrus.Logger, config configs.LogConfig) {
|
|||||||
}
|
}
|
||||||
log.SetOutput(logPrint)
|
log.SetOutput(logPrint)
|
||||||
log.SetLevel(level)
|
log.SetLevel(level)
|
||||||
|
log.SetFormatter(new(MineFormatter))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MineFormatter struct{}
|
||||||
|
|
||||||
|
const TimeFormat = "2006-01-02 15:04:05"
|
||||||
|
|
||||||
|
func (s *MineFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
|
var cstSh, _ = time.LoadLocation(global.CONF.LogConfig.TimeZone)
|
||||||
|
detailInfo := ""
|
||||||
|
if entry.Caller != nil {
|
||||||
|
funcion := strings.ReplaceAll(entry.Caller.Function, "github.com/1Panel-dev/1Panel/", "")
|
||||||
|
detailInfo = fmt.Sprintf("(%s: %d)", funcion, entry.Caller.Line)
|
||||||
|
}
|
||||||
|
if len(entry.Data) == 0 {
|
||||||
|
msg := fmt.Sprintf("[%s] [%s] %s %s \n", time.Now().In(cstSh).Format(TimeFormat), strings.ToUpper(entry.Level.String()), entry.Message, detailInfo)
|
||||||
|
return []byte(msg), nil
|
||||||
|
}
|
||||||
|
msg := fmt.Sprintf("[%s] [%s] %s %s {%v} \n", time.Now().In(cstSh).Format(TimeFormat), strings.ToUpper(entry.Level.String()), entry.Message, detailInfo, entry.Data)
|
||||||
|
return []byte(msg), nil
|
||||||
}
|
}
|
||||||
|
@ -18,5 +18,5 @@ func Init() {
|
|||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
global.LOG.Infof("Migration did run successfully")
|
global.LOG.Info("Migration did run successfully")
|
||||||
}
|
}
|
||||||
|
24
backend/router/command.go
Normal file
24
backend/router/command.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/1Panel-dev/1Panel/app/api/v1"
|
||||||
|
"github.com/1Panel-dev/1Panel/middleware"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandRouter struct{}
|
||||||
|
|
||||||
|
func (s *CommandRouter) InitCommandRouter(Router *gin.RouterGroup) {
|
||||||
|
userRouter := Router.Group("commands")
|
||||||
|
userRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||||
|
withRecordRouter := userRouter.Use(middleware.OperationRecord())
|
||||||
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
|
{
|
||||||
|
withRecordRouter.POST("", baseApi.CreateCommand)
|
||||||
|
withRecordRouter.POST("/del", baseApi.DeleteCommand)
|
||||||
|
userRouter.POST("/search", baseApi.SearchCommand)
|
||||||
|
userRouter.GET("", baseApi.ListCommand)
|
||||||
|
userRouter.PUT(":id", baseApi.UpdateCommand)
|
||||||
|
}
|
||||||
|
}
|
23
backend/router/group.go
Normal file
23
backend/router/group.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "github.com/1Panel-dev/1Panel/app/api/v1"
|
||||||
|
"github.com/1Panel-dev/1Panel/middleware"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GroupRouter struct{}
|
||||||
|
|
||||||
|
func (s *GroupRouter) InitGroupRouter(Router *gin.RouterGroup) {
|
||||||
|
userRouter := Router.Group("group")
|
||||||
|
userRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
|
||||||
|
withRecordRouter := userRouter.Use(middleware.OperationRecord())
|
||||||
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
|
{
|
||||||
|
withRecordRouter.POST("", baseApi.CreateGroup)
|
||||||
|
withRecordRouter.POST("/del", baseApi.DeleteGroup)
|
||||||
|
userRouter.GET("", baseApi.ListGroup)
|
||||||
|
userRouter.PUT(":id", baseApi.UpdateGroup)
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,9 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
|
|||||||
withRecordRouter := userRouter.Use(middleware.OperationRecord())
|
withRecordRouter := userRouter.Use(middleware.OperationRecord())
|
||||||
baseApi := v1.ApiGroupApp.BaseApi
|
baseApi := v1.ApiGroupApp.BaseApi
|
||||||
{
|
{
|
||||||
withRecordRouter.POST("", baseApi.Create)
|
withRecordRouter.POST("", baseApi.CreateHost)
|
||||||
withRecordRouter.POST("/del", baseApi.DeleteHost)
|
withRecordRouter.POST("/del", baseApi.DeleteHost)
|
||||||
userRouter.POST("/search", baseApi.PageHosts)
|
userRouter.POST("/search", baseApi.HostTree)
|
||||||
userRouter.PUT(":id", baseApi.UpdateHost)
|
userRouter.PUT(":id", baseApi.UpdateHost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,9 +80,7 @@ func (sws *LocalWsSession) receiveWsMsg(exitCh chan bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
msgObj := wsMsg{}
|
msgObj := wsMsg{}
|
||||||
if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
_ = json.Unmarshal(wsData, &msgObj)
|
||||||
global.LOG.Errorf("unmarshal websocket message %s failed, err: %v", wsData, err)
|
|
||||||
}
|
|
||||||
switch msgObj.Type {
|
switch msgObj.Type {
|
||||||
case wsMsgResize:
|
case wsMsgResize:
|
||||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||||
|
@ -54,7 +54,7 @@ type LogicSshWsSession struct {
|
|||||||
session *ssh.Session
|
session *ssh.Session
|
||||||
wsConn *websocket.Conn
|
wsConn *websocket.Conn
|
||||||
isAdmin bool
|
isAdmin bool
|
||||||
IsFlagged bool `comment:"当前session是否包含禁止命令"`
|
IsFlagged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogicSshWsSession(cols, rows int, isAdmin bool, sshClient *ssh.Client, wsConn *websocket.Conn) (*LogicSshWsSession, error) {
|
func NewLogicSshWsSession(cols, rows int, isAdmin bool, sshClient *ssh.Client, wsConn *websocket.Conn) (*LogicSshWsSession, error) {
|
||||||
@ -127,9 +127,7 @@ func (sws *LogicSshWsSession) receiveWsMsg(exitCh chan bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
msgObj := wsMsg{}
|
msgObj := wsMsg{}
|
||||||
if err := json.Unmarshal(wsData, &msgObj); err != nil {
|
_ = json.Unmarshal(wsData, &msgObj)
|
||||||
global.LOG.Errorf("unmarshal websocket message %s failed, err: %v", wsData, err)
|
|
||||||
}
|
|
||||||
switch msgObj.Type {
|
switch msgObj.Type {
|
||||||
case wsMsgResize:
|
case wsMsgResize:
|
||||||
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
if msgObj.Cols > 0 && msgObj.Rows > 0 {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import { CommonModel, ReqPage } from '.';
|
import { CommonModel } from '.';
|
||||||
|
|
||||||
export namespace Host {
|
export namespace Host {
|
||||||
|
export interface HostTree {
|
||||||
|
label: string;
|
||||||
|
children: Array<string>;
|
||||||
|
}
|
||||||
export interface Host extends CommonModel {
|
export interface Host extends CommonModel {
|
||||||
name: string;
|
name: string;
|
||||||
addr: string;
|
addr: string;
|
||||||
@ -21,7 +25,7 @@ export namespace Host {
|
|||||||
|
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
export interface ReqSearchWithPage extends ReqPage {
|
export interface ReqSearch {
|
||||||
info?: string;
|
info?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import http from '@/api';
|
import http from '@/api';
|
||||||
import { ResPage } from '../interface';
|
|
||||||
import { Host } from '../interface/host';
|
import { Host } from '../interface/host';
|
||||||
|
|
||||||
export const getHostList = (params: Host.ReqSearchWithPage) => {
|
export const getHostList = (params: Host.ReqSearch) => {
|
||||||
return http.post<ResPage<Host.Host>>(`/hosts/search`, params);
|
return http.post<Array<Host.HostTree>>(`/hosts/search`, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addHost = (params: Host.HostOperate) => {
|
export const addHost = (params: Host.HostOperate) => {
|
||||||
|
@ -5,7 +5,3 @@ import { ResOperationLog } from '../interface/operation-log';
|
|||||||
export const getOperationList = (info: ReqPage) => {
|
export const getOperationList = (info: ReqPage) => {
|
||||||
return http.post<ResPage<ResOperationLog>>(`/operations`, info);
|
return http.post<ResPage<ResOperationLog>>(`/operations`, info);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteOperation = (params: { ids: number[] }) => {
|
|
||||||
return http.post(`/operations/del`, params);
|
|
||||||
};
|
|
||||||
|
@ -91,8 +91,9 @@ export default {
|
|||||||
logout: '退出登录',
|
logout: '退出登录',
|
||||||
},
|
},
|
||||||
terminal: {
|
terminal: {
|
||||||
connHistory: '历史连接',
|
conn: '连接',
|
||||||
hostHistory: '历史主机信息',
|
hostList: '主机信息',
|
||||||
|
quickCmd: '快捷命令',
|
||||||
addHost: '添加主机',
|
addHost: '添加主机',
|
||||||
localhost: '本地服务器',
|
localhost: '本地服务器',
|
||||||
name: '名称',
|
name: '名称',
|
||||||
|
@ -15,9 +15,6 @@ const demoRouter = {
|
|||||||
path: '/demos/table',
|
path: '/demos/table',
|
||||||
name: 'Table',
|
name: 'Table',
|
||||||
component: () => import('@/views/demos/table/index.vue'),
|
component: () => import('@/views/demos/table/index.vue'),
|
||||||
meta: {
|
|
||||||
keepAlive: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/demos/table/:op/:id?',
|
path: '/demos/table/:op/:id?',
|
||||||
@ -27,7 +24,6 @@ const demoRouter = {
|
|||||||
component: () => import('@/views/demos/table/operate/index.vue'),
|
component: () => import('@/views/demos/table/operate/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
activeMenu: '/demos/table',
|
activeMenu: '/demos/table',
|
||||||
keepAlive: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -15,7 +15,6 @@ const operationRouter = {
|
|||||||
name: 'OperationLog',
|
name: 'OperationLog',
|
||||||
component: () => import('@/views/operation-log/index.vue'),
|
component: () => import('@/views/operation-log/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: true,
|
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
key: 'OperationLog',
|
key: 'OperationLog',
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Layout } from '@/routers/constant';
|
import { Layout } from '@/routers/constant';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
|
||||||
const terminalRouter = {
|
const terminalRouter = {
|
||||||
sort: 2,
|
sort: 2,
|
||||||
@ -6,18 +7,44 @@ const terminalRouter = {
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/terminal',
|
redirect: '/terminal',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'menu.terminal',
|
title: i18n.global.t('menu.terminal'),
|
||||||
icon: 'monitor',
|
icon: 'monitor',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/terminal',
|
path: '/terminals/terminal',
|
||||||
name: 'Terminal',
|
name: 'Terminal',
|
||||||
component: () => import('@/views/terminal/index.vue'),
|
component: () => import('@/views/terminal/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: true,
|
|
||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
key: 'Terminal',
|
key: 'Terminal',
|
||||||
|
title: i18n.global.t('terminal.conn'),
|
||||||
|
icon: 'connection',
|
||||||
|
activeMenu: '/terminals',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/terminals/host',
|
||||||
|
name: 'Host',
|
||||||
|
component: () => import('@/views/terminal/host/index.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true,
|
||||||
|
key: 'Host',
|
||||||
|
title: i18n.global.t('terminal.hostList'),
|
||||||
|
icon: 'platform',
|
||||||
|
activeMenu: '/terminals',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/terminals/command',
|
||||||
|
name: 'Command',
|
||||||
|
component: () => import('@/views/terminal/command/index.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true,
|
||||||
|
key: 'Command',
|
||||||
|
title: i18n.global.t('terminal.quickCmd'),
|
||||||
|
icon: 'reading',
|
||||||
|
activeMenu: '/terminals',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -178,3 +178,15 @@
|
|||||||
}
|
}
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row-box {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: wrap;
|
||||||
|
}
|
||||||
|
.row-box .el-card {
|
||||||
|
min-width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin-right: 20px;
|
||||||
|
border: 0;
|
||||||
|
// box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
||||||
|
}
|
@ -1,80 +1,74 @@
|
|||||||
<template>
|
<template>
|
||||||
<LayoutContent :header="$t('menu.operations')">
|
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search">
|
||||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search">
|
<el-table-column :label="$t('operations.operatoin')" fix>
|
||||||
<el-table-column type="selection" fix />
|
<template #default="{ row }">
|
||||||
<el-table-column :label="$t('operations.operatoin')" fix>
|
{{ fmtOperation(row) }}
|
||||||
<template #default="{ row }">
|
</template>
|
||||||
{{ fmtOperation(row) }}
|
</el-table-column>
|
||||||
</template>
|
<el-table-column :label="$t('operations.status')" prop="status">
|
||||||
</el-table-column>
|
<template #default="{ row }">
|
||||||
<el-table-column :label="$t('operations.status')" prop="status">
|
<el-tag v-if="row.status == '200'" class="ml-2" type="success">{{ row.status }}</el-tag>
|
||||||
<template #default="{ row }">
|
<div v-else>
|
||||||
<el-tag v-if="row.status == '200'" class="ml-2" type="success">{{ row.status }}</el-tag>
|
<el-popover
|
||||||
<div v-else>
|
placement="top-start"
|
||||||
<el-popover
|
:title="$t('commons.table.message')"
|
||||||
placement="top-start"
|
:width="400"
|
||||||
:title="$t('commons.table.message')"
|
trigger="hover"
|
||||||
:width="400"
|
:content="row.errorMessage"
|
||||||
trigger="hover"
|
>
|
||||||
:content="row.errorMessage"
|
<template #reference>
|
||||||
>
|
<el-tag class="ml-2" type="warning">{{ row.status }}</el-tag>
|
||||||
<template #reference>
|
</template>
|
||||||
<el-tag class="ml-2" type="warning">{{ row.status }}</el-tag>
|
</el-popover>
|
||||||
</template>
|
</div>
|
||||||
</el-popover>
|
</template>
|
||||||
</div>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column label="IP" prop="ip" />
|
||||||
</el-table-column>
|
<el-table-column align="left" :label="$t('operations.request')" prop="path">
|
||||||
<el-table-column label="IP" prop="ip" />
|
<template #default="{ row }">
|
||||||
<el-table-column align="left" :label="$t('operations.request')" prop="path">
|
<div>
|
||||||
<template #default="{ row }">
|
<el-popover :width="500" v-if="row.body" placement="left-start" trigger="click">
|
||||||
<div>
|
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
|
||||||
<el-popover :width="500" v-if="row.body" placement="left-start" trigger="click">
|
<pre class="pre">{{ fmtBody(row.body) }}</pre>
|
||||||
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
|
</div>
|
||||||
<pre class="pre">{{ fmtBody(row.body) }}</pre>
|
<template #reference>
|
||||||
</div>
|
<el-icon style="cursor: pointer"><warning /></el-icon>
|
||||||
<template #reference>
|
</template>
|
||||||
<el-icon style="cursor: pointer"><warning /></el-icon>
|
</el-popover>
|
||||||
</template>
|
<span v-else>无</span>
|
||||||
</el-popover>
|
</div>
|
||||||
<span v-else>无</span>
|
</template>
|
||||||
</div>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column align="left" :label="$t('operations.response')" prop="path">
|
||||||
</el-table-column>
|
<template #default="{ row }">
|
||||||
<el-table-column align="left" :label="$t('operations.response')" prop="path">
|
<div>
|
||||||
<template #default="{ row }">
|
<el-popover :width="500" v-if="row.resp" placement="left-start" trigger="click">
|
||||||
<div>
|
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
|
||||||
<el-popover :width="500" v-if="row.resp" placement="left-start" trigger="click">
|
<pre class="pre">{{ fmtBody(row.resp) }}</pre>
|
||||||
<div style="word-wrap: break-word; font-size: 12px; white-space: normal">
|
</div>
|
||||||
<pre class="pre">{{ fmtBody(row.resp) }}</pre>
|
<template #reference>
|
||||||
</div>
|
<el-icon style="cursor: pointer"><warning /></el-icon>
|
||||||
<template #reference>
|
</template>
|
||||||
<el-icon style="cursor: pointer"><warning /></el-icon>
|
</el-popover>
|
||||||
</template>
|
<span v-else>无</span>
|
||||||
</el-popover>
|
</div>
|
||||||
<span v-else>无</span>
|
</template>
|
||||||
</div>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column
|
||||||
</el-table-column>
|
prop="createdAt"
|
||||||
<el-table-column
|
:label="$t('commons.table.date')"
|
||||||
prop="createdAt"
|
:formatter="dateFromat"
|
||||||
:label="$t('commons.table.date')"
|
show-overflow-tooltip
|
||||||
:formatter="dateFromat"
|
/>
|
||||||
show-overflow-tooltip
|
</ComplexTable>
|
||||||
/>
|
|
||||||
<fu-table-operations :buttons="buttons" :label="$t('commons.table.operate')" fix />
|
|
||||||
</ComplexTable>
|
|
||||||
</LayoutContent>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
import { dateFromat } from '@/utils/util';
|
import { dateFromat } from '@/utils/util';
|
||||||
import { getOperationList, deleteOperation } from '@/api/modules/operation-log';
|
import { getOperationList } from '@/api/modules/operation-log';
|
||||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||||
import { ResOperationLog } from '@/api/interface/operation-log';
|
import { ResOperationLog } from '@/api/interface/operation-log';
|
||||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
|
|
||||||
const data = ref();
|
const data = ref();
|
||||||
@ -89,29 +83,6 @@ const logSearch = reactive({
|
|||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
});
|
});
|
||||||
|
|
||||||
const selects = ref<any>([]);
|
|
||||||
const batchDelete = async (row: ResOperationLog | null) => {
|
|
||||||
let ids: Array<number> = [];
|
|
||||||
|
|
||||||
if (row === null) {
|
|
||||||
selects.value.forEach((item: ResOperationLog) => {
|
|
||||||
ids.push(item.id);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ids.push(row.id);
|
|
||||||
}
|
|
||||||
await useDeleteData(deleteOperation, { ids: ids }, 'commons.msg.delete');
|
|
||||||
search();
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttons = [
|
|
||||||
{
|
|
||||||
label: i18n.global.t('commons.button.delete'),
|
|
||||||
type: 'danger',
|
|
||||||
click: batchDelete,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
logSearch.page = paginationConfig.currentPage;
|
logSearch.page = paginationConfig.currentPage;
|
||||||
logSearch.pageSize = paginationConfig.pageSize;
|
logSearch.pageSize = paginationConfig.pageSize;
|
||||||
|
144
frontend/src/views/terminal/host/index.vue
Normal file
144
frontend/src/views/terminal/host/index.vue
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<template>
|
||||||
|
<el-row style="margin: 20px; margin-left: 20px" class="row-box" :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card class="el-card">
|
||||||
|
<el-button icon="Plus" @click="readyForCreate" size="small" />
|
||||||
|
<el-button icon="FolderAdd" @click="(folderCreate = true), (newGroupName = '')" size="small" />
|
||||||
|
<el-button icon="Expand" @click="setTreeStatus(true)" size="small" />
|
||||||
|
<el-button icon="Fold" @click="setTreeStatus(false)" size="small" />
|
||||||
|
<el-input size="small" @input="loadHost" clearable style="margin-top: 5px" v-model="searcConfig.info">
|
||||||
|
<template #append><el-button icon="search" @click="loadHost" /></template>
|
||||||
|
</el-input>
|
||||||
|
<el-input size="small" v-if="folderCreate" clearable style="margin-top: 5px" v-model="newGroupName">
|
||||||
|
<template #append>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button icon="Check" @click="loadHost" />
|
||||||
|
<el-button icon="Close" @click="folderCreate = false" />
|
||||||
|
</el-button-group>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-tree ref="tree" :default-expand-all="true" :data="hostTree" :props="defaultProps" />
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-card class="el-card">
|
||||||
|
<el-form ref="hostInfoRef" label-width="100px" label-position="left" :model="hostInfo" :rules="rules">
|
||||||
|
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||||
|
<el-input clearable v-model="hostInfo.name" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="IP" prop="addr">
|
||||||
|
<el-input clearable v-model="hostInfo.addr" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('terminal.port')" prop="port">
|
||||||
|
<el-input clearable v-model.number="hostInfo.port" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('terminal.user')" prop="user">
|
||||||
|
<el-input clearable v-model="hostInfo.user" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('terminal.authMode')" prop="authMode">
|
||||||
|
<el-radio-group v-model="hostInfo.authMode">
|
||||||
|
<el-radio label="password">{{ $t('terminal.passwordMode') }}</el-radio>
|
||||||
|
<el-radio label="key">{{ $t('terminal.keyMode') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('terminal.password')"
|
||||||
|
v-if="hostInfo.authMode === 'password'"
|
||||||
|
prop="password"
|
||||||
|
>
|
||||||
|
<el-input clearable show-password type="password" v-model="hostInfo.password" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
|
||||||
|
<el-input clearable type="textarea" v-model="hostInfo.privateKey" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="submitAddHost(hostInfoRef)">
|
||||||
|
{{ $t('commons.button.create') }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue';
|
||||||
|
import type { ElForm } from 'element-plus';
|
||||||
|
import { Rules } from '@/global/form-rues';
|
||||||
|
import { Host } from '@/api/interface/host';
|
||||||
|
import { getHostList, addHost } from '@/api/modules/host';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
|
||||||
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
|
const hostInfoRef = ref<FormInstance>();
|
||||||
|
const rules = reactive({
|
||||||
|
name: [Rules.requiredInput, Rules.name],
|
||||||
|
addr: [Rules.requiredInput, Rules.ip],
|
||||||
|
port: [Rules.requiredInput, Rules.port],
|
||||||
|
user: [Rules.requiredInput],
|
||||||
|
authMode: [Rules.requiredSelect],
|
||||||
|
password: [Rules.requiredInput],
|
||||||
|
privateKey: [Rules.requiredInput],
|
||||||
|
});
|
||||||
|
|
||||||
|
let hostInfo = reactive<Host.HostOperate>({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
addr: '',
|
||||||
|
port: 22,
|
||||||
|
user: '',
|
||||||
|
authMode: 'password',
|
||||||
|
password: '',
|
||||||
|
privateKey: '',
|
||||||
|
description: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
let searcConfig = reactive<Host.ReqSearch>({
|
||||||
|
info: '',
|
||||||
|
});
|
||||||
|
const tree = ref<any>(null);
|
||||||
|
const hostTree = ref<Array<Host.HostTree>>();
|
||||||
|
const defaultProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: 'label',
|
||||||
|
};
|
||||||
|
const newGroupName = ref();
|
||||||
|
const folderCreate = ref<boolean>(false);
|
||||||
|
|
||||||
|
const loadHost = async () => {
|
||||||
|
const res = await getHostList(searcConfig);
|
||||||
|
hostTree.value = res.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
function setTreeStatus(expend: boolean) {
|
||||||
|
for (let i = 0; i < tree.value.store._getAllNodes().length; i++) {
|
||||||
|
tree.value.store._getAllNodes()[i].expanded = expend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readyForCreate() {
|
||||||
|
if (hostInfoRef.value) {
|
||||||
|
hostInfoRef.value.resetFields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitAddHost = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate(async (valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
try {
|
||||||
|
await addHost(hostInfo);
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
// loadHost();
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.loginSuccess') + ':' + error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadHost();
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,173 +1,189 @@
|
|||||||
<template>
|
<template>
|
||||||
<LayoutContent :header="$t('menu.terminal')">
|
<!-- <el-button class="drawer-container" icon="arrowLeftBold" @click="hostDrawer = true">
|
||||||
<el-button class="drawer-container" icon="arrowLeftBold" @click="hostDrawer = true">
|
{{ $t('terminal.connHistory') }}
|
||||||
{{ $t('terminal.connHistory') }}
|
</el-button> -->
|
||||||
</el-button>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<el-tabs
|
<el-tabs
|
||||||
type="card"
|
type="card"
|
||||||
editable
|
editable
|
||||||
style="background-color: #efefef"
|
class="terminal-tabs"
|
||||||
v-model="terminalValue"
|
style="background-color: #efefef"
|
||||||
@edit="handleTabsEdit"
|
v-model="terminalValue"
|
||||||
>
|
@edit="handleTabsEdit"
|
||||||
<el-tab-pane :key="item.key" v-for="item in terminalTabs" :label="item.title" :name="item.key">
|
>
|
||||||
<template #label>
|
<el-tab-pane :key="item.key" v-for="item in terminalTabs" :label="item.title" :name="item.key">
|
||||||
<span class="custom-tabs-label">
|
<template #label>
|
||||||
<el-icon color="#67C23A" v-if="item.status === 'online'"><circleCheck /></el-icon>
|
<span class="custom-tabs-label">
|
||||||
<el-icon color="#F56C6C" v-if="item.status === 'closed'"><circleClose /></el-icon>
|
<el-icon color="#67C23A" v-if="item.status === 'online'"><circleCheck /></el-icon>
|
||||||
<span> {{ item.title }} </span>
|
<el-icon color="#F56C6C" v-if="item.status === 'closed'"><circleClose /></el-icon>
|
||||||
</span>
|
<span> {{ item.title }} </span>
|
||||||
</template>
|
</span>
|
||||||
<Terminal
|
|
||||||
style="height: calc(100vh - 265px); background-color: #000"
|
|
||||||
:ref="'Ref' + item.key"
|
|
||||||
:wsID="item.wsID"
|
|
||||||
:terminalID="item.key"
|
|
||||||
></Terminal>
|
|
||||||
</el-tab-pane>
|
|
||||||
<div v-if="terminalTabs.length === 0">
|
|
||||||
<el-empty
|
|
||||||
style="background-color: #000; height: calc(100vh - 265px)"
|
|
||||||
:description="$t('terminal.emptyTerminal')"
|
|
||||||
></el-empty>
|
|
||||||
</div>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-drawer :size="320" v-model="hostDrawer" :title="$t('terminal.hostHistory')" direction="rtl">
|
|
||||||
<el-input size="small" clearable style="margin-top: 5px" v-model="searcConfig.info">
|
|
||||||
<template #prepend>
|
|
||||||
<el-button icon="plus" @click="onAddHost">{{ $t('commons.button.add') }}</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
<template #append><el-button icon="search" @click="loadHost" /></template>
|
<Terminal
|
||||||
</el-input>
|
style="height: calc(100vh - 210px); background-color: #000"
|
||||||
<div v-infinite-scroll="nextPage" style="overflow: auto">
|
:ref="'Ref' + item.key"
|
||||||
<el-card
|
:wsID="item.wsID"
|
||||||
@click="onConnLocal()"
|
:terminalID="item.key"
|
||||||
style="margin-top: 5px; cursor: pointer"
|
></Terminal>
|
||||||
:title="$t('terminal.localhost')"
|
<div style="background-color: #000">
|
||||||
shadow="hover"
|
<el-select v-model="quickCmd" style="width: 25%" class="m-2" placeholder="Select" size="small">
|
||||||
>
|
<el-option v-for="cmd in quickCmds" :key="cmd.value" :label="cmd.label" :value="cmd.value" />
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="batchInput" class="terminal-input" size="small">
|
||||||
|
<template #append>
|
||||||
|
<el-switch size="small" v-model="isBatch" class="ml-2" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<div v-if="terminalTabs.length === 0">
|
||||||
|
<el-empty
|
||||||
|
style="background-color: #000; height: calc(100vh - 210px)"
|
||||||
|
:description="$t('terminal.emptyTerminal')"
|
||||||
|
></el-empty>
|
||||||
|
</div>
|
||||||
|
</el-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <el-drawer :size="320" v-model="hostDrawer" :title="$t('terminal.hostHistory')" direction="rtl">
|
||||||
|
<el-input size="small" clearable style="margin-top: 5px" v-model="searcConfig.info">
|
||||||
|
<template #prepend>
|
||||||
|
<el-button icon="plus" @click="onAddHost">{{ $t('commons.button.add') }}</el-button>
|
||||||
|
</template>
|
||||||
|
<template #append><el-button icon="search" @click="loadHost" /></template>
|
||||||
|
</el-input>
|
||||||
|
<div v-infinite-scroll="nextPage" style="overflow: auto">
|
||||||
|
<el-card
|
||||||
|
@click="onConnLocal()"
|
||||||
|
style="margin-top: 5px; cursor: pointer"
|
||||||
|
:title="$t('terminal.localhost')"
|
||||||
|
shadow="hover"
|
||||||
|
>
|
||||||
|
<div :inline="true">
|
||||||
|
<div>
|
||||||
|
<span>{{ $t('terminal.localhost') }}</span>
|
||||||
|
</div>
|
||||||
|
<span style="font-size: 14px; line-height: 25px"> [ 127.0.0.1 ]</span>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<div v-for="(item, index) in data" :key="item.id" @mouseover="hover = index" @mouseleave="hover = null">
|
||||||
|
<el-card @click="onConn(item)" style="margin-top: 5px; cursor: pointer" shadow="hover">
|
||||||
<div :inline="true">
|
<div :inline="true">
|
||||||
<div>
|
<div>
|
||||||
<span>{{ $t('terminal.localhost') }}</span>
|
<span>{{ item.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span style="font-size: 14px; line-height: 25px"> [ 127.0.0.1 ]</span>
|
<span style="font-size: 14px; line-height: 25px">
|
||||||
|
[ {{ item.addr + ':' + item.port }} ]
|
||||||
|
<el-button
|
||||||
|
style="float: right; margin-left: 5px"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="onDeleteHost(item)"
|
||||||
|
v-if="hover === index"
|
||||||
|
icon="delete"
|
||||||
|
></el-button>
|
||||||
|
<el-button
|
||||||
|
style="float: right; margin-left: 5px"
|
||||||
|
size="small"
|
||||||
|
circle
|
||||||
|
@click="onEditHost(item)"
|
||||||
|
v-if="hover === index"
|
||||||
|
icon="edit"
|
||||||
|
></el-button>
|
||||||
|
<div v-if="item.description && hover === index">
|
||||||
|
<span style="font-size: 12px">{{ item.description }}</span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<div v-for="(item, index) in data" :key="item.id" @mouseover="hover = index" @mouseleave="hover = null">
|
|
||||||
<el-card @click="onConn(item)" style="margin-top: 5px; cursor: pointer" shadow="hover">
|
|
||||||
<div :inline="true">
|
|
||||||
<div>
|
|
||||||
<span>{{ item.name }}</span>
|
|
||||||
</div>
|
|
||||||
<span style="font-size: 14px; line-height: 25px">
|
|
||||||
[ {{ item.addr + ':' + item.port }} ]
|
|
||||||
<el-button
|
|
||||||
style="float: right; margin-left: 5px"
|
|
||||||
size="small"
|
|
||||||
circle
|
|
||||||
@click="onDeleteHost(item)"
|
|
||||||
v-if="hover === index"
|
|
||||||
icon="delete"
|
|
||||||
></el-button>
|
|
||||||
<el-button
|
|
||||||
style="float: right; margin-left: 5px"
|
|
||||||
size="small"
|
|
||||||
circle
|
|
||||||
@click="onEditHost(item)"
|
|
||||||
v-if="hover === index"
|
|
||||||
icon="edit"
|
|
||||||
></el-button>
|
|
||||||
<div v-if="item.description && hover === index">
|
|
||||||
<span style="font-size: 12px">{{ item.description }}</span>
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</div>
|
||||||
|
</el-drawer> -->
|
||||||
|
|
||||||
<el-dialog v-model="connVisiable" :title="$t('terminal.addHost')" width="30%">
|
<el-dialog v-model="connVisiable" :title="$t('terminal.addHost')" width="30%">
|
||||||
<el-form ref="hostInfoRef" label-width="80px" :model="hostInfo" :rules="rules">
|
<el-form ref="hostInfoRef" label-width="100px" label-position="left" :model="hostInfo" :rules="rules">
|
||||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||||
<el-input clearable v-model="hostInfo.name" style="width: 80%" />
|
<el-input clearable v-model="hostInfo.name" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="IP" prop="addr">
|
<el-form-item label="IP" prop="addr">
|
||||||
<el-input clearable v-model="hostInfo.addr" style="width: 80%" />
|
<el-input clearable v-model="hostInfo.addr" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.port')" prop="port">
|
<el-form-item :label="$t('terminal.port')" prop="port">
|
||||||
<el-input clearable v-model.number="hostInfo.port" style="width: 80%" />
|
<el-input clearable v-model.number="hostInfo.port" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.user')" prop="user">
|
<el-form-item :label="$t('terminal.user')" prop="user">
|
||||||
<el-input clearable v-model="hostInfo.user" style="width: 80%" />
|
<el-input clearable v-model="hostInfo.user" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.authMode')" prop="authMode">
|
<el-form-item :label="$t('terminal.authMode')" prop="authMode">
|
||||||
<el-radio-group v-model="hostInfo.authMode">
|
<el-radio-group v-model="hostInfo.authMode">
|
||||||
<el-radio label="password">{{ $t('terminal.passwordMode') }}</el-radio>
|
<el-radio label="password">{{ $t('terminal.passwordMode') }}</el-radio>
|
||||||
<el-radio label="key">{{ $t('terminal.keyMode') }}</el-radio>
|
<el-radio label="key">{{ $t('terminal.keyMode') }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.password')" v-if="hostInfo.authMode === 'password'" prop="password">
|
<el-form-item :label="$t('terminal.password')" v-if="hostInfo.authMode === 'password'" prop="password">
|
||||||
<el-input clearable show-password type="password" v-model="hostInfo.password" style="width: 80%" />
|
<el-input clearable show-password type="password" v-model="hostInfo.password" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
|
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
|
||||||
<el-input clearable type="textarea" v-model="hostInfo.privateKey" style="width: 80%" />
|
<el-input clearable type="textarea" v-model="hostInfo.privateKey" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="connVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
<el-button @click="connVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
<el-button v-if="operation === 'conn'" type="primary" @click="submitAddHost(hostInfoRef)">
|
<!-- <el-button v-if="operation === 'conn'" type="primary" @click="submitAddHost(hostInfoRef)">
|
||||||
{{ $t('commons.button.conn') }}
|
{{ $t('commons.button.conn') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-else type="primary" @click="submitAddHost(hostInfoRef)">
|
<el-button v-else type="primary" @click="submitAddHost(hostInfoRef)">
|
||||||
{{ $t('commons.button.confirm') }}
|
{{ $t('commons.button.confirm') }}
|
||||||
</el-button>
|
</el-button> -->
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</LayoutContent>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onBeforeMount, ref, nextTick, reactive, getCurrentInstance } from 'vue';
|
import { onMounted, onBeforeMount, ref, nextTick, reactive, getCurrentInstance } from 'vue';
|
||||||
import { Rules } from '@/global/form-rues';
|
import { Rules } from '@/global/form-rues';
|
||||||
import { getHostList, addHost, editHost, deleteHost } from '@/api/modules/host';
|
// import { getHostList, addHost, editHost, deleteHost } from '@/api/modules/host';
|
||||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
// import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
// import i18n from '@/lang';
|
||||||
import i18n from '@/lang';
|
|
||||||
import type { ElForm } from 'element-plus';
|
import type { ElForm } from 'element-plus';
|
||||||
import { Host } from '@/api/interface/host';
|
import { Host } from '@/api/interface/host';
|
||||||
import { ElMessage } from 'element-plus';
|
// import { ElMessage } from 'element-plus';
|
||||||
import Terminal from '@/views/terminal/terminal.vue';
|
import Terminal from '@/views/terminal/terminal/index.vue';
|
||||||
|
|
||||||
let timer: NodeJS.Timer | null = null;
|
let timer: NodeJS.Timer | null = null;
|
||||||
|
|
||||||
const terminalValue = ref();
|
const terminalValue = ref();
|
||||||
const terminalTabs = ref([]) as any;
|
const terminalTabs = ref([]) as any;
|
||||||
let tabIndex = 0;
|
let tabIndex = 0;
|
||||||
const data = ref();
|
// const data = ref();
|
||||||
const hostDrawer = ref(false);
|
// const hostDrawer = ref(false);
|
||||||
|
|
||||||
let searcConfig = reactive<Host.ReqSearchWithPage>({
|
// let searcConfig = reactive<Host.ReqSearchWithPage>({
|
||||||
info: '',
|
// info: '',
|
||||||
page: 1,
|
// page: 1,
|
||||||
pageSize: 8,
|
// pageSize: 8,
|
||||||
});
|
// });
|
||||||
|
|
||||||
const paginationConfig = reactive({
|
// const paginationConfig = reactive({
|
||||||
currentPage: 1,
|
// currentPage: 1,
|
||||||
pageSize: 8,
|
// pageSize: 8,
|
||||||
total: 0,
|
// total: 0,
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
let quickCmd = ref();
|
||||||
|
const quickCmds = [
|
||||||
|
{ label: 'ls', value: 'ls -l' },
|
||||||
|
{ label: 'pwd', value: 'pwd' },
|
||||||
|
];
|
||||||
|
let batchInput = ref();
|
||||||
|
let isBatch = ref<boolean>(false);
|
||||||
|
|
||||||
const connVisiable = ref<boolean>(false);
|
const connVisiable = ref<boolean>(false);
|
||||||
const operation = ref();
|
const operation = ref();
|
||||||
const hover = ref();
|
// const hover = ref();
|
||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const hostInfoRef = ref<FormInstance>();
|
const hostInfoRef = ref<FormInstance>();
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
@ -222,85 +238,84 @@ const handleTabsEdit = (targetName: string, action: 'remove' | 'add') => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadHost = async () => {
|
// const loadHost = async () => {
|
||||||
searcConfig.page = paginationConfig.currentPage;
|
// searcConfig.page = paginationConfig.currentPage;
|
||||||
searcConfig.pageSize = paginationConfig.pageSize;
|
// searcConfig.pageSize = paginationConfig.pageSize;
|
||||||
const res = await getHostList(searcConfig);
|
// const res = await getHostList(searcConfig);
|
||||||
data.value = res.data.items;
|
// data.value = res.data.items;
|
||||||
paginationConfig.total = res.data.total;
|
// paginationConfig.total = res.data.total;
|
||||||
};
|
// };
|
||||||
|
|
||||||
const nextPage = () => {
|
// const nextPage = () => {
|
||||||
if (paginationConfig.pageSize >= paginationConfig.total) {
|
// if (paginationConfig.pageSize >= paginationConfig.total) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
paginationConfig.pageSize = paginationConfig.pageSize + 3;
|
// paginationConfig.pageSize = paginationConfig.pageSize + 3;
|
||||||
loadHost();
|
// loadHost();
|
||||||
};
|
// };
|
||||||
|
|
||||||
function onAddHost() {
|
// function onAddHost() {
|
||||||
connVisiable.value = true;
|
// connVisiable.value = true;
|
||||||
operation.value = 'create';
|
// operation.value = 'create';
|
||||||
if (hostInfoRef.value) {
|
// if (hostInfoRef.value) {
|
||||||
hostInfoRef.value.resetFields();
|
// hostInfoRef.value.resetFields();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
function onEditHost(row: Host.Host) {
|
// function onEditHost(row: Host.Host) {
|
||||||
hostInfo.id = row.id;
|
// hostInfo.id = row.id;
|
||||||
hostInfo.name = row.name;
|
// hostInfo.name = row.name;
|
||||||
hostInfo.addr = row.addr;
|
// hostInfo.addr = row.addr;
|
||||||
hostInfo.port = row.port;
|
// hostInfo.port = row.port;
|
||||||
hostInfo.user = row.user;
|
// hostInfo.user = row.user;
|
||||||
hostInfo.authMode = row.authMode;
|
// hostInfo.authMode = row.authMode;
|
||||||
hostInfo.password = '';
|
// hostInfo.password = '';
|
||||||
hostInfo.privateKey = '';
|
// hostInfo.privateKey = '';
|
||||||
operation.value = 'update';
|
// operation.value = 'update';
|
||||||
connVisiable.value = true;
|
// connVisiable.value = true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
const submitAddHost = (formEl: FormInstance | undefined) => {
|
// const submitAddHost = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
// if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
// formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
// if (!valid) return;
|
||||||
try {
|
// try {
|
||||||
switch (operation.value) {
|
// switch (operation.value) {
|
||||||
case 'create':
|
// case 'create':
|
||||||
await addHost(hostInfo);
|
// await addHost(hostInfo);
|
||||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
// ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
break;
|
// break;
|
||||||
case 'update':
|
// case 'update':
|
||||||
await editHost(hostInfo);
|
// await editHost(hostInfo);
|
||||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
// ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
break;
|
// break;
|
||||||
case 'conn':
|
// case 'conn':
|
||||||
const res = await addHost(hostInfo);
|
// const res = await addHost(hostInfo);
|
||||||
terminalTabs.value.push({
|
// terminalTabs.value.push({
|
||||||
key: `${res.data.addr}-${++tabIndex}`,
|
// key: `${res.data.addr}-${++tabIndex}`,
|
||||||
title: res.data.addr,
|
// title: res.data.addr,
|
||||||
wsID: res.data.id,
|
// wsID: res.data.id,
|
||||||
status: 'online',
|
// status: 'online',
|
||||||
});
|
// });
|
||||||
terminalValue.value = `${res.data.addr}-${tabIndex}`;
|
// terminalValue.value = `${res.data.addr}-${tabIndex}`;
|
||||||
}
|
// }
|
||||||
connVisiable.value = false;
|
// connVisiable.value = false;
|
||||||
loadHost();
|
// // loadHost();
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
ElMessage.success(i18n.global.t('commons.msg.loginSuccess') + ':' + error);
|
// ElMessage.success(i18n.global.t('commons.msg.loginSuccess') + ':' + error);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const onConn = (row: Host.Host) => {
|
// const onConn = (row: Host.Host) => {
|
||||||
terminalTabs.value.push({
|
// terminalTabs.value.push({
|
||||||
key: `${row.addr}-${++tabIndex}`,
|
// key: `${row.addr}-${++tabIndex}`,
|
||||||
title: row.addr,
|
// title: row.addr,
|
||||||
wsID: row.id,
|
// wsID: row.id,
|
||||||
status: 'online',
|
// status: 'online',
|
||||||
});
|
// });
|
||||||
terminalValue.value = `${row.addr}-${tabIndex}`;
|
// terminalValue.value = `${row.addr}-${tabIndex}`;
|
||||||
hostDrawer.value = false;
|
// };
|
||||||
};
|
|
||||||
|
|
||||||
const onConnLocal = () => {
|
const onConnLocal = () => {
|
||||||
terminalTabs.value.push({
|
terminalTabs.value.push({
|
||||||
@ -310,14 +325,13 @@ const onConnLocal = () => {
|
|||||||
status: 'online',
|
status: 'online',
|
||||||
});
|
});
|
||||||
terminalValue.value = `127.0.0.1-${tabIndex}`;
|
terminalValue.value = `127.0.0.1-${tabIndex}`;
|
||||||
hostDrawer.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteHost = async (row: Host.Host) => {
|
// const onDeleteHost = async (row: Host.Host) => {
|
||||||
let ids: Array<number> = [row.id];
|
// let ids: Array<number> = [row.id];
|
||||||
await useDeleteData(deleteHost, { ids: ids }, 'commons.msg.delete');
|
// await useDeleteData(deleteHost, { ids: ids }, 'commons.msg.delete');
|
||||||
loadHost();
|
// loadHost();
|
||||||
};
|
// };
|
||||||
|
|
||||||
function changeFrameHeight() {
|
function changeFrameHeight() {
|
||||||
let ifm = document.getElementById('iframeTerminal') as HTMLInputElement | null;
|
let ifm = document.getElementById('iframeTerminal') as HTMLInputElement | null;
|
||||||
@ -340,7 +354,7 @@ onMounted(() => {
|
|||||||
changeFrameHeight();
|
changeFrameHeight();
|
||||||
window.addEventListener('resize', changeFrameHeight);
|
window.addEventListener('resize', changeFrameHeight);
|
||||||
});
|
});
|
||||||
loadHost();
|
// loadHost();
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
syncTerminal();
|
syncTerminal();
|
||||||
}, 1000 * 8);
|
}, 1000 * 8);
|
||||||
@ -367,7 +381,13 @@ onBeforeMount(() => {
|
|||||||
border-radius: 4px 0 0 4px;
|
border-radius: 4px 0 0 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.el-tabs {
|
.terminal-input {
|
||||||
|
&:hover {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.terminal-tabs {
|
||||||
:deep .el-tabs__header {
|
:deep .el-tabs__header {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -406,4 +426,16 @@ onBeforeMount(() => {
|
|||||||
transition: all 0.15s;
|
transition: all 0.15s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vertical-tabs > .el-tabs__content {
|
||||||
|
padding: 32px;
|
||||||
|
color: #6b778c;
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-tabs--right .el-tabs__content,
|
||||||
|
.el-tabs--left .el-tabs__content {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user