cron表达式可视化配置替换成自定义组件

This commit is contained in:
2025-09-21 17:53:32 +08:00
parent c97178b68b
commit 69f673b494
2 changed files with 336 additions and 55 deletions

View File

@@ -0,0 +1,330 @@
<template>
<div class="cron-expression-editor">
<el-input
v-model="cronExpression"
placeholder="请输入标准Unix 5位cron表达式如: 0 0 * * *"
readonly
>
<template #append>
<el-button @click="openCronDialog">可视化配置</el-button>
</template>
</el-input>
<el-dialog
v-model="showCronDialog"
title="可视化配置Cron表达式"
width="600px"
:before-close="handleCronDialogClose"
>
<div class="cron-dialog-content">
<el-form :model="cronConfig" label-width="100px">
<!-- -->
<el-form-item label="分">
<el-select
v-model="cronConfig.minute"
placeholder="请选择分钟"
clearable
filterable
allow-create
default-first-option
>
<el-option label="*" value="*">
<span>*</span>
<span class="option-desc">每分钟</span>
</el-option>
<el-option label="*/5" value="*/5">
<span>*/5</span>
<span class="option-desc">每隔5分钟</span>
</el-option>
<el-option label="*/10" value="*/10">
<span>*/10</span>
<span class="option-desc">每隔10分钟</span>
</el-option>
<el-option label="*/15" value="*/15">
<span>*/15</span>
<span class="option-desc">每隔15分钟</span>
</el-option>
<el-option label="*/30" value="*/30">
<span>*/30</span>
<span class="option-desc">每隔30分钟</span>
</el-option>
<el-option
v-for="minute in 60"
:key="minute-1"
:label="minute-1"
:value="(minute-1).toString()"
>
<span>{{ minute-1 }}</span>
<span class="option-desc">{{ minute-1 }}分钟</span>
</el-option>
</el-select>
</el-form-item>
<!-- -->
<el-form-item label="时">
<el-select
v-model="cronConfig.hour"
placeholder="请选择小时"
clearable
filterable
allow-create
default-first-option
>
<el-option label="*" value="*">
<span>*</span>
<span class="option-desc">每小时</span>
</el-option>
<el-option label="*/2" value="*/2">
<span>*/2</span>
<span class="option-desc">每隔2小时</span>
</el-option>
<el-option label="*/3" value="*/3">
<span>*/3</span>
<span class="option-desc">每隔3小时</span>
</el-option>
<el-option label="*/6" value="*/6">
<span>*/6</span>
<span class="option-desc">每隔6小时</span>
</el-option>
<el-option label="*/12" value="*/12">
<span>*/12</span>
<span class="option-desc">每隔12小时</span>
</el-option>
<el-option
v-for="hour in 24"
:key="hour-1"
:label="hour-1"
:value="(hour-1).toString()"
>
<span>{{ hour-1 }}</span>
<span class="option-desc">{{ hour-1 }}</span>
</el-option>
</el-select>
</el-form-item>
<!-- -->
<el-form-item label="日">
<el-select
v-model="cronConfig.day"
placeholder="请选择日期"
clearable
filterable
allow-create
default-first-option
>
<el-option label="*" value="*">
<span>*</span>
<span class="option-desc">每天</span>
</el-option>
<el-option label="*/2" value="*/2">
<span>*/2</span>
<span class="option-desc">每隔2天</span>
</el-option>
<el-option label="*/7" value="*/7">
<span>*/7</span>
<span class="option-desc">每隔7天</span>
</el-option>
<el-option label="*/15" value="*/15">
<span>*/15</span>
<span class="option-desc">每隔15天</span>
</el-option>
<el-option
v-for="day in 31"
:key="day"
:label="day"
:value="day.toString()"
>
<span>{{ day }}</span>
<span class="option-desc">每月{{ day }}</span>
</el-option>
</el-select>
</el-form-item>
<!-- -->
<el-form-item label="月">
<el-select
v-model="cronConfig.month"
placeholder="请选择月份"
clearable
filterable
allow-create
default-first-option
>
<el-option label="*" value="*">
<span>*</span>
<span class="option-desc">每月</span>
</el-option>
<el-option label="*/2" value="*/2">
<span>*/2</span>
<span class="option-desc">每隔2个月</span>
</el-option>
<el-option label="*/3" value="*/3">
<span>*/3</span>
<span class="option-desc">每隔3个月</span>
</el-option>
<el-option label="*/6" value="*/6">
<span>*/6</span>
<span class="option-desc">每隔6个月</span>
</el-option>
<el-option
v-for="month in 12"
:key="month"
:label="month"
:value="month.toString()"
>
<span>{{ month }}</span>
<span class="option-desc">{{ month }}</span>
</el-option>
</el-select>
</el-form-item>
<!-- -->
<el-form-item label="周">
<el-select
v-model="cronConfig.week"
placeholder="请选择星期"
clearable
filterable
allow-create
default-first-option
>
<el-option label="*" value="*">
<span>*</span>
<span class="option-desc">每周</span>
</el-option>
<el-option label="1-5" value="1-5">
<span>1-5</span>
<span class="option-desc">工作日</span>
</el-option>
<el-option
v-for="(week, index) in weekOptions"
:key="index"
:label="week.label"
:value="index.toString()"
>
<span>{{ week.label }}</span>
<span class="option-desc">{{ week.desc }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleCronDialogClose">取消</el-button>
<el-button type="primary" @click="confirmCronExpression">确认</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { ref, computed, watch, reactive } from 'vue'
export default {
name: 'CronExpressionEditor',
props: {
modelValue: {
type: String,
default: ''
}
},
emits: ['update:modelValue'],
setup(props, { emit }) {
// 是否显示Cron表达式配置对话框
const showCronDialog = ref(false)
// 星期选项
const weekOptions = [
{ label: '日', desc: '星期日' },
{ label: '一', desc: '星期一' },
{ label: '二', desc: '星期二' },
{ label: '三', desc: '星期三' },
{ label: '四', desc: '星期四' },
{ label: '五', desc: '星期五' },
{ label: '六', desc: '星期六' }
]
// cron配置
const cronConfig = reactive({
minute: '*',
hour: '*',
day: '*',
month: '*',
week: '*'
})
// 计算属性cron表达式
const cronExpression = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value)
})
// 打开Cron对话框
const openCronDialog = () => {
// 解析当前的cron表达式
if (cronExpression.value) {
const parts = cronExpression.value.split(' ')
if (parts.length === 5) {
cronConfig.minute = parts[0]
cronConfig.hour = parts[1]
cronConfig.day = parts[2]
cronConfig.month = parts[3]
cronConfig.week = parts[4]
}
} else {
// 默认值
cronConfig.minute = '*'
cronConfig.hour = '*'
cronConfig.day = '*'
cronConfig.month = '*'
cronConfig.week = '*'
}
showCronDialog.value = true
}
// 确认Cron表达式
const confirmCronExpression = () => {
cronExpression.value = `${cronConfig.minute} ${cronConfig.hour} ${cronConfig.day} ${cronConfig.month} ${cronConfig.week}`
showCronDialog.value = false
}
// 处理Cron对话框关闭
const handleCronDialogClose = () => {
showCronDialog.value = false
}
return {
showCronDialog,
cronConfig,
cronExpression,
weekOptions,
openCronDialog,
confirmCronExpression,
handleCronDialogClose
}
}
}
</script>
<style scoped>
.cron-expression-editor {
width: 100%;
}
.cron-dialog-content {
padding: 20px;
}
.dialog-footer {
text-align: right;
}
.option-desc {
float: right;
color: #8492a6;
font-size: 13px;
}
</style>

