feat: 表格增加搜索框

This commit is contained in:
ssongliu 2023-02-07 18:48:32 +08:00 committed by ssongliu
parent 1bdc531c7d
commit 3a6e318f56
46 changed files with 803 additions and 214 deletions

View File

@ -38,13 +38,13 @@ func (b *BaseApi) CreateComposeTemplate(c *gin.Context) {
// @Summary Page compose templates
// @Description 获取容器编排模版列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Produce json
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/template/search [post]
func (b *BaseApi) SearchComposeTemplate(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -50,12 +50,12 @@ func (b *BaseApi) SearchContainer(c *gin.Context) {
// @Summary Page composes
// @Description 获取编排列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/compose/search [post]
func (b *BaseApi) SearchCompose(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@ -318,13 +318,13 @@ func (b *BaseApi) ContainerLogs(c *gin.Context) {
// @Summary Page networks
// @Description 获取容器网络列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Produce json
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/network/search [post]
func (b *BaseApi) SearchNetwork(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@ -403,13 +403,13 @@ func (b *BaseApi) CreateNetwork(c *gin.Context) {
// @Summary Page volumes
// @Description 获取容器存储卷分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Produce json
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/volume/search [post]
func (b *BaseApi) SearchVolume(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -169,12 +169,12 @@ func (b *BaseApi) UpdateMysqlConfByFile(c *gin.Context) {
// @Summary Page mysql databases
// @Description 获取 mysql 数据库列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /databases/search [post]
func (b *BaseApi) SearchMysql(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -12,13 +12,13 @@ import (
// @Summary Page images
// @Description 获取镜像列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Produce json
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/image/search [post]
func (b *BaseApi) SearchImage(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -12,13 +12,13 @@ import (
// @Summary Page image repos
// @Description 获取镜像仓库列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchWithPage true "request"
// @Produce json
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /containers/repo/search [post]
func (b *BaseApi) SearchRepo(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -12,12 +12,12 @@ import (
// @Summary Page login logs
// @Description 获取系统登录日志列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchLgLogWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /logs/login [post]
func (b *BaseApi) GetLoginLogs(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchLgLogWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
@ -39,12 +39,12 @@ func (b *BaseApi) GetLoginLogs(c *gin.Context) {
// @Summary Page operation logs
// @Description 获取系统操作日志列表分页
// @Accept json
// @Param request body dto.PageInfo true "request"
// @Param request body dto.SearchOpLogWithPage true "request"
// @Success 200 {object} dto.PageResult
// @Security ApiKeyAuth
// @Router /logs/operation [post]
func (b *BaseApi) GetOperationLogs(c *gin.Context) {
var req dto.PageInfo
var req dto.SearchOpLogWithPage
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return

View File

@ -2,7 +2,7 @@ package dto
type SearchWithPage struct {
PageInfo
Info string `json:"info" validate:"required"`
Info string `json:"info"`
}
type PageInfo struct {

View File

@ -4,6 +4,7 @@ import "time"
type PageContainer struct {
PageInfo
Name string `json:"name"`
Filters string `json:"filters"`
}

View File

@ -5,8 +5,8 @@ import (
)
type OperationLog struct {
ID uint `json:"id"`
Group string `json:"group"`
ID uint `json:"id"`
Source string `json:"source"`
IP string `json:"ip"`
Path string `json:"path"`
@ -22,6 +22,19 @@ type OperationLog struct {
CreatedAt time.Time `json:"createdAt"`
}
type SearchOpLogWithPage struct {
PageInfo
Source string `json:"source"`
Status string `json:"status"`
Operation string `json:"operation"`
}
type SearchLgLogWithPage struct {
PageInfo
IP string `json:"ip"`
Status string `json:"status"`
}
type LoginLog struct {
ID uint `json:"id"`
IP string `json:"ip"`

View File

@ -6,7 +6,7 @@ import (
type OperationLog struct {
BaseModel
Group string `gorm:"type:varchar(64)" json:"group"`
Source string `gorm:"type:varchar(64)" json:"source"`
IP string `gorm:"type:varchar(64)" json:"ip"`
Path string `gorm:"type:varchar(64)" json:"path"`

View File

@ -65,6 +65,9 @@ func (c *CommonRepo) WithByStatus(status string) DBOption {
func (c *CommonRepo) WithLikeName(name string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(name) == 0 {
return g
}
return g.Where("name like ?", "%"+name+"%")
}
}

View File

@ -3,6 +3,7 @@ package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm"
)
type LogRepo struct{}
@ -12,6 +13,10 @@ type ILogRepo interface {
CreateLoginLog(user *model.LoginLog) error
PageLoginLog(limit, offset int, opts ...DBOption) (int64, []model.LoginLog, error)
WithByIP(ip string) DBOption
WithByStatus(status string) DBOption
WithByGroup(group string) DBOption
WithByLikeOperation(operation string) DBOption
CleanOperation() error
CreateOperationLog(user *model.OperationLog) error
PageOperationLog(limit, offset int, opts ...DBOption) (int64, []model.OperationLog, error)
@ -60,3 +65,37 @@ func (u *LogRepo) PageOperationLog(page, size int, opts ...DBOption) (int64, []m
err := db.Limit(size).Offset(size * (page - 1)).Find(&ops).Error
return count, ops, err
}
func (c *LogRepo) WithByStatus(status string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(status) == 0 {
return g
}
return g.Where("status = ?", status)
}
}
func (c *LogRepo) WithByGroup(group string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(group) == 0 {
return g
}
return g.Where("source = ?", group)
}
}
func (c *LogRepo) WithByIP(ip string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(ip) == 0 {
return g
}
return g.Where("ip LIKE ?", "%"+ip+"%")
}
}
func (c *LogRepo) WithByLikeOperation(operation string) DBOption {
return func(g *gorm.DB) *gorm.DB {
if len(operation) == 0 {
return g
}
infoStr := "%" + operation + "%"
return g.Where("detail_zh LIKE ? OR detail_en LIKE ?", infoStr, infoStr)
}
}

View File

@ -11,7 +11,7 @@ type ComposeTemplateService struct{}
type IComposeTemplateService interface {
List() ([]dto.ComposeTemplateInfo, error)
SearchWithPage(search dto.PageInfo) (int64, interface{}, error)
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
Create(composeDto dto.ComposeTemplateCreate) error
Update(id uint, upMap map[string]interface{}) error
Delete(ids []uint) error
@ -37,8 +37,8 @@ func (u *ComposeTemplateService) List() ([]dto.ComposeTemplateInfo, error) {
return dtoLists, err
}
func (u *ComposeTemplateService) SearchWithPage(search dto.PageInfo) (int64, interface{}, error) {
total, composes, err := composeRepo.Page(search.Page, search.PageSize)
func (u *ComposeTemplateService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
total, composes, err := composeRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info))
var dtoComposeTemplates []dto.ComposeTemplateInfo
for _, compose := range composes {
var item dto.ComposeTemplateInfo

View File

@ -29,10 +29,10 @@ type ContainerService struct{}
type IContainerService interface {
Page(req dto.PageContainer) (int64, interface{}, error)
PageNetwork(req dto.PageInfo) (int64, interface{}, error)
PageVolume(req dto.PageInfo) (int64, interface{}, error)
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
ListVolume() ([]dto.Options, error)
PageCompose(req dto.PageInfo) (int64, interface{}, error)
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
CreateCompose(req dto.ComposeCreate) error
ComposeOperation(req dto.ComposeOperation) error
ContainerCreate(req dto.ContainerCreate) error
@ -69,6 +69,17 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
if err != nil {
return 0, nil, err
}
if len(req.Name) != 0 {
lenth, count := len(list), 0
for count < lenth {
if !strings.Contains(list[count].Names[0][1:], req.Name) {
list = append(list[:count], list[(count+1):]...)
lenth--
} else {
count++
}
}
}
sort.Slice(list, func(i, j int) bool {
return list[i].Created > list[j].Created
})

View File

@ -25,7 +25,7 @@ const composeConfigLabel = "com.docker.compose.project.config_files"
const composeWorkdirLabel = "com.docker.compose.project.working_dir"
const composeCreatedBy = "createdBy"
func (u *ContainerService) PageCompose(req dto.PageInfo) (int64, interface{}, error) {
func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface{}, error) {
var (
records []dto.ComposeInfo
BackDatas []dto.ComposeInfo
@ -90,13 +90,24 @@ func (u *ContainerService) PageCompose(req dto.PageInfo) (int64, interface{}, er
}
for _, item := range composeCreatedByLocal {
if err := composeRepo.DeleteRecord(commonRepo.WithByName(item.Name)); err != nil {
fmt.Println(err)
global.LOG.Error(err)
}
}
for key, value := range composeMap {
value.Name = key
records = append(records, value)
}
if len(req.Info) != 0 {
lenth, count := len(records), 0
for count < lenth {
if !strings.Contains(records[count].Name, req.Info) {
records = append(records[:count], records[(count+1):]...)
lenth--
} else {
count++
}
}
}
sort.Slice(records, func(i, j int) bool {
return records[i].CreatedAt > records[j].CreatedAt
})

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"sort"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
@ -11,7 +12,7 @@ import (
"github.com/docker/docker/api/types/network"
)
func (u *ContainerService) PageNetwork(req dto.PageInfo) (int64, interface{}, error) {
func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface{}, error) {
client, err := docker.NewDockerClient()
if err != nil {
return 0, nil, err
@ -20,6 +21,17 @@ func (u *ContainerService) PageNetwork(req dto.PageInfo) (int64, interface{}, er
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
lenth, count := len(list), 0
for count < lenth {
if !strings.Contains(list[count].Name, req.Info) {
list = append(list[:count], list[(count+1):]...)
lenth--
} else {
count++
}
}
}
var (
data []dto.Network
records []types.NetworkResource

View File

@ -3,6 +3,7 @@ package service
import (
"context"
"sort"
"strings"
"time"
"github.com/1Panel-dev/1Panel/backend/app/dto"
@ -12,7 +13,7 @@ import (
"github.com/docker/docker/api/types/volume"
)
func (u *ContainerService) PageVolume(req dto.PageInfo) (int64, interface{}, error) {
func (u *ContainerService) PageVolume(req dto.SearchWithPage) (int64, interface{}, error) {
client, err := docker.NewDockerClient()
if err != nil {
return 0, nil, err
@ -21,6 +22,17 @@ func (u *ContainerService) PageVolume(req dto.PageInfo) (int64, interface{}, err
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
lenth, count := len(list.Volumes), 0
for count < lenth {
if !strings.Contains(list.Volumes[count].Name, req.Info) {
list.Volumes = append(list.Volumes[:count], list.Volumes[(count+1):]...)
lenth--
} else {
count++
}
}
}
var (
data []dto.Volume
records []*types.Volume

View File

@ -30,7 +30,7 @@ import (
type MysqlService struct{}
type IMysqlService interface {
SearchWithPage(search dto.PageInfo) (int64, interface{}, error)
SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error)
ListDBName() ([]string, error)
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
ChangeAccess(info dto.ChangeDBInfo) error
@ -55,8 +55,8 @@ func NewIMysqlService() IMysqlService {
return &MysqlService{}
}
func (u *MysqlService) SearchWithPage(search dto.PageInfo) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize)
func (u *MysqlService) SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) {
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize, commonRepo.WithLikeName(search.Info))
var dtoMysqls []dto.MysqlDBInfo
for _, mysql := range mysqls {
var item dto.MysqlDBInfo

View File

@ -25,7 +25,7 @@ var dockerLogDir = constant.TmpDir + "/docker_logs"
type ImageService struct{}
type IImageService interface {
Page(req dto.PageInfo) (int64, interface{}, error)
Page(req dto.SearchWithPage) (int64, interface{}, error)
List() ([]dto.Options, error)
ImageBuild(req dto.ImageBuild) (string, error)
ImagePull(req dto.ImagePull) (string, error)
@ -38,7 +38,7 @@ type IImageService interface {
func NewIImageService() IImageService {
return &ImageService{}
}
func (u *ImageService) Page(req dto.PageInfo) (int64, interface{}, error) {
func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error) {
var (
list []types.ImageSummary
records []dto.ImageInfo
@ -52,6 +52,24 @@ func (u *ImageService) Page(req dto.PageInfo) (int64, interface{}, error) {
if err != nil {
return 0, nil, err
}
if len(req.Info) != 0 {
lenth, count := len(list), 0
for count < lenth {
hasTag := false
for _, tag := range list[count].RepoTags {
if strings.Contains(tag, req.Info) {
hasTag = true
break
}
}
if !hasTag {
list = append(list[:count], list[(count+1):]...)
lenth--
} else {
count++
}
}
}
for _, image := range list {
size := formatFileSize(image.Size)

View File

@ -19,7 +19,7 @@ import (
type ImageRepoService struct{}
type IImageRepoService interface {
Page(search dto.PageInfo) (int64, interface{}, error)
Page(search dto.SearchWithPage) (int64, interface{}, error)
List() ([]dto.ImageRepoOption, error)
Create(req dto.ImageRepoCreate) error
Update(req dto.ImageRepoUpdate) error
@ -30,8 +30,8 @@ func NewIImageRepoService() IImageRepoService {
return &ImageRepoService{}
}
func (u *ImageRepoService) Page(search dto.PageInfo) (int64, interface{}, error) {
total, ops, err := imageRepoRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
func (u *ImageRepoService) Page(req dto.SearchWithPage) (int64, interface{}, error) {
total, ops, err := imageRepoRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info), commonRepo.WithOrderBy("created_at desc"))
var dtoOps []dto.ImageRepoInfo
for _, op := range ops {
var item dto.ImageRepoInfo

View File

@ -12,10 +12,10 @@ type LogService struct{}
type ILogService interface {
CreateLoginLog(operation model.LoginLog) error
PageLoginLog(search dto.PageInfo) (int64, interface{}, error)
PageLoginLog(search dto.SearchLgLogWithPage) (int64, interface{}, error)
CreateOperationLog(operation model.OperationLog) error
PageOperationLog(search dto.PageInfo) (int64, interface{}, error)
PageOperationLog(search dto.SearchOpLogWithPage) (int64, interface{}, error)
CleanLogs(logtype string) error
}
@ -28,8 +28,14 @@ func (u *LogService) CreateLoginLog(operation model.LoginLog) error {
return logRepo.CreateLoginLog(&operation)
}
func (u *LogService) PageLoginLog(search dto.PageInfo) (int64, interface{}, error) {
total, ops, err := logRepo.PageLoginLog(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
func (u *LogService) PageLoginLog(req dto.SearchLgLogWithPage) (int64, interface{}, error) {
total, ops, err := logRepo.PageLoginLog(
req.Page,
req.PageSize,
logRepo.WithByIP(req.IP),
logRepo.WithByStatus(req.Status),
commonRepo.WithOrderBy("created_at desc"),
)
var dtoOps []dto.LoginLog
for _, op := range ops {
var item dto.LoginLog
@ -45,8 +51,15 @@ func (u *LogService) CreateOperationLog(operation model.OperationLog) error {
return logRepo.CreateOperationLog(&operation)
}
func (u *LogService) PageOperationLog(search dto.PageInfo) (int64, interface{}, error) {
total, ops, err := logRepo.PageOperationLog(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
func (u *LogService) PageOperationLog(req dto.SearchOpLogWithPage) (int64, interface{}, error) {
total, ops, err := logRepo.PageOperationLog(
req.Page,
req.PageSize,
logRepo.WithByGroup(req.Source),
logRepo.WithByLikeOperation(req.Operation),
logRepo.WithByStatus(req.Status),
commonRepo.WithOrderBy("created_at desc"),
)
var dtoOps []dto.OperationLog
for _, op := range ops {
var item dto.OperationLog

View File

@ -25,9 +25,9 @@ func OperationLog() gin.HandlerFunc {
return
}
group := loadLogInfo(c.Request.URL.Path)
source := loadLogInfo(c.Request.URL.Path)
record := model.OperationLog{
Group: group,
Source: source,
IP: c.ClientIP(),
Method: strings.ToLower(c.Request.Method),
Path: strings.ReplaceAll(c.Request.URL.Path, "/api/v1", ""),

View File

@ -1553,7 +1553,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2140,7 +2140,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2351,7 +2351,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2556,7 +2556,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2871,7 +2871,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -3082,7 +3082,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -4423,7 +4423,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -5777,7 +5777,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchLgLogWithPage"
}
}
],
@ -5813,7 +5813,7 @@ var doc = `{
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchOpLogWithPage"
}
}
],
@ -6582,7 +6582,7 @@ var doc = `{
"ApiKeyAuth": []
}
],
"description": "从 OSS 加载系统更新信息",
"description": "系统更新信息",
"tags": [
"System Setting"
],
@ -9996,6 +9996,9 @@ var doc = `{
"filters": {
"type": "string"
},
"name": {
"type": "string"
},
"page": {
"type": "integer"
},
@ -10253,6 +10256,51 @@ var doc = `{
}
}
},
"dto.SearchLgLogWithPage": {
"type": "object",
"required": [
"page",
"pageSize"
],
"properties": {
"ip": {
"type": "string"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"status": {
"type": "string"
}
}
},
"dto.SearchOpLogWithPage": {
"type": "object",
"required": [
"page",
"pageSize"
],
"properties": {
"operation": {
"type": "string"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"dto.SearchRecord": {
"type": "object",
"required": [
@ -10283,7 +10331,6 @@ var doc = `{
"dto.SearchWithPage": {
"type": "object",
"required": [
"info",
"page",
"pageSize"
],
@ -11251,6 +11298,9 @@ var doc = `{
"request.FileOption": {
"type": "object",
"properties": {
"containSub": {
"type": "boolean"
},
"dir": {
"type": "boolean"
},

View File

@ -1539,7 +1539,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2126,7 +2126,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2337,7 +2337,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2542,7 +2542,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -2857,7 +2857,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -3068,7 +3068,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -4409,7 +4409,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchWithPage"
}
}
],
@ -5763,7 +5763,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchLgLogWithPage"
}
}
],
@ -5799,7 +5799,7 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.PageInfo"
"$ref": "#/definitions/dto.SearchOpLogWithPage"
}
}
],
@ -6568,7 +6568,7 @@
"ApiKeyAuth": []
}
],
"description": "从 OSS 加载系统更新信息",
"description": "系统更新信息",
"tags": [
"System Setting"
],
@ -9982,6 +9982,9 @@
"filters": {
"type": "string"
},
"name": {
"type": "string"
},
"page": {
"type": "integer"
},
@ -10239,6 +10242,51 @@
}
}
},
"dto.SearchLgLogWithPage": {
"type": "object",
"required": [
"page",
"pageSize"
],
"properties": {
"ip": {
"type": "string"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"status": {
"type": "string"
}
}
},
"dto.SearchOpLogWithPage": {
"type": "object",
"required": [
"page",
"pageSize"
],
"properties": {
"operation": {
"type": "string"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"source": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"dto.SearchRecord": {
"type": "object",
"required": [
@ -10269,7 +10317,6 @@
"dto.SearchWithPage": {
"type": "object",
"required": [
"info",
"page",
"pageSize"
],
@ -11237,6 +11284,9 @@
"request.FileOption": {
"type": "object",
"properties": {
"containSub": {
"type": "boolean"
},
"dir": {
"type": "boolean"
},

View File

@ -1049,6 +1049,8 @@ definitions:
properties:
filters:
type: string
name:
type: string
page:
type: integer
pageSize:
@ -1222,6 +1224,36 @@ definitions:
info:
type: string
type: object
dto.SearchLgLogWithPage:
properties:
ip:
type: string
page:
type: integer
pageSize:
type: integer
status:
type: string
required:
- page
- pageSize
type: object
dto.SearchOpLogWithPage:
properties:
operation:
type: string
page:
type: integer
pageSize:
type: integer
source:
type: string
status:
type: string
required:
- page
- pageSize
type: object
dto.SearchRecord:
properties:
cronjobID:
@ -1249,7 +1281,6 @@ definitions:
pageSize:
type: integer
required:
- info
- page
- pageSize
type: object
@ -1883,6 +1914,8 @@ definitions:
type: object
request.FileOption:
properties:
containSub:
type: boolean
dir:
type: boolean
expand:
@ -3562,7 +3595,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
responses:
"200":
description: OK
@ -3935,7 +3968,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
produces:
- application/json
responses:
@ -4069,7 +4102,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
produces:
- application/json
responses:
@ -4200,7 +4233,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
produces:
- application/json
responses:
@ -4398,7 +4431,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
produces:
- application/json
responses:
@ -4532,7 +4565,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
produces:
- application/json
responses:
@ -5390,7 +5423,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchWithPage'
responses:
"200":
description: OK
@ -6253,7 +6286,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchLgLogWithPage'
responses:
"200":
description: OK
@ -6275,7 +6308,7 @@ paths:
name: request
required: true
schema:
$ref: '#/definitions/dto.PageInfo'
$ref: '#/definitions/dto.SearchOpLogWithPage'
responses:
"200":
description: OK
@ -6763,7 +6796,7 @@ paths:
paramKeys: []
/settings/upgrade:
get:
description: 从 OSS 加载系统更新信息
description: 系统更新信息
responses:
"200":
description: OK

View File

@ -7,6 +7,7 @@ export namespace Container {
newName: string;
}
export interface ContainerSearch extends ReqPage {
name: string;
filters: string;
}
export interface ContainerCreate {

View File

@ -18,6 +18,11 @@ export interface ReqPage {
page: number;
pageSize: number;
}
export interface SearchWithPage {
info: string;
page: number;
pageSize: number;
}
export interface CommonModel {
id: number;
CreatedAt?: string;

View File

@ -1,9 +1,9 @@
import { DateTimeFormats } from '@intlify/core-base';
import { ReqPage } from '.';
export namespace Log {
export interface OperationLog {
id: number;
group: string;
source: string;
action: string;
ip: string;
@ -20,6 +20,15 @@ export namespace Log {
detail: string;
createdAt: DateTimeFormats;
}
export interface SearchOpLog extends ReqPage {
source: string;
status: string;
operation: string;
}
export interface SearchLgLog extends ReqPage {
ip: string;
status: string;
}
export interface LoginLogs {
ip: string;
address: string;

View File

@ -1,5 +1,5 @@
import http from '@/api';
import { ResPage, ReqPage } from '../interface';
import { ResPage, SearchWithPage } from '../interface';
import { Container } from '../interface/container';
export const searchContainer = (params: Container.ContainerSearch) => {
@ -22,7 +22,7 @@ export const inspect = (params: Container.ContainerInspect) => {
};
// image
export const searchImage = (params: ReqPage) => {
export const searchImage = (params: SearchWithPage) => {
return http.post<ResPage<Container.ImageInfo>>(`/containers/image/search`, params);
};
export const listImage = () => {
@ -51,7 +51,7 @@ export const imageRemove = (params: Container.BatchDelete) => {
};
// network
export const searchNetwork = (params: ReqPage) => {
export const searchNetwork = (params: SearchWithPage) => {
return http.post<ResPage<Container.NetworkInfo>>(`/containers/network/search`, params);
};
export const deleteNetwork = (params: Container.BatchDelete) => {
@ -62,7 +62,7 @@ export const createNetwork = (params: Container.NetworkCreate) => {
};
// volume
export const searchVolume = (params: ReqPage) => {
export const searchVolume = (params: SearchWithPage) => {
return http.post<ResPage<Container.VolumeInfo>>(`/containers/volume/search`, params);
};
export const listVolume = () => {
@ -76,7 +76,7 @@ export const createVolume = (params: Container.VolumeCreate) => {
};
// repo
export const searchImageRepo = (params: ReqPage) => {
export const searchImageRepo = (params: SearchWithPage) => {
return http.post<ResPage<Container.RepoInfo>>(`/containers/repo/search`, params);
};
export const listImageRepo = () => {
@ -93,7 +93,7 @@ export const deleteImageRepo = (params: Container.RepoDelete) => {
};
// composeTemplate
export const searchComposeTemplate = (params: ReqPage) => {
export const searchComposeTemplate = (params: SearchWithPage) => {
return http.post<ResPage<Container.TemplateInfo>>(`/containers/template/search`, params);
};
export const listComposeTemplate = () => {
@ -110,7 +110,7 @@ export const updateComposeTemplate = (params: Container.TemplateUpdate) => {
};
// compose
export const searchCompose = (params: ReqPage) => {
export const searchCompose = (params: SearchWithPage) => {
return http.post<ResPage<Container.ComposeInfo>>(`/containers/compose/search`, params);
};
export const upCompose = (params: Container.ComposeCreate) => {

View File

@ -1,8 +1,8 @@
import http from '@/api';
import { ResPage, ReqPage } from '../interface';
import { ResPage, SearchWithPage } from '../interface';
import { Cronjob } from '../interface/cronjob';
export const getCronjobPage = (params: ReqPage) => {
export const getCronjobPage = (params: SearchWithPage) => {
return http.post<ResPage<Cronjob.CronjobInfo>>(`/cronjobs/search`, params);
};

View File

@ -1,8 +1,8 @@
import http from '@/api';
import { ReqPage, ResPage } from '../interface';
import { SearchWithPage, ReqPage, ResPage } from '../interface';
import { Database } from '../interface/database';
export const searchMysqlDBs = (params: ReqPage) => {
export const searchMysqlDBs = (params: SearchWithPage) => {
return http.post<ResPage<Database.MysqlDBInfo>>(`/databases/search`, params);
};

View File

@ -1,12 +1,12 @@
import http from '@/api';
import { ResPage, ReqPage } from '../interface';
import { ResPage } from '../interface';
import { Log } from '../interface/log';
export const getOperationLogs = (info: ReqPage) => {
export const getOperationLogs = (info: Log.SearchOpLog) => {
return http.post<ResPage<Log.OperationLog>>(`/logs/operation`, info);
};
export const getLoginLogs = (info: ReqPage) => {
export const getLoginLogs = (info: Log.SearchLgLog) => {
return http.post<ResPage<Log.OperationLog>>(`/logs/login`, info);
};

View File

@ -43,6 +43,7 @@ export default {
dateEnd: 'Date end',
},
table: {
all: 'All',
total: 'Total {0}',
name: 'Name',
type: 'Type',
@ -611,6 +612,7 @@ export default {
users: 'User',
hosts: 'Host',
apps: 'App',
websites: 'Website',
containers: 'Container',
commands: 'Command',
groups: 'System Group',

View File

@ -45,6 +45,7 @@ export default {
dateEnd: '结束日期',
},
table: {
all: '所有',
total: ' {0} ',
name: '名称',
type: '类型',
@ -528,9 +529,6 @@ export default {
website: '备份网站',
rulesHelper: '压缩排除规则( ; 号为分隔符)例如 \n*.log;*.sql',
lastRecrodTime: '上次执行时间',
all: '所有',
failedRecord: '失败任务',
successRecord: '成功任务',
database: '备份数据库',
missBackupAccount: '未能找到备份账号',
syncDate: '同步时间 ',
@ -569,7 +567,7 @@ export default {
shellContent: '脚本内容',
errRecord: '错误的日志记录',
errHandle: '任务执行失败',
noRecord: '执行未产生任何日志',
noRecord: '当前计划任务暂未产生记录',
},
monitor: {
avgLoad: '平均负载',
@ -634,6 +632,7 @@ export default {
users: '用户',
hosts: '主机',
apps: '应用',
websites: '网站',
containers: '容器',
groups: '系统组',
commands: '快捷命令',

View File

@ -18,9 +18,26 @@
:class="{ mask: dockerStatus != 'Running' }"
>
<template #toolbar>
<el-button type="primary" @click="onOpenDialog()">
{{ $t('container.createCompose') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onOpenDialog()">
{{ $t('container.createCompose') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -95,6 +112,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -110,6 +128,7 @@ const goSetting = async () => {
const search = async () => {
let params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -13,32 +13,49 @@
:class="{ mask: dockerStatus != 'Running' }"
>
<template #toolbar>
<el-button type="primary" @click="onCreate()">
{{ $t('container.createContainer') }}
</el-button>
<el-button-group style="margin-left: 10px">
<el-button :disabled="checkStatus('start')" @click="onOperate('start')">
{{ $t('container.start') }}
</el-button>
<el-button :disabled="checkStatus('stop')" @click="onOperate('stop')">
{{ $t('container.stop') }}
</el-button>
<el-button :disabled="checkStatus('restart')" @click="onOperate('restart')">
{{ $t('container.restart') }}
</el-button>
<el-button :disabled="checkStatus('kill')" @click="onOperate('kill')">
{{ $t('container.kill') }}
</el-button>
<el-button :disabled="checkStatus('pause')" @click="onOperate('pause')">
{{ $t('container.pause') }}
</el-button>
<el-button :disabled="checkStatus('unpause')" @click="onOperate('unpause')">
{{ $t('container.unpause') }}
</el-button>
<el-button :disabled="checkStatus('remove')" @click="onOperate('remove')">
{{ $t('container.remove') }}
</el-button>
</el-button-group>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onCreate()">
{{ $t('container.createContainer') }}
</el-button>
<el-button-group style="margin-left: 10px">
<el-button :disabled="checkStatus('start')" @click="onOperate('start')">
{{ $t('container.start') }}
</el-button>
<el-button :disabled="checkStatus('stop')" @click="onOperate('stop')">
{{ $t('container.stop') }}
</el-button>
<el-button :disabled="checkStatus('restart')" @click="onOperate('restart')">
{{ $t('container.restart') }}
</el-button>
<el-button :disabled="checkStatus('kill')" @click="onOperate('kill')">
{{ $t('container.kill') }}
</el-button>
<el-button :disabled="checkStatus('pause')" @click="onOperate('pause')">
{{ $t('container.pause') }}
</el-button>
<el-button :disabled="checkStatus('unpause')" @click="onOperate('unpause')">
{{ $t('container.unpause') }}
</el-button>
<el-button :disabled="checkStatus('remove')" @click="onOperate('remove')">
{{ $t('container.remove') }}
</el-button>
</el-button-group>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -124,6 +141,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -153,6 +171,7 @@ const dialogReNameRef = ref();
const search = async () => {
let filterItem = props.filters ? props.filters : '';
let params = {
name: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
filters: filterItem,

View File

@ -10,15 +10,32 @@
<LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }">
<template #toolbar>
<el-button type="primary" plain @click="onOpenPull">
{{ $t('container.imagePull') }}
</el-button>
<el-button type="primary" plain @click="onOpenload">
{{ $t('container.importImage') }}
</el-button>
<el-button type="primary" plain @click="onOpenBuild">
{{ $t('container.build') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" plain @click="onOpenPull">
{{ $t('container.imagePull') }}
</el-button>
<el-button type="primary" plain @click="onOpenload">
{{ $t('container.importImage') }}
</el-button>
<el-button type="primary" plain @click="onOpenBuild">
{{ $t('container.build') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search">
@ -105,6 +122,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -134,6 +152,7 @@ const deleteForm = reactive({
const search = async () => {
const repoSearch = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -14,12 +14,29 @@
:class="{ mask: dockerStatus != 'Running' }"
>
<template #toolbar>
<el-button type="primary" @click="onCreate()">
{{ $t('container.createNetwork') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onCreate()">
{{ $t('container.createNetwork') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -104,6 +121,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -132,6 +150,7 @@ function selectable(row) {
const search = async () => {
const params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -10,12 +10,29 @@
<LayoutContent v-loading="loading" :title="$t('container.repo')" :class="{ mask: dockerStatus != 'Running' }">
<template #toolbar>
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createRepo') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createRepo') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -78,6 +95,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -93,6 +111,7 @@ const goSetting = async () => {
const search = async () => {
let params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -14,12 +14,29 @@
:class="{ mask: dockerStatus != 'Running' }"
>
<template #toolbar>
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createComposeTemplate') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createComposeTemplate') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -109,6 +126,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -124,6 +142,7 @@ const goSetting = async () => {
const search = async () => {
let params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -10,12 +10,29 @@
<LayoutContent v-loading="loading" :title="$t('container.volume')" :class="{ mask: dockerStatus != 'Running' }">
<template #toolbar>
<el-button type="primary" @click="onCreate()">
{{ $t('container.createVolume') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onCreate()">
{{ $t('container.createVolume') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -88,6 +105,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const dockerStatus = ref();
const loadStatus = async () => {
@ -112,6 +130,7 @@ const onCreate = async () => {
const search = async () => {
const params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -10,12 +10,29 @@
/>
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('cronjob.cronTask')">
<template #toolbar>
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main>
<ComplexTable
@ -25,12 +42,12 @@
:data="data"
>
<el-table-column type="selection" fix />
<el-table-column :label="$t('cronjob.taskName')" prop="name">
<el-table-column :label="$t('cronjob.taskName')" :min-width="120" prop="name">
<template #default="{ row }">
<el-link @click="loadDetail(row)" type="primary">{{ row.name }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
<el-table-column :label="$t('commons.table.status')" :min-width="80" prop="status">
<template #default="{ row }">
<el-button
v-if="row.status === 'Enable'"
@ -45,7 +62,7 @@
</el-button>
</template>
</el-table-column>
<el-table-column :label="$t('cronjob.cronSpec')">
<el-table-column :label="$t('cronjob.cronSpec')" :min-width="120">
<template #default="{ row }">
<span v-if="row.specType.indexOf('N') === -1 || row.specType === 'perWeek'">
{{ $t('cronjob.' + row.specType) }}
@ -73,18 +90,18 @@
{{ $t('cronjob.handle') }}
</template>
</el-table-column>
<el-table-column :label="$t('cronjob.retainCopies')" :width="90" prop="retainCopies">
<el-table-column :label="$t('cronjob.retainCopies')" :min-width="90" prop="retainCopies">
<template #default="{ row }">
{{ loadCopies(row) }}
</template>
</el-table-column>
<el-table-column :label="$t('cronjob.lastRecrodTime')" prop="lastRecrodTime">
<el-table-column :label="$t('cronjob.lastRecrodTime')" :min-width="120" prop="lastRecrodTime">
<template #default="{ row }">
{{ row.lastRecrodTime }}
</template>
</el-table-column>
<el-table-column :width="80" :label="$t('cronjob.target')" prop="targetDir">
<el-table-column :min-width="80" :label="$t('cronjob.target')" prop="targetDir">
<template #default="{ row }">
{{ loadBackupName(row.targetDir) }}
</template>
@ -101,7 +118,7 @@
</LayoutContent>
<OperatrDialog @search="search" ref="dialogRef" />
<Records ref="dialogRecordRef" />
<Records @search="search()" ref="dialogRecordRef" />
</div>
</template>
@ -130,6 +147,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const weekOptions = [
{ label: i18n.global.t('cronjob.monday'), value: 1 },
@ -143,6 +161,7 @@ const weekOptions = [
const search = async () => {
let params = {
info: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};
@ -261,13 +280,6 @@ const buttons = [
onBatchDelete(row);
},
},
{
label: i18n.global.t('cronjob.record'),
icon: 'Clock',
click: (row: Cronjob.CronjobInfo) => {
loadDetail(row);
},
},
];
function loadWeek(i: number) {
for (const week of weekOptions) {

View File

@ -3,9 +3,14 @@
<div class="a-card" style="margin-top: 20px">
<el-card>
<div>
<el-tag style="float: left" effect="dark" type="success">{{ dialogData.rowData.name }}</el-tag>
<el-tag round class="status-content" type="success">
{{ $t('cronjob.' + dialogData.rowData.type) }}
<el-tag style="float: left" effect="dark" type="success">
{{ dialogData.rowData.name }}-{{ $t('cronjob.' + dialogData.rowData.type) }}
</el-tag>
<el-tag v-if="dialogData.rowData.status === 'Enable'" round class="status-content" type="success">
{{ $t('commons.status.running') }}
</el-tag>
<el-tag v-if="dialogData.rowData.status === 'Disable'" round class="status-content" type="info">
{{ $t('commons.status.stopped') }}
</el-tag>
<el-tag class="status-content">
<span
@ -47,13 +52,30 @@
<el-button type="primary" @click="onHandle(dialogData.rowData)" link>
{{ $t('commons.button.handle') }}
</el-button>
<el-divider direction="vertical" />
<el-button
type="primary"
v-if="dialogData.rowData.status === 'Enable'"
@click="onChangeStatus(dialogData.rowData.id, 'disable')"
link
>
{{ $t('commons.button.disable') }}
</el-button>
<el-button
type="primary"
v-if="dialogData.rowData.status === 'Disable'"
@click="onChangeStatus(dialogData.rowData.id, 'enable')"
link
>
{{ $t('commons.button.enable') }}
</el-button>
</span>
</div>
</el-card>
</div>
<LayoutContent :title="$t('cronjob.record')" :reload="true">
<template #search>
<template #search v-if="hasRecords">
<el-row :gutter="20">
<el-col :span="6">
<el-date-picker
@ -69,15 +91,16 @@
</el-col>
<el-col :span="18">
<el-select @change="search()" v-model="searchInfo.status">
<el-option :label="$t('cronjob.all')" value="" />
<el-option :label="$t('cronjob.failedRecord')" value="Failed" />
<el-option :label="$t('cronjob.successRecord')" value="Success" />
<template #prefix>{{ $t('commons.table.status') }}</template>
<el-option :label="$t('commons.table.all')" value="" />
<el-option :label="$t('commons.status.success')" value="Success" />
<el-option :label="$t('commons.status.failed')" value="Failed" />
</el-select>
</el-col>
</el-row>
</template>
<template #main>
<el-row :gutter="20">
<el-row :gutter="20" v-if="hasRecords">
<el-col :span="6">
<el-card>
<ul v-infinite-scroll="nextPage" class="infinite-list" style="overflow: auto">
@ -233,6 +256,14 @@
</el-card>
</el-col>
</el-row>
<div class="app-warn" v-if="!hasRecords">
<div>
<span>{{ $t('cronjob.noRecord') }}</span>
<div>
<img src="@/assets/images/no_app.svg" />
</div>
</div>
</div>
</template>
</LayoutContent>
</div>
@ -243,10 +274,10 @@ import { reactive, ref } from 'vue';
import { Cronjob } from '@/api/interface/cronjob';
import { loadZero } from '@/utils/util';
import { loadBackupName } from '@/views/setting/helper';
import { searchRecords, download, handleOnce } from '@/api/modules/cronjob';
import { searchRecords, download, handleOnce, updateStatus } from '@/api/modules/cronjob';
import { dateFormat, dateFormatForName } from '@/utils/util';
import i18n from '@/lang';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { LoadFile } from '@/api/modules/files';
import LayoutContent from '@/layout/layout-content.vue';
import { Codemirror } from 'vue-codemirror';
@ -254,6 +285,7 @@ import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark';
const loading = ref();
const hasRecords = ref();
const mymirror = ref();
const extensions = [javascript(), oneDark];
@ -281,9 +313,11 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
const res = await searchRecords(itemSearch);
records.value = res.data.items || [];
if (records.value.length === 0) {
ElMessage.info(i18n.global.t('commons.msg.notRecords'));
hasRecords.value = false;
recordShow.value = true;
return;
}
hasRecords.value = true;
currentRecord.value = records.value[0];
currentRecordIndex.value = 0;
loadRecord(currentRecord.value.records);
@ -367,6 +401,18 @@ const onHandle = async (row: Cronjob.CronjobInfo) => {
});
};
const onChangeStatus = async (id: number, status: string) => {
ElMessageBox.confirm(i18n.global.t('cronjob.' + status + 'Msg'), i18n.global.t('cronjob.changeStatus'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
}).then(async () => {
let itemStatus = status === 'enable' ? 'Enable' : 'Disable';
await updateStatus({ id: id, status: itemStatus });
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
dialogData.value.rowData.status = itemStatus;
});
};
const search = async () => {
if (timeRangeLoad.value && timeRangeLoad.value.length === 2) {
searchInfo.startTime = timeRangeLoad.value[0];
@ -489,4 +535,26 @@ defineExpose({
float: left;
margin-left: 50px;
}
.app-warn {
text-align: center;
margin-top: 100px;
span:first-child {
color: #bbbfc4;
}
span:nth-child(2) {
color: $primary-color;
cursor: pointer;
}
span:nth-child(2):hover {
color: #74a4f3;
}
img {
width: 300px;
height: 300px;
}
}
</style>

View File

@ -11,18 +11,33 @@
</template>
<template #toolbar v-if="mysqlIsExist && !isOnSetting">
<div :class="{ mask: mysqlStatus != 'Running' }">
<el-button type="primary" @click="onOpenDialog()">
{{ $t('database.create') }}
</el-button>
<el-button @click="onChangeRootPassword" type="primary" plain>
{{ $t('database.rootPassword') }}
</el-button>
<el-button @click="onChangeAccess" type="primary" plain>
{{ $t('database.remoteAccess') }}
</el-button>
<el-button @click="goDashboard" type="primary" plain>phpMyAdmin</el-button>
</div>
<el-row :class="{ mask: mysqlStatus != 'Running' }">
<el-col :span="20">
<el-button type="primary" @click="onOpenDialog()">
{{ $t('database.create') }}
</el-button>
<el-button @click="onChangeRootPassword" type="primary" plain>
{{ $t('database.rootPassword') }}
</el-button>
<el-button @click="onChangeAccess" type="primary" plain>
{{ $t('database.remoteAccess') }}
</el-button>
<el-button @click="goDashboard" type="primary" plain>phpMyAdmin</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #main v-if="mysqlIsExist && !isOnSetting">
<ComplexTable
@ -172,6 +187,7 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
const searchName = ref();
const mysqlIsExist = ref(false);
const mysqlContainer = ref();
@ -228,6 +244,7 @@ const search = async () => {
let params = {
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
info: searchName.value,
};
const res = await searchMysqlDBs(params);
data.value = res.data.items || [];

View File

@ -2,9 +2,35 @@
<div>
<LayoutContent v-loading="loading" :title="$t('logs.login')">
<template #toolbar>
<el-button type="primary" plain @click="onClean()">
{{ $t('logs.deleteLogs') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" plain @click="onClean()">
{{ $t('logs.deleteLogs') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchIP"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search') + ' ip'"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #search>
<el-select v-model="searchStatus" @change="search()" clearable>
<template #prefix>{{ $t('commons.table.status') }}</template>
<el-option :label="$t('commons.table.all')" value=""></el-option>
<el-option :label="$t('commons.status.success')" value="Success"></el-option>
<el-option :label="$t('commons.status.failed')" value="Failed"></el-option>
</el-select>
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search">
@ -51,12 +77,16 @@ const data = ref();
const confirmDialogRef = ref();
const paginationConfig = reactive({
currentPage: 1,
pageSize: 15,
pageSize: 10,
total: 0,
});
const searchIP = ref();
const searchStatus = ref();
const search = async () => {
let params = {
ip: searchIP.value,
status: searchStatus.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
};

View File

@ -2,15 +2,56 @@
<div>
<LayoutContent v-loading="loading" :title="$t('logs.operation')">
<template #toolbar>
<el-button type="primary" plain @click="onClean()">
{{ $t('logs.deleteLogs') }}
</el-button>
<el-row>
<el-col :span="20">
<el-button type="primary" plain @click="onClean()">
{{ $t('logs.deleteLogs') }}
</el-button>
</el-col>
<el-col :span="4">
<div class="search-button">
<el-input
v-model="searchName"
clearable
@clear="search()"
suffix-icon="Search"
@keyup.enter="search()"
@blur="search()"
:placeholder="$t('commons.button.search')"
></el-input>
</div>
</el-col>
</el-row>
</template>
<template #search>
<el-select v-model="searchGroup" @change="search()" clearable>
<template #prefix>{{ $t('logs.resource') }}</template>
<el-option :label="$t('commons.table.all')" value=""></el-option>
<el-option :label="$t('logs.detail.apps')" value="apps"></el-option>
<el-option :label="$t('logs.detail.websites')" value="websites"></el-option>
<el-option :label="$t('logs.detail.databases')" value="databases"></el-option>
<el-option :label="$t('logs.detail.containers')" value="containers"></el-option>
<el-option :label="$t('logs.detail.cronjobs')" value="cronjobs"></el-option>
<el-option :label="$t('logs.detail.files')" value="files"></el-option>
<el-option :label="$t('logs.detail.hosts')" value="hosts"></el-option>
<el-option :label="$t('logs.detail.commands')" value="commands"></el-option>
<el-option :label="$t('logs.detail.logs')" value="logs"></el-option>
<el-option :label="$t('logs.detail.settings')" value="settings"></el-option>
<el-option :label="$t('logs.detail.backups')" value="backups"></el-option>
<el-option :label="$t('logs.detail.groups')" value="groups"></el-option>
</el-select>
<el-select v-model="searchStatus" @change="search()" clearable style="margin-left: 10px">
<template #prefix>{{ $t('commons.table.status') }}</template>
<el-option :label="$t('commons.table.all')" value=""></el-option>
<el-option :label="$t('commons.status.success')" value="Success"></el-option>
<el-option :label="$t('commons.status.failed')" value="Failed"></el-option>
</el-select>
</template>
<template #main>
<ComplexTable :pagination-config="paginationConfig" :data="data" @search="search">
<el-table-column :label="$t('logs.resource')" prop="group" fix>
<template #default="{ row }">
{{ $t('logs.detail.' + row.group) }}
{{ $t('logs.detail.' + row.source) }}
</template>
</el-table-column>
<el-table-column :label="$t('logs.operate')" min-width="150px" prop="detailZH" />
@ -63,14 +104,20 @@ const data = ref();
const confirmDialogRef = ref();
const paginationConfig = reactive({
currentPage: 1,
pageSize: 15,
pageSize: 10,
total: 0,
});
const searchName = ref();
const searchGroup = ref();
const searchStatus = ref();
const search = async () => {
let params = {
operation: searchName.value,
page: paginationConfig.currentPage,
pageSize: paginationConfig.pageSize,
status: searchStatus.value,
source: searchGroup.value,
};
loading.value = true;
await getOperationLogs(params)