/** @ Name:layui.cron Cron表达式解析器 @ Author:贝哥哥 @ License:MIT */ layui.define(['lay', 'element', 'form'], function(exports){ //假如该组件依赖 layui.form var $ = layui.$ ,layer = layui.layer ,lay = layui.lay ,element = layui.element ,form = layui.form //字符常量 ,MOD_NAME = 'cron', ELEM = '.layui-cron', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide' ,ELEM_STATIC = 'layui-cron-static', ELEM_FOOTER = 'layui-cron-footer', ELEM_CONFIRM = '.cron-btns-confirm', ELEM_HINT = 'layui-cron-hint' ,ELEM_RUN_HINT = 'layui-cron-run-hint' //外部接口 ,cron = { v:'2.0.0' // cron 组件当前版本 ,index: layui.cron ? (layui.cron.index + 10000) : 0 // corn 实例标识 //设置全局项 ,set: function(options){ var that = this; that.config = $.extend({}, that.config, options); return that; } //事件监听 ,on: function(events, callback){ return layui.onevent.call(this, MOD_NAME, events, callback); } //主体CSS等待事件 ,ready: function (fn) { var cssPath = layui.cache.base + "/cron.css?v=" + cron.v; layui.link(cssPath, fn, "cron"); //此处的“cron”要对应 cron.css 中的样式: html #layuicss-cron{} return this; } } //操作当前实例 ,thisIns = function(){ var that = this ,options = that.config ,id = options.id || options.index; return { //提示框 hint: function(content){ that.hint.call(that, content); } ,config: options } } //构造器,创建实例 ,Class = function(options){ var that = this; that.index = ++cron.index; that.config = $.extend({}, that.config, cron.config, options); cron.ready(function () { that.init(); }); }; //默认配置 Class.prototype.config = { value: null // 当前表达式值,每秒执行一次 ,isInitValue: true //用于控制是否自动向元素填充初始值(需配合 value 参数使用) ,lang: "cn" //语言,只支持cn/en,即中文和英文 ,tabs:[{key:'seconds',range:'0-59'},{key:'minutes',range:'0-59'},{key:'hours',range:'0-23'},{key:'days',range:'1-31'},{key:'months',range:'1-12'},{key:'weeks',range:'1-7'},{key:'years'}] ,defaultCron: {seconds:"*",minutes:"*",hours:"*",days:"*", months:"*", weeks:"?", years:""} ,trigger: "click" //呼出控件的事件 ,btns: ['run', 'confirm'] //右下角显示的按钮,会按照数组顺序排列 ,position: null //控件定位方式定位, 默认absolute,支持:fixed/absolute/static ,zIndex: null //控件层叠顺序 ,show: false //是否直接显示,如果设置 true,则默认直接显示控件 ,showBottom: true //是否显示底部栏 ,done: null //控件选择完毕后的回调,点击运行/确定也均会触发 ,run: null // 最近运行时间接口 }; //多语言 Class.prototype.lang = function(){ var that = this ,options = that.config ,text = { cn: { tabs: [{title: "秒"} , {title: "分"} , {title: "时"} , {title: "日"} , {title: "月"} , {title: "周", rateBegin: "第", rateMid: "周的星期", rateEnd:""} , {title: "年"}] , every: "每" , unspecified: "不指定" , period: "周期" , periodFrom: "从" , rate: "按照" , rateBegin: "从" , rateMid: "开始,每" , rateEnd: "执行一次" , weekday: "工作日" , weekdayPrefix: "每月" , weekdaySuffix: "号最近的那个工作日" , lastday: "本月最后一日" , lastweek: "本月最后一个星期" , custom: "指定" ,tools: { confirm: '确定' ,run: '运行' } ,formatError: ['Cron格式不合法', '
已为你重置'] } ,en: { tabs: [{title:"Seconds"} , {title:"Minutes"} , {title:"Hours"} , {title:"Days"} , {title:"Months"} , {title:"Weeks"} , {title:"Years"}] , every:"Every " , unspecified:"Unspecified" , period:"Period" , periodFrom: "From" , rate: "According to" , rateBegin: "begin at" , rateMid: ", every" , rateEnd: " execute once" , weekday: "Weekday" , weekdayPrefix: "Every month at " , weekdaySuffix: "号最近的那个工作日" , lastday: "Last day of the month" , lastweek: "本月最后一个星期" , custom: "Custom" ,tools: { confirm: 'Confirm' ,run: 'Run' } ,formatError: ['The cron format error', '
It has been reset'] } }; return text[options.lang] || text['cn']; }; //初始准备 Class.prototype.init = function(){ var that = this ,options = that.config ,isStatic = options.position === 'static'; options.elem = lay(options.elem); options.eventElem = lay(options.eventElem); if(!options.elem[0]) return; //如果不是input|textarea元素,则默认采用click事件 if(!that.isInput(options.elem[0])){ if(options.trigger === 'focus'){ options.trigger = 'click'; } } // 设置渲染所绑定元素的唯一KEY if(!options.elem.attr('lay-key')){ options.elem.attr('lay-key', that.index); options.eventElem.attr('lay-key', that.index); } // 当前实例主面板ID that.elemID = 'layui-icon'+ options.elem.attr('lay-key'); //默认赋值 if(options.value && options.isInitValue){ that.setValue(options.value); } if(!options.value){ options.value = options.elem[0].value||''; } var cronArr = options.value.split(' '); if(cronArr.length >= 6){ options.cron = { seconds:cronArr[0], minutes:cronArr[1], hours:cronArr[2], days:cronArr[3], months:cronArr[4], weeks:cronArr[5], years:"", }; }else{ options.cron = lay.extend({},options.defaultCron); } if(options.show || isStatic) that.render(); isStatic || that.events(); }; // 控件主体渲染 Class.prototype.render = function(){ var that = this ,options = that.config ,lang = that.lang() ,isStatic = options.position === 'static' ,tabFilter = 'cron-tab' + options.elem.attr('lay-key') //主面板 ,elem = that.elem = lay.elem('div', { id: that.elemID ,'class': [ 'layui-cron' ,isStatic ? (' '+ ELEM_STATIC) : '' ].join('') }) // tab 内容区域 ,elemTab = that.elemTab = lay.elem('div', { 'class': 'layui-tab layui-tab-card', 'lay-filter':tabFilter }) ,tabHead = lay.elem('ul',{ 'class': 'layui-tab-title' }) ,tabContent = lay.elem('div',{ 'class': 'layui-tab-content' }) //底部区域 ,divFooter = that.footer = lay.elem('div', { 'class': ELEM_FOOTER }); if(options.zIndex) elem.style.zIndex = options.zIndex; // 生成tab 内容区域 elemTab.appendChild(tabHead); elemTab.appendChild(tabContent); lay.each(lang.tabs, function(i,item){ // 表头 var li = lay.elem('li',{ 'class':i===0?THIS:"", 'lay-id':i }); li.innerHTML = item.title; tabHead.appendChild(li); // 表体 tabContent.appendChild(that.getTabContentChildElem(i)); }); // 主区域 elemMain = that.elemMain = lay.elem('div', { 'class': 'layui-cron-main' }); elemMain.appendChild(elemTab); //生成底部栏 lay(divFooter).html(function(){ var html = [], btns = []; lay.each(options.btns, function(i, item){ var title = lang.tools[item] || 'btn'; btns.push(''+ title +''); }); html.push(''); return html.join(''); }()); //插入到主区域 elem.appendChild(elemMain); options.showBottom && elem.appendChild(divFooter); //移除上一个控件 that.remove(Class.thisElemCron); //如果是静态定位,则插入到指定的容器中,否则,插入到body isStatic ? options.elem.append(elem) : ( document.body.appendChild(elem) ,that.position() ); that.checkCron(); that.elemEvent(); // 主面板事件 Class.thisElemCron = that.elemID; form.render(); } // 渲染 tab 子控件 Class.prototype.getTabContentChildElem = function(index){ var that = this, options = that.config, tabItem = options.tabs[index], tabItemKey = tabItem.key, lang = that.lang(), tabItemLang = lang.tabs[index], cron = options.cron, formFilter = 'cronForm'+tabItemKey+options.elem.attr('lay-key') ,data = function(){ if(cron[tabItemKey].indexOf('-') != -1){ // 周期数据 var arr = cron[tabItemKey].split('-'); return { type:'range', start:arr[0], end:arr[1] }; } if(cron[tabItemKey].indexOf('/') != -1){ // 频率数据 var arr = cron[tabItemKey].split('/'); return { type:'rate', begin:arr[0], rate:arr[1] }; } if(cron[tabItemKey].indexOf(',') != -1 || /^\+?[0-9][0-9]*$/.test(cron[tabItemKey])){ // 按照指定执行 var arr = cron[tabItemKey].split(',').map(Number); return { type:'custom', values:arr }; } if(cron[tabItemKey].indexOf('W') != -1){ // 最近的工作日 var value = cron[tabItemKey].replace('W',''); return { type:'weekday', value: value }; } if(index===3 && cron[tabItemKey] === 'L'){ // 本月最后一日 return { type:'lastday', value: 'L' }; } if(index===5 && cron[tabItemKey].indexOf('L') != -1){ // 本月最后一个周 value var value = cron[tabItemKey].replace('L',''); return { type:'lastweek', value: value }; } if(cron[tabItemKey] === '*'){ // 每次 return { type:'every', value:'*' }; } if(cron[tabItemKey] === '?'||cron[tabItemKey]===undefined||cron[tabItemKey]===''){ // 不指定 return { type:'unspecified', value:cron[tabItemKey] }; } }() , rangeData = function(){ if(tabItem.range){ var arr = tabItem.range.split('-'); return { min:parseInt(arr[0]), max:parseInt(arr[1]) }; } }(); var elem = lay.elem('div', { 'class': 'layui-tab-item layui-form '+(index===0?SHOW:"") ,'lay-filter': formFilter }); // 每次 elem.appendChild(function(){ var everyRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'every' ,'title': lang.every+tabItemLang.title }); if(data.type === 'every'){ lay(everyRadio).attr('checked', true); } var everyDiv = lay.elem('div',{ 'class':'cron-row' }); everyDiv.appendChild(everyRadio); return everyDiv; }()); // 不指定,从日开始 if(index >= 3){ elem.appendChild(function(){ var unspecifiedRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'unspecified' ,'title': lang.unspecified }); if(data.type==='unspecified'){ lay(unspecifiedRadio).attr('checked', true); } var unspecifiedDiv = lay.elem('div',{ 'class':'cron-row' }); unspecifiedDiv.appendChild(unspecifiedRadio); return unspecifiedDiv; }()); } // 周期 var rangeChild = [function(){ var rangeRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'range' ,'title': lang.period }); if(data.type === 'range'){ lay(rangeRadio).attr('checked', true); } return rangeRadio; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = lang.periodFrom; return elem; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'rangeStart', 'value': data.start||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = '-'; return elem; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'rangeEnd', 'value': data.end||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = tabItemLang.title; return elem; }()] ,rangeDiv = lay.elem('div',{ 'class':'cron-row' }); lay.each(rangeChild,function(i,item){ rangeDiv.appendChild(item); }); if(tabItem.range){ var rangeTip = lay.elem('div',{ 'class':'cron-tips' }); rangeTip.innerHTML = ['(',tabItem.range,')'].join(''); rangeDiv.appendChild(rangeTip); } elem.appendChild(rangeDiv); // 频率,年没有 if(index<6){ var rateChild = [function(){ var rateRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'rate' ,'title': lang.rate }); if(data.type === 'rate'){ lay(rateRadio).attr('checked', true); } return rateRadio; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = tabItemLang.rateBegin || lang.rateBegin; return elem; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'begin', 'value': data.begin||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = tabItemLang.rateMid || (tabItemLang.title+lang.rateMid); return elem; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'rate', 'value': data.rate||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = undefined!=tabItemLang.rateEnd ? tabItemLang.rateEnd:(tabItemLang.title+lang.rateEnd); if(undefined!=tabItemLang.rateEnd&&tabItemLang.rateEnd===''){ lay(elem).addClass(HIDE); } return elem; }()] ,rateDiv = lay.elem('div',{ 'class':'cron-row' }); lay.each(rateChild,function(i,item){ rateDiv.appendChild(item); }); if(tabItem.range){ var rateTip = lay.elem('div',{ 'class':'cron-tips' }); if(index===5){ // 周 rateTip.innerHTML = '(1-4/1-7)'; }else{ rateTip.innerHTML = ['(',rangeData.min,'/',(rangeData.max+(index<=2?1:0)),')'].join(''); } rateDiv.appendChild(rateTip); } elem.appendChild(rateDiv); } // 特殊:日(最近的工作日、最后一日),周(最后一周) if(index===3){ // 日 // 最近的工作日 var weekChild = [function(){ var weekRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'weekday' ,'title': lang.weekday }); if(data.type === 'weekday'){ lay(weekRadio).attr('checked', true); } return weekRadio; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = lang.weekdayPrefix; return elem; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'weekday', 'value': data.value||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-input-mid' }); elem.innerHTML = lang.weekdaySuffix; return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-tips' }); elem.innerHTML = ['(',tabItem.range,')'].join(''); return elem; }()] ,weekDiv = lay.elem('div',{ 'class':'cron-row' }); lay.each(weekChild,function(i,item){ weekDiv.appendChild(item); }); elem.appendChild(weekDiv); // 本月最后一日 elem.appendChild(function(){ var lastRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'lastday' ,'title': lang.lastday }); if(data.type === 'lastday'){ lay(lastRadio).attr('checked', true); } var lastDiv = lay.elem('div',{ 'class':'cron-row' }); lastDiv.appendChild(lastRadio); return lastDiv; }()); } if(index===5){ // 本月最后一个周几 var lastWeekChild = [function(){ var lastWeekRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'lastweek' ,'title': lang.lastweek }); if(data.type === 'lastweek'){ lay(lastWeekRadio).attr('checked', true); } return lastWeekRadio; }(),function(){ var elem = lay.elem('input',{ 'class':'cron-input', 'type': 'number', 'name': 'lastweek', 'value': data.value||'' }); return elem; }(),function(){ var elem = lay.elem('div',{ 'class':'cron-tips' }); elem.innerHTML = ['(',tabItem.range,')'].join(''); return elem; }()] ,lastWeekDiv = lay.elem('div',{ 'class':'cron-row' }); lay.each(lastWeekChild,function(i,item){ lastWeekDiv.appendChild(item); }); elem.appendChild(lastWeekDiv); } // 指定 if(index <= 5){ elem.appendChild(function(){ var customRadio = lay.elem('input',{ 'name': tabItemKey+'[type]' ,'type': 'radio' ,'value': 'custom' ,'title': lang.custom }); if(data.type === 'custom'){ lay(customRadio).attr('checked', true); } var customDiv = lay.elem('div',{ 'class':'cron-row' }); customDiv.appendChild(customRadio); return customDiv; }()); // 指定数值,时分秒显示两位数,自动补零 elem.appendChild(function(){ var customGrid = lay.elem('div',{ 'class': 'cron-grid' }); var i = rangeData.min; while(i<=rangeData.max){ // 时分秒显示两位数,自动补零 var gridItemValue = index<=2 ? lay.digit(i,2) : i; var gridItem = lay.elem('input',{ 'type': 'checkbox', 'title': gridItemValue, 'lay-skin': 'primary', 'name':tabItemKey+'[custom]', 'value':i }); if(data.values && data.values.includes(i)){ lay(gridItem).attr('checked',true); } customGrid.appendChild(gridItem); i++; } return customGrid; }()); } return elem; } //是否输入框 Class.prototype.isInput = function(elem){ return /input|textarea/.test(elem.tagName.toLocaleLowerCase()); }; // 绑定的元素事件处理 Class.prototype.events = function(){ var that = this ,options = that.config //绑定呼出控件事件 ,showEvent = function(elem, bind){ elem.on(options.trigger, function(){ bind && (that.bindElem = this); that.render(); }); }; if(!options.elem[0] || options.elem[0].eventHandler) return; showEvent(options.elem, 'bind'); showEvent(options.eventElem); //绑定关闭控件事件 lay(document).on('click', function(e){ if(e.target === options.elem[0] || e.target === options.eventElem[0] || e.target === lay(options.closeStop)[0]){ return; } that.remove(); }).on('keydown', function(e){ if(e.keyCode === 13){ if(lay('#'+ that.elemID)[0] && that.elemID === Class.thisElemDate){ e.preventDefault(); lay(that.footer).find(ELEM_CONFIRM)[0].click(); } } }); //自适应定位 lay(window).on('resize', function(){ if(!that.elem || !lay(ELEM)[0]){ return false; } that.position(); }); options.elem[0].eventHandler = true; }; // 主面板事件 Class.prototype.elemEvent = function(){ var that = this ,options = that.config ,tabFilter = 'cron-tab' + options.elem.attr('lay-key'); // 阻止主面板点击冒泡,避免因触发文档事件而关闭主面 lay(that.elem).on('click', function(e){ lay.stope(e); }); // tab选项卡切换 var lis = lay(that.elemTab).find('li'); lis.on('click',function(){ var layid = lay(this).attr('lay-id'); if(undefined === layid){ return; } element.tabChange(tabFilter, layid); }); // cron选项点击 form.on('radio', function(data){ var $parent = data.othis.parent(); var formFilter = $parent.parent().attr('lay-filter'); var formData = form.val(formFilter); var radioType = data.value; if('range'===radioType){ // 范围 form.val(formFilter,{ rangeStart: formData.rangeStart||0, rangeEnd: formData.rangeEnd||2 }); } if('rate'===radioType){ // 频率 form.val(formFilter,{ begin: formData.begin||0, rate: formData.rate||2 }); } if('custom'===radioType){ // custom var $grid = $parent.next(); if($grid.find(':checkbox:checked').length<=0){ $grid.children(':checkbox:first').next().click() } } if('weekday'===radioType){ // weekday form.val(formFilter,{ weekday: formData.weekday||1 }); } if('lastweek'===radioType){ // lastweek form.val(formFilter,{ lastweek: formData.lastweek||1 }); } }); //点击底部按钮 lay(that.footer).find('span').on('click', function(){ var type = lay(this).attr('lay-type'); that.tool(this, type); }); }; //底部按钮点击事件 Class.prototype.tool = function(btn, type){ var that = this ,options = that.config ,lang = that.lang() ,isStatic = options.position === 'static' ,active = { //运行 run: function(){ var value = that.parse(); var loading = layer.load(); $.get(options.run,{cron:value},function(res){ layer.close(loading); if(res.code !== 0){ return that.hint(res.msg); } that.runHint(res.data); },'json').fail(function(){ layer.close(loading); that.hint('服务器异常!'); }); } //确定 ,confirm: function(){ var value = that.parse(); that.done([value]); that.setValue(value).remove() } }; active[type] && active[type](); }; //执行 done/change 回调 Class.prototype.done = function(param, type){ var that = this ,options = that.config; param = param || [that.parse()]; typeof options[type || 'done'] === 'function' && options[type || 'done'].apply(options, param); return that; }; // 解析cron表达式 Class.prototype.parse = function(){ var that = this ,options = that.config ,valueArr = []; lay.each(options.tabs, function(index, item){ var key = item.key; var formFilter = 'cronForm' + key + options.elem.attr('lay-key'); var formData = form.val(formFilter); var radioType = (key+'[type]'); var current = ""; if(formData[radioType] === 'every'){ // 每次 current = "*"; } if(formData[radioType] === 'range'){ // 范围 current = formData.rangeStart + "-" + formData.rangeEnd; } if(formData[radioType] === 'rate'){ // 频率 current = formData.begin + "/" + formData.rate; } if(formData[radioType] === 'custom'){ // 指定 var checkboxName = (item.key+'[custom]'); var customArr = []; $('input[name="' + checkboxName + '"]:checked').each(function() { customArr.push($(this).val()); }); current = customArr.join(','); } if(formData[radioType] === 'weekday'){ // 每月 formData.weekday 号最近的那个工作日 current = formData.weekday + "W"; } if(formData[radioType] === 'lastday'){ // 本月最后一日 current = "L"; } if(formData[radioType] === 'lastweek'){ // 本月最后星期 current = formData.lastweek + "L"; } if(formData[radioType] === 'unspecified' && index != 6){ // 不指定 current = "?"; } if(current !== ""){ valueArr.push(current); options.cron[key] = current; } }); return valueArr.join(' '); }; //控件移除 Class.prototype.remove = function(prev){ var that = this ,options = that.config ,elem = lay('#'+ (prev || that.elemID)); if(!elem[0]) return that; if(!elem.hasClass(ELEM_STATIC)){ that.checkCron(function(){ elem.remove(); }); } return that; }; //定位算法 Class.prototype.position = function(){ var that = this ,options = that.config; lay.position(that.bindElem || options.elem[0], that.elem, { position: options.position }); return that; }; //提示 Class.prototype.hint = function(content){ var that = this ,options = that.config ,div = lay.elem('div', { 'class': ELEM_HINT }); if(!that.elem) return; div.innerHTML = content || ''; lay(that.elem).find('.'+ ELEM_HINT).remove(); that.elem.appendChild(div); clearTimeout(that.hinTimer); that.hinTimer = setTimeout(function(){ lay(that.elem).find('.'+ ELEM_HINT).remove(); }, 3000); }; //运行提示 Class.prototype.runHint = function(runList){ var that = this ,options = that.config ,div = lay.elem('div', { 'class': ELEM_RUN_HINT }); // debugger; if(!that.elem||!runList||!runList.length) return; lay(div).html(function(){ var html = []; lay.each(runList, function(i, item){ html.push('
'+ item +'
'); }); return html.join(''); }()); lay(that.elem).find('.'+ ELEM_RUN_HINT).remove(); that.elem.appendChild(div); }; //赋值 Class.prototype.setValue = function(value=''){ var that = this ,options = that.config ,elem = that.bindElem || options.elem[0] ,valType = that.isInput(elem) ? 'val' : 'html' options.position === 'static' || lay(elem)[valType](value || ''); elem.textContent = '生成'; return this; }; //cron校验 Class.prototype.checkCron = function(fn){ var that = this ,options = that.config ,lang = that.lang() ,elem = that.bindElem || options.elem[0] ,value = that.isInput(elem) ? elem.value : (options.position === 'static' ? '' : elem.innerHTML) ,checkValid = function(value=""){ }; // cron 值,多个空格替换为一个空格,去掉首尾空格 value = value || options.value; if(typeof value === 'string'){ value = value.replace(/\s+/g, ' ').replace(/^\s|\s$/g, ''); } if(fn==='init') return checkValid(value),that; value = that.parse(); if(value){ that.setValue(value); } fn && fn(); return that; }; //核心入口 cron.render = function(options){ var ins = new Class(options); return thisIns.call(ins); }; exports('cron', cron); });