diff --git a/backend/app/api/v1/cronjob.go b/backend/app/api/v1/cronjob.go index 62b0c5ca2..ecf968d9c 100644 --- a/backend/app/api/v1/cronjob.go +++ b/backend/app/api/v1/cronjob.go @@ -171,3 +171,16 @@ func (b *BaseApi) TargetDownload(c *gin.Context) { } c.File(filePath) } + +func (b *BaseApi) HandleOnce(c *gin.Context) { + id, err := helper.GetParamID(c) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := cronjobService.HandleOnce(id); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} diff --git a/backend/app/model/cronjob.go b/backend/app/model/cronjob.go index 18fa3f586..8c737eb48 100644 --- a/backend/app/model/cronjob.go +++ b/backend/app/model/cronjob.go @@ -5,7 +5,7 @@ import "time" type Cronjob struct { BaseModel - Name string `gorm:"type:varchar(64);not null" json:"name"` + 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"` diff --git a/backend/app/service/cornjob.go b/backend/app/service/cornjob.go index b2cb73b15..ba3328a84 100644 --- a/backend/app/service/cornjob.go +++ b/backend/app/service/cornjob.go @@ -25,7 +25,6 @@ import ( const ( errRecord = "errRecord" errHandle = "errHandle" - noRecord = "noRecord" ) type CronjobService struct{} @@ -34,6 +33,7 @@ type ICronjobService interface { SearchWithPage(search dto.SearchWithPage) (int64, interface{}, error) SearchRecords(search dto.SearchRecord) (int64, interface{}, error) Create(cronjobDto dto.CronjobCreate) error + HandleOnce(id uint) error Save(id uint, req dto.CronjobUpdate) error UpdateStatus(id uint, status string) error Delete(ids []uint) error @@ -143,6 +143,15 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) { return name, nil } +func (u *CronjobService) HandleOnce(id uint) error { + cronjob, _ := cronjobRepo.Get(commonRepo.WithByID(id)) + if cronjob.ID == 0 { + return constant.ErrRecordNotFound + } + u.HandleJob(&cronjob) + return nil +} + func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error { cronjob, _ := cronjobRepo.Get(commonRepo.WithByName(cronjobDto.Name)) if cronjob.ID != 0 { @@ -165,24 +174,7 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error { func (u *CronjobService) StartJob(cronjob *model.Cronjob) error { global.Cron.Remove(cron.EntryID(cronjob.EntryID)) - var ( - entryID int - err error - ) - switch cronjob.Type { - case "shell": - entryID, err = u.AddShellJob(cronjob) - case "curl": - entryID, err = u.AddCurlJob(cronjob) - case "directory": - 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) - } + entryID, err := u.AddCronJob(cronjob) if err != nil { return err } @@ -244,23 +236,9 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error { return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status}) } -func (u *CronjobService) AddShellJob(cronjob *model.Cronjob) (int, error) { +func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) { addFunc := func() { - record := cronjobRepo.StartRecords(cronjob.ID, "") - - cmd := exec.Command(cronjob.Script) - stdout, err := cmd.CombinedOutput() - if err != nil { - record.Records = errHandle - cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle) - return - } - record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, stdout) - 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) + u.HandleJob(cronjob) } global.LOG.Infof("add %s job %s successful", cronjob.Type, cronjob.Name) entryID, err := global.Cron.AddFunc(cronjob.Spec, addFunc) @@ -270,9 +248,26 @@ func (u *CronjobService) AddShellJob(cronjob *model.Cronjob) (int, error) { return int(entryID), nil } -func (u *CronjobService) AddCurlJob(cronjob *model.Cronjob) (int, error) { - addFunc := func() { - record := cronjobRepo.StartRecords(cronjob.ID, "") +func (u *CronjobService) HandleJob(cronjob *model.Cronjob) { + var ( + message []byte + err error + ) + record := cronjobRepo.StartRecords(cronjob.ID, "") + switch cronjob.Type { + case "shell": + cmd := exec.Command(cronjob.Script) + message, err = cmd.CombinedOutput() + case "website": + message, err = tarWithExclude(cronjob, record.StartTime) + case "database": + message, err = tarWithExclude(cronjob, record.StartTime) + case "directory": + if len(cronjob.SourceDir) == 0 { + return + } + message, err = tarWithExclude(cronjob, record.StartTime) + case "curl": if len(cronjob.URL) == 0 { return } @@ -287,107 +282,19 @@ func (u *CronjobService) AddCurlJob(cronjob *model.Cronjob) (int, error) { cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle) } defer response.Body.Close() - stdout, _ := ioutil.ReadAll(response.Body) - - record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, stdout) - 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) + message, _ = ioutil.ReadAll(response.Body) } - 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 + record.Records = errHandle + cronjobRepo.EndRecords(record, constant.StatusFailed, err.Error(), errHandle) + return } - return int(entryID), nil -} - -func (u *CronjobService) AddDirectoryJob(cronjob *model.Cronjob) (int, error) { - addFunc := func() { - record := cronjobRepo.StartRecords(cronjob.ID, "") - if len(cronjob.SourceDir) == 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) + record.Records, err = mkdirAndWriteFile(cronjob, record.StartTime, message) if err != nil { - return 0, err + record.Records = errRecord + global.LOG.Errorf("save file %s failed, err: %v", record.Records, err) } - return int(entryID), nil -} - -func (u *CronjobService) AddWebSiteJob(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 - } - if len(message) == 0 { - record.Records = noRecord - cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) - 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) - 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) - if err != nil { - return 0, err - } - return int(entryID), nil + cronjobRepo.EndRecords(record, constant.StatusSuccess, "", record.Records) } func mkdirAndWriteFile(cronjob *model.Cronjob, startTime time.Time, msg []byte) (string, error) { @@ -451,7 +358,7 @@ func tarWithExclude(cronjob *model.Cronjob, startTime time.Time) ([]byte, error) } } if backType, ok := varMaps["type"].(string); ok { - rmOverdueCloud(backType, targetdir, cronjob, backClient) + rmExpiredRecords(backType, targetdir, cronjob, backClient) } return stdout, nil } @@ -493,7 +400,7 @@ func loadTargetInfo(cronjob *model.Cronjob) (map[string]interface{}, string, err return varMap, dir, nil } -func rmOverdueCloud(backType, path string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) { +func rmExpiredRecords(backType, path string, cronjob *model.Cronjob, backClient cloud_storage.CloudStorageClient) { timeNow := time.Now() timeZero := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, timeNow.Location()) timeStart := timeZero.AddDate(0, 0, -int(cronjob.RetainDays)+1) @@ -544,7 +451,7 @@ func rmOverdueCloud(backType, path string, cronjob *model.Cronjob, backClient cl _ = os.Remove(path + "/" + file.Name()) } } - _ = cronjobRepo.DeleteRecord(cronjobRepo.WithByStartDate(timeStart)) + _ = cronjobRepo.DeleteRecord(cronjobRepo.WithByJobID(int(cronjob.ID)), cronjobRepo.WithByStartDate(timeStart)) } func loadSpec(cronjob model.Cronjob) string { diff --git a/backend/router/ro_cronjob.go b/backend/router/ro_cronjob.go index 11b89c855..404d5f97d 100644 --- a/backend/router/ro_cronjob.go +++ b/backend/router/ro_cronjob.go @@ -18,7 +18,8 @@ func (s *CronjobRouter) InitCronjobRouter(Router *gin.RouterGroup) { withRecordRouter.POST("/del", baseApi.DeleteCronjob) withRecordRouter.PUT(":id", baseApi.UpdateCronjob) withRecordRouter.POST("/status", baseApi.UpdateCronjobStatus) - withRecordRouter.POST("/download", baseApi.TargetDownload) + cmdRouter.POST("/handle/:id", baseApi.HandleOnce) + cmdRouter.POST("/download", baseApi.TargetDownload) cmdRouter.POST("/search", baseApi.SearchCronjob) cmdRouter.POST("/search/records", baseApi.SearchJobRecords) cmdRouter.POST("/search/detail", baseApi.LoadRecordDetail) diff --git a/backend/utils/cloud_storage/client/minio_test.go b/backend/utils/cloud_storage/client/minio_test.go new file mode 100644 index 000000000..a90eae580 --- /dev/null +++ b/backend/utils/cloud_storage/client/minio_test.go @@ -0,0 +1,40 @@ +package client + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/1Panel-dev/1Panel/app/model" + "github.com/1Panel-dev/1Panel/constant" + "github.com/1Panel-dev/1Panel/global" + "github.com/1Panel-dev/1Panel/init/db" + "github.com/1Panel-dev/1Panel/init/log" + "github.com/1Panel-dev/1Panel/init/viper" +) + +func TestMinio(t *testing.T) { + viper.Init() + log.Init() + db.Init() + + var backup model.BackupAccount + if err := global.DB.Where("id = ?", 3).First(&backup).Error; err != nil { + fmt.Println(err) + } + + varMap := make(map[string]interface{}) + if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { + fmt.Println(err) + } + varMap["type"] = backup.Type + varMap["bucket"] = backup.Bucket + switch backup.Type { + case constant.Sftp: + varMap["password"] = backup.Credential + case constant.OSS, constant.S3, constant.MinIo: + varMap["secretKey"] = backup.Credential + } + client, _ := NewMinIoClient(varMap) + _, _ = client.ListObjects("directory/directory-test-minio/") +} diff --git a/backend/utils/cloud_storage/client/s3.go b/backend/utils/cloud_storage/client/s3.go index 0929ff54c..aa29abc67 100644 --- a/backend/utils/cloud_storage/client/s3.go +++ b/backend/utils/cloud_storage/client/s3.go @@ -187,7 +187,7 @@ func (s3C *s3Client) ListObjects(prefix string) ([]interface{}, error) { Prefix: &prefix, }, func(p *s3.ListObjectsOutput, last bool) (shouldContinue bool) { for _, obj := range p.Contents { - result = append(result, obj) + result = append(result, *obj.Key) } return true }); err != nil { diff --git a/backend/utils/cloud_storage/client/sftp_test.go b/backend/utils/cloud_storage/client/sftp_test.go new file mode 100644 index 000000000..90c00273e --- /dev/null +++ b/backend/utils/cloud_storage/client/sftp_test.go @@ -0,0 +1,44 @@ +package client + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/1Panel-dev/1Panel/app/model" + "github.com/1Panel-dev/1Panel/constant" + "github.com/1Panel-dev/1Panel/global" + "github.com/1Panel-dev/1Panel/init/db" + "github.com/1Panel-dev/1Panel/init/log" + "github.com/1Panel-dev/1Panel/init/viper" +) + +func TestCronS(t *testing.T) { + viper.Init() + log.Init() + db.Init() + + var backup model.BackupAccount + if err := global.DB.Where("id = ?", 5).First(&backup).Error; err != nil { + fmt.Println(err) + } + + varMap := make(map[string]interface{}) + if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil { + fmt.Println(err) + } + varMap["type"] = backup.Type + varMap["bucket"] = backup.Bucket + switch backup.Type { + case constant.Sftp: + varMap["password"] = backup.Credential + case constant.OSS, constant.S3, constant.MinIo: + varMap["secretKey"] = backup.Credential + } + client, err := NewS3Client(varMap) + if err != nil { + fmt.Println(err) + } + + _, _ = client.ListObjects("directory/directory-test-s3") +} diff --git a/frontend/src/api/modules/cronjob.ts b/frontend/src/api/modules/cronjob.ts index 292f4ee44..ab70e9164 100644 --- a/frontend/src/api/modules/cronjob.ts +++ b/frontend/src/api/modules/cronjob.ts @@ -33,3 +33,7 @@ export const updateStatus = (params: Cronjob.UpdateStatus) => { export const download = (params: Cronjob.Download) => { return http.download(`cronjobs/download`, params, { responseType: 'blob' }); }; + +export const handleOnce = (params: number) => { + return http.post(`cronjobs/handle/${params}`); +}; diff --git a/frontend/src/assets/iconfont/iconfont.css b/frontend/src/assets/iconfont/iconfont.css index f86cc44e0..13a706ea2 100644 --- a/frontend/src/assets/iconfont/iconfont.css +++ b/frontend/src/assets/iconfont/iconfont.css @@ -1,9 +1,9 @@ @font-face { font-family: "panel"; /* Project id 3575356 */ - src: url('iconfont.woff2?t=1663584463212') format('woff2'), - url('iconfont.woff?t=1663584463212') format('woff'), - url('iconfont.ttf?t=1663584463212') format('truetype'), - url('iconfont.svg?t=1663584463212#panel') format('svg'); + src: url('iconfont.woff2?t=1664421291278') format('woff2'), + url('iconfont.woff?t=1664421291278') format('woff'), + url('iconfont.ttf?t=1664421291278') format('truetype'), + url('iconfont.svg?t=1664421291278#panel') format('svg'); } .panel { @@ -14,12 +14,16 @@ -moz-osx-font-smoothing: grayscale; } -.p-taolun:before { - content: "\e602"; +.p-star:before { + content: "\e60f"; } -.p-StarStar:before { - content: "\e635"; +.p-aws:before { + content: "\e600"; +} + +.p-taolun:before { + content: "\e602"; } .p-bug:before { @@ -38,10 +42,6 @@ content: "\e607"; } -.p-s3:before { - content: "\e8e4"; -} - .p-minio:before { content: "\e63c"; } diff --git a/frontend/src/assets/iconfont/iconfont.js b/frontend/src/assets/iconfont/iconfont.js index 77f588725..e58c70979 100644 --- a/frontend/src/assets/iconfont/iconfont.js +++ b/frontend/src/assets/iconfont/iconfont.js @@ -1 +1 @@ -window._iconfont_svg_string_3575356='',function(h){var c=(c=document.getElementsByTagName("script"))[c.length-1],l=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var a,t,v,m,o,z=function(c,l){l.parentNode.insertBefore(c,l)};if(l&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}a=function(){var c,l=document.createElement("div");l.innerHTML=h._iconfont_svg_string_3575356,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(c=document.body).firstChild?z(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(v=a,m=h.document,o=!1,p(),m.onreadystatechange=function(){"complete"==m.readyState&&(m.onreadystatechange=null,i())})}function i(){o||(o=!0,v())}function p(){try{m.documentElement.doScroll("left")}catch(c){return void setTimeout(p,50)}i()}}(window); \ No newline at end of file +window._iconfont_svg_string_3575356='',function(h){var c=(c=document.getElementsByTagName("script"))[c.length-1],l=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var a,t,v,o,m,z=function(c,l){l.parentNode.insertBefore(c,l)};if(l&&!h.__iconfont__svg__cssinject__){h.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}a=function(){var c,l=document.createElement("div");l.innerHTML=h._iconfont_svg_string_3575356,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(c=document.body).firstChild?z(l,c.firstChild):c.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(v=a,o=h.document,m=!1,p(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,i())})}function i(){m||(m=!0,v())}function p(){try{o.documentElement.doScroll("left")}catch(c){return void setTimeout(p,50)}i()}}(window); \ No newline at end of file diff --git a/frontend/src/assets/iconfont/iconfont.json b/frontend/src/assets/iconfont/iconfont.json index 1c072380b..6e4975306 100644 --- a/frontend/src/assets/iconfont/iconfont.json +++ b/frontend/src/assets/iconfont/iconfont.json @@ -5,6 +5,20 @@ "css_prefix_text": "p-", "description": "", "glyphs": [ + { + "icon_id": "974125", + "name": "star", + "font_class": "star", + "unicode": "e60f", + "unicode_decimal": 58895 + }, + { + "icon_id": "32101973", + "name": "Amazon_Web_Services_Logo", + "font_class": "aws", + "unicode": "e600", + "unicode_decimal": 58880 + }, { "icon_id": "1760690", "name": "讨论", @@ -12,13 +26,6 @@ "unicode": "e602", "unicode_decimal": 58882 }, - { - "icon_id": "5192988", - "name": "Star Star", - "font_class": "StarStar", - "unicode": "e635", - "unicode_decimal": 58933 - }, { "icon_id": "6642940", "name": "bug", @@ -47,13 +54,6 @@ "unicode": "e607", "unicode_decimal": 58887 }, - { - "icon_id": "17895439", - "name": "Amazon S3上传", - "font_class": "s3", - "unicode": "e8e4", - "unicode_decimal": 59620 - }, { "icon_id": "20290513", "name": "minio", diff --git a/frontend/src/assets/iconfont/iconfont.svg b/frontend/src/assets/iconfont/iconfont.svg index 207bff1c0..1166af676 100644 --- a/frontend/src/assets/iconfont/iconfont.svg +++ b/frontend/src/assets/iconfont/iconfont.svg @@ -14,9 +14,11 @@ /> - + - + + + @@ -26,8 +28,6 @@ - - diff --git a/frontend/src/assets/iconfont/iconfont.ttf b/frontend/src/assets/iconfont/iconfont.ttf index 37b64c4d1..3ae81ea07 100644 Binary files a/frontend/src/assets/iconfont/iconfont.ttf and b/frontend/src/assets/iconfont/iconfont.ttf differ diff --git a/frontend/src/assets/iconfont/iconfont.woff b/frontend/src/assets/iconfont/iconfont.woff index e9eafe0bc..1f03d16c8 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff and b/frontend/src/assets/iconfont/iconfont.woff differ diff --git a/frontend/src/assets/iconfont/iconfont.woff2 b/frontend/src/assets/iconfont/iconfont.woff2 index 96bd7ae45..5c243e635 100644 Binary files a/frontend/src/assets/iconfont/iconfont.woff2 and b/frontend/src/assets/iconfont/iconfont.woff2 differ diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index f6bb51d6a..914b39b90 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -18,6 +18,7 @@ export default { login: 'Login', close: 'Close', view: 'View', + handle: 'Handle', expand: 'Expand', log: 'Log', saveAndEnable: 'Save and enable', @@ -244,6 +245,8 @@ export default { commands: 'Command', backups: 'Backup Account', settings: 'Panel Setting', + cronjobs: 'Cronjob', + status: ' Update status', auth: 'User', login: ' login', logout: ' logout', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 08b7494e0..318738145 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -18,6 +18,7 @@ export default { login: '登录', close: '关闭', view: '详情', + handle: '执行', expand: '展开', log: '日志', saveAndEnable: '保存并启用', @@ -241,6 +242,8 @@ export default { commands: '快捷命令', backups: '备份账号', settings: '面板设置', + cronjobs: '计划任务', + status: '状态修改', auth: '用户', post: '创建', put: '更新', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 66afa4d01..59583cd7f 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -89,6 +89,10 @@ export function getRandomStr(e: number): string { return n; } +export function loadZero(i: number) { + return i < 10 ? '0' + i : '' + i; +} + export function computeSize(size: number): string { const num = 1024.0; diff --git a/frontend/src/views/cronjob/index.vue b/frontend/src/views/cronjob/index.vue index e59ce907d..98d7a6f41 100644 --- a/frontend/src/views/cronjob/index.vue +++ b/frontend/src/views/cronjob/index.vue @@ -73,11 +73,10 @@ import ComplexTable from '@/components/complex-table/index.vue'; import OperatrDialog from '@/views/cronjob/operate/index.vue'; import RecordDialog from '@/views/cronjob/record/index.vue'; -import { loadZero } from '@/views/cronjob/options'; +import { loadZero } from '@/utils/util'; import { onMounted, reactive, ref } from 'vue'; -import { deleteCronjob, getCronjobPage, updateStatus } from '@/api/modules/cronjob'; +import { deleteCronjob, getCronjobPage, handleOnce, updateStatus } from '@/api/modules/cronjob'; import { loadBackupName } from '@/views/setting/helper'; -import { loadWeek } from './options'; import i18n from '@/lang'; import { Cronjob } from '@/api/interface/cronjob'; import { useDeleteData } from '@/hooks/use-delete-data'; @@ -97,6 +96,15 @@ const logSearch = reactive({ page: 1, pageSize: 5, }); +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: 7 }, +]; const search = async () => { logSearch.page = paginationConfig.currentPage; @@ -158,8 +166,20 @@ const onChangeStatus = async (row: Cronjob.CronjobInfo) => { search(); } }; +const onHandle = async (row: Cronjob.CronjobInfo) => { + await handleOnce(row.id); + ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); + search(); +}; const buttons = [ + { + label: i18n.global.t('commons.button.handle'), + icon: 'Pointer', + click: (row: Cronjob.CronjobInfo) => { + onHandle(row); + }, + }, { label: i18n.global.t('commons.button.edit'), icon: 'Edit', @@ -189,6 +209,14 @@ const onOpenRecordDialog = async (rowData: Partial = {}) => dialogRecordRef.value!.acceptParams(params); }; +function loadWeek(i: number) { + for (const week of weekOptions) { + if (week.value === i) { + return week.label; + } + } + return ''; +} onMounted(() => { search(); }); diff --git a/frontend/src/views/cronjob/operate/index.vue b/frontend/src/views/cronjob/operate/index.vue index 4a274bb1a..5100c054f 100644 --- a/frontend/src/views/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/operate/index.vue @@ -145,7 +145,6 @@ import { onMounted, reactive, ref } from 'vue'; import { Rules } from '@/global/form-rules'; import { loadBackupName } from '@/views/setting/helper'; -import { typeOptions, specOptions, weekOptions } from '@/views/cronjob/options'; import FileList from '@/components/file-list/index.vue'; import { getBackupList } from '@/api/modules/backup'; import i18n from '@/lang'; @@ -222,6 +221,31 @@ const varifySpec = (rule: any, value: any, callback: any) => { } callback(); }; +const typeOptions = [ + { label: i18n.global.t('cronjob.shell'), value: 'shell' }, + { label: i18n.global.t('cronjob.website'), value: 'website' }, + { label: i18n.global.t('cronjob.database'), value: 'database' }, + { label: i18n.global.t('cronjob.directory'), value: 'directory' }, + { label: i18n.global.t('cronjob.curl') + ' URL', value: 'curl' }, +]; + +const specOptions = [ + { label: i18n.global.t('cronjob.perMonth'), value: 'perMonth' }, + { label: i18n.global.t('cronjob.perWeek'), value: 'perWeek' }, + { label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' }, + { label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' }, + { label: i18n.global.t('cronjob.perHour'), value: 'perHour' }, + { label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' }, +]; +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: 7 }, +]; const rules = reactive({ name: [Rules.requiredInput, Rules.name], type: [Rules.requiredSelect], @@ -265,8 +289,9 @@ function isBackup() { dialogData.value.rowData!.type === 'directory' ); } + function hasScript() { - return dialogData.value.rowData!.type === 'shell' || dialogData.value.rowData!.type === 'sync'; + return dialogData.value.rowData!.type === 'shell'; } function changeName(isChangeType: boolean, type: string) { if (isChangeType) { diff --git a/frontend/src/views/cronjob/options.ts b/frontend/src/views/cronjob/options.ts deleted file mode 100644 index 182e4379a..000000000 --- a/frontend/src/views/cronjob/options.ts +++ /dev/null @@ -1,41 +0,0 @@ -import i18n from '@/lang'; - -export const typeOptions = [ - { label: i18n.global.t('cronjob.shell'), value: 'shell' }, - { label: i18n.global.t('cronjob.website'), value: 'website' }, - { label: i18n.global.t('cronjob.database'), value: 'database' }, - { label: i18n.global.t('cronjob.directory'), value: 'directory' }, - { label: i18n.global.t('cronjob.syncDate'), value: 'sync' }, - // { label: i18n.global.t('cronjob.releaseMemory'), value: 'release' }, - { label: i18n.global.t('cronjob.curl') + ' URL', value: 'curl' }, -]; - -export const specOptions = [ - { label: i18n.global.t('cronjob.perMonth'), value: 'perMonth' }, - { label: i18n.global.t('cronjob.perWeek'), value: 'perWeek' }, - { label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' }, - { label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' }, - { label: i18n.global.t('cronjob.perHour'), value: 'perHour' }, - { label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' }, -]; - -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: 7 }, -]; -export const loadWeek = (i: number) => { - for (const week of weekOptions) { - if (week.value === i) { - return week.label; - } - } - return ''; -}; -export const loadZero = (i: number) => { - return i < 10 ? '0' + i : '' + i; -}; diff --git a/frontend/src/views/cronjob/record/index.vue b/frontend/src/views/cronjob/record/index.vue index 02cb1a2b7..538f4ed34 100644 --- a/frontend/src/views/cronjob/record/index.vue +++ b/frontend/src/views/cronjob/record/index.vue @@ -59,35 +59,35 @@ dialogData.rowData?.specType === 'perWeek' " > - {{ $t('cronjob.' + dialogData.rowData?.specType) }} + {{ $t('cronjob.' + dialogData.rowData?.specType) }}  {{ $t('cronjob.per') }} - {{ dialogData.rowData?.day }}{{ $t('cronjob.day') }} + {{ dialogData.rowData?.day }}{{ $t('cronjob.day') }}  {{ loadZero(dialogData.rowData?.hour) }} : {{ loadZero(dialogData.rowData?.minute) }} - {{ loadWeek(dialogData.rowData?.week) }} + {{ loadWeek(dialogData.rowData?.week) }}  {{ loadZero(dialogData.rowData?.hour) }} : {{ loadZero(dialogData.rowData?.minute) }} - {{ dialogData.rowData?.day }}{{ $t('cronjob.day1') }}, + {{ dialogData.rowData?.day }}{{ $t('cronjob.day1') }},  {{ loadZero(dialogData.rowData?.hour) }} : {{ loadZero(dialogData.rowData?.minute) }} - {{ dialogData.rowData?.hour }}{{ $t('cronjob.hour') }}, + {{ dialogData.rowData?.hour }}{{ $t('cronjob.hour') }},  {{ loadZero(dialogData.rowData?.minute) }} - {{ loadZero(dialogData.rowData?.minute) }} +  {{ loadZero(dialogData.rowData?.minute) }} - {{ dialogData.rowData?.minute }}{{ $t('cronjob.minute') }} +  {{ dialogData.rowData?.minute }}{{ $t('cronjob.minute') }} - {{ $t('cronjob.handle') }} +  {{ $t('cronjob.handle') }} @@ -233,7 +233,7 @@