mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-18 22:22:59 +08:00
feat: 计划任务支持多周期执行 (#3676)
This commit is contained in:
parent
64def5bebd
commit
115b9c58b0
@ -3,14 +3,9 @@ package dto
|
||||
import "time"
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
SpecType string `json:"specType" validate:"required"`
|
||||
Week int `json:"week" validate:"number,max=6,min=0"`
|
||||
Day int `json:"day" validate:"number"`
|
||||
Hour int `json:"hour" validate:"number"`
|
||||
Minute int `json:"minute" validate:"number"`
|
||||
Second int `json:"second" validate:"number"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
@ -27,14 +22,9 @@ type CronjobCreate struct {
|
||||
}
|
||||
|
||||
type CronjobUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
SpecType string `json:"specType" validate:"required"`
|
||||
Week int `json:"week" validate:"number,max=6,min=0"`
|
||||
Day int `json:"day" validate:"number"`
|
||||
Hour int `json:"hour" validate:"number"`
|
||||
Minute int `json:"minute" validate:"number"`
|
||||
Second int `json:"second" validate:"number"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
@ -71,15 +61,10 @@ type CronjobBatchDelete struct {
|
||||
}
|
||||
|
||||
type CronjobInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SpecType string `json:"specType"`
|
||||
Week int `json:"week"`
|
||||
Day int `json:"day"`
|
||||
Hour int `json:"hour"`
|
||||
Minute int `json:"minute"`
|
||||
Second int `json:"second"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Spec string `json:"spec"`
|
||||
|
||||
Script string `json:"script"`
|
||||
ContainerName string `json:"containerName"`
|
||||
|
@ -5,15 +5,9 @@ import "time"
|
||||
type Cronjob struct {
|
||||
BaseModel
|
||||
|
||||
Name string `gorm:"type:varchar(64);not null;unique" json:"name"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
SpecType string `gorm:"type:varchar(64);not null" json:"specType"`
|
||||
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
|
||||
Week uint64 `gorm:"type:decimal" json:"week"`
|
||||
Day uint64 `gorm:"type:decimal" json:"day"`
|
||||
Hour uint64 `gorm:"type:decimal" json:"hour"`
|
||||
Minute uint64 `gorm:"type:decimal" json:"minute"`
|
||||
Second uint64 `gorm:"type:decimal" json:"second"`
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
Type string `gorm:"type:varchar(64);not null" json:"type"`
|
||||
Spec string `gorm:"type:varchar(64);not null" json:"spec"`
|
||||
|
||||
ContainerName string `gorm:"type:varchar(64)" json:"containerName"`
|
||||
Script string `gorm:"longtext" json:"script"`
|
||||
@ -29,9 +23,9 @@ type Cronjob struct {
|
||||
TargetDirID uint64 `gorm:"type:decimal" json:"targetDirID"`
|
||||
RetainCopies uint64 `gorm:"type:decimal" json:"retainCopies"`
|
||||
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
EntryID uint64 `gorm:"type:decimal" json:"entryID"`
|
||||
Records []JobRecords `json:"records"`
|
||||
Status string `gorm:"type:varchar(64)" json:"status"`
|
||||
EntryIDs string `gorm:"type:varchar(64)" json:"entryIDs"`
|
||||
Records []JobRecords `json:"records"`
|
||||
}
|
||||
|
||||
type JobRecords struct {
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@ -28,7 +30,7 @@ type ICronjobService interface {
|
||||
UpdateStatus(id uint, status string) error
|
||||
Delete(req dto.CronjobBatchDelete) error
|
||||
Download(down dto.CronjobDownload) (string, error)
|
||||
StartJob(cronjob *model.Cronjob) (int, error)
|
||||
StartJob(cronjob *model.Cronjob) (string, error)
|
||||
CleanRecord(req dto.CronjobClean) error
|
||||
|
||||
LoadRecordLog(req dto.OperateByID) (string, error)
|
||||
@ -184,29 +186,40 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
cronjob.Status = constant.StatusEnable
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
|
||||
global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec)
|
||||
entryID, err := u.StartJob(&cronjob)
|
||||
spec := cronjob.Spec
|
||||
entryIDs, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.EntryID = uint64(entryID)
|
||||
cronjob.Spec = spec
|
||||
cronjob.EntryIDs = entryIDs
|
||||
if err := cronjobRepo.Create(&cronjob); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
|
||||
if cronjob.EntryID != 0 {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (string, error) {
|
||||
if len(cronjob.EntryIDs) != 0 {
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
}
|
||||
entryID, err := u.AddCronJob(cronjob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
specs := strings.Split(cronjob.Spec, ",")
|
||||
var ids []string
|
||||
for _, spec := range specs {
|
||||
cronjob.Spec = spec
|
||||
entryID, err := u.AddCronJob(cronjob)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ids = append(ids, fmt.Sprintf("%v", entryID))
|
||||
}
|
||||
return entryID, nil
|
||||
return strings.Join(ids, ","), nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
@ -215,8 +228,12 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
|
||||
if cronjob.ID == 0 {
|
||||
return errors.New("find cronjob in db failed")
|
||||
}
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
||||
if err := u.CleanRecord(dto.CronjobClean{CronjobID: id, CleanData: req.CleanData}); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -238,29 +255,27 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
upMap := make(map[string]interface{})
|
||||
cronjob.EntryID = cronModel.EntryID
|
||||
cronjob.EntryIDs = cronModel.EntryIDs
|
||||
cronjob.Type = cronModel.Type
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
spec := cronjob.Spec
|
||||
if cronModel.Status == constant.StatusEnable {
|
||||
newEntryID, err := u.StartJob(&cronjob)
|
||||
newEntryIDs, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upMap["entry_id"] = newEntryID
|
||||
upMap["entry_ids"] = newEntryIDs
|
||||
} else {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
}
|
||||
|
||||
upMap["name"] = req.Name
|
||||
upMap["spec"] = cronjob.Spec
|
||||
upMap["spec"] = spec
|
||||
upMap["script"] = req.Script
|
||||
upMap["container_name"] = req.ContainerName
|
||||
upMap["spec_type"] = req.SpecType
|
||||
upMap["week"] = req.Week
|
||||
upMap["day"] = req.Day
|
||||
upMap["hour"] = req.Hour
|
||||
upMap["minute"] = req.Minute
|
||||
upMap["second"] = req.Second
|
||||
upMap["app_id"] = req.AppID
|
||||
upMap["website"] = req.Website
|
||||
upMap["exclusion_rules"] = req.ExclusionRules
|
||||
@ -280,19 +295,23 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
return errors.WithMessage(constant.ErrRecordNotFound, "record not found")
|
||||
}
|
||||
var (
|
||||
entryID int
|
||||
err error
|
||||
entryIDs string
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
entryID, err = u.StartJob(&cronjob)
|
||||
entryIDs, err = u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
ids := strings.Split(cronjob.EntryIDs, ",")
|
||||
for _, id := range ids {
|
||||
idItem, _ := strconv.Atoi(id)
|
||||
global.Cron.Remove(cron.EntryID(idItem))
|
||||
}
|
||||
global.LOG.Infof("stop cronjob entryID: %s", cronjob.EntryIDs)
|
||||
}
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_id": entryID})
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_ids": entryIDs})
|
||||
}
|
||||
|
||||
func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
|
||||
@ -328,26 +347,3 @@ func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte)
|
||||
write.Flush()
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func loadSpec(cronjob model.Cronjob) string {
|
||||
switch cronjob.SpecType {
|
||||
case "perMonth":
|
||||
return fmt.Sprintf("%v %v %v * *", cronjob.Minute, cronjob.Hour, cronjob.Day)
|
||||
case "perWeek":
|
||||
return fmt.Sprintf("%v %v * * %v", cronjob.Minute, cronjob.Hour, cronjob.Week)
|
||||
case "perNDay":
|
||||
return fmt.Sprintf("%v %v */%v * *", cronjob.Minute, cronjob.Hour, cronjob.Day)
|
||||
case "perDay":
|
||||
return fmt.Sprintf("%v %v * * *", cronjob.Minute, cronjob.Hour)
|
||||
case "perNHour":
|
||||
return fmt.Sprintf("%v */%v * * *", cronjob.Minute, cronjob.Hour)
|
||||
case "perHour":
|
||||
return fmt.Sprintf("%v * * * *", cronjob.Minute)
|
||||
case "perNMinute":
|
||||
return fmt.Sprintf("@every %vm", cronjob.Minute)
|
||||
case "perNSecond":
|
||||
return fmt.Sprintf("@every %vs", cronjob.Second)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
@ -66,11 +66,11 @@ func Run() {
|
||||
global.LOG.Errorf("start my cronjob failed, err: %v", err)
|
||||
}
|
||||
for i := 0; i < len(cronJobs); i++ {
|
||||
entryID, err := service.NewICronjobService().StartJob(&cronJobs[i])
|
||||
entryIDs, err := service.NewICronjobService().StartJob(&cronJobs[i])
|
||||
if err != nil {
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
|
||||
}
|
||||
if err := repo.NewICronjobRepo().Update(cronJobs[i].ID, map[string]interface{}{"entry_id": entryID}); err != nil {
|
||||
if err := repo.NewICronjobRepo().Update(cronJobs[i].ID, map[string]interface{}{"entry_ids": entryIDs}); err != nil {
|
||||
global.LOG.Errorf("update cronjob %s %s failed, err: %v", cronJobs[i].Type, cronJobs[i].Name, err)
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ func Init() {
|
||||
migrations.AddPostgresqlSuperUser,
|
||||
migrations.UpdateCronjobWithWebsite,
|
||||
migrations.UpdateOneDriveToken,
|
||||
migrations.UpdateCronjobSpec,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
@ -254,3 +254,20 @@ var UpdateOneDriveToken = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var UpdateCronjobSpec = &gormigrate.Migration{
|
||||
ID: "20240122-update-cronjob-spec",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.AutoMigrate(&model.Cronjob{}); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN spec_type;").Error
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN week;").Error
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN day;").Error
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN hour;").Error
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN minute;").Error
|
||||
_ = tx.Exec("ALTER TABLE cronjobs DROP COLUMN second;").Error
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -14918,7 +14918,7 @@ const docTemplate = `{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"specType",
|
||||
"spec",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@ -14928,9 +14928,6 @@ const docTemplate = `{
|
||||
"containerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"day": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -14940,15 +14937,9 @@ const docTemplate = `{
|
||||
"exclusionRules": {
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -14959,13 +14950,10 @@ const docTemplate = `{
|
||||
"script": {
|
||||
"type": "string"
|
||||
},
|
||||
"second": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sourceDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"specType": {
|
||||
"spec": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetDirID": {
|
||||
@ -14979,11 +14967,6 @@ const docTemplate = `{
|
||||
},
|
||||
"website": {
|
||||
"type": "string"
|
||||
},
|
||||
"week": {
|
||||
"type": "integer",
|
||||
"maximum": 6,
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -15007,7 +14990,7 @@ const docTemplate = `{
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"specType"
|
||||
"spec"
|
||||
],
|
||||
"properties": {
|
||||
"appID": {
|
||||
@ -15016,9 +14999,6 @@ const docTemplate = `{
|
||||
"containerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"day": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -15028,18 +15008,12 @@ const docTemplate = `{
|
||||
"exclusionRules": {
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -15050,13 +15024,10 @@ const docTemplate = `{
|
||||
"script": {
|
||||
"type": "string"
|
||||
},
|
||||
"second": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sourceDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"specType": {
|
||||
"spec": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetDirID": {
|
||||
@ -15067,11 +15038,6 @@ const docTemplate = `{
|
||||
},
|
||||
"website": {
|
||||
"type": "string"
|
||||
},
|
||||
"week": {
|
||||
"type": "integer",
|
||||
"maximum": 6,
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -14911,7 +14911,7 @@
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"specType",
|
||||
"spec",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
@ -14921,9 +14921,6 @@
|
||||
"containerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"day": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -14933,15 +14930,9 @@
|
||||
"exclusionRules": {
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -14952,13 +14943,10 @@
|
||||
"script": {
|
||||
"type": "string"
|
||||
},
|
||||
"second": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sourceDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"specType": {
|
||||
"spec": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetDirID": {
|
||||
@ -14972,11 +14960,6 @@
|
||||
},
|
||||
"website": {
|
||||
"type": "string"
|
||||
},
|
||||
"week": {
|
||||
"type": "integer",
|
||||
"maximum": 6,
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -15000,7 +14983,7 @@
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"specType"
|
||||
"spec"
|
||||
],
|
||||
"properties": {
|
||||
"appID": {
|
||||
@ -15009,9 +14992,6 @@
|
||||
"containerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"day": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -15021,18 +15001,12 @@
|
||||
"exclusionRules": {
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
@ -15043,13 +15017,10 @@
|
||||
"script": {
|
||||
"type": "string"
|
||||
},
|
||||
"second": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sourceDir": {
|
||||
"type": "string"
|
||||
},
|
||||
"specType": {
|
||||
"spec": {
|
||||
"type": "string"
|
||||
},
|
||||
"targetDirID": {
|
||||
@ -15060,11 +15031,6 @@
|
||||
},
|
||||
"website": {
|
||||
"type": "string"
|
||||
},
|
||||
"week": {
|
||||
"type": "integer",
|
||||
"maximum": 6,
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -582,20 +582,14 @@ definitions:
|
||||
type: string
|
||||
containerName:
|
||||
type: string
|
||||
day:
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
dbType:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
retainCopies:
|
||||
@ -603,11 +597,9 @@ definitions:
|
||||
type: integer
|
||||
script:
|
||||
type: string
|
||||
second:
|
||||
type: integer
|
||||
sourceDir:
|
||||
type: string
|
||||
specType:
|
||||
spec:
|
||||
type: string
|
||||
targetDirID:
|
||||
type: integer
|
||||
@ -617,13 +609,9 @@ definitions:
|
||||
type: string
|
||||
website:
|
||||
type: string
|
||||
week:
|
||||
maximum: 6
|
||||
minimum: 0
|
||||
type: integer
|
||||
required:
|
||||
- name
|
||||
- specType
|
||||
- spec
|
||||
- type
|
||||
type: object
|
||||
dto.CronjobDownload:
|
||||
@ -642,22 +630,16 @@ definitions:
|
||||
type: string
|
||||
containerName:
|
||||
type: string
|
||||
day:
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
dbType:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
retainCopies:
|
||||
@ -665,11 +647,9 @@ definitions:
|
||||
type: integer
|
||||
script:
|
||||
type: string
|
||||
second:
|
||||
type: integer
|
||||
sourceDir:
|
||||
type: string
|
||||
specType:
|
||||
spec:
|
||||
type: string
|
||||
targetDirID:
|
||||
type: integer
|
||||
@ -677,14 +657,10 @@ definitions:
|
||||
type: string
|
||||
website:
|
||||
type: string
|
||||
week:
|
||||
maximum: 6
|
||||
minimum: 0
|
||||
type: integer
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- specType
|
||||
- spec
|
||||
type: object
|
||||
dto.CronjobUpdateStatus:
|
||||
properties:
|
||||
|
@ -5,12 +5,8 @@ export namespace Cronjob {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
specType: string;
|
||||
week: number;
|
||||
day: number;
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
spec: string;
|
||||
specObjs: Array<SpecObj>;
|
||||
|
||||
script: string;
|
||||
inContainer: boolean;
|
||||
@ -31,12 +27,8 @@ export namespace Cronjob {
|
||||
export interface CronjobCreate {
|
||||
name: string;
|
||||
type: string;
|
||||
specType: string;
|
||||
week: number;
|
||||
day: number;
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
spec: string;
|
||||
specObjs: Array<SpecObj>;
|
||||
|
||||
script: string;
|
||||
website: string;
|
||||
@ -49,14 +41,17 @@ export namespace Cronjob {
|
||||
targetDirID: number;
|
||||
retainCopies: number;
|
||||
}
|
||||
export interface CronjobUpdate {
|
||||
id: number;
|
||||
export interface SpecObj {
|
||||
specType: string;
|
||||
week: number;
|
||||
day: number;
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
}
|
||||
export interface CronjobUpdate {
|
||||
id: number;
|
||||
spec: string;
|
||||
|
||||
script: string;
|
||||
website: string;
|
||||
|
227
frontend/src/views/cronjob/helper.ts
Normal file
227
frontend/src/views/cronjob/helper.ts
Normal file
@ -0,0 +1,227 @@
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import i18n from '@/lang';
|
||||
import { loadZero } from '@/utils/util';
|
||||
|
||||
export const specOptions = [
|
||||
{ label: i18n.global.t('cronjob.perMonth'), value: 'perMonth' },
|
||||
{ label: i18n.global.t('cronjob.perWeek'), value: 'perWeek' },
|
||||
{ label: i18n.global.t('cronjob.perDay'), value: 'perDay' },
|
||||
{ label: i18n.global.t('cronjob.perHour'), value: 'perHour' },
|
||||
{ label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' },
|
||||
{ label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' },
|
||||
{ label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' },
|
||||
{ label: i18n.global.t('cronjob.perNSecond'), value: 'perNSecond' },
|
||||
];
|
||||
export const weekOptions = [
|
||||
{ label: i18n.global.t('cronjob.monday'), value: 1 },
|
||||
{ label: i18n.global.t('cronjob.tuesday'), value: 2 },
|
||||
{ label: i18n.global.t('cronjob.wednesday'), value: 3 },
|
||||
{ label: i18n.global.t('cronjob.thursday'), value: 4 },
|
||||
{ label: i18n.global.t('cronjob.friday'), value: 5 },
|
||||
{ label: i18n.global.t('cronjob.saturday'), value: 6 },
|
||||
{ label: i18n.global.t('cronjob.sunday'), value: 0 },
|
||||
];
|
||||
function loadWeek(i: number) {
|
||||
for (const week of weekOptions) {
|
||||
if (week.value === i) {
|
||||
return week.label;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function loadDefaultSpec(type: string) {
|
||||
let item = {} as Cronjob.SpecObj;
|
||||
switch (type) {
|
||||
case 'shell':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'app':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 2;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'database':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 2;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'clean':
|
||||
case 'website':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'log':
|
||||
case 'snapshot':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'directory':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'curl':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
export function checkScript(specType: string, week, day, hour, minute, second) {
|
||||
switch (specType) {
|
||||
case 'perMonth':
|
||||
return day > 0 && day < 32 && hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
|
||||
case 'perWeek':
|
||||
return week >= 0 && week < 7 && hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
|
||||
case 'perDay':
|
||||
return hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
|
||||
case 'perHour':
|
||||
return minute >= 0 && minute < 60;
|
||||
case 'perNDay':
|
||||
return day > 0 && day < 366 && hour >= 0 && hour < 24 && minute >= 0 && minute < 60;
|
||||
case 'perNHour':
|
||||
return hour > 0 && hour < 8784 && minute >= 0 && minute < 60;
|
||||
case 'perNMinute':
|
||||
return minute > 0 && minute < 527040;
|
||||
case 'perNSecond':
|
||||
return second > 0 && second < 31622400;
|
||||
}
|
||||
}
|
||||
|
||||
export function transObjToSpec(specType: string, week, day, hour, minute, second): string {
|
||||
switch (specType) {
|
||||
case 'perMonth':
|
||||
return `${minute} ${hour} ${day} * *`;
|
||||
case 'perWeek':
|
||||
return `${minute} ${hour} * * ${week}`;
|
||||
case 'perNDay':
|
||||
return `${minute} ${hour} */${day} * *`;
|
||||
case 'perDay':
|
||||
return `${minute} ${hour} * * *`;
|
||||
case 'perNHour':
|
||||
return `${minute} */${hour} * * *`;
|
||||
case 'perHour':
|
||||
return `${minute} * * * *`;
|
||||
case 'perNMinute':
|
||||
return `@every ${minute}m`;
|
||||
case 'perNSecond':
|
||||
return `@every ${second}s`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function transSpecToObj(spec: string) {
|
||||
let specs = spec.split(' ');
|
||||
let specItem = {
|
||||
specType: 'perNMinute',
|
||||
week: 0,
|
||||
day: 0,
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
};
|
||||
if (specs.length === 2) {
|
||||
if (specs[1].indexOf('m') !== -1) {
|
||||
specItem.specType = 'perNMinute';
|
||||
specItem.minute = Number(specs[1].replaceAll('m', ''));
|
||||
return specItem;
|
||||
} else {
|
||||
specItem.specType = 'perNSecond';
|
||||
specItem.second = Number(specs[1].replaceAll('s', ''));
|
||||
return specItem;
|
||||
}
|
||||
}
|
||||
if (specs.length !== 5 || specs[0] === '*') {
|
||||
return null;
|
||||
}
|
||||
specItem.minute = Number(specs[0]);
|
||||
if (specs[1] === '*') {
|
||||
specItem.specType = 'perHour';
|
||||
return specItem;
|
||||
}
|
||||
if (specs[1].indexOf('*/') !== -1) {
|
||||
specItem.specType = 'perNHour';
|
||||
specItem.hour = Number(specs[1].replaceAll('*/', ''));
|
||||
return specItem;
|
||||
}
|
||||
specItem.hour = Number(specs[1]);
|
||||
if (specs[2].indexOf('*/') !== -1) {
|
||||
specItem.specType = 'perNDay';
|
||||
specItem.day = Number(specs[2].replaceAll('*/', ''));
|
||||
return specItem;
|
||||
}
|
||||
if (specs[2] !== '*') {
|
||||
specItem.specType = 'perMonth';
|
||||
specItem.day = Number(specs[2]);
|
||||
return specItem;
|
||||
}
|
||||
if (specs[4] !== '*') {
|
||||
specItem.specType = 'perWeek';
|
||||
specItem.week = Number(specs[4]);
|
||||
return specItem;
|
||||
}
|
||||
specItem.specType = 'perDay';
|
||||
return specItem;
|
||||
}
|
||||
|
||||
export function transSpecToStr(spec: string): string {
|
||||
const specObj = transSpecToObj(spec);
|
||||
let str = '';
|
||||
if (specObj.specType.indexOf('N') === -1 || specObj.specType === 'perWeek') {
|
||||
str += i18n.global.t('cronjob.' + specObj.specType) + ' ';
|
||||
} else {
|
||||
str += i18n.global.t('cronjob.per') + ' ';
|
||||
}
|
||||
switch (specObj.specType) {
|
||||
case 'perMonth':
|
||||
str +=
|
||||
specObj.day +
|
||||
i18n.global.t('cronjob.day') +
|
||||
' ' +
|
||||
loadZero(specObj.hour) +
|
||||
':' +
|
||||
loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perWeek':
|
||||
str += loadWeek(specObj.week) + ' ' + loadZero(specObj.hour) + ':' + loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perDay':
|
||||
str += loadZero(specObj.hour) + ':' + loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perNDay':
|
||||
str +=
|
||||
specObj.day +
|
||||
i18n.global.t('commons.units.day') +
|
||||
', ' +
|
||||
loadZero(specObj.hour) +
|
||||
':' +
|
||||
loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perNHour':
|
||||
str += specObj.hour + i18n.global.t('commons.units.hour') + ', ' + loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perHour':
|
||||
str += loadZero(specObj.minute);
|
||||
break;
|
||||
case 'perNMinute':
|
||||
str += loadZero(specObj.minute) + i18n.global.t('commons.units.minute');
|
||||
break;
|
||||
case 'perNSecond':
|
||||
str += loadZero(specObj.second) + i18n.global.t('commons.units.second');
|
||||
break;
|
||||
}
|
||||
|
||||
return str + ' ' + i18n.global.t('cronjob.handle');
|
||||
}
|
@ -81,35 +81,23 @@
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('cronjob.cronSpec')" show-overflow-tooltip :min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.specType.indexOf('N') === -1 || row.specType === 'perWeek'">
|
||||
{{ $t('cronjob.' + row.specType) }}
|
||||
</span>
|
||||
<span v-else>{{ $t('cronjob.per') }}</span>
|
||||
<span v-if="row.specType === 'perMonth'">
|
||||
{{ row.day }}{{ $t('cronjob.day') }} {{ loadZero(row.hour) }} :
|
||||
{{ loadZero(row.minute) }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perWeek'">
|
||||
{{ loadWeek(row.week) }} {{ loadZero(row.hour) }} : {{ loadZero(row.minute) }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perDay'">
|
||||
 {{ loadZero(row.hour) }} : {{ loadZero(row.minute) }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perNDay'">
|
||||
{{ row.day }} {{ $t('commons.units.day') }}, {{ loadZero(row.hour) }} :
|
||||
{{ loadZero(row.minute) }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perNHour'">
|
||||
{{ row.hour }}{{ $t('commons.units.hour') }}, {{ loadZero(row.minute) }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perHour'">{{ loadZero(row.minute) }}</span>
|
||||
<span v-if="row.specType === 'perNMinute'">
|
||||
{{ row.minute }}{{ $t('commons.units.minute') }}
|
||||
</span>
|
||||
<span v-if="row.specType === 'perNSecond'">
|
||||
{{ row.second }}{{ $t('commons.units.second') }}
|
||||
</span>
|
||||
{{ $t('cronjob.handle') }}
|
||||
<div v-for="(item, index) of row.spec.split(',')" :key="index" class="mt-1">
|
||||
<div v-if="row.expand || (!row.expand && index < 3)">
|
||||
<el-tag>
|
||||
{{ transSpecToStr(item) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!row.expand && row.spec.split(',').length > 3">
|
||||
<el-button type="primary" link @click="row.expand = true">
|
||||
{{ $t('commons.button.expand') }}...
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="row.expand && row.spec.split(',').length > 3">
|
||||
<el-button type="primary" link @click="row.expand = false">
|
||||
{{ $t('commons.button.collapse') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('cronjob.retainCopies')" :min-width="90" prop="retainCopies" />
|
||||
@ -158,13 +146,13 @@ import TableSetting from '@/components/table-setting/index.vue';
|
||||
import Tooltip from '@/components/tooltip/index.vue';
|
||||
import OperateDialog from '@/views/cronjob/operate/index.vue';
|
||||
import Records from '@/views/cronjob/record/index.vue';
|
||||
import { loadZero } from '@/utils/util';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { deleteCronjob, getCronjobPage, handleOnce, updateStatus } from '@/api/modules/cronjob';
|
||||
import i18n from '@/lang';
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { transSpecToStr } from './helper';
|
||||
|
||||
const loading = ref();
|
||||
const selects = ref<any>([]);
|
||||
@ -186,16 +174,6 @@ const paginationConfig = reactive({
|
||||
});
|
||||
const searchName = ref();
|
||||
|
||||
const weekOptions = [
|
||||
{ label: i18n.global.t('cronjob.monday'), value: 1 },
|
||||
{ label: i18n.global.t('cronjob.tuesday'), value: 2 },
|
||||
{ label: i18n.global.t('cronjob.wednesday'), value: 3 },
|
||||
{ label: i18n.global.t('cronjob.thursday'), value: 4 },
|
||||
{ label: i18n.global.t('cronjob.friday'), value: 5 },
|
||||
{ label: i18n.global.t('cronjob.saturday'), value: 6 },
|
||||
{ label: i18n.global.t('cronjob.sunday'), value: 0 },
|
||||
];
|
||||
|
||||
const search = async (column?: any) => {
|
||||
paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
|
||||
paginationConfig.order = column?.order ? column.order : paginationConfig.order;
|
||||
@ -229,13 +207,17 @@ const dialogRef = ref();
|
||||
const onOpenDialog = async (
|
||||
title: string,
|
||||
rowData: Partial<Cronjob.CronjobInfo> = {
|
||||
specType: 'perMonth',
|
||||
specObjs: [
|
||||
{
|
||||
specType: 'perMonth',
|
||||
week: 1,
|
||||
day: 3,
|
||||
hour: 1,
|
||||
minute: 30,
|
||||
second: 30,
|
||||
},
|
||||
],
|
||||
type: 'shell',
|
||||
week: 1,
|
||||
day: 3,
|
||||
hour: 1,
|
||||
minute: 30,
|
||||
second: 30,
|
||||
keepLocal: true,
|
||||
retainCopies: 7,
|
||||
},
|
||||
@ -370,14 +352,7 @@ const buttons = [
|
||||
},
|
||||
},
|
||||
];
|
||||
function loadWeek(i: number) {
|
||||
for (const week of weekOptions) {
|
||||
if (week.value === i) {
|
||||
return week.label;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
|
@ -64,46 +64,64 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
|
||||
<el-select class="specTypeClass" v-model="dialogData.rowData!.specType">
|
||||
<el-option
|
||||
v-for="item in specOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-if="dialogData.rowData!.specType === 'perWeek'"
|
||||
class="specClass"
|
||||
v-model="dialogData.rowData!.week"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in weekOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-if="hasDay()" class="specClass" v-model.number="dialogData.rowData!.day">
|
||||
<template #append>{{ $t('cronjob.day') }}</template>
|
||||
</el-input>
|
||||
<el-input v-if="hasHour()" class="specClass" v-model.number="dialogData.rowData!.hour">
|
||||
<template #append>{{ $t('commons.units.hour') }}</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="dialogData.rowData!.specType !== 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="dialogData.rowData!.minute"
|
||||
>
|
||||
<template #append>{{ $t('commons.units.minute') }}</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="dialogData.rowData!.specType === 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="dialogData.rowData!.second"
|
||||
>
|
||||
<template #append>{{ $t('commons.units.second') }}</template>
|
||||
</el-input>
|
||||
<div v-for="(specObj, index) of dialogData.rowData.specObjs" :key="index" style="width: 100%">
|
||||
<el-select class="specTypeClass" v-model="specObj.specType">
|
||||
<el-option
|
||||
v-for="item in specOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select v-if="specObj.specType === 'perWeek'" class="specClass" v-model="specObj.week">
|
||||
<el-option
|
||||
v-for="item in weekOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-if="hasDay(specObj)" class="specClass" v-model.number="specObj.day">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('cronjob.day') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-if="hasHour(specObj)" class="specClass" v-model.number="specObj.hour">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.hour') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType !== 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.minute"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.minute') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType === 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.second"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.second') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
style="float: right; margin-top: 5px"
|
||||
@click="handleSpecDelete(index)"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
<el-divider class="divider" />
|
||||
</div>
|
||||
<el-button class="mt-3" @click="handleSpecAdd()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="hasScript()">
|
||||
@ -296,7 +314,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { checkNumberRange, Rules } from '@/global/form-rules';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import FileList from '@/components/file-list/index.vue';
|
||||
import { getBackupList } from '@/api/modules/setting';
|
||||
import i18n from '@/lang';
|
||||
@ -311,6 +329,7 @@ import { useRouter } from 'vue-router';
|
||||
import { listContainer } from '@/api/modules/container';
|
||||
import { Database } from '@/api/interface/database';
|
||||
import { ListAppInstalled } from '@/api/modules/app';
|
||||
import { checkScript, loadDefaultSpec, specOptions, transObjToSpec, transSpecToObj, weekOptions } from './../helper';
|
||||
const router = useRouter();
|
||||
|
||||
interface DialogProps {
|
||||
@ -326,6 +345,13 @@ const dialogData = ref<DialogProps>({
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
dialogData.value = params;
|
||||
if (dialogData.value.rowData?.spec) {
|
||||
let objs = [];
|
||||
for (const item of dialogData.value.rowData.spec.split(',')) {
|
||||
objs.push(transSpecToObj(item));
|
||||
}
|
||||
dialogData.value.rowData.specObjs = objs;
|
||||
}
|
||||
if (dialogData.value.title === 'create') {
|
||||
changeType();
|
||||
dialogData.value.rowData.dbType = 'mysql';
|
||||
@ -373,96 +399,52 @@ const dbInfo = reactive({
|
||||
});
|
||||
|
||||
const verifySpec = (rule: any, value: any, callback: any) => {
|
||||
switch (dialogData.value.rowData!.specType) {
|
||||
case 'perMonth':
|
||||
case 'perNDay':
|
||||
if (
|
||||
!(
|
||||
Number.isInteger(dialogData.value.rowData!.day) &&
|
||||
Number.isInteger(dialogData.value.rowData!.hour) &&
|
||||
Number.isInteger(dialogData.value.rowData!.minute)
|
||||
)
|
||||
) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perWeek':
|
||||
if (
|
||||
!(
|
||||
Number.isInteger(dialogData.value.rowData!.week) &&
|
||||
Number.isInteger(dialogData.value.rowData!.hour) &&
|
||||
Number.isInteger(dialogData.value.rowData!.minute)
|
||||
)
|
||||
) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perDay':
|
||||
if (
|
||||
!(
|
||||
Number.isInteger(dialogData.value.rowData!.hour) &&
|
||||
Number.isInteger(dialogData.value.rowData!.minute)
|
||||
)
|
||||
) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perNHour':
|
||||
if (
|
||||
!(
|
||||
Number.isInteger(dialogData.value.rowData!.hour) &&
|
||||
Number.isInteger(dialogData.value.rowData!.minute)
|
||||
)
|
||||
) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perHour':
|
||||
case 'perNMinute':
|
||||
if (!Number.isInteger(dialogData.value.rowData!.minute)) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perNSecond':
|
||||
if (!Number.isInteger(dialogData.value.rowData!.second)) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
for (const item of dialogData.value.rowData!.specObjs) {
|
||||
switch (item.specType) {
|
||||
case 'perMonth':
|
||||
case 'perNDay':
|
||||
if (!(Number.isInteger(item.day) && Number.isInteger(item.hour) && Number.isInteger(item.minute))) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perWeek':
|
||||
if (!(Number.isInteger(item.week) && Number.isInteger(item.hour) && Number.isInteger(item.minute))) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perDay':
|
||||
if (!(Number.isInteger(item.hour) && Number.isInteger(item.minute))) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perNHour':
|
||||
if (!(Number.isInteger(item.hour) && Number.isInteger(item.minute))) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perHour':
|
||||
case 'perNMinute':
|
||||
if (!Number.isInteger(item.minute)) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
case 'perNSecond':
|
||||
if (!Number.isInteger(item.second)) {
|
||||
callback(new Error(i18n.global.t('cronjob.cronSpecRule')));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
const specOptions = [
|
||||
{ label: i18n.global.t('cronjob.perMonth'), value: 'perMonth' },
|
||||
{ label: i18n.global.t('cronjob.perWeek'), value: 'perWeek' },
|
||||
{ label: i18n.global.t('cronjob.perDay'), value: 'perDay' },
|
||||
{ label: i18n.global.t('cronjob.perHour'), value: 'perHour' },
|
||||
{ label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' },
|
||||
{ label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' },
|
||||
{ label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' },
|
||||
{ label: i18n.global.t('cronjob.perNSecond'), value: 'perNSecond' },
|
||||
];
|
||||
const weekOptions = [
|
||||
{ label: i18n.global.t('cronjob.monday'), value: 1 },
|
||||
{ label: i18n.global.t('cronjob.tuesday'), value: 2 },
|
||||
{ label: i18n.global.t('cronjob.wednesday'), value: 3 },
|
||||
{ label: i18n.global.t('cronjob.thursday'), value: 4 },
|
||||
{ label: i18n.global.t('cronjob.friday'), value: 5 },
|
||||
{ label: i18n.global.t('cronjob.saturday'), value: 6 },
|
||||
{ label: i18n.global.t('cronjob.sunday'), value: 0 },
|
||||
];
|
||||
const rules = reactive({
|
||||
name: [Rules.requiredInput],
|
||||
type: [Rules.requiredSelect],
|
||||
specType: [Rules.requiredSelect],
|
||||
spec: [
|
||||
{ validator: verifySpec, trigger: 'blur', required: true },
|
||||
{ validator: verifySpec, trigger: 'change', required: true },
|
||||
],
|
||||
week: [Rules.requiredSelect, Rules.number],
|
||||
day: [Rules.number, checkNumberRange(1, 31)],
|
||||
hour: [Rules.number, checkNumberRange(1, 23)],
|
||||
minute: [Rules.number, checkNumberRange(1, 59)],
|
||||
|
||||
script: [Rules.requiredInput],
|
||||
website: [Rules.requiredSelect],
|
||||
@ -480,15 +462,11 @@ const loadDir = async (path: string) => {
|
||||
dialogData.value.rowData!.sourceDir = path;
|
||||
};
|
||||
|
||||
const hasDay = () => {
|
||||
return dialogData.value.rowData!.specType === 'perMonth' || dialogData.value.rowData!.specType === 'perNDay';
|
||||
const hasDay = (item: any) => {
|
||||
return item.specType === 'perMonth' || item.specType === 'perNDay';
|
||||
};
|
||||
const hasHour = () => {
|
||||
return (
|
||||
dialogData.value.rowData!.specType !== 'perHour' &&
|
||||
dialogData.value.rowData!.specType !== 'perNMinute' &&
|
||||
dialogData.value.rowData!.specType !== 'perNSecond'
|
||||
);
|
||||
const hasHour = (item: any) => {
|
||||
return item.specType !== 'perHour' && item.specType !== 'perNMinute' && item.specType !== 'perNSecond';
|
||||
};
|
||||
|
||||
const loadDatabases = async (dbType: string) => {
|
||||
@ -497,57 +475,34 @@ const loadDatabases = async (dbType: string) => {
|
||||
};
|
||||
|
||||
const changeType = () => {
|
||||
switch (dialogData.value.rowData!.type) {
|
||||
case 'shell':
|
||||
dialogData.value.rowData.specType = 'perWeek';
|
||||
dialogData.value.rowData.week = 1;
|
||||
dialogData.value.rowData.hour = 1;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
case 'app':
|
||||
dialogData.value.rowData.specType = 'perDay';
|
||||
dialogData.value.rowData.hour = 2;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
case 'database':
|
||||
dialogData.value.rowData.specType = 'perDay';
|
||||
dialogData.value.rowData.hour = 2;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
case 'clean':
|
||||
case 'website':
|
||||
dialogData.value.rowData.specType = 'perWeek';
|
||||
dialogData.value.rowData.week = 1;
|
||||
dialogData.value.rowData.hour = 1;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
case 'log':
|
||||
case 'snapshot':
|
||||
dialogData.value.rowData.specType = 'perWeek';
|
||||
dialogData.value.rowData.week = 1;
|
||||
dialogData.value.rowData.hour = 1;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
dialogData.value.rowData.keepLocal = false;
|
||||
dialogData.value.rowData.targetDirID = null;
|
||||
for (const item of backupOptions.value) {
|
||||
if (item.label !== i18n.global.t('setting.LOCAL')) {
|
||||
dialogData.value.rowData.targetDirID = item.value;
|
||||
break;
|
||||
}
|
||||
if (dialogData.value.rowData.type === 'snapshot') {
|
||||
dialogData.value.rowData.keepLocal = false;
|
||||
dialogData.value.rowData.targetDirID = null;
|
||||
for (const item of backupOptions.value) {
|
||||
if (item.label !== i18n.global.t('setting.LOCAL')) {
|
||||
dialogData.value.rowData.targetDirID = item.value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'directory':
|
||||
dialogData.value.rowData.specType = 'perDay';
|
||||
dialogData.value.rowData.hour = 1;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
case 'curl':
|
||||
dialogData.value.rowData.specType = 'perWeek';
|
||||
dialogData.value.rowData.week = 1;
|
||||
dialogData.value.rowData.hour = 1;
|
||||
dialogData.value.rowData.minute = 30;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dialogData.value.rowData!.specObjs = [loadDefaultSpec(dialogData.value.rowData.type)];
|
||||
};
|
||||
|
||||
const handleSpecAdd = () => {
|
||||
let item = {
|
||||
specType: 'perWeek',
|
||||
week: 1,
|
||||
day: 0,
|
||||
hour: 1,
|
||||
minute: 30,
|
||||
second: 0,
|
||||
};
|
||||
dialogData.value.rowData!.specObjs.push(item);
|
||||
};
|
||||
|
||||
const handleSpecDelete = (index: number) => {
|
||||
dialogData.value.rowData!.specObjs.splice(index, 1);
|
||||
};
|
||||
|
||||
const loadBackups = async () => {
|
||||
@ -597,40 +552,21 @@ function hasScript() {
|
||||
return dialogData.value.rowData!.type === 'shell';
|
||||
}
|
||||
|
||||
function checkScript() {
|
||||
let row = dialogData.value.rowData;
|
||||
switch (row.specType) {
|
||||
case 'perMonth':
|
||||
return row.day > 0 && row.day < 32 && row.hour >= 0 && row.hour < 24 && row.minute >= 0 && row.minute < 60;
|
||||
case 'perWeek':
|
||||
return (
|
||||
row.week >= 0 && row.week < 7 && row.hour >= 0 && row.hour < 24 && row.minute >= 0 && row.minute < 60
|
||||
);
|
||||
case 'perDay':
|
||||
return row.hour >= 0 && row.hour < 24 && row.minute >= 0 && row.minute < 60;
|
||||
case 'perHour':
|
||||
return row.minute >= 0 && row.minute < 60;
|
||||
case 'perNDay':
|
||||
return row.day > 0 && row.day < 366 && row.hour >= 0 && row.hour < 24 && row.minute >= 0 && row.minute < 60;
|
||||
case 'perNHour':
|
||||
return row.hour > 0 && row.hour < 8784 && row.minute >= 0 && row.minute < 60;
|
||||
case 'perNMinute':
|
||||
return row.minute > 0 && row.minute < 527040;
|
||||
case 'perNSecond':
|
||||
return row.second > 0 && row.second < 31622400;
|
||||
}
|
||||
}
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
dialogData.value.rowData.week = Number(dialogData.value.rowData.week);
|
||||
dialogData.value.rowData.day = Number(dialogData.value.rowData.day);
|
||||
dialogData.value.rowData.hour = Number(dialogData.value.rowData.hour);
|
||||
dialogData.value.rowData.minute = Number(dialogData.value.rowData.minute);
|
||||
dialogData.value.rowData.second = Number(dialogData.value.rowData.second);
|
||||
if (!checkScript()) {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||
return;
|
||||
const specs = [];
|
||||
for (const item of dialogData.value.rowData.specObjs) {
|
||||
if (!checkScript(item.specType, item.week, item.day, item.hour, item.minute, item.second)) {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||
return;
|
||||
}
|
||||
const itemSpec = transObjToSpec(item.specType, item.week, item.day, item.hour, item.minute, item.second);
|
||||
if (itemSpec === '') {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||
return;
|
||||
}
|
||||
specs.push(itemSpec);
|
||||
}
|
||||
dialogData.value.rowData.spec = specs.join(',');
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
@ -660,14 +596,20 @@ defineExpose({
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.specClass {
|
||||
width: 22% !important;
|
||||
width: 20% !important;
|
||||
margin-left: 20px;
|
||||
.append {
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1000px) {
|
||||
.specClass {
|
||||
width: 100% !important;
|
||||
margin-top: 20px;
|
||||
margin-left: 0;
|
||||
.append {
|
||||
width: 43px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.specTypeClass {
|
||||
@ -695,4 +637,12 @@ defineExpose({
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
display: block;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin: 3px 0;
|
||||
border-top: 1px var(--el-border-color) var(--el-border-style);
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user