diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue new file mode 100644 index 0000000000000000000000000000000000000000..da8a586f194d715072d0509aaa931b157a7210d0 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/InputCron.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/InputCron.vue new file mode 100644 index 0000000000000000000000000000000000000000..868d4b3589473817d8a760d60f71b5c84e140398 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/InputCron.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/format-date.js b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/format-date.js new file mode 100644 index 0000000000000000000000000000000000000000..8a55974fcf804d52f6aaa9d06fc3873f51a0f3d9 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/format-date.js @@ -0,0 +1,37 @@ +const dateFormat = (date, block) => { + if (!date) { + return '' + } + + let format = block || 'yyyy-MM-dd' + + date = new Date(date) + + const map = { + M: date.getMonth() + 1, // 月份 + d: date.getDate(), // 日 + h: date.getHours(), // 小时 + m: date.getMinutes(), // 分 + s: date.getSeconds(), // 秒 + q: Math.floor((date.getMonth() + 3) / 3), // 季度 + S: date.getMilliseconds() // 毫秒 + } + + format = format.replace(/([yMdhmsqS])+/g, (all, t) => { + let v = map[t] + if (v !== undefined) { + if (all.length > 1) { + v = `0${v}` + v = v.substr(v.length - 2) + } + return v + } else if (t === 'y') { + return (date.getFullYear().toString()).substr(4 - all.length) + } + return all + }) + + return format +} + +export default dateFormat diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/index.js b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/index.js new file mode 100644 index 0000000000000000000000000000000000000000..f7f462446512c2c6fa03da830453ea4c3b7c4574 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/index.js @@ -0,0 +1,6 @@ +// 原开源项目地址:https://gitee.com/toktok/easy-cron + +import InputCron from './InputCron.vue' + +InputCron.name = 'JEasyCron' +export default InputCron \ No newline at end of file diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/const.js b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/const.js new file mode 100644 index 0000000000000000000000000000000000000000..e076ee183dacfbfcb6b7a3a468643b62d83b6f91 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/const.js @@ -0,0 +1,21 @@ +export const WEEK_MAP_EN = { + 'SUN': '0', + 'MON': '1', + 'TUE': '2', + 'WED': '3', + 'THU': '4', + 'FRI': '5', + 'SAT': '6' +} + +export const replaceWeekName = (c) => { + // console.info('after: ' + c) + if (c) { + Object.keys(WEEK_MAP_EN).forEach(k => { + c = c.replace(new RegExp(k, 'g'), WEEK_MAP_EN[k]) + }) + c = c.replace(new RegExp('7', 'g'), '0') + } + // console.info('after: ' + c) + return c +} diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue new file mode 100644 index 0000000000000000000000000000000000000000..fc2accb1737d99fe4593ea293072e075fbc5e3cb --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/hour.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/hour.vue new file mode 100644 index 0000000000000000000000000000000000000000..881956597027f58890b55aac87755a9ad374b3be --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/hour.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/minute.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/minute.vue new file mode 100644 index 0000000000000000000000000000000000000000..eda3df35f56d0ea433c3174aa32942079ea3b370 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/minute.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.js b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.js new file mode 100644 index 0000000000000000000000000000000000000000..a805d42f65296197576111109fdc0fb2184293ec --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.js @@ -0,0 +1,151 @@ +// 主要用于日和星期的互斥使用 +const TYPE_NOT_SET = 'TYPE_NOT_SET' +const TYPE_EVERY = 'TYPE_EVERY' +const TYPE_RANGE = 'TYPE_RANGE' +const TYPE_LOOP = 'TYPE_LOOP' +const TYPE_WORK = 'TYPE_WORK' +const TYPE_LAST = 'TYPE_LAST' +const TYPE_SPECIFY = 'TYPE_SPECIFY' + +const DEFAULT_VALUE = '?' + +export default { + model: { + prop: 'prop', + event: 'change' + }, + props: { + prop: { + type: String, + default: DEFAULT_VALUE + }, + disabled: { + type: Boolean, + default: false + } + }, + data () { + const type = TYPE_EVERY + return { + DEFAULT_VALUE, + // 类型 + type, + // 启用日或者星期互斥用 + TYPE_NOT_SET, + TYPE_EVERY, + TYPE_RANGE, + TYPE_LOOP, + TYPE_WORK, + TYPE_LAST, + TYPE_SPECIFY, + // 对于不同的类型,所定义的值也有所不同 + valueRange: { + start: 0, + end: 0 + }, + valueLoop: { + start: 0, + interval: 1 + }, + valueWeek: { + start: 0, + end: 0 + }, + valueList: [], + valueWork: 1, + maxValue: 0, + minValue: 0 + } + }, + watch: { + prop (newVal, oldVal) { + if (newVal === this.value_c) { + // console.info('skip ' + newVal) + return + } + this.parseProp(newVal) + } + }, + computed: { + value_c () { + let result = [] + switch (this.type) { + case TYPE_NOT_SET: + result.push('?') + break + case TYPE_EVERY: + result.push('*') + break + case TYPE_RANGE: + result.push(`${this.valueRange.start}-${this.valueRange.end}`) + break + case TYPE_LOOP: + result.push(`${this.valueLoop.start}/${this.valueLoop.interval}`) + break + case TYPE_WORK: + result.push(`${this.valueWork}W`) + break + case TYPE_LAST: + result.push('L') + break + case TYPE_SPECIFY: + result.push(this.valueList.join(',')) + break + default: + result.push(this.DEFAULT_VALUE) + break + } + return result.length > 0 ? result.join('') : this.DEFAULT_VALUE + } + }, + methods: { + parseProp (value) { + if (value === this.value_c) { + // console.info('same ' + value) + return + } + if (typeof (this.preProcessProp) === 'function') { + value = this.preProcessProp(value) + } + try { + if (!value || value === this.DEFAULT_VALUE) { + this.type = TYPE_EVERY + } else if (value.indexOf('?') >= 0) { + this.type = TYPE_NOT_SET + } else if (value.indexOf('-') >= 0) { + this.type = TYPE_RANGE + const values = value.split('-') + if (values.length >= 2) { + this.valueRange.start = parseInt(values[0]) + this.valueRange.end = parseInt(values[1]) + } + } else if (value.indexOf('/') >= 0) { + this.type = TYPE_LOOP + const values = value.split('/') + if (values.length >= 2) { + this.valueLoop.start = value[0] === '*' ? 0 : parseInt(values[0]) + this.valueLoop.interval = parseInt(values[1]) + } + } else if (value.indexOf('W') >= 0) { + this.type = TYPE_WORK + const values = value.split('W') + if (!values[0] && !isNaN(values[0])) { + this.valueWork = parseInt(values[0]) + } + } else if (value.indexOf('L') >= 0) { + this.type = TYPE_LAST + const values = value.split('L') + this.valueLast = parseInt(values[0]) + } else if (value.indexOf(',') >= 0 || !isNaN(value)) { + this.type = TYPE_SPECIFY + this.valueList = value.split(',').map(item => parseInt(item)) + } else { + this.type = TYPE_EVERY + } + } catch (e) { + // console.info(e) + this.type = TYPE_EVERY + } + } + } +} diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.less b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.less new file mode 100644 index 0000000000000000000000000000000000000000..7278ab431b3abae17cf016eeb4b589778d8bc1c8 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/mixin.less @@ -0,0 +1,35 @@ + +.config-list { + text-align: left; + margin: 0 10px 10px 10px; +} + +.item { + margin-top: 5px; +} + +.choice { + padding: 5px 8px; +} + + +.w60 { + width: 60px; +} +.w80 { + width: 80px; +} + +.list { + margin: 0 20px; +} + +.list-check-item { + padding: 1px 3px; + width: 4em; +} + +.tip-info { + color: #999 +} + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/month.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/month.vue new file mode 100644 index 0000000000000000000000000000000000000000..28dc2308fc073e4029beb2dff7453c60f367bdef --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/month.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/second.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/second.vue new file mode 100644 index 0000000000000000000000000000000000000000..90252ab9ea74e2683471ab1864f08ed859ca12f9 --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/second.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/week.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/week.vue new file mode 100644 index 0000000000000000000000000000000000000000..589c54f8c2022be3d9e810d5d584af2208f7371d --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/week.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/year.vue b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/year.vue new file mode 100644 index 0000000000000000000000000000000000000000..7d4bbdb41fb9115366a4240c9814c98be3e0f3dd --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/year.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/validator.js b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/validator.js new file mode 100644 index 0000000000000000000000000000000000000000..f38daca7c3274ee36c329c4d36b1cd231a69d97c --- /dev/null +++ b/ant-design-vue-jeecg/src/components/jeecg/JEasyCron/validator.js @@ -0,0 +1,51 @@ +import CronParser from 'cron-parser' +import { replaceWeekName } from './tabs/const' + +export default (rule, value, callback) => { + // 没填写就不校验 + if (!value) { + callback() + return true + } + const values = value.split(' ').filter(item => !!item) + if (values.length > 7) { + callback(new Error('Cron表达式最多7项!')) + return false + } + // 检查第7项 + let e = value + if (values.length === 7) { + const year = replaceWeekName(values[6]) + if (year !== '*' && year !== '?') { + let yearValues = [] + if (year.indexOf('-') >= 0) { + yearValues = year.split('-') + } else if (year.indexOf('/')) { + yearValues = year.split('/') + } else { + yearValues = [year] + } + // console.info(yearValues) + // 判断是否都是数字 + const checkYear = yearValues.some(item => isNaN(item)) + if (checkYear) { + callback(new Error('Cron表达式参数[年]错误:' + year)) + return false + } + } + // 取其中的前六项 + e = values.slice(0, 6).join(' ') + } + // 6位 没有年 + // 5位没有秒、年 + let result = true + try { + const iter = CronParser.parseExpression(e) + iter.next() + callback() + } catch (e) { + callback(new Error('Cron表达式错误:' + e)) + result = false + } + return result +}