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 @@
+
+
+
+
+
+
区间
+ 从
+
+
+ {{k}}
+
+
+ 至
+
+
+ {{k}}
+
+
+
+
+
循环
+ 从
+
+
+ {{k}}
+
+
+ 开始,间隔
+
+ 天
+
+
+
+
+
+
+
+
+
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
+}