feat: Modify the way of creating cronjob (#8403)

This commit is contained in:
ssongliu 2025-04-16 14:00:17 +08:00 committed by GitHub
parent c59105f050
commit d10d83b648
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 982 additions and 763 deletions

View file

@ -12,14 +12,14 @@ import (
// @Tags Cronjob // @Tags Cronjob
// @Summary Create cronjob // @Summary Create cronjob
// @Accept json // @Accept json
// @Param request body dto.CronjobCreate true "request" // @Param request body dto.CronjobOperate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /cronjobs [post] // @Router /cronjobs [post]
// @x-panel-log {"bodyKeys":["type","name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建计划任务 [type][name]","formatEN":"create cronjob [type][name]"} // @x-panel-log {"bodyKeys":["type","name"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"创建计划任务 [type][name]","formatEN":"create cronjob [type][name]"}
func (b *BaseApi) CreateCronjob(c *gin.Context) { func (b *BaseApi) CreateCronjob(c *gin.Context) {
var req dto.CronjobCreate var req dto.CronjobOperate
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }
@ -31,6 +31,28 @@ func (b *BaseApi) CreateCronjob(c *gin.Context) {
helper.SuccessWithOutData(c) helper.SuccessWithOutData(c)
} }
// @Tags Cronjob
// @Summary Load cronjob info
// @Accept json
// @Param request body dto.OperateByID true "request"
// @Success 200
// @Security ApiKeyAuth
// @Security Timestamp
// @Router /cronjobs/load/info [post]
func (b *BaseApi) LoadCronjobInfo(c *gin.Context) {
var req dto.OperateByID
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}
data, err := cronjobService.LoadInfo(req)
if err != nil {
helper.InternalServer(c, err)
return
}
helper.SuccessWithData(c, data)
}
// @Tags Cronjob // @Tags Cronjob
// @Summary Load cronjob spec time // @Summary Load cronjob spec time
// @Accept json // @Accept json
@ -174,14 +196,14 @@ func (b *BaseApi) DeleteCronjob(c *gin.Context) {
// @Tags Cronjob // @Tags Cronjob
// @Summary Update cronjob // @Summary Update cronjob
// @Accept json // @Accept json
// @Param request body dto.CronjobUpdate true "request" // @Param request body dto.CronjobOperate true "request"
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Security Timestamp // @Security Timestamp
// @Router /cronjobs/update [post] // @Router /cronjobs/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"} // @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFunctions":[{"input_column":"id","input_value":"id","isList":false,"db":"cronjobs","output_column":"name","output_value":"name"}],"formatZH":"更新计划任务 [name]","formatEN":"update cronjob [name]"}
func (b *BaseApi) UpdateCronjob(c *gin.Context) { func (b *BaseApi) UpdateCronjob(c *gin.Context) {
var req dto.CronjobUpdate var req dto.CronjobOperate
if err := helper.CheckBindAndValidate(&req, c); err != nil { if err := helper.CheckBindAndValidate(&req, c); err != nil {
return return
} }

View file

@ -15,7 +15,8 @@ type CronjobSpec struct {
Spec string `json:"spec" validate:"required"` Spec string `json:"spec" validate:"required"`
} }
type CronjobCreate struct { type CronjobOperate struct {
ID uint `json:"id"`
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Type string `json:"type" validate:"required"` Type string `json:"type" validate:"required"`
SpecCustom bool `json:"specCustom"` SpecCustom bool `json:"specCustom"`
@ -48,40 +49,6 @@ type CronjobCreate struct {
AlertTitle string `json:"alertTitle"` AlertTitle string `json:"alertTitle"`
} }
type CronjobUpdate struct {
ID uint `json:"id" validate:"required"`
Type string `json:"type" validate:"required"`
Name string `json:"name" validate:"required"`
SpecCustom bool `json:"specCustom"`
Spec string `json:"spec" validate:"required"`
Executor string `json:"executor"`
ScriptMode string `json:"scriptMode"`
Script string `json:"script"`
Command string `json:"command"`
ContainerName string `json:"containerName"`
User string `json:"user"`
AppID string `json:"appID"`
Website string `json:"website"`
ExclusionRules string `json:"exclusionRules"`
DBType string `json:"dbType"`
DBName string `json:"dbName"`
URL string `json:"url"`
IsDir bool `json:"isDir"`
SourceDir string `json:"sourceDir"`
SourceAccountIDs string `json:"sourceAccountIDs"`
DownloadAccountID uint `json:"downloadAccountID"`
RetainCopies int `json:"retainCopies" validate:"number,min=1"`
RetryTimes int `json:"retryTimes" validate:"number,min=0"`
Timeout uint `json:"timeout" validate:"number,min=1"`
Secret string `json:"secret"`
AlertCount uint `json:"alertCount"`
AlertTitle string `json:"alertTitle"`
}
type CronjobUpdateStatus struct { type CronjobUpdateStatus struct {
ID uint `json:"id" validate:"required"` ID uint `json:"id" validate:"required"`
Status string `json:"status" validate:"required"` Status string `json:"status" validate:"required"`

View file

@ -27,16 +27,17 @@ type CronjobService struct{}
type ICronjobService interface { type ICronjobService interface {
SearchWithPage(search dto.PageCronjob) (int64, interface{}, error) SearchWithPage(search dto.PageCronjob) (int64, interface{}, error)
SearchRecords(search dto.SearchRecord) (int64, interface{}, error) SearchRecords(search dto.SearchRecord) (int64, interface{}, error)
Create(cronjobDto dto.CronjobCreate) error Create(cronjobDto dto.CronjobOperate) error
LoadNextHandle(spec string) ([]string, error) LoadNextHandle(spec string) ([]string, error)
HandleOnce(id uint) error HandleOnce(id uint) error
Update(id uint, req dto.CronjobUpdate) error Update(id uint, req dto.CronjobOperate) error
UpdateStatus(id uint, status string) error UpdateStatus(id uint, status string) error
Delete(req dto.CronjobBatchDelete) error Delete(req dto.CronjobBatchDelete) error
Download(down dto.CronjobDownload) (string, error) Download(down dto.CronjobDownload) (string, error)
StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error) StartJob(cronjob *model.Cronjob, isUpdate bool) (string, error)
CleanRecord(req dto.CronjobClean) error CleanRecord(req dto.CronjobClean) error
LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, error)
LoadRecordLog(req dto.OperateByID) string LoadRecordLog(req dto.OperateByID) string
} }
@ -75,6 +76,25 @@ func (u *CronjobService) SearchWithPage(search dto.PageCronjob) (int64, interfac
return total, dtoCronjobs, err return total, dtoCronjobs, err
} }
func (u *CronjobService) LoadInfo(req dto.OperateByID) (*dto.CronjobOperate, error) {
cronjob, err := cronjobRepo.Get(repo.WithByID(req.ID))
var item dto.CronjobOperate
if err := copier.Copy(&item, &cronjob); err != nil {
return nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
}
alertBase := dto.AlertBase{
AlertType: cronjob.Type,
EntryID: cronjob.ID,
}
alertCount := xpack.GetAlert(alertBase)
if alertCount != 0 {
item.AlertCount = alertCount
} else {
item.AlertCount = 0
}
return &item, err
}
func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interface{}, error) { func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interface{}, error) {
total, records, err := cronjobRepo.PageRecords( total, records, err := cronjobRepo.PageRecords(
search.Page, search.Page,
@ -216,7 +236,7 @@ func (u *CronjobService) HandleOnce(id uint) error {
return nil return nil
} }
func (u *CronjobService) Create(req dto.CronjobCreate) error { func (u *CronjobService) Create(req dto.CronjobOperate) error {
cronjob, _ := cronjobRepo.Get(repo.WithByName(req.Name)) cronjob, _ := cronjobRepo.Get(repo.WithByName(req.Name))
if cronjob.ID != 0 { if cronjob.ID != 0 {
return buserr.New("ErrRecordExist") return buserr.New("ErrRecordExist")
@ -306,7 +326,7 @@ func (u *CronjobService) Delete(req dto.CronjobBatchDelete) error {
return nil return nil
} }
func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error { func (u *CronjobService) Update(id uint, req dto.CronjobOperate) error {
var cronjob model.Cronjob var cronjob model.Cronjob
if err := copier.Copy(&cronjob, &req); err != nil { if err := copier.Copy(&cronjob, &req); err != nil {
return buserr.WithDetail("ErrStructTransform", err.Error(), nil) return buserr.WithDetail("ErrStructTransform", err.Error(), nil)
@ -353,6 +373,8 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
upMap["source_account_ids"] = req.SourceAccountIDs upMap["source_account_ids"] = req.SourceAccountIDs
upMap["download_account_id"] = req.DownloadAccountID upMap["download_account_id"] = req.DownloadAccountID
upMap["retain_copies"] = req.RetainCopies upMap["retain_copies"] = req.RetainCopies
upMap["retry_times"] = req.RetryTimes
upMap["timeout"] = req.Timeout
upMap["secret"] = req.Secret upMap["secret"] = req.Secret
err = cronjobRepo.Update(id, upMap) err = cronjobRepo.Update(id, upMap)
if err != nil { if err != nil {

View file

@ -13,6 +13,7 @@ func (s *CronjobRouter) InitRouter(Router *gin.RouterGroup) {
{ {
cmdRouter.POST("", baseApi.CreateCronjob) cmdRouter.POST("", baseApi.CreateCronjob)
cmdRouter.POST("/next", baseApi.LoadNextHandle) cmdRouter.POST("/next", baseApi.LoadNextHandle)
cmdRouter.POST("/load/info", baseApi.LoadCronjobInfo)
cmdRouter.POST("/del", baseApi.DeleteCronjob) cmdRouter.POST("/del", baseApi.DeleteCronjob)
cmdRouter.POST("/update", baseApi.UpdateCronjob) cmdRouter.POST("/update", baseApi.UpdateCronjob)
cmdRouter.POST("/status", baseApi.UpdateCronjobStatus) cmdRouter.POST("/status", baseApi.UpdateCronjobStatus)

View file

@ -111,10 +111,10 @@ func (c *CommandHelper) run(name string, arg ...string) (string, error) {
cmd.Dir = c.workDir cmd.Dir = c.workDir
} }
if err := cmd.Start(); err != nil {
return "", err
}
if c.timeout != 0 { if c.timeout != 0 {
if err := cmd.Start(); err != nil {
return "", err
}
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
done <- cmd.Wait() done <- cmd.Wait()

View file

@ -111,10 +111,10 @@ func (c *CommandHelper) run(name string, arg ...string) (string, error) {
cmd.Dir = c.workDir cmd.Dir = c.workDir
} }
if err := cmd.Start(); err != nil {
return "", err
}
if c.timeout != 0 { if c.timeout != 0 {
if err := cmd.Start(); err != nil {
return "", err
}
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
done <- cmd.Wait() done <- cmd.Wait()

View file

@ -36,6 +36,10 @@ export namespace Cronjob {
sourceAccountItems: Array<number>; sourceAccountItems: Array<number>;
retainCopies: number; retainCopies: number;
retryTimes: number;
timeout: number;
timeoutItem: number;
timeoutUint: string;
status: string; status: string;
secret: string; secret: string;
hasAlert: boolean; hasAlert: boolean;
@ -45,25 +49,41 @@ export namespace Cronjob {
export interface Item { export interface Item {
val: string; val: string;
} }
export interface CronjobCreate { export interface CronjobOperate {
id: number;
name: string; name: string;
type: string; type: string;
specCustom: boolean; specCustom: boolean;
spec: string; spec: string;
specs: Array<string>;
specObjs: Array<SpecObj>; specObjs: Array<SpecObj>;
script: string; appID: string;
website: string; website: string;
exclusionRules: string; exclusionRules: string;
dbType: string; dbType: string;
dbName: string; dbName: string;
url: string; url: string;
isDir: boolean;
sourceDir: string; sourceDir: string;
//shell
executor: string;
scriptMode: string;
script: string;
command: string;
containerName: string;
user: string;
sourceAccountIDs: string; sourceAccountIDs: string;
downloadAccountID: number; downloadAccountID: number;
retainCopies: number; retainCopies: number;
retryTimes: number;
timeout: number;
secret: string; secret: string;
alertCount: number;
alertTitle: string;
} }
export interface SpecObj { export interface SpecObj {
specType: string; specType: string;
@ -73,24 +93,6 @@ export namespace Cronjob {
minute: number; minute: number;
second: number; second: number;
} }
export interface CronjobUpdate {
id: number;
specCustom: boolean;
spec: string;
script: string;
website: string;
exclusionRules: string;
dbType: string;
dbName: string;
url: string;
sourceDir: string;
sourceAccountIDs: string;
downloadAccountID: number;
retainCopies: number;
secret: string;
}
export interface CronjobDelete { export interface CronjobDelete {
ids: Array<number>; ids: Array<number>;
cleanData: boolean; cleanData: boolean;

View file

@ -11,15 +11,19 @@ export const loadNextHandle = (spec: string) => {
return http.post<Array<String>>(`/cronjobs/next`, { spec: spec }); return http.post<Array<String>>(`/cronjobs/next`, { spec: spec });
}; };
export const loadCronjobInfo = (id: number) => {
return http.post<Cronjob.CronjobOperate>(`/cronjobs/load/info`, { id: id });
};
export const getRecordLog = (id: number) => { export const getRecordLog = (id: number) => {
return http.post<string>(`/cronjobs/records/log`, { id: id }); return http.post<string>(`/cronjobs/records/log`, { id: id });
}; };
export const addCronjob = (params: Cronjob.CronjobCreate) => { export const addCronjob = (params: Cronjob.CronjobOperate) => {
return http.post<Cronjob.CronjobCreate>(`/cronjobs`, params); return http.post<Cronjob.CronjobOperate>(`/cronjobs`, params);
}; };
export const editCronjob = (params: Cronjob.CronjobUpdate) => { export const editCronjob = (params: Cronjob.CronjobOperate) => {
return http.post(`/cronjobs/update`, params); return http.post(`/cronjobs/update`, params);
}; };

View file

@ -966,8 +966,7 @@ const message = {
ntp_helper: 'You can configure the NTP server on the Quick Setup page of the Toolbox.', ntp_helper: 'You can configure the NTP server on the Quick Setup page of the Toolbox.',
app: 'Backup App', app: 'Backup App',
website: 'Backup Website', website: 'Backup Website',
rulesHelper: rulesHelper: 'When multiple compression exclusion rules exist, separate them with [,]. Example: *.log,*.sql',
'When there are multiple compression exclusion rules, they need to be displayed with line breaks. For example: \n*.log \n*.sql',
lastRecordTime: 'Last Execution', lastRecordTime: 'Last Execution',
all: 'All', all: 'All',
failedRecord: 'Failed Records', failedRecord: 'Failed Records',
@ -995,6 +994,9 @@ const message = {
url: 'URL Address', url: 'URL Address',
targetHelper: 'Backup accounts are maintained in panel settings.', targetHelper: 'Backup accounts are maintained in panel settings.',
retainCopies: 'Retain Copies', retainCopies: 'Retain Copies',
retryTimes: 'Retry Attempts',
timeout: 'Timeout',
retryTimesHelper: '0 means no retry after failure',
retainCopiesHelper: 'Number of copies to retain for execution records and logs', retainCopiesHelper: 'Number of copies to retain for execution records and logs',
retainCopiesHelper1: 'Number of copies to retain for backup files', retainCopiesHelper1: 'Number of copies to retain for backup files',
retainCopiesUnit: ' copies (View)', retainCopiesUnit: ' copies (View)',

View file

@ -935,7 +935,7 @@ const message = {
ntp_helper: 'ツールボックスのクイックセットアップページでNTPサーバーを構成できます', ntp_helper: 'ツールボックスのクイックセットアップページでNTPサーバーを構成できます',
app: 'バックアップアプリ', app: 'バックアップアプリ',
website: 'バックアップウェブサイト', website: 'バックアップウェブサイト',
rulesHelper: '圧縮除外ルールがある場合ラインブレークで表示する必要がありますたとえば n*.log n*.sql', rulesHelper: '複数の圧縮除外ルールがある場合[,]で区切ります: *.log,*.sql',
lastRecordTime: '最後の実行時間', lastRecordTime: '最後の実行時間',
all: '全て', all: '全て',
failedRecord: '失敗記録', failedRecord: '失敗記録',
@ -962,6 +962,9 @@ const message = {
url: 'URLアドレス', url: 'URLアドレス',
targetHelper: 'バックアップアカウントはパネル設定で維持されます', targetHelper: 'バックアップアカウントはパネル設定で維持されます',
retainCopies: '記録を保持します', retainCopies: '記録を保持します',
retryTimes: 'リトライ回数',
timeout: 'タイムアウト',
retryTimesHelper: '0は失敗後リトライしないことを意味します',
retainCopiesHelper: '実行記録とログのために保持するコピーの数', retainCopiesHelper: '実行記録とログのために保持するコピーの数',
retainCopiesHelper1: 'バックアップファイル用に保持するコピーの数', retainCopiesHelper1: 'バックアップファイル用に保持するコピーの数',
retainCopiesUnit: 'コピー表示', retainCopiesUnit: 'コピー表示',

View file

@ -925,7 +925,7 @@ const message = {
ntp_helper: 'Toolbox 빠른 설정 페이지에서 NTP 서버를 구성할 있습니다.', ntp_helper: 'Toolbox 빠른 설정 페이지에서 NTP 서버를 구성할 있습니다.',
app: '백업 ', app: '백업 ',
website: '백업 웹사이트', website: '백업 웹사이트',
rulesHelper: '여러 개의 압축 제외 규칙이 경우 바꿈으로 표시해야 합니다. 예시:\n*.log \n*.sql', rulesHelper: '여러 개의 압축 제외 규칙이 경우 [,] 구분하세요. : *.log,*.sql',
lastRecordTime: '마지막 실행 시간', lastRecordTime: '마지막 실행 시간',
all: '전체', all: '전체',
failedRecord: '실패한 레코드', failedRecord: '실패한 레코드',
@ -950,6 +950,9 @@ const message = {
url: 'URL 주소', url: 'URL 주소',
targetHelper: '백업 계정은 패널 설정에서 관리됩니다.', targetHelper: '백업 계정은 패널 설정에서 관리됩니다.',
retainCopies: '기록 보관', retainCopies: '기록 보관',
retryTimes: '재시도 횟수',
timeout: '타임아웃',
retryTimesHelper: '0 실패 재시도 함을 의미합니다',
retainCopiesHelper: '실행 기록과 로그에 대해 보관할 복사본 ', retainCopiesHelper: '실행 기록과 로그에 대해 보관할 복사본 ',
retainCopiesHelper1: '백업 파일에 대해 보관할 복사본 ', retainCopiesHelper1: '백업 파일에 대해 보관할 복사본 ',
retainCopiesUnit: ' (보기)', retainCopiesUnit: ' (보기)',

View file

@ -958,7 +958,7 @@ const message = {
app: 'Aplikasi sandaran', app: 'Aplikasi sandaran',
website: 'Laman web sandaran', website: 'Laman web sandaran',
rulesHelper: rulesHelper:
'Apabila terdapat pelbagai peraturan pengecualian mampatan, ia perlu dipaparkan dengan pemecahan baris. Sebagai contoh,\n*.log \n*.sql', 'Apabila terdapat pelbagai peraturan pengecualian mampatan, gunakan [,] sebagai pemisah. Contoh: *.log,*.sql',
lastRecordTime: 'Waktu pelaksanaan terakhir', lastRecordTime: 'Waktu pelaksanaan terakhir',
all: 'Semua', all: 'Semua',
failedRecord: 'Rekod kegagalan', failedRecord: 'Rekod kegagalan',
@ -985,6 +985,9 @@ const message = {
url: 'Alamat URL', url: 'Alamat URL',
targetHelper: 'Akaun sandaran diselenggara dalam tetapan panel.', targetHelper: 'Akaun sandaran diselenggara dalam tetapan panel.',
retainCopies: 'Simpan salinan', retainCopies: 'Simpan salinan',
retryTimes: 'Bilangan Cubaan Semula',
timeout: 'Masa Tamat',
retryTimesHelper: '0 bermaksud tiada cubaan semula selepas gagal',
retainCopiesHelper: 'Bilangan salinan untuk menyimpan rekod pelaksanaan dan log', retainCopiesHelper: 'Bilangan salinan untuk menyimpan rekod pelaksanaan dan log',
retainCopiesHelper1: 'Bilangan salinan untuk menyimpan fail sandaran', retainCopiesHelper1: 'Bilangan salinan untuk menyimpan fail sandaran',
retainCopiesUnit: ' salinan (Lihat)', retainCopiesUnit: ' salinan (Lihat)',

View file

@ -953,7 +953,7 @@ const message = {
app: 'Backup de app', app: 'Backup de app',
website: 'Backup de site', website: 'Backup de site',
rulesHelper: rulesHelper:
'Quando houver múltiplas regras de exclusão de compressão, elas devem ser exibidas com quebras de linha. Por exemplo,\n*.log\n*.sql', 'Quando existem múltiplas regras de exclusão de compactação, separe-as com [,]. Exemplo: *.log,*.sql',
lastRecordTime: 'Última execução', lastRecordTime: 'Última execução',
all: 'Todos', all: 'Todos',
failedRecord: 'Registros de falha', failedRecord: 'Registros de falha',
@ -980,6 +980,9 @@ const message = {
url: 'Endereço URL', url: 'Endereço URL',
targetHelper: 'As contas de backup são mantidas nas configurações do painel.', targetHelper: 'As contas de backup são mantidas nas configurações do painel.',
retainCopies: 'Manter cópias', retainCopies: 'Manter cópias',
retryTimes: 'Tentativas de Repetição',
timeout: 'Tempo Limite',
retryTimesHelper: '0 significa não repetir após falha',
retainCopiesHelper: 'Número de cópias a serem mantidas para registros de execução e logs', retainCopiesHelper: 'Número de cópias a serem mantidas para registros de execução e logs',
retainCopiesHelper1: 'Número de cópias a serem mantidas para arquivos de backup', retainCopiesHelper1: 'Número de cópias a serem mantidas para arquivos de backup',
retainCopiesUnit: ' cópias (Visualizar)', retainCopiesUnit: ' cópias (Visualizar)',

View file

@ -952,8 +952,7 @@ const message = {
ntp_helper: 'Вы можете настроить NTP сервер на странице Быстрой настройки в Инструментах.', ntp_helper: 'Вы можете настроить NTP сервер на странице Быстрой настройки в Инструментах.',
app: 'Резервное копирование приложения', app: 'Резервное копирование приложения',
website: 'Резервное копирование сайта', website: 'Резервное копирование сайта',
rulesHelper: rulesHelper: 'При наличии нескольких правил исключения сжатия разделяйте их [,]. Пример: *.log,*.sql',
'Когда существует несколько правил исключения сжатия, они должны отображаться с переносом строки. Например,\n*.log \n*.sql',
lastRecordTime: 'Время последнего выполнения', lastRecordTime: 'Время последнего выполнения',
all: 'Все', all: 'Все',
failedRecord: 'Неудачные записи', failedRecord: 'Неудачные записи',
@ -980,6 +979,9 @@ const message = {
url: 'URL-адрес', url: 'URL-адрес',
targetHelper: 'Учетные записи резервного копирования управляются в настройках панели.', targetHelper: 'Учетные записи резервного копирования управляются в настройках панели.',
retainCopies: 'Сохранять записи', retainCopies: 'Сохранять записи',
retryTimes: 'Количество повторов',
timeout: 'Таймаут',
retryTimesHelper: '0 означает отсутствие повторов после сбоя',
retainCopiesHelper: 'Количество копий для сохранения записей выполнения и логов', retainCopiesHelper: 'Количество копий для сохранения записей выполнения и логов',
retainCopiesHelper1: 'Количество копий для сохранения файлов резервных копий', retainCopiesHelper1: 'Количество копий для сохранения файлов резервных копий',
retainCopiesUnit: ' копий (Просмотр)', retainCopiesUnit: ' копий (Просмотр)',

View file

@ -920,7 +920,7 @@ const message = {
ntp_helper: '您可以在工具箱的快速設定頁面配置 NTP 伺服器', ntp_helper: '您可以在工具箱的快速設定頁面配置 NTP 伺服器',
app: '備份應用', app: '備份應用',
website: '備份網站', website: '備份網站',
rulesHelper: '當存在多個壓縮排除規則時需要換行顯示\n*.log \n*.sql', rulesHelper: '當存在多個壓縮排除規則時使用[,]分隔*.log,*.sql',
lastRecordTime: '上次執行情況', lastRecordTime: '上次執行情況',
database: '備份數據庫', database: '備份數據庫',
missBackupAccount: '未能找到備份賬號', missBackupAccount: '未能找到備份賬號',
@ -943,6 +943,9 @@ const message = {
url: 'URL 地址', url: 'URL 地址',
targetHelper: '備份賬號可在面板設置中維護', targetHelper: '備份賬號可在面板設置中維護',
retainCopies: '保留份數', retainCopies: '保留份數',
retryTimes: '失敗重試次數',
timeout: '逾時時間',
retryTimesHelper: '為0表示失敗後不重試',
retainCopiesHelper: '執行記錄及日誌保留份数', retainCopiesHelper: '執行記錄及日誌保留份数',
retainCopiesHelper1: '備份文件保留份数', retainCopiesHelper1: '備份文件保留份数',
retainCopiesUnit: ' (查看)', retainCopiesUnit: ' (查看)',

View file

@ -918,7 +918,7 @@ const message = {
ntp_helper: '您可以在工具箱的快速设置页面配置 NTP 服务器', ntp_helper: '您可以在工具箱的快速设置页面配置 NTP 服务器',
app: '备份应用', app: '备份应用',
website: '备份网站', website: '备份网站',
rulesHelper: '当存在多个压缩排除规则时需要换行显示\n*.log \n*.sql', rulesHelper: '当存在多个压缩排除规则时使用 [,] 分隔*.log,*.sql',
lastRecordTime: '上次执行情况', lastRecordTime: '上次执行情况',
database: '备份数据库', database: '备份数据库',
missBackupAccount: '未能找到备份账号', missBackupAccount: '未能找到备份账号',
@ -941,6 +941,9 @@ const message = {
url: 'URL 地址', url: 'URL 地址',
targetHelper: '备份账号可在面板设置中维护', targetHelper: '备份账号可在面板设置中维护',
retainCopies: '保留份数', retainCopies: '保留份数',
retryTimes: '失败重试次数',
timeout: '超时时间',
retryTimesHelper: ' 0 表示失败后不重试',
retainCopiesHelper: '执行记录及日志保留份数', retainCopiesHelper: '执行记录及日志保留份数',
retainCopiesHelper1: '备份文件保留份数', retainCopiesHelper1: '备份文件保留份数',
retainCopiesUnit: ' (查看)', retainCopiesUnit: ' (查看)',

View file

@ -76,7 +76,13 @@ router.afterEach((to) => {
notMathParam = false; notMathParam = false;
} }
if (notMathParam) { if (notMathParam) {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, to.path); if (to.meta.activeMenu === '/cronjobs' && to.path === '/cronjobs/cronjob/operate') {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, '/cronjobs/cronjob');
} else if (to.meta.activeMenu === '/containers' && to.path === '/containers/container/operate') {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, '/containers/container');
} else {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, to.path);
}
} }
} }

View file

@ -28,6 +28,16 @@ const cronRouter = {
requiresAuth: false, requiresAuth: false,
}, },
}, },
{
path: 'cronjob/operate',
name: 'CronjobOperate',
component: () => import('@/views/cronjob/cronjob/operate/index.vue'),
hidden: true,
meta: {
activeMenu: '/cronjobs',
requiresAuth: false,
},
},
{ {
path: 'library', path: 'library',
name: 'Library', name: 'Library',

View file

@ -444,6 +444,21 @@ export function getProvider(provider: string): string {
} }
} }
export function transferTimeToSecond(item: string): any {
if (item.indexOf('s') !== -1) {
return Number(item.replaceAll('s', ''));
}
if (item.indexOf('m') !== -1) {
return Number(item.replaceAll('m', '')) * 60;
}
if (item.indexOf('h') !== -1) {
return Number(item.replaceAll('h', '')) * 60 * 60;
}
if (item.indexOf('d') !== -1) {
return Number(item.replaceAll('d', '')) * 60 * 60 * 24;
}
return Number(item);
}
export function splitTime(item: string): any { export function splitTime(item: string): any {
if (item.indexOf('s') !== -1) { if (item.indexOf('s') !== -1) {
return { time: Number(item.replaceAll('s', '')), unit: 's' }; return { time: Number(item.replaceAll('s', '')), unit: 's' };

View file

@ -2,7 +2,7 @@
<div> <div>
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('menu.cronjob')"> <LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('menu.cronjob')">
<template #leftToolBar> <template #leftToolBar>
<el-button type="primary" @click="onOpenDialog('create')"> <el-button type="primary" @click="onOpenDialog('')">
{{ $t('commons.button.create') }}{{ $t('menu.cronjob') }} {{ $t('commons.button.create') }}{{ $t('menu.cronjob') }}
</el-button> </el-button>
<el-button-group class="ml-4"> <el-button-group class="ml-4">
@ -150,14 +150,12 @@
</el-form> </el-form>
</template> </template>
</OpDialog> </OpDialog>
<OperateDialog @search="search" ref="dialogRef" />
<Records @search="search" ref="dialogRecordRef" /> <Records @search="search" ref="dialogRecordRef" />
<Backups @search="search" ref="dialogBackupRef" /> <Backups @search="search" ref="dialogBackupRef" />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import OperateDialog from '@/views/cronjob/cronjob/operate/index.vue';
import Records from '@/views/cronjob/cronjob/record/index.vue'; import Records from '@/views/cronjob/cronjob/record/index.vue';
import Backups from '@/views/cronjob/cronjob/backup/index.vue'; import Backups from '@/views/cronjob/cronjob/backup/index.vue';
import { computed, onMounted, reactive, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
@ -168,6 +166,7 @@ import { ElMessageBox } from 'element-plus';
import { MsgSuccess } from '@/utils/message'; import { MsgSuccess } from '@/utils/message';
import { transSpecToStr } from './helper'; import { transSpecToStr } from './helper';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
import router from '@/routers';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
const mobile = computed(() => { const mobile = computed(() => {
@ -219,29 +218,8 @@ const search = async (column?: any) => {
const dialogRecordRef = ref(); const dialogRecordRef = ref();
const dialogBackupRef = ref(); const dialogBackupRef = ref();
const dialogRef = ref(); const onOpenDialog = async (id: string) => {
const onOpenDialog = async ( router.push({ name: 'CronjobOperate', query: { id: id } });
title: string,
rowData: Partial<Cronjob.CronjobInfo> = {
specObjs: [
{
specType: 'perMonth',
week: 1,
day: 3,
hour: 1,
minute: 30,
second: 30,
},
],
type: 'shell',
retainCopies: 7,
},
) => {
let params = {
title,
rowData: { ...rowData },
};
dialogRef.value!.acceptParams(params);
}; };
const onDelete = async (row: Cronjob.CronjobInfo | null) => { const onDelete = async (row: Cronjob.CronjobInfo | null) => {
@ -362,7 +340,7 @@ const buttons = [
{ {
label: i18n.global.t('commons.button.edit'), label: i18n.global.t('commons.button.edit'),
click: (row: Cronjob.CronjobInfo) => { click: (row: Cronjob.CronjobInfo) => {
onOpenDialog('edit', row); onOpenDialog(row.id + '');
}, },
}, },
{ {

File diff suppressed because it is too large Load diff