From 49f0fb10a8d571e4ecfd8610496725d60c12dcba Mon Sep 17 00:00:00 2001 From: ssongliu Date: Thu, 29 Sep 2022 11:13:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20s3=20=E5=AE=9A=E6=97=B6=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/cronjob.go | 13 ++ backend/app/model/cronjob.go | 2 +- backend/app/service/cornjob.go | 181 +++++------------- backend/router/ro_cronjob.go | 3 +- .../utils/cloud_storage/client/minio_test.go | 40 ++++ backend/utils/cloud_storage/client/s3.go | 2 +- .../utils/cloud_storage/client/sftp_test.go | 44 +++++ frontend/src/api/modules/cronjob.ts | 4 + frontend/src/assets/iconfont/iconfont.css | 24 +-- frontend/src/assets/iconfont/iconfont.js | 2 +- frontend/src/assets/iconfont/iconfont.json | 28 +-- frontend/src/assets/iconfont/iconfont.svg | 8 +- frontend/src/assets/iconfont/iconfont.ttf | Bin 11264 -> 11220 bytes frontend/src/assets/iconfont/iconfont.woff | Bin 7072 -> 7080 bytes frontend/src/assets/iconfont/iconfont.woff2 | Bin 5928 -> 5912 bytes frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/zh.ts | 3 + frontend/src/utils/util.ts | 4 + frontend/src/views/cronjob/index.vue | 34 +++- frontend/src/views/cronjob/operate/index.vue | 29 ++- frontend/src/views/cronjob/options.ts | 41 ---- frontend/src/views/cronjob/record/index.vue | 35 +++- frontend/src/views/setting/tabs/about.vue | 2 +- frontend/src/views/setting/tabs/backup.vue | 6 +- 24 files changed, 277 insertions(+), 231 deletions(-) create mode 100644 backend/utils/cloud_storage/client/minio_test.go create mode 100644 backend/utils/cloud_storage/client/sftp_test.go delete mode 100644 frontend/src/views/cronjob/options.ts 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 37b64c4d19076655c990f529cac9a8b01a964be8..3ae81ea07cbe25d5d6d5cc6548f5a112cf2c1bed 100644 GIT binary patch delta 1503 zcmY*XZ){Ul6hHUAckk=#>$~rDZC^{vUc0`nUANJ(wreM_KfnZ(jEp~n2?QyOvB<_2 zw#itcor{P;G(dv^gT|00@Btw@1N&eI2}b>3NJPFMA6#NmP!ah;B8geO-7wL6bMBvW ze)pW;`Q=V@-`#f7%Dn`DP5{8}y#v{yp)bb;06YdD#`pIh>HTS}<1zq!0#H%ew=dgM zIdXFg$Ify~_i=~)O}dGnzv5QeH!w2x!PVklJl`XJKhZz9H~aqaGk5v>OZ>iWAUigM zTHq;<`}jR{Fgvhs?Yng@5un=5i>@9T93J`l`0E9Lnr;pn2LvEY6enOOy;6L}(_B1t z+uu|@`|bFv+KQ*3@P~Z-y!}S)zkBgnae`hH-r{!~;F6aQo&_xUH6KEQ$ellldN93` ze~h~G8}I=c3b-H@w1SbpiEF)czwav+IlLD}aI#Q}k>|0Xa{9sL2cJLq=3&jlo_t)` zh}!ZKg7r!}toh#rFd+m%UR;315C(~t7onWfA>e}mECLD&I6wsk8tCAJGH`(#D!>B< z*uf7ncsXa9e@pDk_lQ4uI32DC*N5-V4TO9Pu@*_(qb*pe$%3(9Am+!3g-HGrQqS|; zCfD<)=;B;Ix`xN_tgu`7TYOo(Ov*?nnIuyb(;j+9GHrFTDSv1W+fUeUD{GYRl*bOY zW0~Vq^@jS0UDABoA^r4%q{5_tctic@?7nZt33E7y%j=?oWCcD81?odEK2vz6NW;!Xq(S9 z6%YcsSWG`UV^sU)t}a|LH za+EN<0n~#2d+_iK0zb@%{x$m+U%meQqpY>r@X3X z?dJVk0~NklrQVb#C7}3-QoeA5vi8)or7wWcpn4}WI%vBZXWoFH$mZo50Wz^$Ty&i>EwyP3b zx+0OX>N=ZKW^#So_QOMOjF0|#|Hn%o%x@qbj+ip?0+{ zI#jRUk{A)nRRh~ix5q_wn~&HW<*p4I+t+oIoFKvk*DmTW2h=fQ?36x1jDD11?q4p(}%d5TVxyP#-;yz#3rn5F(qOZNMJQQw| zRDXvXBN>;;epNw;x!Yq)tK;PovfI|xcJO~W{e&Jx)2cirOn;`W2t>r;k?bKMdw7_R kWC#044+?um_luj?Z0WT1jb`^`4>mOkgTur5vf4lX0hF;O@c;k- delta 1474 zcmYLJU1%It6u#%)JNM3=nVp&J&&+O;-A#7W*)&OaWjDJ?u}zg?tVLU_qEhP5+N2HG zG{vNv;?Jg_#fMg^qdxiIgH$Q>p|t)%AEXq-T7?!-kYbCJO`#QvkYXR|dPWfk4)>h% zopZkL-UIXFlS@w>Ew<`}z+pnjb3137`wrZCb%hYRNC+?Q-g96V_qsnPMBE~z|KXYG z=2ZXb#)nvY6|FIY3HdYo82vM712eM=i-)1}C(gTx@!>slJDW!a-MW5RoOJG>B=XJ= z-Q(XJiQWIKvu=f$*ofbiNA7I>@9f;^EOEjPVyqJyW%0u)qzHQ02XjEeqc9cfbTYJQ zGTcI6khCq^Ub`NirNjQU>wn#t?sTwz7g?aSHf?MFV4MxZwXn<{4G*$vaT4(y=_7fZ z+)D~X5Qbb?WaK1GdPs(7;ZH2DBvHgidJ!JvGvO4!s8CTmQU&2=t(XxQdH)(tAZ=Vk zWQ2x?v?B2ExK;rz{6+ghT_fZ=8j<1KBERu0*zgkErti|L{2BhW7HCu22iljy6N{oP ztNMMas*W2C<0IoYbGv!jqSm0b#X23kWE1<0GvXX_kDc0Kya_FQm`=#d zbKO(FnxC+iLT$_JJNhlDlLyFt@)h}>w8=8L1roI;J>N^AQc)^*f0zQ ztdmHh6-oi}t%uQCHF~OA6?>2^dYk&_1dXzupQAFB3`(d0d;Fx2qjMnfJ*6o6D61$C zL@w+{VL2EJP^t(bm6(fsj9O7xl1Z=H7!3+y43TIdDGv+l5_f{TXjGxD3kq6-8%!G9 zt@H$Iz_EKOZdc697Q6agp;0D4Xo;ks9;?0L_E}OwENkcUsO+{hU=sz-a_Ed!z!Vu_ z!abwZ5ZM;f0AMp1vKzrl1j635pKyhcj7fJOo^_>i{WXPLSMNa5Fp|=c7S7gs^F6lI zK{<)x{wzROHtu7e6Pj1?Pi2xj*O{4 z)@~hdjc;8$y_!*>vkX`k%`ja6U(F;1J8d#9Sd4M$8YvG(2IBoznt|pOdv!^va)hEv z6V>WFW=y4REbJck`a#K?nvAZc<)Pn!{0&Cp{@MTl diff --git a/frontend/src/assets/iconfont/iconfont.woff b/frontend/src/assets/iconfont/iconfont.woff index e9eafe0bc8c7be43f3f5f50d0972bcc22def836c..1f03d16c8420c25faf764741c252719552b8fa6e 100644 GIT binary patch delta 6642 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∋4v6aetL^0@Wxd8j9oM z-g2xEiBrtGrL-gxB1Z)of|4*i{9#p-<2o=Vd)xw+#aDQdNhOQl{SEgW+9O(Xyl&9B%6+}@J&0}7Td1#^7s8XiS4qq`nvo%hb21C3Ar49X?sE3|Q z$5Gq>jjK3fgIt$N&9gD4fBV~><>_4T3bw~9wMI0V{Yx2JNq^byj%Sj|xRoM_eYPp( z6ZW1*viP)dI^ENIc8L)Dx%LZNmZ##o4}B>3$~ye0ZBL)IK7WUtjA6y@%BiX#n8_8X zJKWa1!Km_`Q+{^qLsR*wP=+_?2WbT5P!Adf8%BHqtkfK7)(gXK27+$UU&z8xgGEnP zw+bxCvQ``7E`JCXhFYkIKxYciBCbHr4Tg2g((!kru~;@1ya#^}ve<6}6Y5d?OV*|< zdlfsW+@RPW)@&%JY$!)8ojk)@Ut)~kXkYXVmcOK1cqi*18v~xC9VRz)K4uB(;05rL z|4Ob#HYy_|VLCEk?0V^s#fUHC=Dk4-VHAa~KVj#0*)*WzcS>o_! z!6`ZQ@TK$DDsjUpMAn{KTafDYr1l4J>nBe?{qlkR!)ep=>+i>dy>%<=m;M3YJH2K4 zvS~!aF@GZDGjrGh;YP_}z1JIclP@*u9=xPy@$=6wem?lo-FN@^lbVGR+@QQP^m&e9PcdM1ER8s9{ASFxM¥5_J2aGu;-b%e9dI-)8$F>;N;GolYTNl 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 A?EnA( diff --git a/frontend/src/assets/iconfont/iconfont.woff2 b/frontend/src/assets/iconfont/iconfont.woff2 index 96bd7ae45b5e51fb9c8dbf9f6682075580b6bd08..5c243e6350b65db810754ed95f9a1f4e9e2f0276 100644 GIT binary patch literal 5912 zcmV+z7w71APew8T0RR9102del3jhEB04vl002ays0RR9100000000000000000000 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 literal 5928 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 { 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 @@