├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── README_zh_CN.md ├── nginx └── nginx.conf ├── package.json ├── public ├── favicon.ico └── index.html ├── resources ├── snapshot.png └── snapshot_zh_CN.png ├── src ├── App.vue ├── components │ ├── config │ │ ├── common │ │ │ ├── every.vue │ │ │ ├── fixed.vue │ │ │ ├── period.vue │ │ │ └── range.vue │ │ ├── custom │ │ │ ├── dayOfWeek │ │ │ │ ├── last.vue │ │ │ │ ├── period.vue │ │ │ │ ├── range.vue │ │ │ │ └── weekDay.vue │ │ │ ├── last.vue │ │ │ ├── lastWorkDay.vue │ │ │ ├── unfixed.vue │ │ │ ├── workDay.vue │ │ │ └── year │ │ │ │ └── empty.vue │ │ └── ext │ │ │ ├── symbolTip.vue │ │ │ └── valTip.vue │ ├── cron-input.vue │ ├── cron.vue │ └── time │ │ ├── dayOfMonth.vue │ │ ├── dayOfWeek.vue │ │ ├── hour.vue │ │ ├── minute.vue │ │ ├── month.vue │ │ ├── second.vue │ │ └── year.vue ├── constant │ ├── filed.js │ └── reg.js ├── locale │ ├── en.js │ ├── index.js │ └── zh.js ├── main.js ├── mixins │ ├── watchTime.js │ └── watchValue.js ├── styles │ └── global.css ├── translate │ └── dict.js └── util │ └── tools.js └── vue.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@vue/app" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | src/assets 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | sourceType: 'module' 6 | }, 7 | env: { 8 | browser: true, 9 | node: true, 10 | es6: true, 11 | }, 12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], 13 | 14 | // add your custom rules here 15 | //it is base on https://github.com/vuejs/eslint-config-vue 16 | rules: { 17 | "vue/max-attributes-per-line": [2, { 18 | "singleline": 10, 19 | "multiline": { 20 | "max": 1, 21 | "allowFirstLine": false 22 | } 23 | }], 24 | "vue/name-property-casing": ["error", "PascalCase"], 25 | 'accessor-pairs': 2, 26 | 'arrow-spacing': [2, { 27 | 'before': true, 28 | 'after': true 29 | }], 30 | 'block-spacing': [2, 'always'], 31 | 'brace-style': [2, '1tbs', { 32 | 'allowSingleLine': true 33 | }], 34 | 'camelcase': [0, { 35 | 'properties': 'always' 36 | }], 37 | 'comma-dangle': [2, 'never'], 38 | 'comma-spacing': [2, { 39 | 'before': false, 40 | 'after': true 41 | }], 42 | 'comma-style': [2, 'last'], 43 | 'constructor-super': 2, 44 | 'curly': [2, 'multi-line'], 45 | 'dot-location': [2, 'property'], 46 | 'eol-last': 2, 47 | 'eqeqeq': [2, 'allow-null'], 48 | 'generator-star-spacing': [2, { 49 | 'before': true, 50 | 'after': true 51 | }], 52 | 'handle-callback-err': [2, '^(err|error)$'], 53 | 'indent': [2, 2, { 54 | 'SwitchCase': 1 55 | }], 56 | 'jsx-quotes': [2, 'prefer-single'], 57 | 'key-spacing': [2, { 58 | 'beforeColon': false, 59 | 'afterColon': true 60 | }], 61 | 'keyword-spacing': [2, { 62 | 'before': true, 63 | 'after': true 64 | }], 65 | 'new-cap': [2, { 66 | 'newIsCap': true, 67 | 'capIsNew': false 68 | }], 69 | 'new-parens': 2, 70 | 'no-array-constructor': 2, 71 | 'no-caller': 2, 72 | 'no-console': 'off', 73 | 'no-class-assign': 2, 74 | 'no-cond-assign': 2, 75 | 'no-const-assign': 2, 76 | 'no-control-regex': 0, 77 | 'no-delete-var': 2, 78 | 'no-dupe-args': 2, 79 | 'no-dupe-class-members': 2, 80 | 'no-dupe-keys': 2, 81 | 'no-duplicate-case': 2, 82 | 'no-empty-character-class': 2, 83 | 'no-empty-pattern': 2, 84 | 'no-eval': 2, 85 | 'no-ex-assign': 2, 86 | 'no-extend-native': 2, 87 | 'no-extra-bind': 2, 88 | 'no-extra-boolean-cast': 2, 89 | 'no-extra-parens': [2, 'functions'], 90 | 'no-fallthrough': 2, 91 | 'no-floating-decimal': 2, 92 | 'no-func-assign': 2, 93 | 'no-implied-eval': 2, 94 | 'no-inner-declarations': [2, 'functions'], 95 | 'no-invalid-regexp': 2, 96 | 'no-irregular-whitespace': 2, 97 | 'no-iterator': 2, 98 | 'no-label-var': 2, 99 | 'no-labels': [2, { 100 | 'allowLoop': false, 101 | 'allowSwitch': false 102 | }], 103 | 'no-lone-blocks': 2, 104 | 'no-mixed-spaces-and-tabs': 2, 105 | 'no-multi-spaces': 2, 106 | 'no-multi-str': 2, 107 | 'no-multiple-empty-lines': [2, { 108 | 'max': 1 109 | }], 110 | 'no-native-reassign': 2, 111 | 'no-negated-in-lhs': 2, 112 | 'no-new-object': 2, 113 | 'no-new-require': 2, 114 | 'no-new-symbol': 2, 115 | 'no-new-wrappers': 2, 116 | 'no-obj-calls': 2, 117 | 'no-octal': 2, 118 | 'no-octal-escape': 2, 119 | 'no-path-concat': 2, 120 | 'no-proto': 2, 121 | 'no-redeclare': 2, 122 | 'no-regex-spaces': 2, 123 | 'no-return-assign': [2, 'except-parens'], 124 | 'no-self-assign': 2, 125 | 'no-self-compare': 2, 126 | 'no-sequences': 2, 127 | 'no-shadow-restricted-names': 2, 128 | 'no-spaced-func': 2, 129 | 'no-sparse-arrays': 2, 130 | 'no-this-before-super': 2, 131 | 'no-throw-literal': 2, 132 | 'no-trailing-spaces': 2, 133 | 'no-undef': 2, 134 | 'no-undef-init': 2, 135 | 'no-unexpected-multiline': 2, 136 | 'no-unmodified-loop-condition': 2, 137 | 'no-unneeded-ternary': [2, { 138 | 'defaultAssignment': false 139 | }], 140 | 'no-unreachable': 2, 141 | 'no-unsafe-finally': 2, 142 | 'no-unused-vars': [2, { 143 | 'vars': 'all', 144 | 'args': 'none' 145 | }], 146 | 'no-useless-call': 2, 147 | 'no-useless-computed-key': 2, 148 | 'no-useless-constructor': 2, 149 | 'no-useless-escape': 0, 150 | 'no-whitespace-before-property': 2, 151 | 'no-with': 2, 152 | 'one-var': [2, { 153 | 'initialized': 'always' 154 | }], 155 | 'operator-linebreak': [2, 'after', { 156 | 'overrides': { 157 | '?': 'before', 158 | ':': 'before' 159 | } 160 | }], 161 | 'padded-blocks': [2, 'never'], 162 | 'quotes': [2, 'single', { 163 | 'avoidEscape': true, 164 | 'allowTemplateLiterals': true 165 | }], 166 | 'semi': [2, 'never'], 167 | 'semi-spacing': [2, { 168 | 'before': false, 169 | 'after': true 170 | }], 171 | 'space-before-blocks': [2, 'always'], 172 | 'space-before-function-paren': [2, 'never'], 173 | 'space-in-parens': [2, 'never'], 174 | 'space-infix-ops': 2, 175 | 'space-unary-ops': [2, { 176 | 'words': true, 177 | 'nonwords': false 178 | }], 179 | 'spaced-comment': [2, 'always', { 180 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] 181 | }], 182 | 'template-curly-spacing': [2, 'never'], 183 | 'use-isnan': 2, 184 | 'valid-typeof': 2, 185 | 'wrap-iife': [2, 'any'], 186 | 'yield-star-spacing': [2, 'both'], 187 | 'yoda': [2, 'never'], 188 | 'prefer-const': 2, 189 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 190 | 'object-curly-spacing': [2, 'always', { 191 | objectsInObjects: false 192 | }], 193 | 'array-bracket-spacing': [2, 'never'] 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | yarn-error.log 5 | 6 | # Editor directories and files 7 | .idea 8 | *.suo 9 | *.ntvs* 10 | *.njsproj 11 | *.sln 12 | dist/ 13 | 14 | package-lock.json 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | 3 | COPY dist /usr/share/app/src/dist/ 4 | RUN chmod -R 755 /usr/share/app/src/dist 5 | COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf 6 | 7 | EXPOSE 8090 8 | 9 | CMD ["nginx","-g","daemon off;"] 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 党羚(ldang) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cron-generator 2 | 3 | > a project using vue,element-ui to generate cron expression [中文](./README_zh_CN.md) [Online demo](http://106.14.246.234:8090/) 4 | 5 | **Used by** 6 | >👉 Attemper: A distributed,multi-tenancy,job-flow scheduling application 👈 7 | >>[Github](https://github.com/attemper/attemper) 8 | >>[Gitee](https://gitee.com/attemper/attemper) 9 | 10 | ![Preview](https://gitee.com/ldang264/vue-cron-generator/raw/master/resources/snapshot.png) 11 | 12 | ## Use(Example) 13 | - Install dependency([npm](https://www.npmjs.com/package/vue-cron-generator)) 14 | ``` bash 15 | npm install vue-cron-generator 16 | ``` 17 | 18 | - [src/lang/index.js](https://github.com/attemper/attemper/blob/master/attemper-admin/src/lang/index.js) 19 | ``` typescript 20 | import Vue from 'vue' 21 | import VueI18n from 'vue-i18n' 22 | import elementEnLocale from 'element-ui/lib/locale/lang/en' 23 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' 24 | import cronEnLocale from 'vue-cron-generator/src/locale/en' 25 | import cronZhLocale from 'vue-cron-generator/src/locale/zh' 26 | import { getLocale } from 'vue-cron-generator/src/util/tools' 27 | 28 | Vue.use(VueI18n) 29 | 30 | const messages = { 31 | en: { 32 | ...enLocale, 33 | ...elementEnLocale 34 | }, 35 | zh: { 36 | ...zhLocale, 37 | ...elementZhLocale 38 | } 39 | }, 40 | 41 | i18n = new VueI18n({ 42 | // set locale 43 | // options: 'en' | 'zh' 44 | locale: getLocale(), 45 | // set locale messages 46 | messages 47 | }) 48 | 49 | export default i18n 50 | 51 | ``` 52 | 53 | - [main.js](https://github.com/attemper/attemper/blob/master/attemper-admin/src/lang/index.js) 54 | ``` typescript 55 | import Vue from 'vue' 56 | 57 | import Element from 'element-ui' 58 | import 'element-ui/lib/theme-chalk/index.css' 59 | 60 | import 'vue-cron-generator/src/styles/global.css' 61 | 62 | import App from './App' 63 | 64 | import i18n from './lang' 65 | 66 | Vue.use(Element, { 67 | size: localStorage.getItem('size') || 'small', // set element-ui default size 68 | i18n: (key, value) => i18n.t(key, value) 69 | }) 70 | 71 | new Vue({ 72 | el: '#app', 73 | i18n, 74 | render: h => h(App) 75 | }) 76 | 77 | ``` 78 | 79 | - Vue file 80 | 81 | ``` vue 82 | 91 | 92 | 116 | 117 | 127 | 128 | ``` 129 | 130 | - Run your project 131 | 132 | ## Build Source Code 133 | 134 | ``` bash 135 | # install dependencies 136 | npm install vue-cron-generator 137 | 138 | # serve with hot reload at localhost:8080 139 | npm run dev 140 | 141 | # build for production with minification 142 | npm run build 143 | ``` 144 | -------------------------------------------------------------------------------- /README_zh_CN.md: -------------------------------------------------------------------------------- 1 | # vue-cron-generator 2 | 3 | > 一个基于Vue&Element-UI构建的在线Cron表达式生成器 [English](./README.md) [在线demo](http://106.14.246.234:8090/) 4 | 5 | **使用的项目** 6 | >👉 Attemper: 分布式多租户的支持流程编排的任务调度平台(用之作为cron表达式生成器) 👈 7 | >>[Github](https://github.com/attemper/attemper) 8 | >>[Gitee](https://gitee.com/attemper/attemper) 9 | 10 | ![预览](https://gitee.com/ldang264/vue-cron-generator/raw/master/resources/snapshot_zh_CN.png) 11 | 12 | ## 使用(例子代码) 13 | - 下载依赖([npm](https://www.npmjs.com/package/vue-cron-generator)) 14 | ``` typescript 15 | import Vue from 'vue' 16 | import VueI18n from 'vue-i18n' 17 | import elementEnLocale from 'element-ui/lib/locale/lang/en' 18 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' 19 | import cronEnLocale from 'vue-cron-generator/src/locale/en' 20 | import cronZhLocale from 'vue-cron-generator/src/locale/zh' 21 | import { getLocale } from 'vue-cron-generator/src/util/tools' 22 | 23 | Vue.use(VueI18n) 24 | 25 | const messages = { 26 | en: { 27 | ...enLocale, 28 | ...elementEnLocale 29 | }, 30 | zh: { 31 | ...zhLocale, 32 | ...elementZhLocale 33 | } 34 | }, 35 | 36 | i18n = new VueI18n({ 37 | // set locale 38 | // options: 'en' | 'zh' 39 | locale: getLocale(), 40 | // set locale messages 41 | messages 42 | }) 43 | 44 | export default i18n 45 | 46 | ``` 47 | 48 | - [main.js](https://github.com/attemper/attemper/blob/master/attemper-admin/src/lang/index.js) 49 | ``` typescript 50 | import Vue from 'vue' 51 | 52 | import Element from 'element-ui' 53 | import 'element-ui/lib/theme-chalk/index.css' 54 | 55 | import 'vue-cron-generator/src/styles/global.css' 56 | 57 | import App from './App' 58 | 59 | import i18n from './lang' 60 | 61 | Vue.use(Element, { 62 | size: localStorage.getItem('size') || 'small', // set element-ui default size 63 | i18n: (key, value) => i18n.t(key, value) 64 | }) 65 | 66 | new Vue({ 67 | el: '#app', 68 | i18n, 69 | render: h => h(App) 70 | }) 71 | 72 | ``` 73 | 74 | - Vue文件 75 | 76 | ``` vue 77 | 86 | 87 | 111 | 112 | 122 | 123 | ``` 124 | 125 | - 运行项目 126 | 127 | ## 构建本项目源码 128 | 129 | ``` bash 130 | # 下载依赖 131 | npm install vue-cron-generator 132 | 133 | # 服务启动在localhost:8080 134 | npm run dev 135 | 136 | # 构建生产文件 137 | npm run build 138 | ``` 139 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8090; 3 | server_name 127.0.0.1; 4 | charset utf-8; 5 | client_max_body_size 1024m; 6 | 7 | root /usr/share/app/src/dist; 8 | 9 | location / { 10 | index /index.html; 11 | } 12 | 13 | location ~ .*\.(gif|jpg|jpeg|png|bpm|swf|apk|tar.gz|ico|woff|svg|bpmn|map)$ { 14 | expires 30d; 15 | } 16 | 17 | location ~ .*\.(html|js|css)$ { 18 | expires 12h; 19 | } 20 | 21 | location /api { 22 | proxy_pass http://106.14.246.234:5210/api; 23 | proxy_http_version 1.1; 24 | proxy_set_header Host $host; 25 | proxy_set_header X-Forwarded-For $remote_addr; 26 | proxy_set_header Upgrade $http_upgrade; 27 | proxy_set_header Connection "Upgrade"; 28 | proxy_set_header X_REMOTE_IP $remote_addr; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cron-generator", 3 | "description": "a project using vue,element-ui to generate cron expression", 4 | "version": "0.2.4", 5 | "author": "ldang264 <820704815@qq.com>", 6 | "license": "MIT", 7 | "private": false, 8 | "scripts": { 9 | "dev": "vue-cli-service serve --open", 10 | "build": "vue-cli-service build", 11 | "lint": "vue-cli-service lint", 12 | "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src", 13 | "test:unit": "vue-cli-service test:unit", 14 | "test:e2e": "vue-cli-service test:e2e" 15 | }, 16 | "lint-staged": { 17 | "*.js": [ 18 | "vue-cli-service lint", 19 | "git add" 20 | ], 21 | "*.vue": [ 22 | "vue-cli-service lint", 23 | "git add" 24 | ] 25 | }, 26 | "keywords": [ 27 | "vue", 28 | "element-ui", 29 | "i18n", 30 | "cron", 31 | "crontab" 32 | ], 33 | "dependencies": { 34 | "core-js": "3.6.5", 35 | "element-ui": "2.13.2", 36 | "vue": "2.6.11", 37 | "vue-i18n": "8.15.3" 38 | }, 39 | "browserslist": [ 40 | "> 1%", 41 | "last 2 versions", 42 | "not ie <= 8" 43 | ], 44 | "devDependencies": { 45 | "@vue/cli-plugin-babel": "4.4.4", 46 | "@vue/cli-plugin-eslint": "4.4.4", 47 | "@vue/cli-plugin-unit-jest": "4.4.4", 48 | "@vue/cli-service": "4.4.4", 49 | "@vue/test-utils": "1.0.0-beta.29", 50 | "axios": "0.26.0", 51 | "babel-eslint": "10.1.0", 52 | "babel-plugin-dynamic-import-node": "2.3.3", 53 | "eslint": "6.7.2", 54 | "eslint-plugin-vue": "6.2.2", 55 | "lint-staged": "8.1.5", 56 | "vue-template-compiler": "2.6.11" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldang264/vue-cron-generator/14643521eb8b792d36eaeec8c05ea8e07282b5f1/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= webpackConfig.name %> 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /resources/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldang264/vue-cron-generator/14643521eb8b792d36eaeec8c05ea8e07282b5f1/resources/snapshot.png -------------------------------------------------------------------------------- /resources/snapshot_zh_CN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ldang264/vue-cron-generator/14643521eb8b792d36eaeec8c05ea8e07282b5f1/resources/snapshot_zh_CN.png -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 96 | 97 | 107 | -------------------------------------------------------------------------------- /src/components/config/common/every.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 65 | -------------------------------------------------------------------------------- /src/components/config/common/fixed.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 133 | -------------------------------------------------------------------------------- /src/components/config/common/period.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 93 | -------------------------------------------------------------------------------- /src/components/config/common/range.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 98 | -------------------------------------------------------------------------------- /src/components/config/custom/dayOfWeek/last.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 94 | -------------------------------------------------------------------------------- /src/components/config/custom/dayOfWeek/period.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 108 | -------------------------------------------------------------------------------- /src/components/config/custom/dayOfWeek/range.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 120 | -------------------------------------------------------------------------------- /src/components/config/custom/dayOfWeek/weekDay.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 103 | -------------------------------------------------------------------------------- /src/components/config/custom/last.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 82 | -------------------------------------------------------------------------------- /src/components/config/custom/lastWorkDay.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 66 | -------------------------------------------------------------------------------- /src/components/config/custom/unfixed.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 54 | -------------------------------------------------------------------------------- /src/components/config/custom/workDay.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 78 | -------------------------------------------------------------------------------- /src/components/config/custom/year/empty.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 53 | -------------------------------------------------------------------------------- /src/components/config/ext/symbolTip.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /src/components/config/ext/valTip.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | -------------------------------------------------------------------------------- /src/components/cron-input.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 62 | -------------------------------------------------------------------------------- /src/components/cron.vue: -------------------------------------------------------------------------------- 1 | 123 | 124 | 283 | -------------------------------------------------------------------------------- /src/components/time/dayOfMonth.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 198 | -------------------------------------------------------------------------------- /src/components/time/dayOfWeek.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 186 | -------------------------------------------------------------------------------- /src/components/time/hour.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 137 | -------------------------------------------------------------------------------- /src/components/time/minute.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 137 | -------------------------------------------------------------------------------- /src/components/time/month.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 145 | -------------------------------------------------------------------------------- /src/components/time/second.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 136 | -------------------------------------------------------------------------------- /src/components/time/year.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 146 | -------------------------------------------------------------------------------- /src/constant/filed.js: -------------------------------------------------------------------------------- 1 | export const 2 | /** 12 months */ 3 | JAN = 'JAN', FEB = 'FEB', MAR = 'MAR', APR = 'APR', MAY = 'MAY', JUN = 'JUN', // 1 - 6 4 | JUL = 'JUL', AUG = 'AUG', SEP = 'SEP', OCT = 'OCT', NOV = 'NOV', DEC = 'DEC', // 7 - 12 5 | MONTHS = [JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC], 6 | /** 7 days of week */ 7 | SUN = 'SUN', MON = 'MON', TUE = 'TUE', WED = 'WED', THU = 'THU', FRI = 'FRI', SAT = 'SAT', 8 | DAYS_OF_WEEK = [SUN, MON, TUE, WED, THU, FRI, SAT], 9 | /** symbols */ 10 | EVERY = '*', 11 | PERIOD = '/', 12 | RANGE = '-', 13 | FIXED = ',', 14 | UNFIXED = '?', 15 | LAST = 'L', 16 | WORK_DAY = 'W', 17 | WEEK_DAY = '#', 18 | CALENDAR = 'C', 19 | BASE_SYMBOL = EVERY + ' ' + PERIOD + ' ' + RANGE + ' ' + FIXED, 20 | DAY_OF_MONTH_SYMBOL = BASE_SYMBOL + ' ' + LAST + ' ' + WORK_DAY + ' ' + CALENDAR, 21 | DAY_OF_WEEK_SYMBOL = BASE_SYMBOL + ' ' + UNFIXED + ' ' + LAST + ' ' + WEEK_DAY + ' ' + CALENDAR, 22 | EMPTY = '', 23 | LAST_WORK_DAY = 'LW', 24 | // current year like 2019 25 | CUR_YEAR = new Date().getFullYear(), 26 | // 27 | UPPER_LIMIT_YEAR = 2099, 28 | // default cron expression 29 | DEFAULT_CRON_EXPRESSION = '0 0 12 * * ?' 30 | -------------------------------------------------------------------------------- /src/constant/reg.js: -------------------------------------------------------------------------------- 1 | export const 2 | NUMBER = /^[0-9]+$/ 3 | -------------------------------------------------------------------------------- /src/locale/en.js: -------------------------------------------------------------------------------- 1 | import { CUR_YEAR, UPPER_LIMIT_YEAR } from '../constant/filed' 2 | 3 | export default { 4 | common: { 5 | from: 'From', 6 | fromThe: 'From', 7 | start: ' Start ', 8 | every: 'Per ', 9 | between: '', 10 | and: ' To ', 11 | end: ' ', 12 | specified: 'Specified', 13 | symbolTip: 'Symbol ', 14 | valTip: 'Value ', 15 | nearest: ' Nearest', 16 | current: 'Current ', 17 | nth: ' The', 18 | index: 'th ', 19 | placeholder: 'Select', 20 | placeholderMulti: '(Multi)Select', 21 | help: 'Help', 22 | wordNumError: 'Need 6 or 7 words', 23 | reverse: 'Reverse', 24 | reset: 'Reset', 25 | tagError: 'Tag Error ', 26 | numError: 'Number Error ', 27 | use: 'Use', 28 | inputPlaceholder: 'Cron Expression' 29 | }, 30 | custom: { 31 | unspecified: 'Unspecified', 32 | workDay: ' Work Day', 33 | lastTh: ' Last', 34 | lastOne: ' Last', 35 | latestWorkday: ' Last Work Day', 36 | empty: 'Empty' 37 | }, 38 | second: { 39 | title: 'Second', 40 | val: '0 1 2...59' 41 | }, 42 | minute: { 43 | title: 'Minute', 44 | val: '0 1 2...59' 45 | }, 46 | hour: { 47 | title: 'Hour', 48 | val: '0 1 2...23' 49 | }, 50 | dayOfMonth: { 51 | timeUnit: 'Day', 52 | title: 'Day', 53 | val: '1 2...31' 54 | }, 55 | month: { 56 | title: 'Month', 57 | val: '1 2...12 or JAN ... DEC' 58 | }, 59 | dayOfWeek: { 60 | timeUnit: 'Day', 61 | title: 'Week', 62 | val: '1 2...7 or SUN ... SAT', 63 | SUN: 'Sunday', 64 | MON: 'Monday', 65 | TUE: 'Tuesday', 66 | WED: 'Wednesday', 67 | THU: 'Thursday', 68 | FRI: 'Friday', 69 | SAT: 'Saturday' 70 | }, 71 | year: { 72 | title: 'Year', 73 | val: CUR_YEAR + ' ... ' + UPPER_LIMIT_YEAR 74 | }, 75 | period: { 76 | startError: 'Start is Error', 77 | cycleError: 'Cycle is Error' 78 | }, 79 | range: { 80 | lowerError: 'Lower is Error', 81 | upperError: 'Upper is Error', 82 | lowerBiggerThanUpperError: 'Lower should smaller than Upper' 83 | }, 84 | weekDay: { 85 | weekDayNumError: 'The Week Number is Error', 86 | nthError: 'The Day in Week is Error' 87 | }, 88 | app: { 89 | title: 'Cron Generator Implemented by Vue.js and Element-ui', 90 | next10FireTimes: 'The 10 fired times recently' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/locale/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | import elementEnLocale from 'element-ui/lib/locale/lang/en' 4 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' 5 | import enLocale from './en' 6 | import zhLocale from './zh' 7 | import { getLocale } from '../util/tools' 8 | 9 | Vue.use(VueI18n) 10 | 11 | const messages = { 12 | en: { 13 | ...enLocale, 14 | ...elementEnLocale 15 | }, 16 | zh: { 17 | ...zhLocale, 18 | ...elementZhLocale 19 | } 20 | }, 21 | 22 | i18n = new VueI18n({ 23 | // set locale 24 | // options: 'en' | 'zh' 25 | locale: getLocale(), 26 | // set locale messages 27 | messages 28 | }) 29 | 30 | export default i18n 31 | -------------------------------------------------------------------------------- /src/locale/zh.js: -------------------------------------------------------------------------------- 1 | import { CUR_YEAR, UPPER_LIMIT_YEAR } from '../constant/filed' 2 | 3 | export default { 4 | common: { 5 | from: '从', 6 | fromThe: '从第', 7 | start: '开始', 8 | every: '每', 9 | between: '在', 10 | and: '到', 11 | end: '之间的', 12 | specified: '固定的', 13 | symbolTip: '通配符支持', 14 | valTip: '值为', 15 | nearest: '最近的', 16 | current: '本', 17 | nth: '第', 18 | index: '个', 19 | placeholder: '请选择', 20 | placeholderMulti: '请选择(支持多选)', 21 | help: '帮助', 22 | wordNumError: '格式不正确,必须有6或7位', 23 | reverse: '反向解析', 24 | reset: '重置', 25 | tagError: '表达式不正确', 26 | numError: '含有非法数字', 27 | use: '使用', 28 | inputPlaceholder: 'Cron表达式' 29 | }, 30 | custom: { 31 | unspecified: '不固定', 32 | workDay: '工作日', 33 | lastTh: '倒数第', 34 | lastOne: '最后一个', 35 | latestWorkday: '最后一个工作日', 36 | empty: '不配置' 37 | }, 38 | second: { 39 | title: '秒', 40 | val: '0 1 2...59' 41 | }, 42 | minute: { 43 | title: '分', 44 | val: '0 1 2...59' 45 | }, 46 | hour: { 47 | title: '时', 48 | val: '0 1 2...23' 49 | }, 50 | dayOfMonth: { 51 | timeUnit: '日', 52 | title: '日', 53 | val: '1 2...31' 54 | }, 55 | month: { 56 | title: '月', 57 | val: '1 2...12,或12个月的缩写(JAN ... DEC)' 58 | }, 59 | dayOfWeek: { 60 | timeUnit: '日', 61 | title: '周', 62 | val: '1 2...7或星期的缩写(SUN ... SAT)', 63 | SUN: '星期天', 64 | MON: '星期一', 65 | TUE: '星期二', 66 | WED: '星期三', 67 | THU: '星期四', 68 | FRI: '星期五', 69 | SAT: '星期六' 70 | }, 71 | year: { 72 | title: '年', 73 | val: CUR_YEAR + ' ... ' + UPPER_LIMIT_YEAR 74 | }, 75 | period: { 76 | startError: '开始格式不符', 77 | cycleError: '循环格式不符' 78 | }, 79 | range: { 80 | lowerError: '下限格式不符', 81 | upperError: '上限格式不符', 82 | lowerBiggerThanUpperError: '下限不能比上限大' 83 | }, 84 | weekDay: { 85 | weekDayNumError: '周数格式不符', 86 | nthError: '天数格式不符' 87 | }, 88 | app: { 89 | title: '基于Vue&Element-ui实现的Cron表达式生成器', 90 | next10FireTimes: '最近10次执行时刻' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import Element from 'element-ui' 4 | import 'element-ui/lib/theme-chalk/index.css' 5 | import i18n from './locale' // Internationalization 6 | import './styles/global.css' 7 | 8 | Vue.use(Element, { 9 | i18n: (key, value) => i18n.t(key, value) 10 | }) 11 | 12 | new Vue({ 13 | el: '#app', 14 | i18n, 15 | render: h => h(App) 16 | }) 17 | -------------------------------------------------------------------------------- /src/mixins/watchTime.js: -------------------------------------------------------------------------------- 1 | import { EMPTY, EVERY, FIXED, LAST, LAST_WORK_DAY, PERIOD, RANGE, UNFIXED, WEEK_DAY, WORK_DAY } from '../constant/filed' 2 | 3 | export default { 4 | watch: { 5 | tag(val) { 6 | this.resolveTag(val) 7 | } 8 | }, 9 | created() { 10 | this.initNums() 11 | }, 12 | mounted() { 13 | this.resolveTag(this.tag) 14 | }, 15 | methods: { 16 | resolveTag(val) { 17 | if (val == null) { 18 | val = EMPTY 19 | } 20 | let temp = null 21 | val = this.resolveCustom(val) 22 | // equals 23 | if (val === EMPTY) { 24 | temp = EMPTY 25 | } else if (val === UNFIXED) { 26 | temp = UNFIXED 27 | } else if (val === EVERY) { 28 | temp = EVERY 29 | } else if (val === LAST_WORK_DAY) { 30 | temp = LAST_WORK_DAY 31 | } 32 | // contains 33 | if (temp == null) { 34 | if (val.startsWith(LAST + '-')) { 35 | temp = LAST 36 | } else if (val.endsWith(LAST)) { 37 | temp = LAST 38 | } else if (val.endsWith(WORK_DAY) && val.length > WORK_DAY.length) { 39 | temp = WORK_DAY 40 | } else if (val.indexOf(WEEK_DAY) > 0) { 41 | temp = WEEK_DAY 42 | } else if (val.indexOf(PERIOD) > 0) { 43 | temp = PERIOD 44 | } else if (val.indexOf(RANGE) > 0) { 45 | temp = RANGE 46 | } else { 47 | temp = FIXED 48 | } 49 | } 50 | this.type_ = temp 51 | this.changeSiblingType(this.type_) 52 | this.tag_ = val 53 | }, 54 | resolveCustom(val) { 55 | return val 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/mixins/watchValue.js: -------------------------------------------------------------------------------- 1 | export default { 2 | watch: { 3 | tag_(val) { 4 | if (this.type_ === this.label) { 5 | this.$emit('tag-changed', val) 6 | } 7 | }, 8 | tag(val) { 9 | this.tag_ = val 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/styles/global.css: -------------------------------------------------------------------------------- 1 | .cell-dev{ 2 | margin-bottom: 8px; 3 | } 4 | 5 | .cell-symbol{ 6 | color: #67C23A; 7 | } 8 | 9 | .cron-row{ 10 | margin-top: 8px; 11 | max-width: 550px; 12 | } 13 | -------------------------------------------------------------------------------- /src/translate/dict.js: -------------------------------------------------------------------------------- 1 | export const cases_zh = [ 2 | { 3 | label: '每秒', 4 | value: '* * * * * ?' 5 | }, 6 | { 7 | label: '每30分钟', 8 | value: '0 */30 * * * ?' 9 | }, 10 | { 11 | label: '在每小时的第15,30,45分钟', 12 | value: '0 15,30,45 * * * ?' 13 | }, 14 | { 15 | label: '每个偶数小时', 16 | value: '0 0 0/2 * * ?' 17 | }, 18 | { 19 | label: '每个奇数小时', 20 | value: '0 0 1/2 * * ?' 21 | }, 22 | { 23 | label: '每天凌晨12点(12am)', 24 | value: '0 0 0 * * ?' 25 | }, 26 | { 27 | label: '每天中午12点(12pm)', 28 | value: '0 0 12 * * ?' 29 | }, 30 | { 31 | label: '每周一12点', 32 | value: '0 0 12 ? * MON' 33 | }, 34 | { 35 | label: '每周一至周五12点', 36 | value: '0 0 12 ? * MON-FRI' 37 | }, 38 | { 39 | label: '每月1号开始每隔4天的中午12点', 40 | value: '0 0 12 1/4 * ?' 41 | }, 42 | { 43 | label: '每月最后一天的中午12点', 44 | value: '0 0 12 L * ?' 45 | }, 46 | { 47 | label: '每月最后一天前两天(倒数第三天)中午12点', 48 | value: '0 0 12 L-2 * ?' 49 | }, 50 | { 51 | label: '每月最后一个工作日的12点', 52 | value: '0 0 12 LW * ?' 53 | }, 54 | { 55 | label: '最接近每月1号的那个工作日的12点', 56 | value: '0 0 12 1W * ?' 57 | }, 58 | { 59 | label: '每月最后一个星期天12点', 60 | value: '0 0 12 ? * 1L' 61 | }, 62 | { 63 | label: '每月第一个星期五的12点', 64 | value: '0 0 12 ? * 6#1' 65 | }, 66 | { 67 | label: '1月和6月的每天中午12点', 68 | value: '0 0 12 * JAN,JUN ?' 69 | } 70 | ], 71 | daysOfWeek_zh = [ 72 | { 73 | label: '星期天', 74 | value: 1 75 | }, 76 | { 77 | label: '星期一', 78 | value: 2 79 | }, 80 | { 81 | label: '星期二', 82 | value: 3 83 | }, 84 | { 85 | label: '星期三', 86 | value: 4 87 | }, 88 | { 89 | label: '星期四', 90 | value: 5 91 | }, 92 | { 93 | label: '星期五', 94 | value: 6 95 | }, 96 | { 97 | label: '星期六', 98 | value: 7 99 | } 100 | ], 101 | cases_en = [ 102 | { 103 | label: 'Every second', 104 | value: '* * * * * ?' 105 | }, 106 | { 107 | label: 'Every 30 minutes', 108 | value: '0 */30 * * * ?' 109 | }, 110 | { 111 | label: 'Every hour at minutes 15, 30 and 45', 112 | value: '0 15,30,45 * * * ?' 113 | }, 114 | { 115 | label: 'Every even hour', 116 | value: '0 0 0/2 * * ?' 117 | }, 118 | { 119 | label: 'Every uneven hour', 120 | value: '0 0 1/2 * * ?' 121 | }, 122 | { 123 | label: 'Every day at midnight - 12am', 124 | value: '0 0 0 * * ?' 125 | }, 126 | { 127 | label: 'Every day at noon - 12pm', 128 | value: '0 0 12 * * ?' 129 | }, 130 | { 131 | label: 'Every Monday at noon', 132 | value: '0 0 12 ? * MON' 133 | }, 134 | { 135 | label: 'Every Weekday at noon', 136 | value: '0 0 12 ? * MON-FRI' 137 | }, 138 | { 139 | label: 'Every 4 days staring on the 1st of the month, at noon', 140 | value: '0 0 12 1/4 * ?' 141 | }, 142 | { 143 | label: 'Every month on the last day of the month, at noon', 144 | value: '0 0 12 L * ?' 145 | }, 146 | { 147 | label: 'Every month on the second to last day of the month, at noon', 148 | value: '0 0 12 L-2 * ?' 149 | }, 150 | { 151 | label: 'Every month on the last weekday, at noon', 152 | value: '0 0 12 LW * ?' 153 | }, 154 | { 155 | label: 'Every month on the nearest Weekday to the 1st of the month, at noon', 156 | value: '0 0 12 1W * ?' 157 | }, 158 | { 159 | label: 'Every month on the last Sunday, at noon', 160 | value: '0 0 12 ? * 1L' 161 | }, 162 | { 163 | label: 'Every month on the first Friday of the Month, at noon', 164 | value: '0 0 12 ? * 6#1' 165 | }, 166 | { 167 | label: 'Every day at noon in January and June', 168 | value: '0 0 12 * JAN,JUN ?' 169 | } 170 | ], 171 | daysOfWeek_en = [ 172 | { 173 | label: 'Sunday', 174 | value: 1 175 | }, 176 | { 177 | label: 'Monday', 178 | value: 2 179 | }, 180 | { 181 | label: 'Tuesday', 182 | value: 3 183 | }, 184 | { 185 | label: 'Wednesday', 186 | value: 4 187 | }, 188 | { 189 | label: 'Thursday', 190 | value: 5 191 | }, 192 | { 193 | label: 'Friday', 194 | value: 6 195 | }, 196 | { 197 | label: 'Saturday', 198 | value: 7 199 | } 200 | ] 201 | -------------------------------------------------------------------------------- /src/util/tools.js: -------------------------------------------------------------------------------- 1 | import { NUMBER } from '../constant/reg' 2 | 3 | export const 4 | sortNum = (a, b) => { 5 | return a - b 6 | }, 7 | isNumber = (str) => { 8 | return new RegExp(NUMBER).test(str) 9 | }, 10 | getLocale = () => { 11 | const lang = localStorage.getItem('locale') || sessionStorage.getItem('locale') || 12 | localStorage.getItem('lang') || sessionStorage.getItem('lang') || 13 | localStorage.getItem('language') || sessionStorage.getItem('language') || navigator.language, 14 | index = lang.indexOf('-') 15 | return index <= 0 ? lang : lang.substring(0, index) 16 | } 17 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path'), 4 | name = 'vue-cron-generator', // page title 5 | port = process.env.port || process.env.npm_config_port || 8090 // dev port 6 | 7 | function resolve(dir) { 8 | return path.join(__dirname, dir) 9 | } 10 | 11 | module.exports = { 12 | publicPath: './', 13 | outputDir: 'dist', 14 | lintOnSave: true, 15 | productionSourceMap: false, 16 | devServer: { 17 | port: port, 18 | open: false, 19 | overlay: { 20 | warnings: false, 21 | errors: true 22 | }, 23 | proxy: { 24 | '/api': { 25 | target: `http://106.14.246.234:5210`, 26 | changeOrigin: true, 27 | pathRewrite: { 28 | '^/api': '/api' 29 | } 30 | } 31 | }, 32 | disableHostCheck: true 33 | }, 34 | configureWebpack: { 35 | // provide the app's title in webpack's name field, so that 36 | // it can be accessed in index.html to inject the correct title. 37 | name: name, 38 | resolve: { 39 | alias: { 40 | '@': resolve('src') 41 | } 42 | } 43 | } 44 | } 45 | --------------------------------------------------------------------------------