View File

@@ -57,15 +57,10 @@
label="执行频率"
prop="cron_expression"
v-if="formData.execution_type === 'automatic'">
<el-input
<cron-expression-editor
v-model="formData.cron_expression"
placeholder="请输入cron表达式0 0 6 * * *"
>
<template #append>
<el-button @click="showCronDialog = true">可视化配置</el-button>
</template>
</el-input>
<div class="form-item-tip">Cron表达式格式 </div>
/>
<div class="form-item-tip">Cron表达式格式 </div>
</el-form-item>
</el-form>
@@ -81,35 +76,17 @@
</div>
</template>
</el-dialog>
<!-- Cron表达式可视化配置对话框 -->
<el-dialog
v-model="showCronDialog"
title="可视化配置执行频率"
width="800px"
:before-close="handleCronDialogClose"
>
<div style="padding: 10px 20px;">
<vue3-cron-plus-picker
@fill="handleCronFill"
@hide="handleCronDialogClose"
:expression="tempCronExpression"
:hide-year="true"
/>
</div>
</el-dialog>
</template>
<script>
import { ref, reactive, computed, watch } from 'vue';
import { ElMessage } from 'element-plus';
import { Vue3CronPlusPicker } from 'vue3-cron-plus-picker';
import 'vue3-cron-plus-picker/style.css';
import CronExpressionEditor from './CronExpressionEditor.vue';
export default {
name: 'PlanForm',
components: {
Vue3CronPlusPicker
CronExpressionEditor
},
props: {
visible: {
@@ -133,12 +110,6 @@ export default {
// 加载状态
const loading = ref(false);
// 是否显示Cron表达式配置对话框
const showCronDialog = ref(false);
// 临时存储cron表达式
const tempCronExpression = ref('');
// 表单数据
const formData = reactive({
id: null,
@@ -183,18 +154,6 @@ export default {
}
};
// 处理Cron表达式填充
const handleCronFill = (cronExpression) => {
formData.cron_expression = cronExpression;
tempCronExpression.value = cronExpression;
showCronDialog.value = false;
};
// 处理Cron对话框关闭
const handleCronDialogClose = () => {
showCronDialog.value = false;
};
// 关闭对话框
const handleClose = () => {
emit('update:visible', false);
@@ -239,9 +198,6 @@ export default {
formData[key] = newVal[key];
}
});
// 初始化临时cron表达式
tempCronExpression.value = newVal.cron_expression || '';
} else {
// 重置表单数据
Object.keys(formData).forEach(key => {
@@ -253,21 +209,16 @@ export default {
});
// 默认值
formData.execution_type = 'automatic';
tempCronExpression.value = '';
}
}, { immediate: true });
return {
formRef,
loading,
showCronDialog,
tempCronExpression,
formData,
rules,
title,
handleExecutionTypeChange,
handleCronFill,
handleCronDialogClose,
handleClose,
handleSubmit
};