mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-13 02:55:18 +08:00
feat: 计划任务支持自定义表达式,预览最近五次执行时间 (#6685)
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Some checks failed
sync2gitee / repo-sync (push) Has been cancelled
Refs #4831
This commit is contained in:
parent
1184c7d60e
commit
72311617d9
14 changed files with 264 additions and 110 deletions
|
@ -32,6 +32,28 @@ func (b *BaseApi) CreateCronjob(c *gin.Context) {
|
|||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Load cronjob spec time
|
||||
// @Description 预览最近五次执行时间
|
||||
// @Accept json
|
||||
// @Param request body dto.CronjobSpec true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /cronjobs/next [post]
|
||||
func (b *BaseApi) LoadNextHandle(c *gin.Context) {
|
||||
var req dto.CronjobSpec
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := cronjobService.LoadNextHandle(req.Spec)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
// @Summary Page cronjobs
|
||||
// @Description 获取计划任务分页
|
||||
|
|
|
@ -11,10 +11,15 @@ type PageCronjob struct {
|
|||
Order string `json:"order" validate:"required,oneof=null ascending descending"`
|
||||
}
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
type CronjobSpec struct {
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
}
|
||||
|
||||
type CronjobCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
SpecCustom bool `json:"specCustom"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
|
||||
Script string `json:"script"`
|
||||
Command string `json:"command"`
|
||||
|
@ -34,9 +39,10 @@ type CronjobCreate struct {
|
|||
}
|
||||
|
||||
type CronjobUpdate struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
SpecCustom bool `json:"specCustom"`
|
||||
Spec string `json:"spec" validate:"required"`
|
||||
|
||||
Script string `json:"script"`
|
||||
Command string `json:"command"`
|
||||
|
@ -77,10 +83,11 @@ type CronjobBatchDelete struct {
|
|||
}
|
||||
|
||||
type CronjobInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Spec string `json:"spec"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SpecCustom bool `json:"specCustom"`
|
||||
Spec string `json:"spec"`
|
||||
|
||||
Script string `json:"script"`
|
||||
Command string `json:"command"`
|
||||
|
|
|
@ -9,9 +9,10 @@ import (
|
|||
type Cronjob struct {
|
||||
BaseModel
|
||||
|
||||
Name string `gorm:"not null" json:"name"`
|
||||
Type string `gorm:"not null" json:"type"`
|
||||
Spec string `gorm:"not null" json:"spec"`
|
||||
Name string `gorm:"not null" json:"name"`
|
||||
Type string `gorm:"not null" json:"type"`
|
||||
SpecCustom bool `json:"specCustom"`
|
||||
Spec string `gorm:"not null" json:"spec"`
|
||||
|
||||
Command string `json:"command"`
|
||||
ContainerName string `json:"containerName"`
|
||||
|
|
|
@ -24,6 +24,7 @@ type ICronjobService interface {
|
|||
SearchWithPage(search dto.PageCronjob) (int64, interface{}, error)
|
||||
SearchRecords(search dto.SearchRecord) (int64, interface{}, error)
|
||||
Create(cronjobDto dto.CronjobCreate) error
|
||||
LoadNextHandle(spec string) ([]string, error)
|
||||
HandleOnce(id uint) error
|
||||
Update(id uint, req dto.CronjobUpdate) error
|
||||
UpdateStatus(id uint, status string) error
|
||||
|
@ -77,6 +78,23 @@ func (u *CronjobService) SearchRecords(search dto.SearchRecord) (int64, interfac
|
|||
return total, dtoCronjobs, err
|
||||
}
|
||||
|
||||
func (u *CronjobService) LoadNextHandle(specStr string) ([]string, error) {
|
||||
spec := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
|
||||
sched, err := spec.Parse(specStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
var nexts [5]string
|
||||
for i := 0; i < 5; i++ {
|
||||
nextTime := sched.Next(now)
|
||||
nexts[i] = nextTime.Format("2006-01-02 15:04:05")
|
||||
fmt.Println(nextTime)
|
||||
now = nextTime
|
||||
}
|
||||
return nexts[:], nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) LoadRecordLog(req dto.OperateByID) string {
|
||||
record, err := cronjobRepo.GetRecord(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
|
@ -261,6 +279,7 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
|||
}
|
||||
|
||||
upMap["name"] = req.Name
|
||||
upMap["spec_custom"] = req.SpecCustom
|
||||
upMap["spec"] = spec
|
||||
upMap["script"] = req.Script
|
||||
upMap["command"] = req.Command
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
)
|
||||
|
||||
var AddTable = &gormigrate.Migration{
|
||||
ID: "20240903-add-table",
|
||||
ID: "20241009-add-table",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(
|
||||
&model.AppDetail{},
|
||||
|
|
|
@ -12,6 +12,7 @@ func (s *CronjobRouter) InitRouter(Router *gin.RouterGroup) {
|
|||
baseApi := v2.ApiGroupApp.BaseApi
|
||||
{
|
||||
cmdRouter.POST("", baseApi.CreateCronjob)
|
||||
cmdRouter.POST("/next", baseApi.LoadNextHandle)
|
||||
cmdRouter.POST("/del", baseApi.DeleteCronjob)
|
||||
cmdRouter.POST("/update", baseApi.UpdateCronjob)
|
||||
cmdRouter.POST("/status", baseApi.UpdateCronjobStatus)
|
||||
|
|
|
@ -5,7 +5,9 @@ export namespace Cronjob {
|
|||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
specCustom: boolean;
|
||||
spec: string;
|
||||
specs: Array<string>;
|
||||
specObjs: Array<SpecObj>;
|
||||
|
||||
script: string;
|
||||
|
@ -31,6 +33,7 @@ export namespace Cronjob {
|
|||
export interface CronjobCreate {
|
||||
name: string;
|
||||
type: string;
|
||||
specCustom: boolean;
|
||||
spec: string;
|
||||
specObjs: Array<SpecObj>;
|
||||
|
||||
|
@ -57,6 +60,7 @@ export namespace Cronjob {
|
|||
}
|
||||
export interface CronjobUpdate {
|
||||
id: number;
|
||||
specCustom: boolean;
|
||||
spec: string;
|
||||
|
||||
script: string;
|
||||
|
|
|
@ -7,6 +7,10 @@ export const getCronjobPage = (params: SearchWithPage) => {
|
|||
return http.post<ResPage<Cronjob.CronjobInfo>>(`/cronjobs/search`, params);
|
||||
};
|
||||
|
||||
export const loadNextHandle = (spec: string) => {
|
||||
return http.post<Array<String>>(`/cronjobs/next`, { spec: spec });
|
||||
};
|
||||
|
||||
export const getRecordLog = (id: number) => {
|
||||
return http.post<string>(`/cronjobs/records/log`, { id: id });
|
||||
};
|
||||
|
|
|
@ -857,6 +857,7 @@ const message = {
|
|||
enableMsg:
|
||||
'Enabling the scheduled task will allow the task to automatically execute on a regular basis. Do you want to continue?',
|
||||
taskType: 'Type',
|
||||
nextTime: 'Next 5 executions',
|
||||
record: 'Records',
|
||||
shell: 'Shell',
|
||||
log: 'Backup Logs',
|
||||
|
@ -902,6 +903,7 @@ const message = {
|
|||
retainCopiesHelper1: 'Number of copies to retain for backup files',
|
||||
retainCopiesUnit: ' copies (View)',
|
||||
cronSpecRule: 'The execution period format in line {0} is incorrect. Please check and try again!',
|
||||
cronSpecRule2: 'Execution period format is incorrect, please check and try again!',
|
||||
perMonth: 'Every monthly',
|
||||
perWeek: 'Every week',
|
||||
perHour: 'Every hour',
|
||||
|
|
|
@ -818,6 +818,7 @@ const message = {
|
|||
disableMsg: '停止計劃任務會導致該任務不再自動執行。是否繼續?',
|
||||
enableMsg: '啟用計劃任務會讓該任務定期自動執行。是否繼續?',
|
||||
taskType: '任務類型',
|
||||
nextTime: '近 5 次執行',
|
||||
record: '報告',
|
||||
shell: 'Shell 腳本',
|
||||
log: '備份日誌',
|
||||
|
@ -857,6 +858,7 @@ const message = {
|
|||
retainCopiesHelper1: '備份文件保留份数',
|
||||
retainCopiesUnit: ' 份 (查看)',
|
||||
cronSpecRule: '第 {0} 行中執行週期格式錯誤,請檢查後重試!',
|
||||
cronSpecRule2: '執行週期格式錯誤,請檢查後重試!',
|
||||
perMonth: '每月',
|
||||
perWeek: '每周',
|
||||
perHour: '每小時',
|
||||
|
|
|
@ -819,6 +819,7 @@ const message = {
|
|||
disableMsg: '停止计划任务会导致该任务不再自动执行。是否继续?',
|
||||
enableMsg: '启用计划任务会让该任务定期自动执行。是否继续?',
|
||||
taskType: '任务类型',
|
||||
nextTime: '近 5 次执行',
|
||||
record: '报告',
|
||||
shell: 'Shell 脚本',
|
||||
log: '备份日志',
|
||||
|
@ -858,6 +859,7 @@ const message = {
|
|||
retainCopiesHelper1: '备份文件保留份数',
|
||||
retainCopiesUnit: ' 份 (查看)',
|
||||
cronSpecRule: '第 {0} 行中执行周期格式错误,请检查后重试!',
|
||||
cronSpecRule2: '执行周期格式错误,请检查后重试!',
|
||||
perMonth: '每月',
|
||||
perWeek: '每周',
|
||||
perHour: '每小时',
|
||||
|
|
|
@ -39,35 +39,22 @@ export function loadDefaultSpec(type: string) {
|
|||
item.second = 0;
|
||||
switch (type) {
|
||||
case 'shell':
|
||||
case 'clean':
|
||||
case 'website':
|
||||
case 'log':
|
||||
case 'snapshot':
|
||||
case 'curl':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'app':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 2;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'database':
|
||||
item.specType = 'perDay';
|
||||
item.hour = 2;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'clean':
|
||||
case 'website':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'log':
|
||||
case 'snapshot':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'directory':
|
||||
case 'cutWebsiteLog':
|
||||
case 'ntp':
|
||||
|
@ -75,16 +62,31 @@ export function loadDefaultSpec(type: string) {
|
|||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
case 'curl':
|
||||
item.specType = 'perWeek';
|
||||
item.week = 1;
|
||||
item.hour = 1;
|
||||
item.minute = 30;
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
export function loadDefaultSpecCustom(type: string) {
|
||||
switch (type) {
|
||||
case 'shell':
|
||||
case 'clean':
|
||||
case 'website':
|
||||
case 'log':
|
||||
case 'snapshot':
|
||||
case 'curl':
|
||||
return '30 1 * * 1';
|
||||
case 'app':
|
||||
case 'database':
|
||||
return '30 2 * * *';
|
||||
case 'directory':
|
||||
case 'cutWebsiteLog':
|
||||
case 'ntp':
|
||||
return '30 1 * * *';
|
||||
default:
|
||||
return '30 1 * * 1';
|
||||
}
|
||||
}
|
||||
|
||||
export function transObjToSpec(specType: string, week, day, hour, minute, second): string {
|
||||
switch (specType) {
|
||||
case 'perMonth':
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
<div v-for="(item, index) of row.spec.split(',')" :key="index">
|
||||
<div v-if="row.expand || (!row.expand && index < 3)">
|
||||
<span>
|
||||
{{ transSpecToStr(item) }}
|
||||
{{ row.specCustom ? item : transSpecToStr(item) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -68,67 +68,113 @@
|
|||
<el-input :disabled="dialogData.title === 'edit'" clearable v-model.trim="dialogData.rowData!.name" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
|
||||
<div v-for="(specObj, index) of dialogData.rowData.specObjs" :key="index" style="width: 100%">
|
||||
<el-select class="specTypeClass" v-model="specObj.specType" @change="changeSpecType(index)">
|
||||
<el-option
|
||||
v-for="item in specOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select v-if="specObj.specType === 'perWeek'" class="specClass" v-model="specObj.week">
|
||||
<el-option
|
||||
v-for="item in weekOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-if="hasDay(specObj)" class="specClass" v-model.number="specObj.day">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('cronjob.day') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-if="hasHour(specObj)" class="specClass" v-model.number="specObj.hour">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.hour') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType !== 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.minute"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.minute') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType === 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.second"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.second') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
class="ml-2.5"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleSpecDelete(index)"
|
||||
v-if="dialogData.rowData.specObjs.length > 1"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
<el-divider v-if="dialogData.rowData.specObjs.length > 1" class="divider" />
|
||||
</div>
|
||||
<el-form-item :label="$t('cronjob.cronSpec')" prop="specCustom">
|
||||
<el-checkbox :label="$t('container.custom')" v-model="dialogData.rowData!.specCustom" />
|
||||
</el-form-item>
|
||||
<el-button class="mb-3" @click="handleSpecAdd()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
<div v-if="!dialogData.rowData!.specCustom">
|
||||
<el-form-item prop="spec">
|
||||
<div v-for="(specObj, index) of dialogData.rowData.specObjs" :key="index" style="width: 100%">
|
||||
<el-select class="specTypeClass" v-model="specObj.specType" @change="changeSpecType(index)">
|
||||
<el-option
|
||||
v-for="item in specOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select v-if="specObj.specType === 'perWeek'" class="specClass" v-model="specObj.week">
|
||||
<el-option
|
||||
v-for="item in weekOptions"
|
||||
:key="item.label"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</el-select>
|
||||
<el-input v-if="hasDay(specObj)" class="specClass" v-model.number="specObj.day">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('cronjob.day') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-if="hasHour(specObj)" class="specClass" v-model.number="specObj.hour">
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.hour') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType !== 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.minute"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.minute') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input
|
||||
v-if="specObj.specType === 'perNSecond'"
|
||||
class="specClass"
|
||||
v-model.number="specObj.second"
|
||||
>
|
||||
<template #append>
|
||||
<div class="append">{{ $t('commons.units.second') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-popover placement="top-start" :title="$t('cronjob.nextTime')" width="200" trigger="click">
|
||||
<div v-for="(time, index_t) of nextTimes" :key="index_t">
|
||||
<el-tag class="mt-2">{{ time }}</el-tag>
|
||||
</div>
|
||||
<template #reference>
|
||||
<el-button class="ml-2.5" @click="loadNext(specObj)" link type="primary">
|
||||
{{ $t('commons.button.preview') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button
|
||||
class="ml-2.5"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleSpecDelete(index)"
|
||||
v-if="dialogData.rowData.specObjs.length > 1"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
<el-divider v-if="dialogData.rowData.specObjs.length > 1" class="divider" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-button class="mb-3" @click="handleSpecAdd()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="dialogData.rowData!.specCustom">
|
||||
<el-form-item prop="spec">
|
||||
<div v-for="(spec, index) of dialogData.rowData.specs" :key="index" style="width: 100%">
|
||||
<el-input style="width: 80%" v-model="dialogData.rowData.specs[index]" />
|
||||
<el-popover placement="top-start" :title="$t('cronjob.nextTime')" width="200" trigger="click">
|
||||
<div v-for="(time, index_t) of nextTimes" :key="index_t">
|
||||
<el-tag class="mt-2">{{ time }}</el-tag>
|
||||
</div>
|
||||
<template #reference>
|
||||
<el-button class="ml-2.5" @click="loadNext(spec)" link type="primary">
|
||||
{{ $t('commons.button.preview') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-button
|
||||
class="ml-2.5"
|
||||
link
|
||||
type="primary"
|
||||
@click="handleSpecCustomDelete(index)"
|
||||
v-if="dialogData.rowData.specs.length > 1"
|
||||
>
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
<el-divider v-if="dialogData.rowData.specs.length > 1" class="divider" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-button class="mb-3" @click="handleSpecCustomAdd()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-form-item v-if="hasScript()">
|
||||
<el-checkbox v-model="dialogData.rowData!.inContainer">
|
||||
|
@ -336,7 +382,7 @@ import { getBackupList } from '@/api/modules/backup';
|
|||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { Cronjob } from '@/api/interface/cronjob';
|
||||
import { addCronjob, editCronjob } from '@/api/modules/cronjob';
|
||||
import { addCronjob, editCronjob, loadNextHandle } from '@/api/modules/cronjob';
|
||||
import { listDbItems } from '@/api/modules/database';
|
||||
import { GetWebsiteOptions } from '@/api/modules/website';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
@ -344,7 +390,14 @@ import { useRouter } from 'vue-router';
|
|||
import { listContainer } from '@/api/modules/container';
|
||||
import { Database } from '@/api/interface/database';
|
||||
import { ListAppInstalled } from '@/api/modules/app';
|
||||
import { loadDefaultSpec, specOptions, transObjToSpec, transSpecToObj, weekOptions } from './../helper';
|
||||
import {
|
||||
loadDefaultSpec,
|
||||
loadDefaultSpecCustom,
|
||||
specOptions,
|
||||
transObjToSpec,
|
||||
transSpecToObj,
|
||||
weekOptions,
|
||||
} from './../helper';
|
||||
const router = useRouter();
|
||||
|
||||
interface DialogProps {
|
||||
|
@ -357,16 +410,22 @@ const drawerVisible = ref(false);
|
|||
const dialogData = ref<DialogProps>({
|
||||
title: '',
|
||||
});
|
||||
const nextTimes = ref([]);
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
dialogData.value = params;
|
||||
if (dialogData.value.rowData?.spec) {
|
||||
if (!dialogData.value.rowData?.specCustom && dialogData.value.rowData?.spec) {
|
||||
let objs = [];
|
||||
for (const item of dialogData.value.rowData.spec.split(',')) {
|
||||
objs.push(transSpecToObj(item));
|
||||
}
|
||||
dialogData.value.rowData.specObjs = objs;
|
||||
}
|
||||
dialogData.value.rowData.specObjs = dialogData.value.rowData.specObjs || [];
|
||||
if (dialogData.value.rowData?.specCustom && dialogData.value.rowData?.spec) {
|
||||
dialogData.value.rowData.specs = dialogData.value.rowData.spec.split(',');
|
||||
}
|
||||
dialogData.value.rowData.specs = dialogData.value.rowData.specs || [];
|
||||
if (dialogData.value.title === 'create') {
|
||||
changeType();
|
||||
dialogData.value.rowData.dbType = 'mysql';
|
||||
|
@ -548,6 +607,22 @@ const hasHour = (item: any) => {
|
|||
return item.specType !== 'perHour' && item.specType !== 'perNMinute' && item.specType !== 'perNSecond';
|
||||
};
|
||||
|
||||
const loadNext = async (spec: any) => {
|
||||
nextTimes.value = [];
|
||||
let specItem = '';
|
||||
if (!dialogData.value.rowData.specCustom) {
|
||||
specItem = transObjToSpec(spec.specType, spec.week, spec.day, spec.hour, spec.minute, spec.second);
|
||||
} else {
|
||||
specItem = spec;
|
||||
}
|
||||
if (!specItem) {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecRule2'));
|
||||
return;
|
||||
}
|
||||
const data = await loadNextHandle(specItem);
|
||||
nextTimes.value = data.data || [];
|
||||
};
|
||||
|
||||
const loadDatabases = async (dbType: string) => {
|
||||
const data = await listDbItems(dbType);
|
||||
dbInfo.dbs = data.data || [];
|
||||
|
@ -555,6 +630,7 @@ const loadDatabases = async (dbType: string) => {
|
|||
|
||||
const changeType = () => {
|
||||
dialogData.value.rowData!.specObjs = [loadDefaultSpec(dialogData.value.rowData.type)];
|
||||
dialogData.value.rowData!.specs = [loadDefaultSpecCustom(dialogData.value.rowData.type)];
|
||||
};
|
||||
|
||||
const changeSpecType = (index: number) => {
|
||||
|
@ -598,10 +674,18 @@ const handleSpecAdd = () => {
|
|||
dialogData.value.rowData!.specObjs.push(item);
|
||||
};
|
||||
|
||||
const handleSpecCustomAdd = () => {
|
||||
dialogData.value.rowData!.specs.push('');
|
||||
};
|
||||
|
||||
const handleSpecDelete = (index: number) => {
|
||||
dialogData.value.rowData!.specObjs.splice(index, 1);
|
||||
};
|
||||
|
||||
const handleSpecCustomDelete = (index: number) => {
|
||||
dialogData.value.rowData!.specs.splice(index, 1);
|
||||
};
|
||||
|
||||
const loadBackups = async () => {
|
||||
const res = await getBackupList();
|
||||
backupOptions.value = [];
|
||||
|
@ -679,14 +763,18 @@ function hasScript() {
|
|||
}
|
||||
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
const specs = [];
|
||||
for (const item of dialogData.value.rowData.specObjs) {
|
||||
const itemSpec = transObjToSpec(item.specType, item.week, item.day, item.hour, item.minute, item.second);
|
||||
if (itemSpec === '') {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||
return;
|
||||
let specs = [];
|
||||
if (!dialogData.value.rowData.specCustom) {
|
||||
for (const item of dialogData.value.rowData.specObjs) {
|
||||
const itemSpec = transObjToSpec(item.specType, item.week, item.day, item.hour, item.minute, item.second);
|
||||
if (itemSpec === '') {
|
||||
MsgError(i18n.global.t('cronjob.cronSpecHelper'));
|
||||
return;
|
||||
}
|
||||
specs.push(itemSpec);
|
||||
}
|
||||
specs.push(itemSpec);
|
||||
} else {
|
||||
specs = dialogData.value.rowData.specs;
|
||||
}
|
||||
dialogData.value.rowData.sourceAccountIDs = dialogData.value.rowData.sourceAccounts.join(',');
|
||||
dialogData.value.rowData.spec = specs.join(',');
|
||||
|
@ -719,7 +807,7 @@ defineExpose({
|
|||
</script>
|
||||
<style scoped lang="scss">
|
||||
.specClass {
|
||||
width: 20% !important;
|
||||
width: 17% !important;
|
||||
margin-left: 20px;
|
||||
.append {
|
||||
width: 20px;
|
||||
|
|
Loading…
Reference in a new issue