1
+ <template >
2
+ <el-tabs v-model =" tab" >
3
+ <el-tab-pane label =" CRON表达式" name =" cron" >
4
+ <div style =" margin-bottom : 10px ;" >
5
+ <el-input v-model =" cronStr" readonly style =" width : 400px ; font-weight : bold ;" :key =" 'cronStr'" />
6
+ </div >
7
+ <div style =" display : flex ; gap : 8px ; margin-bottom : 8px ;" >
8
+ <el-input v-model =" fields.second" placeholder =" 秒" style =" width : 80px ;" :key =" 'second'" />
9
+ <el-input v-model =" fields.minute" placeholder =" 分" style =" width : 80px ;" :key =" 'minute'" />
10
+ <el-input v-model =" fields.hour" placeholder =" 时" style =" width : 80px ;" :key =" 'hour'" />
11
+ <el-input v-model =" fields.day" placeholder =" 天" style =" width : 80px ;" :key =" 'day'" />
12
+ <el-input v-model =" fields.month" placeholder =" 月" style =" width : 80px ;" :key =" 'month'" />
13
+ <el-input v-model =" fields.week" placeholder =" 周" style =" width : 80px ;" :key =" 'week'" />
14
+ <el-input v-model =" fields.year" placeholder =" 年" style =" width : 80px ;" :key =" 'year'" />
15
+ </div >
16
+ <el-tabs v-model =" activeField" type =" card" style =" margin-bottom : 8px ;" >
17
+ <el-tab-pane v-for =" f in cronFieldList" :label =" f.label" :name =" f.key" :key =" f.key" >
18
+ <div style =" margin-bottom : 8px ;" >
19
+ <el-radio-group v-model =" cronMode[f.key]" :key =" 'radio-'+f.key" >
20
+ <el-radio label =" every" :key =" 'every-'+f.key" >每{{f.label}}</el-radio >
21
+ <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 >
22
+ <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 >
23
+ <el-radio label =" appoint" :key =" 'appoint-'+f.key" >指定</el-radio >
24
+ </el-radio-group >
25
+ </div >
26
+ <div v-if =" cronMode[f.key]==='appoint'" >
27
+ <el-checkbox-group v-model =" cronAppoint[f.key]" :key =" 'group-'+f.key" >
28
+ <el-checkbox v-for =" n in f.max+1" :label =" pad(n-1)" :key =" 'cb-'+f.key+'-'+(n-1)" >{{pad(n-1)}}</el-checkbox >
29
+ </el-checkbox-group >
30
+ </div >
31
+ </el-tab-pane >
32
+ </el-tabs >
33
+ </el-tab-pane >
34
+ <el-tab-pane label =" 标准格式" name =" iso" :key =" 'iso-tab'" >
35
+ <div style =" margin-bottom : 10px ;" >
36
+ <el-input v-model =" isoStr" placeholder =" 如R1/2025-05-21T21:59:54/P3DT30M30S" style =" width : 400px ; font-weight : bold ;" :key =" 'isoStr'" />
37
+ </div >
38
+ <div style =" margin-bottom : 10px ;" >循环次数:<el-input-number v-model =" repeat" :min =" 1" style =" width : 100px ;" :key =" 'repeat'" /></div >
39
+ <div style =" margin-bottom : 10px ;" >日期时间:<el-date-picker v-model =" isoDate" type =" datetime" placeholder =" 选择日期时间" style =" width : 200px ;" :key =" 'isoDate'" /></div >
40
+ <div style =" margin-bottom : 10px ;" >当前时长:<el-input v-model =" isoDuration" placeholder =" 如P3DT30M30S" style =" width : 200px ;" :key =" 'isoDuration'" /></div >
41
+ <div >
42
+ <div >秒:<el-button v-for =" s in [5,10,30,50]" @click =" setDuration('S',s)" :key =" 'sec-'+s" >{{s}}</el-button >自定义</div >
43
+ <div >分:<el-button v-for =" m in [5,10,30,50]" @click =" setDuration('M',m)" :key =" 'min-'+m" >{{m}}</el-button >自定义</div >
44
+ <div >小时:<el-button v-for =" h in [4,8,12,24]" @click =" setDuration('H',h)" :key =" 'hour-'+h" >{{h}}</el-button >自定义</div >
45
+ <div >天:<el-button v-for =" d in [1,2,3,4]" @click =" setDuration('D',d)" :key =" 'day-'+d" >{{d}}</el-button >自定义</div >
46
+ <div >月:<el-button v-for =" mo in [1,2,3,4]" @click =" setDuration('M',mo)" :key =" 'mon-'+mo" >{{mo}}</el-button >自定义</div >
47
+ <div >年:<el-button v-for =" y in [1,2,3,4]" @click =" setDuration('Y',y)" :key =" 'year-'+y" >{{y}}</el-button >自定义</div >
48
+ </div >
49
+ </el-tab-pane >
50
+ </el-tabs >
51
+ </template >
52
+ <script setup>
53
+ import { ref , watch , computed } from ' vue'
54
+ const props = defineProps ({ value: String })
55
+ const emit = defineEmits ([' change' ])
56
+
57
+ const tab = ref (' cron' )
58
+ const cronStr = ref (props .value || ' * * * * * ?' )
59
+ const fields = ref ({ second: ' *' , minute: ' *' , hour: ' *' , day: ' *' , month: ' *' , week: ' ?' , year: ' ' })
60
+ const cronFieldList = [
61
+ { key: ' second' , label: ' 秒' , min: 0 , max: 59 },
62
+ { key: ' minute' , label: ' 分' , min: 0 , max: 59 },
63
+ { key: ' hour' , label: ' 时' , min: 0 , max: 23 },
64
+ { key: ' day' , label: ' 天' , min: 1 , max: 31 },
65
+ { key: ' month' , label: ' 月' , min: 1 , max: 12 },
66
+ { key: ' week' , label: ' 周' , min: 1 , max: 7 },
67
+ { key: ' year' , label: ' 年' , min: 1970 , max: 2099 }
68
+ ]
69
+ const activeField = ref (' second' )
70
+ const cronMode = ref ({ second: ' appoint' , minute: ' every' , hour: ' every' , day: ' every' , month: ' every' , week: ' every' , year: ' every' })
71
+ const cronAppoint = ref ({ second: [' 00' ,' 01' ], minute: [], hour: [], day: [], month: [], week: [], year: [] })
72
+ const cronRange = ref ({ second: [0 ,1 ], minute: [0 ,1 ], hour: [0 ,1 ], day: [1 ,2 ], month: [1 ,2 ], week: [1 ,2 ], year: [1970 ,1971 ] })
73
+ const cronStep = ref ({ second: [1 ,1 ], minute: [1 ,1 ], hour: [1 ,1 ], day: [1 ,1 ], month: [1 ,1 ], week: [1 ,1 ], year: [1970 ,1 ] })
74
+
75
+ function pad (n ) { return n< 10 ? ' 0' + n : ' ' + n }
76
+
77
+ watch ([fields, cronMode, cronAppoint, cronRange, cronStep], () => {
78
+ // 组装cron表达式
79
+ let arr = cronFieldList .map (f => {
80
+ if (cronMode .value [f .key ]=== ' every' ) return ' *'
81
+ if (cronMode .value [f .key ]=== ' appoint' ) return cronAppoint .value [f .key ].join (' ,' ) || ' *'
82
+ if (cronMode .value [f .key ]=== ' range' ) return ` ${ cronRange .value [f .key ][0 ]} -${ cronRange .value [f .key ][1 ]} `
83
+ if (cronMode .value [f .key ]=== ' step' ) return ` ${ cronStep .value [f .key ][0 ]} /${ cronStep .value [f .key ][1 ]} `
84
+ return fields .value [f .key ] || ' *'
85
+ })
86
+ // week和year特殊处理
87
+ arr[5 ] = arr[5 ] || ' ?'
88
+ cronStr .value = arr .join (' ' )
89
+ if (tab .value === ' cron' ) emit (' change' , cronStr .value )
90
+ }, { deep: true })
91
+
92
+ // 标准格式
93
+ const isoStr = ref (' ' )
94
+ const repeat = ref (1 )
95
+ const isoDate = ref (' ' )
96
+ const isoDuration = ref (' ' )
97
+ function setDuration (type , val ) {
98
+ // 组装ISO 8601字符串
99
+ let d = isoDuration .value
100
+ if (! d .includes (type)) d += val + type
101
+ else d = d .replace (new RegExp (` \\ d+${ type} ` ), val + type)
102
+ isoDuration .value = d
103
+ updateIsoStr ()
104
+ }
105
+ function updateIsoStr () {
106
+ let str = ` R${ repeat .value } `
107
+ if (isoDate .value ) str += ' /' + (typeof isoDate .value === ' string' ? isoDate .value : new Date (isoDate .value ).toISOString ())
108
+ if (isoDuration .value ) str += ' /' + isoDuration .value
109
+ isoStr .value = str
110
+ if (tab .value === ' iso' ) emit (' change' , isoStr .value )
111
+ }
112
+ watch ([repeat, isoDate, isoDuration], updateIsoStr)
113
+ watch (() => props .value , (val ) => {
114
+ if (! val) return
115
+ if (tab .value === ' cron' ) cronStr .value = val
116
+ if (tab .value === ' iso' ) isoStr .value = val
117
+ }, { immediate: true })
118
+ </script >
0 commit comments