| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- <template>
- <el-tabs v-model="tab">
- <el-tab-pane label="CRON表达式" name="cron">
- <div style="margin-bottom: 10px">
- <el-input
- v-model="cronStr"
- readonly
- style="width: 400px; font-weight: bold"
- :key="'cronStr'"
- />
- </div>
- <div style="display: flex; gap: 8px; margin-bottom: 8px">
- <el-input v-model="fields.second" placeholder="秒" style="width: 80px" :key="'second'" />
- <el-input v-model="fields.minute" placeholder="分" style="width: 80px" :key="'minute'" />
- <el-input v-model="fields.hour" placeholder="时" style="width: 80px" :key="'hour'" />
- <el-input v-model="fields.day" placeholder="天" style="width: 80px" :key="'day'" />
- <el-input v-model="fields.month" placeholder="月" style="width: 80px" :key="'month'" />
- <el-input v-model="fields.week" placeholder="周" style="width: 80px" :key="'week'" />
- <el-input v-model="fields.year" placeholder="年" style="width: 80px" :key="'year'" />
- </div>
- <el-tabs v-model="activeField" type="card" style="margin-bottom: 8px">
- <el-tab-pane v-for="f in cronFieldList" :label="f.label" :name="f.key" :key="f.key">
- <div style="margin-bottom: 8px">
- <el-radio-group v-model="cronMode[f.key]" :key="'radio-' + f.key">
- <el-radio label="every" :key="'every-' + f.key">每{{ f.label }}</el-radio>
- <el-radio label="range" :key="'range-' + f.key"
- >从
- <el-input-number
- v-model="cronRange[f.key][0]"
- :min="f.min"
- :max="f.max"
- size="small"
- style="width: 60px"
- :key="'range0-' + f.key"
- />
- 到
- <el-input-number
- v-model="cronRange[f.key][1]"
- :min="f.min"
- :max="f.max"
- size="small"
- style="width: 60px"
- :key="'range1-' + f.key"
- />
- 之间每{{ f.label }}</el-radio
- >
- <el-radio label="step" :key="'step-' + f.key"
- >从第
- <el-input-number
- v-model="cronStep[f.key][0]"
- :min="f.min"
- :max="f.max"
- size="small"
- style="width: 60px"
- :key="'step0-' + f.key"
- />
- 开始每
- <el-input-number
- v-model="cronStep[f.key][1]"
- :min="1"
- :max="f.max"
- size="small"
- style="width: 60px"
- :key="'step1-' + f.key"
- />
- {{ f.label }}</el-radio
- >
- <el-radio label="appoint" :key="'appoint-' + f.key">指定</el-radio>
- </el-radio-group>
- </div>
- <div v-if="cronMode[f.key] === 'appoint'">
- <el-checkbox-group v-model="cronAppoint[f.key]" :key="'group-' + f.key">
- <el-checkbox
- v-for="n in f.max + 1"
- :label="pad(n - 1)"
- :key="'cb-' + f.key + '-' + (n - 1)"
- >{{ pad(n - 1) }}</el-checkbox
- >
- </el-checkbox-group>
- </div>
- </el-tab-pane>
- </el-tabs>
- </el-tab-pane>
- <el-tab-pane label="标准格式" name="iso" :key="'iso-tab'">
- <div style="margin-bottom: 10px">
- <el-input
- v-model="isoStr"
- placeholder="如R1/2025-05-21T21:59:54/P3DT30M30S"
- style="width: 400px; font-weight: bold"
- :key="'isoStr'"
- />
- </div>
- <div style="margin-bottom: 10px"
- >循环次数:<el-input-number v-model="repeat" :min="1" style="width: 100px" :key="'repeat'"
- /></div>
- <div style="margin-bottom: 10px"
- >日期时间:<el-date-picker
- v-model="isoDate"
- type="datetime"
- placeholder="选择日期时间"
- style="width: 200px"
- :key="'isoDate'"
- /></div>
- <div style="margin-bottom: 10px"
- >当前时长:<el-input
- v-model="isoDuration"
- placeholder="如P3DT30M30S"
- style="width: 200px"
- :key="'isoDuration'"
- /></div>
- <div>
- <div
- >秒:<el-button
- v-for="s in [5, 10, 30, 50]"
- @click="setDuration('S', s)"
- :key="'sec-' + s"
- >{{ s }}</el-button
- >自定义</div
- >
- <div
- >分:<el-button
- v-for="m in [5, 10, 30, 50]"
- @click="setDuration('M', m)"
- :key="'min-' + m"
- >{{ m }}</el-button
- >自定义</div
- >
- <div
- >小时:<el-button
- v-for="h in [4, 8, 12, 24]"
- @click="setDuration('H', h)"
- :key="'hour-' + h"
- >{{ h }}</el-button
- >自定义</div
- >
- <div
- >天:<el-button
- v-for="d in [1, 2, 3, 4]"
- @click="setDuration('D', d)"
- :key="'day-' + d"
- >{{ d }}</el-button
- >自定义</div
- >
- <div
- >月:<el-button
- v-for="mo in [1, 2, 3, 4]"
- @click="setDuration('M', mo)"
- :key="'mon-' + mo"
- >{{ mo }}</el-button
- >自定义</div
- >
- <div
- >年:<el-button
- v-for="y in [1, 2, 3, 4]"
- @click="setDuration('Y', y)"
- :key="'year-' + y"
- >{{ y }}</el-button
- >自定义</div
- >
- </div>
- </el-tab-pane>
- </el-tabs>
- </template>
- <script setup>
- import { ref, watch, computed } from 'vue'
- const props = defineProps({ value: String })
- const emit = defineEmits(['change'])
- const tab = ref('cron')
- const cronStr = ref(props.value || '* * * * * ?')
- const fields = ref({
- second: '*',
- minute: '*',
- hour: '*',
- day: '*',
- month: '*',
- week: '?',
- year: ''
- })
- const cronFieldList = [
- { key: 'second', label: '秒', min: 0, max: 59 },
- { key: 'minute', label: '分', min: 0, max: 59 },
- { key: 'hour', label: '时', min: 0, max: 23 },
- { key: 'day', label: '天', min: 1, max: 31 },
- { key: 'month', label: '月', min: 1, max: 12 },
- { key: 'week', label: '周', min: 1, max: 7 },
- { key: 'year', label: '年', min: 1970, max: 2099 }
- ]
- const activeField = ref('second')
- const cronMode = ref({
- second: 'appoint',
- minute: 'every',
- hour: 'every',
- day: 'every',
- month: 'every',
- week: 'every',
- year: 'every'
- })
- const cronAppoint = ref({
- second: ['00', '01'],
- minute: [],
- hour: [],
- day: [],
- month: [],
- week: [],
- year: []
- })
- const cronRange = ref({
- second: [0, 1],
- minute: [0, 1],
- hour: [0, 1],
- day: [1, 2],
- month: [1, 2],
- week: [1, 2],
- year: [1970, 1971]
- })
- const cronStep = ref({
- second: [1, 1],
- minute: [1, 1],
- hour: [1, 1],
- day: [1, 1],
- month: [1, 1],
- week: [1, 1],
- year: [1970, 1]
- })
- function pad(n) {
- return n < 10 ? '0' + n : '' + n
- }
- watch(
- [fields, cronMode, cronAppoint, cronRange, cronStep],
- () => {
- // 组装cron表达式
- let arr = cronFieldList.map((f) => {
- if (cronMode.value[f.key] === 'every') return '*'
- if (cronMode.value[f.key] === 'appoint') return cronAppoint.value[f.key].join(',') || '*'
- if (cronMode.value[f.key] === 'range')
- return `${cronRange.value[f.key][0]}-${cronRange.value[f.key][1]}`
- if (cronMode.value[f.key] === 'step')
- return `${cronStep.value[f.key][0]}/${cronStep.value[f.key][1]}`
- return fields.value[f.key] || '*'
- })
- // week和year特殊处理
- arr[5] = arr[5] || '?'
- cronStr.value = arr.join(' ')
- if (tab.value === 'cron') emit('change', cronStr.value)
- },
- { deep: true }
- )
- // 标准格式
- const isoStr = ref('')
- const repeat = ref(1)
- const isoDate = ref('')
- const isoDuration = ref('')
- function setDuration(type, val) {
- // 组装ISO 8601字符串
- let d = isoDuration.value
- if (!d.includes(type)) d += val + type
- else d = d.replace(new RegExp(`\\d+${type}`), val + type)
- isoDuration.value = d
- updateIsoStr()
- }
- function updateIsoStr() {
- let str = `R${repeat.value}`
- if (isoDate.value)
- str +=
- '/' +
- (typeof isoDate.value === 'string' ? isoDate.value : new Date(isoDate.value).toISOString())
- if (isoDuration.value) str += '/' + isoDuration.value
- isoStr.value = str
- if (tab.value === 'iso') emit('change', isoStr.value)
- }
- watch([repeat, isoDate, isoDuration], updateIsoStr)
- watch(
- () => props.value,
- (val) => {
- if (!val) return
- if (tab.value === 'cron') cronStr.value = val
- if (tab.value === 'iso') isoStr.value = val
- },
- { immediate: true }
- )
- </script>
|