1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-31 14:08:06 +08:00

feat: 服务重启重新拉起定时任务

This commit is contained in:
ssongliu 2022-09-27 17:26:01 +08:00 committed by ssongliu
parent fdcfdd7963
commit 7d14d37057
12 changed files with 221 additions and 80 deletions

View File

@ -111,6 +111,24 @@ func (b *BaseApi) UpdateCronjob(c *gin.Context) {
helper.SuccessWithData(c, nil) helper.SuccessWithData(c, nil)
} }
func (b *BaseApi) UpdateCronjobStatus(c *gin.Context) {
var req dto.CronjobUpdateStatus
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := global.VALID.Struct(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := cronjobService.UpdateStatus(req.ID, req.Status); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) LoadRecordDetail(c *gin.Context) { func (b *BaseApi) LoadRecordDetail(c *gin.Context) {
var req dto.DetailFile var req dto.DetailFile
if err := c.ShouldBindJSON(&req); err != nil { if err := c.ShouldBindJSON(&req); err != nil {

View File

@ -37,8 +37,11 @@ type CronjobUpdate struct {
SourceDir string `json:"sourceDir"` SourceDir string `json:"sourceDir"`
TargetDirID int `json:"targetDirID"` TargetDirID int `json:"targetDirID"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"` RetainCopies int `json:"retainCopies" validate:"number,min=1"`
}
Status string `json:"status"` type CronjobUpdateStatus struct {
ID uint `json:"id" validate:"required"`
Status string `json:"status" validate:"required"`
} }
type DetailFile struct { type DetailFile struct {

View File

@ -13,6 +13,7 @@ type CronjobRepo struct{}
type ICronjobRepo interface { type ICronjobRepo interface {
Get(opts ...DBOption) (model.Cronjob, error) Get(opts ...DBOption) (model.Cronjob, error)
List(opts ...DBOption) ([]model.Cronjob, error)
Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error) Page(limit, offset int, opts ...DBOption) (int64, []model.Cronjob, error)
Create(cronjob *model.Cronjob) error Create(cronjob *model.Cronjob) error
WithByDate(startTime, endTime time.Time) DBOption WithByDate(startTime, endTime time.Time) DBOption
@ -20,6 +21,7 @@ type ICronjobRepo interface {
Save(id uint, cronjob model.Cronjob) error Save(id uint, cronjob model.Cronjob) error
Update(id uint, vars map[string]interface{}) error Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error Delete(opts ...DBOption) error
DeleteRecord(jobID uint) error
StartRecords(cronjobID uint, targetPath string) model.JobRecords StartRecords(cronjobID uint, targetPath string) model.JobRecords
EndRecords(record model.JobRecords, status, message, records string) EndRecords(record model.JobRecords, status, message, records string)
} }
@ -38,28 +40,40 @@ func (u *CronjobRepo) Get(opts ...DBOption) (model.Cronjob, error) {
return cronjob, err return cronjob, err
} }
func (u *CronjobRepo) Page(page, size int, opts ...DBOption) (int64, []model.Cronjob, error) { func (u *CronjobRepo) List(opts ...DBOption) ([]model.Cronjob, error) {
var users []model.Cronjob var cronjobs []model.Cronjob
db := global.DB.Model(&model.Cronjob{}) db := global.DB.Model(&model.Cronjob{})
for _, opt := range opts { for _, opt := range opts {
db = opt(db) db = opt(db)
} }
count := int64(0) count := int64(0)
db = db.Count(&count) db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error err := db.Find(&cronjobs).Error
return count, users, err return cronjobs, err
}
func (u *CronjobRepo) Page(page, size int, opts ...DBOption) (int64, []model.Cronjob, error) {
var cronjobs []model.Cronjob
db := global.DB.Model(&model.Cronjob{})
for _, opt := range opts {
db = opt(db)
}
count := int64(0)
db = db.Count(&count)
err := db.Order("created_at").Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error
return count, cronjobs, err
} }
func (u *CronjobRepo) PageRecords(page, size int, opts ...DBOption) (int64, []model.JobRecords, error) { func (u *CronjobRepo) PageRecords(page, size int, opts ...DBOption) (int64, []model.JobRecords, error) {
var users []model.JobRecords var cronjobs []model.JobRecords
db := global.DB.Model(&model.JobRecords{}) db := global.DB.Model(&model.JobRecords{})
for _, opt := range opts { for _, opt := range opts {
db = opt(db) db = opt(db)
} }
count := int64(0) count := int64(0)
db = db.Count(&count) db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Find(&users).Error err := db.Order("created_at").Limit(size).Offset(size * (page - 1)).Find(&cronjobs).Error
return count, users, err return count, cronjobs, err
} }
func (u *CronjobRepo) Create(cronjob *model.Cronjob) error { func (u *CronjobRepo) Create(cronjob *model.Cronjob) error {
@ -112,3 +126,6 @@ func (u *CronjobRepo) Delete(opts ...DBOption) error {
} }
return db.Delete(&model.Cronjob{}).Error return db.Delete(&model.Cronjob{}).Error
} }
func (u *CronjobRepo) DeleteRecord(jobID uint) error {
return global.DB.Where("cronjob_id = ?", jobID).Delete(&model.JobRecords{}).Error
}

View File

@ -19,11 +19,13 @@ import (
"github.com/1Panel-dev/1Panel/utils/cloud_storage" "github.com/1Panel-dev/1Panel/utils/cloud_storage"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/robfig/cron/v3"
) )
const ( const (
errRecord = "errRecord" errRecord = "errRecord"
errHandle = "errHandle" errHandle = "errHandle"
noRecord = "noRecord"
) )
type CronjobService struct{} type CronjobService struct{}
@ -33,6 +35,7 @@ type ICronjobService interface {
SearchRecords(search dto.SearchRecord) (int64, interface{}, error) SearchRecords(search dto.SearchRecord) (int64, interface{}, error)
Create(cronjobDto dto.CronjobCreate) error Create(cronjobDto dto.CronjobCreate) error
Save(id uint, req dto.CronjobUpdate) error Save(id uint, req dto.CronjobUpdate) error
UpdateStatus(id uint, status string) error
Delete(ids []uint) error Delete(ids []uint) error
} }
@ -93,19 +96,32 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
if err := cronjobRepo.Create(&cronjob); err != nil { if err := cronjobRepo.Create(&cronjob); err != nil {
return err return err
} }
if err := u.StartJob(&cronjob); err != nil {
return err
}
return nil
}
func (u *CronjobService) StartJob(cronjob *model.Cronjob) error {
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
var ( var (
entryID int entryID int
err error err error
) )
switch cronjobDto.Type { switch cronjob.Type {
case "shell": case "shell":
entryID, err = u.AddShellJob(&cronjob) entryID, err = u.AddShellJob(cronjob)
case "curl": case "curl":
entryID, err = u.AddCurlJob(&cronjob) entryID, err = u.AddCurlJob(cronjob)
case "directory": case "directory":
entryID, err = u.AddDirectoryJob(&cronjob) entryID, err = u.AddDirectoryJob(cronjob)
case "website":
entryID, err = u.AddWebSiteJob(cronjob)
case "database":
entryID, err = u.AddDatabaseJob(cronjob)
default:
entryID, err = u.AddShellJob(cronjob)
} }
if err != nil { if err != nil {
return err return err
} }
@ -119,8 +135,25 @@ func (u *CronjobService) Delete(ids []uint) error {
if cronjob.ID == 0 { if cronjob.ID == 0 {
return constant.ErrRecordNotFound return constant.ErrRecordNotFound
} }
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
_ = cronjobRepo.DeleteRecord(ids[0])
if err := os.RemoveAll(fmt.Sprintf("%s/%s/%s-%v", constant.TaskDir, cronjob.Type, cronjob.Name, cronjob.ID)); err != nil {
global.LOG.Errorf("rm file %s/%s/%s-%v failed, err: %v", constant.TaskDir, cronjob.Type, cronjob.Name, cronjob.ID, err)
}
return cronjobRepo.Delete(commonRepo.WithByID(ids[0])) return cronjobRepo.Delete(commonRepo.WithByID(ids[0]))
} }
cronjobs, err := cronjobRepo.List(commonRepo.WithIdsIn(ids))
if err != nil {
return err
}
for i := range cronjobs {
global.Cron.Remove(cron.EntryID(cronjobs[i].EntryID))
_ = cronjobRepo.DeleteRecord(cronjobs[i].ID)
if err := os.RemoveAll(fmt.Sprintf("%s/%s/%s-%v", constant.TaskDir, cronjobs[i].Type, cronjobs[i].Name, cronjobs[i].ID)); err != nil {
global.LOG.Errorf("rm file %s/%s/%s-%v failed, err: %v", constant.TaskDir, cronjobs[i].Type, cronjobs[i].Name, cronjobs[i].ID, err)
}
}
return cronjobRepo.Delete(commonRepo.WithIdsIn(ids)) return cronjobRepo.Delete(commonRepo.WithIdsIn(ids))
} }
@ -129,15 +162,33 @@ func (u *CronjobService) Save(id uint, req dto.CronjobUpdate) error {
if err := copier.Copy(&cronjob, &req); err != nil { if err := copier.Copy(&cronjob, &req); err != nil {
return errors.WithMessage(constant.ErrStructTransform, err.Error()) return errors.WithMessage(constant.ErrStructTransform, err.Error())
} }
if err := u.StartJob(&cronjob); err != nil {
return err
}
return cronjobRepo.Save(id, cronjob) return cronjobRepo.Save(id, cronjob)
} }
func (u *CronjobService) UpdateStatus(id uint, status string) error {
cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id))
if cronjob.ID == 0 {
return errors.WithMessage(constant.ErrRecordNotFound, "record not found")
}
if status == constant.StatusEnable {
if err := u.StartJob(&cronjob); err != nil {
return err
}
} else {
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
}
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status})
}
func (u *CronjobService) AddShellJob(cronjob *model.Cronjob) (int, error) { func (u *CronjobService) AddShellJob(cronjob *model.Cronjob) (int, error) {
addFunc := func() { addFunc := func() {
record := cronjobRepo.StartRecords(cronjob.ID, "") record := cronjobRepo.StartRecords(cronjob.ID, "")
cmd := exec.Command(cronjob.Script) cmd := exec.Command(cronjob.Script)
stdout, err := cmd.Output() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
record.Records = errHandle record.Records = errHandle
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle) cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle)
@ -150,6 +201,7 @@ func (u *CronjobService) AddShellJob(cronjob *model.Cronjob) (int, error) {
} }
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
} }
global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name)
entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc) entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc)
if err != nil { if err != nil {
return 0, err return 0, err
@ -183,6 +235,7 @@ func (u *CronjobService) AddCurlJob(cronjob *model.Cronjob) (int, error) {
} }
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
} }
global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name)
entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc) entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc)
if err != nil { if err != nil {
return 0, err return 0, err
@ -209,6 +262,7 @@ func (u *CronjobService) AddDirectoryJob(cronjob *model.Cronjob) (int, error) {
} }
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
} }
global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name)
entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc) entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc)
if err != nil { if err != nil {
return 0, err return 0, err
@ -228,6 +282,11 @@ func (u *CronjobService) AddWebSiteJob(cronjob *model.Cronjob) (int, error) {
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle) cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle)
return return
} }
if len(message) == 0 {
record.Records = noRecord
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
return
}
record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, message) record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, message)
if err != nil { if err != nil {
record.Records = errRecord record.Records = errRecord
@ -235,6 +294,34 @@ func (u *CronjobService) AddWebSiteJob(cronjob *model.Cronjob) (int, error) {
} }
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
} }
global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name)
entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc)
if err != nil {
return 0, err
}
return int(entryID), nil
}
func (u *CronjobService) AddDatabaseJob(cronjob *model.Cronjob) (int, error) {
addFunc := func() {
record := cronjobRepo.StartRecords(cronjob.ID, "")
if len(cronjob.URL) == 0 {
return
}
message, err := tarWithExclude(cronjob, record.StartTime)
if err != nil {
record.Records = errHandle
cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle)
return
}
record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, message)
if err != nil {
record.Records = errRecord
global.LOG.Errorf("save file %s failed, err: %v", record.Records, err)
}
cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records)
}
global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name)
entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc) entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc)
if err != nil { if err != nil {
return 0, err return 0, err
@ -268,18 +355,27 @@ func tarWithExclude(cronjob *model.Cronjob, startTime time.Time) ([]byte, error)
return nil, fmt.Errorf("load target dir failed, err: %v", err) return nil, fmt.Errorf("load target dir failed, err: %v", err)
} }
excludes := strings.Split(cronjob.ExclusionRules, ";") exStr := []string{}
name := fmt.Sprintf("%s/%s.tar.gz", targetdir, startTime.Format("20060102150405")) name := ""
exStr := []string{"-zcvPf", name} if cronjob.Type == "database" {
for _, exclude := range excludes { exStr = append(exStr, "-zvPf")
exStr = append(exStr, "--exclude") name = fmt.Sprintf("%s/%s.gz", targetdir, startTime.Format("20060102150405"))
exStr = append(exStr, exclude) exStr = append(exStr, name)
} else {
exStr = append(exStr, "-zcvPf")
name = fmt.Sprintf("%s/%s.tar.gz", targetdir, startTime.Format("20060102150405"))
exStr = append(exStr, name)
excludes := strings.Split(cronjob.ExclusionRules, ";")
for _, exclude := range excludes {
exStr = append(exStr, "--exclude")
exStr = append(exStr, exclude)
}
} }
exStr = append(exStr, cronjob.SourceDir) exStr = append(exStr, cronjob.SourceDir)
cmd := exec.Command("tar", exStr...) cmd := exec.Command("tar", exStr...)
stdout, err := cmd.Output() stdout, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return nil, fmt.Errorf("tar zcvPf failed, err: %v", err) return nil, fmt.Errorf("tar zcPf failed, err: %v", err)
} }
if varMaps["type"] != "LOCAL" { if varMaps["type"] != "LOCAL" {
@ -291,6 +387,9 @@ func tarWithExclude(cronjob *model.Cronjob, startTime time.Time) ([]byte, error)
if !isOK { if !isOK {
return nil, fmt.Errorf("cloud storage upload failed, err: %v", err) return nil, fmt.Errorf("cloud storage upload failed, err: %v", err)
} }
if err := os.RemoveAll(fmt.Sprintf("%s/%s/%s-%v", constant.TmpDir, cronjob.Type, cronjob.Name, cronjob.ID)); err != nil {
global.LOG.Errorf("rm file %s/%s/%s-%v failed, err: %v", constant.TaskDir, cronjob.Type, cronjob.Name, cronjob.ID, err)
}
} }
return stdout, nil return stdout, nil
} }
@ -305,8 +404,8 @@ func loadTargetInfo(cronjob *model.Cronjob) (map[string]interface{}, string, err
return nil, "", err return nil, "", err
} }
dir := "" dir := ""
varMap["type"] = backup.Type
if backup.Type != "LOCAL" { if backup.Type != "LOCAL" {
varMap["type"] = backup.Type
varMap["bucket"] = backup.Bucket varMap["bucket"] = backup.Bucket
switch backup.Type { switch backup.Type {
case constant.Sftp: case constant.Sftp:

View File

@ -3,6 +3,9 @@ package cron
import ( import (
"time" "time"
"github.com/1Panel-dev/1Panel/app/model"
"github.com/1Panel-dev/1Panel/app/service"
"github.com/1Panel-dev/1Panel/constant"
"github.com/1Panel-dev/1Panel/cron/job" "github.com/1Panel-dev/1Panel/cron/job"
"github.com/1Panel-dev/1Panel/global" "github.com/1Panel-dev/1Panel/global"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
@ -10,15 +13,7 @@ import (
func Run() { func Run() {
nyc, _ := time.LoadLocation("Asia/Shanghai") nyc, _ := time.LoadLocation("Asia/Shanghai")
Cron := cron.New(cron.WithLocation(nyc)) Cron := cron.New(cron.WithLocation(nyc), cron.WithChain(cron.Recover(cron.DefaultLogger)), cron.WithChain(cron.DelayIfStillRunning(cron.DefaultLogger)))
// var Cronjobs []model.Cronjob
// if err := global.DB.Where("status = ?", constant.StatusEnable).Find(&Cronjobs).Error; err != nil {
// global.LOG.Errorf("start my cronjob failed, err: %v", err)
// }
// for _, cronjob := range Cronjobs {
// switch cronjob.Type {}
// }
_, err := Cron.AddJob("@every 1m", job.NewMonitorJob()) _, err := Cron.AddJob("@every 1m", job.NewMonitorJob())
if err != nil { if err != nil {
global.LOG.Errorf("can not add corn job: %s", err.Error()) global.LOG.Errorf("can not add corn job: %s", err.Error())
@ -26,4 +21,14 @@ func Run() {
Cron.Start() Cron.Start()
global.Cron = Cron global.Cron = Cron
var Cronjobs []model.Cronjob
if err := global.DB.Where("status = ?", constant.StatusEnable).Find(&Cronjobs).Error; err != nil {
global.LOG.Errorf("start my cronjob failed, err: %v", err)
}
for _, cronjob := range Cronjobs {
if err := service.ServiceGroupApp.StartJob(&cronjob); err != nil {
global.LOG.Errorf("start %s job %s failed, err: %v", cronjob.Type, cronjob.Name, err)
}
}
} }

View File

@ -17,6 +17,7 @@ func (s *CronjobRouter) InitCronjobRouter(Router *gin.RouterGroup) {
withRecordRouter.POST("", baseApi.CreateCronjob) withRecordRouter.POST("", baseApi.CreateCronjob)
withRecordRouter.POST("/del", baseApi.DeleteCronjob) withRecordRouter.POST("/del", baseApi.DeleteCronjob)
withRecordRouter.PUT(":id", baseApi.UpdateCronjob) withRecordRouter.PUT(":id", baseApi.UpdateCronjob)
withRecordRouter.POST("/status", baseApi.UpdateCronjobStatus)
cmdRouter.POST("/search", baseApi.SearchCronjob) cmdRouter.POST("/search", baseApi.SearchCronjob)
cmdRouter.POST("/search/records", baseApi.SearchJobRecords) cmdRouter.POST("/search/records", baseApi.SearchJobRecords)
cmdRouter.POST("/search/detail", baseApi.LoadRecordDetail) cmdRouter.POST("/search/detail", baseApi.LoadRecordDetail)

View File

@ -56,6 +56,9 @@ export namespace Cronjob {
sourceDir: string; sourceDir: string;
targetDirID: number; targetDirID: number;
retainCopies: number; retainCopies: number;
}
export interface UpdateStatus {
id: number;
status: string; status: string;
} }
export interface SearchRecord extends ReqPage { export interface SearchRecord extends ReqPage {

View File

@ -25,3 +25,7 @@ export const searchRecords = (params: Cronjob.SearchRecord) => {
export const getRecordDetail = (params: string) => { export const getRecordDetail = (params: string) => {
return http.post<string>(`cronjobs/search/detail`, { path: params }); return http.post<string>(`cronjobs/search/detail`, { path: params });
}; };
export const updateStatus = (params: Cronjob.UpdateStatus) => {
return http.post(`cronjobs/status`, params);
};

View File

@ -183,6 +183,9 @@ export default {
saturday: '周六', saturday: '周六',
sunday: '周日', sunday: '周日',
shellContent: '脚本内容', shellContent: '脚本内容',
errRecord: '错误的日志记录',
errHandle: '任务执行失败',
noRecord: '执行未产生任何日志',
}, },
monitor: { monitor: {
avgLoad: '平均负载', avgLoad: '平均负载',

View File

@ -72,7 +72,7 @@ import RecordDialog from '@/views/cronjob/record/index.vue';
import { loadZero } from '@/views/cronjob/options'; import { loadZero } from '@/views/cronjob/options';
import { onMounted, reactive, ref } from 'vue'; import { onMounted, reactive, ref } from 'vue';
import { loadBackupName } from '@/views/setting/helper'; import { loadBackupName } from '@/views/setting/helper';
import { deleteCronjob, editCronjob, getCronjobPage } from '@/api/modules/cronjob'; import { deleteCronjob, getCronjobPage, updateStatus } from '@/api/modules/cronjob';
import { loadWeek } from './options'; import { loadWeek } from './options';
import i18n from '@/lang'; import i18n from '@/lang';
import { Cronjob } from '@/api/interface/cronjob'; import { Cronjob } from '@/api/interface/cronjob';
@ -149,7 +149,7 @@ const beforeChangeStatus = () => {
}; };
const onChangeStatus = async (row: Cronjob.CronjobInfo) => { const onChangeStatus = async (row: Cronjob.CronjobInfo) => {
if (switchState.value) { if (switchState.value) {
await editCronjob(row); await updateStatus({ id: row.id, status: row.status });
ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
search(); search();
} }

View File

@ -8,7 +8,7 @@
<el-form ref="formRef" :model="dialogData.rowData" label-position="left" :rules="rules" label-width="120px"> <el-form ref="formRef" :model="dialogData.rowData" label-position="left" :rules="rules" label-width="120px">
<el-form-item :label="$t('cronjob.taskType')" prop="type"> <el-form-item :label="$t('cronjob.taskType')" prop="type">
<el-select <el-select
@change="changeName(true, dialogData.rowData!.type, dialogData.rowData!.website)" @change="changeName(true, dialogData.rowData!.type)"
style="width: 100%" style="width: 100%"
v-model="dialogData.rowData!.type" v-model="dialogData.rowData!.type"
> >
@ -17,12 +17,7 @@
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.taskName')" prop="name"> <el-form-item :label="$t('cronjob.taskName')" prop="name">
<el-input <el-input style="width: 100%" clearable v-model="dialogData.rowData!.name" />
:disabled="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'database'"
style="width: 100%"
clearable
v-model="dialogData.rowData!.name"
/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec"> <el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
@ -56,12 +51,18 @@
</el-form-item> </el-form-item>
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script"> <el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
<el-input style="width: 100%" clearable type="textarea" v-model="dialogData.rowData!.script" /> <el-input
style="width: 100%"
clearable
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
v-model="dialogData.rowData!.script"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="dialogData.rowData!.type === 'website'" :label="$t('cronjob.website')" prop="website"> <el-form-item v-if="dialogData.rowData!.type === 'website'" :label="$t('cronjob.website')" prop="website">
<el-select <el-select
@change="changeName(false, dialogData.rowData!.type, dialogData.rowData!.website)" @change="changeName(false, dialogData.rowData!.type)"
style="width: 100%" style="width: 100%"
v-model="dialogData.rowData!.website" v-model="dialogData.rowData!.website"
> >
@ -86,7 +87,7 @@
prop="sourceDir" prop="sourceDir"
> >
<el-input <el-input
@input="changeName(false, dialogData.rowData!.type, dialogData.rowData!.website)" @input="changeName(false, dialogData.rowData!.type)"
style="width: 100%" style="width: 100%"
clearable clearable
v-model="dialogData.rowData!.sourceDir" v-model="dialogData.rowData!.sourceDir"
@ -120,7 +121,13 @@
:label="$t('cronjob.exclusionRules')" :label="$t('cronjob.exclusionRules')"
prop="exclusionRules" prop="exclusionRules"
> >
<el-input style="width: 100%" type="textarea" clearable v-model="dialogData.rowData!.exclusionRules" /> <el-input
style="width: 100%"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
clearable
v-model="dialogData.rowData!.exclusionRules"
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@ -216,7 +223,7 @@ const varifySpec = (rule: any, value: any, callback: any) => {
callback(); callback();
}; };
const rules = reactive({ const rules = reactive({
name: [Rules.requiredInput], name: [Rules.requiredInput, Rules.name],
type: [Rules.requiredSelect], type: [Rules.requiredSelect],
specType: [Rules.requiredSelect], specType: [Rules.requiredSelect],
spec: [ spec: [
@ -232,7 +239,7 @@ const rules = reactive({
website: [Rules.requiredSelect], website: [Rules.requiredSelect],
database: [Rules.requiredSelect], database: [Rules.requiredSelect],
url: [Rules.requiredInput], url: [Rules.requiredInput],
sourceDir: [Rules.requiredInput], sourceDir: [Rules.requiredSelect],
targetDirID: [Rules.requiredSelect, Rules.number], targetDirID: [Rules.requiredSelect, Rules.number],
retainCopies: [Rules.number], retainCopies: [Rules.number],
}); });
@ -261,42 +268,15 @@ function isBackup() {
function hasScript() { function hasScript() {
return dialogData.value.rowData!.type === 'shell' || dialogData.value.rowData!.type === 'sync'; return dialogData.value.rowData!.type === 'shell' || dialogData.value.rowData!.type === 'sync';
} }
function changeName(isChangeType: boolean, type: string, targetName: string) { function changeName(isChangeType: boolean, type: string) {
if (isChangeType) { if (isChangeType) {
targetName = '';
if (isBackup()) { if (isBackup()) {
if (backupOptions.value.length === 0) { if (backupOptions.value.length === 0) {
ElMessage.error(i18n.global.t('cronjob.missBackupAccount')); ElMessage.error(i18n.global.t('cronjob.missBackupAccount'));
} }
} }
} }
switch (type) { dialogData.value.rowData!.name = `${type}-test`;
case 'website':
targetName = targetName ? targetName : i18n.global.t('cronjob.all');
dialogData.value.rowData!.name = `${i18n.global.t('cronjob.website')} [ ${targetName} ]`;
break;
case 'database':
targetName = targetName ? targetName : i18n.global.t('cronjob.all');
dialogData.value.rowData!.name = `${i18n.global.t('cronjob.database')} [ ${targetName} ]`;
break;
case 'directory':
targetName = targetName ? targetName : '/etc/1panel';
dialogData.value.rowData!.name = `${i18n.global.t('cronjob.directory')} [ ${targetName} ]`;
break;
case 'sync':
dialogData.value.rowData!.name = i18n.global.t('cronjob.syncDateName');
break;
case 'release':
dialogData.value.rowData!.name = i18n.global.t('cronjob.releaseMemory');
break;
case 'curl':
dialogData.value.rowData!.name = i18n.global.t('cronjob.curl');
dialogData.value.rowData!.url = 'http://';
break;
default:
dialogData.value.rowData!.name = '';
break;
}
} }
function restForm() { function restForm() {
if (formRef.value) { if (formRef.value) {

View File

@ -95,7 +95,7 @@
trigger="click" trigger="click"
style="white-space: pre-wrap" style="white-space: pre-wrap"
> >
<div style="margin-left: 20px; height: 400px; overflow: auto"> <div style="margin-left: 20px; max-height: 400px; overflow: auto">
<span style="white-space: pre-wrap">{{ dialogData.rowData!.script }}</span> <span style="white-space: pre-wrap">{{ dialogData.rowData!.script }}</span>
</div> </div>
<template #reference> <template #reference>
@ -121,7 +121,7 @@
</el-col> </el-col>
<el-col :span="8" v-if="isBackup()"> <el-col :span="8" v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')"> <el-form-item :label="$t('cronjob.target')">
{{ dialogData.rowData!.targetDirID }} {{ loadBackupName(dialogData.rowData!.targetDir) }}
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8" v-if="isBackup()"> <el-col :span="8" v-if="isBackup()">
@ -139,7 +139,9 @@
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'" v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'"
> >
<el-form-item :label="$t('cronjob.exclusionRules')"> <el-form-item :label="$t('cronjob.exclusionRules')">
{{ dialogData.rowData!.exclusionRules }} <div v-for="item in dialogData.rowData!.exclusionRules.split(';')" :key="item">
<el-tag>{{ item }}</el-tag>
</div>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -176,13 +178,18 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-form-item :label="$t('commons.table.records')"> <el-form-item :label="$t('commons.table.records')">
<span
v-if="currentRecord?.records! === 'errRecord' || currentRecord?.records! === 'errHandle'|| currentRecord?.records! === 'noRecord'"
>
{{ $t('cronjob.' + currentRecord?.records!) }}
</span>
<el-popover <el-popover
placement="right" placement="right"
:width="600" :width="600"
trigger="click" trigger="click"
style="white-space: pre-wrap" style="white-space: pre-wrap"
> >
<div style="margin-left: 20px; height: 400px; overflow: auto"> <div style="margin-left: 20px; max-height: 400px; overflow: auto">
<span style="white-space: pre-wrap"> <span style="white-space: pre-wrap">
{{ currentRecordDetail }} {{ currentRecordDetail }}
</span> </span>
@ -212,6 +219,7 @@
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { Cronjob } from '@/api/interface/cronjob'; import { Cronjob } from '@/api/interface/cronjob';
import { loadZero, loadWeek } from '@/views/cronjob/options'; import { loadZero, loadWeek } from '@/views/cronjob/options';
import { loadBackupName } from '@/views/setting/helper';
import { searchRecords, getRecordDetail } from '@/api/modules/cronjob'; import { searchRecords, getRecordDetail } from '@/api/modules/cronjob';
import { dateFromat } from '@/utils/util'; import { dateFromat } from '@/utils/util';
import i18n from '@/lang'; import i18n from '@/lang';