Skip to content

Commit 0a379a4

Browse files
committed
feat: Switch to cron expression
1 parent c098e0f commit 0a379a4

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@vavt/cm-extension": "^1.9.1",
2626
"@vueuse/core": "^13.3.0",
2727
"axios": "^1.8.4",
28+
"cron-validator": "^1.4.0",
2829
"cropperjs": "^1.6.2",
2930
"dingtalk-jsapi": "^3.1.0",
3031
"echarts": "^5.6.0",

ui/src/views/trigger/TriggerDrawer.vue

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,45 @@
7676
shadow="never"
7777
class="card-never mt-16 w-full"
7878
>
79-
<p style="margin-top: -8px">{{ $t('views.trigger.triggerCycle.title') }}</p>
79+
<div class="flex-between">
80+
<p style="margin-top: -8px">
81+
{{
82+
form.trigger_setting.schedule_type === 'cron'
83+
? 'Cron表达式'
84+
: $t('views.trigger.triggerCycle.title')
85+
}}
86+
</p>
87+
<el-tooltip
88+
:content="
89+
form.trigger_setting.schedule_type === 'cron'
90+
? '切换为触发周期'
91+
: '切换为Cron表达式'
92+
"
93+
placement="top"
94+
effect="light"
95+
>
96+
<el-button text @click.stop="switchScheduleType">
97+
<el-icon><Switch /></el-icon>
98+
</el-button>
99+
</el-tooltip>
100+
</div>
80101

81102
<el-cascader
103+
v-if="form.trigger_setting.schedule_type !== 'cron'"
82104
v-model="scheduled"
83105
:options="triggerCycleOptions"
84106
@change="handleChangeScheduled"
85107
style="width: 100%"
86108
/>
109+
<el-input
110+
v-else
111+
v-model="form.trigger_setting.cron_expression"
112+
placeholder="请输入Cron表达式(如:0 0 1 * *)"
113+
clearable
114+
@blur="validateCron"
115+
@input="validateCron"
116+
/>
117+
<div v-if="cronError" class="el-form-item__error">{{ cronError }}</div>
87118
</el-card>
88119
</el-card>
89120
<el-card
@@ -500,6 +531,8 @@ import { triggerCycleOptions } from '@/utils/trigger.ts'
500531
import { t } from '@/locales'
501532
import { type FormInstance } from 'element-plus'
502533
import { useRoute } from 'vue-router'
534+
import { cloneDeep } from 'lodash'
535+
import { isValidCron } from 'cron-validator'
503536
import Result from '@/request/Result'
504537
import { hasPermission } from '@/utils/permission'
505538
import permissionMap from '@/permission'
@@ -577,6 +610,52 @@ const event_url = computed(() => {
577610
return `${window.origin}${window.MaxKB.prefix}/api/trigger/v1/webhook/${form.value.id}`
578611
})
579612
613+
const lastPresetSetting = ref<any>(null)
614+
const cronError = ref('')
615+
616+
const validateCron = () => {
617+
const cron = form.value.trigger_setting.cron_expression?.trim()
618+
if (!cron) {
619+
cronError.value = ''
620+
return
621+
}
622+
const fields = cron.split(/\s+/)
623+
if (fields.length !== 5 || !isValidCron(cron)) {
624+
cronError.value = 'Cron表达式不合法'
625+
} else {
626+
cronError.value = ''
627+
}
628+
}
629+
630+
function switchScheduleType() {
631+
const currentType = form.value.trigger_setting.schedule_type || 'daily'
632+
const isCron = currentType === 'cron'
633+
634+
if (!isCron) {
635+
lastPresetSetting.value = cloneDeep({
636+
schedule_type: form.value.trigger_setting.schedule_type,
637+
interval_unit: form.value.trigger_setting.interval_unit,
638+
interval_value: form.value.trigger_setting.interval_value,
639+
days: form.value.trigger_setting.days,
640+
time: form.value.trigger_setting.time,
641+
})
642+
643+
form.value.trigger_setting.schedule_type = 'cron'
644+
form.value.trigger_setting.interval_unit = undefined
645+
form.value.trigger_setting.interval_value = undefined
646+
form.value.trigger_setting.days = undefined
647+
form.value.trigger_setting.time = undefined
648+
return
649+
}
650+
cronError.value = ''
651+
const backup = lastPresetSetting.value
652+
form.value.trigger_setting.schedule_type = backup?.schedule_type || 'daily'
653+
form.value.trigger_setting.interval_unit = backup?.interval_unit
654+
form.value.trigger_setting.interval_value = backup?.interval_value
655+
form.value.trigger_setting.days = backup?.days
656+
form.value.trigger_setting.time = backup?.time
657+
}
658+
580659
const addParameter = () => {
581660
form.value.trigger_setting.body.push({ field: '', type: '' })
582661
}
@@ -779,12 +858,21 @@ const open = (trigger_id?: string, source_type?: string, source_id?: string) =>
779858
}
780859
781860
const close = () => {
861+
cronError.value = ''
782862
current_source_id.value = undefined
783863
current_source_type.value = undefined
784864
drawer.value = false
785865
form.value = getDefaultValue()
786866
}
787867
const submit = () => {
868+
if (
869+
form.value.trigger_type === 'SCHEDULED' &&
870+
form.value.trigger_setting.schedule_type === 'cron'
871+
) {
872+
validateCron()
873+
if (cronError.value) return
874+
}
875+
788876
Promise.all([
789877
...(toolParameterRef.value ? toolParameterRef.value.map((item) => item.validate()) : []),
790878
...(applicationParameterRef.value

0 commit comments

Comments
 (0)