├── .gitignore ├── LICENSE ├── README.md ├── generator ├── index.js └── templates │ └── default │ ├── .editorconfig │ ├── .env.local │ ├── .eslintignore │ ├── public │ ├── favicon.ico │ ├── icons │ │ ├── android-chrome-192x192.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── msapplication-icon-144x144.png │ │ └── safari-pinned-tab.svg │ ├── manifest.json │ └── robots.txt │ ├── src │ ├── assets │ │ ├── less │ │ │ └── var.less │ │ └── sass │ │ │ └── var.scss │ ├── bootstrap.js │ ├── components │ │ ├── charts │ │ │ ├── bar.vue │ │ │ ├── index.js │ │ │ ├── pie.vue │ │ │ └── theme.json │ │ ├── common-icon.vue │ │ ├── count-to │ │ │ └── index.vue │ │ ├── icons.vue │ │ ├── index.js │ │ └── info-card │ │ │ └── index.vue │ ├── config.js │ ├── i18n │ │ ├── en-US.js │ │ ├── index.js │ │ └── zh-CN.js │ ├── lib │ │ └── services │ │ │ └── index.js │ ├── pages │ │ └── index │ │ │ ├── App.vue │ │ │ ├── components │ │ │ ├── common │ │ │ │ ├── footer.vue │ │ │ │ └── header.vue │ │ │ ├── index.js │ │ │ ├── language.vue │ │ │ └── layout.vue │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── routes │ │ │ ├── index.js │ │ │ ├── manage.js │ │ │ ├── report.js │ │ │ └── system.js │ │ │ ├── store │ │ │ └── index.js │ │ │ └── views │ │ │ ├── 404.vue │ │ │ ├── account.vue │ │ │ ├── home.vue │ │ │ ├── login.vue │ │ │ ├── manage │ │ │ ├── hello.vue │ │ │ ├── index.vue │ │ │ └── world.vue │ │ │ ├── report.vue │ │ │ └── system.vue │ ├── registerServiceWorker.js │ ├── router.js │ └── store │ │ ├── index.js │ │ ├── modules │ │ ├── Language.js │ │ ├── User.js │ │ ├── Webconfig.js │ │ └── index.js │ │ ├── mutation-type.js │ │ └── plugins.js │ └── vue.config.js ├── package.json ├── preset.json ├── prompts.js └── screenshot ├── element-ui.png ├── iview-en.png └── iview.png /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kuaizi™ 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 | <<<<<<< HEAD 22 | SOFTWARE. 23 | ======= 24 | SOFTWARE. 25 | >>>>>>> 6accc9d8a11e7126c2eb3f2bff463ba5843424ba 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cli-preset-kz 2 | 3 | vue项目开发预设模板 4 | 5 | [https://kuaizi-co.github.io/vue-cli-preset-kz](https://kuaizi-co.github.io/vue-cli-preset-kz) 6 | 7 | ## Install 8 | 9 | ``` 10 | # 首先安装vue-cli 3.0 11 | > npm install -g @vue/cli 12 | 13 | > vue create --preset kuaizi-co/vue-cli-preset-kz project-name --no-git 14 | 15 | # OR more faster!!! 16 | # - project-name 17 | # - vue-cli-preset-kz 18 | project-name> cd .. 19 | > git clone https://github.com/Kuaizi-co/vue-cli-preset-kz.git 20 | > cd vue-cli-preset-kz 21 | > git pull origin master 22 | > cd .. 23 | > vue create --preset ./vue-cli-preset-kz project-name --no-git 24 | ``` 25 | 26 | ## Develop 27 | 28 | ``` 29 | npm run dev 30 | ``` 31 | 32 | ## Build 33 | 34 | ``` 35 | npm run build 36 | ``` 37 | 38 | ## Review 39 | 40 | ``` 41 | npm run review 42 | ``` 43 | 44 | ## 功能列表 45 | 46 | - [x] postcss/less/sass 47 | - [x] ES6/Typescript 48 | - [x] element-ui/iview 49 | - [x] vue-router/vuex 50 | - [x] mock server 51 | - [x] style-resources-loader 52 | - [x] i18n 53 | - [x] axios 54 | - [x] PWA 55 | - [x] unit(mocha)/e2e(Nightwatch) 56 | - [ ] nuxt.js/egg.js 57 | 58 | ### css预处理器全局变量 59 | 60 | 内置`style-resources-loader`,支持`less`、`sass` 加载全局变量文件。 61 | 62 | ``` 63 | # vue.config.js 64 | /** 65 | * 样式预处理器全局变量资源插件 66 | * @param {String} rule webpack 规则 67 | */ 68 | function addStyleResource (rule) { 69 | rule.use('style-resource') 70 | .loader('style-resources-loader') 71 | .options({ 72 | patterns: [ 73 | resolve('./src/assets/less/var.less') 74 | ] 75 | }) 76 | } 77 | ``` 78 | 79 | 在`*.vue`文件中直接使用 `var.less(scss)`定义的变量,增加共同`mixin`只需手动添加文件的路径。 80 | 81 | ``` 82 | # App.vue 83 | 89 | ``` 90 | 91 | ### preset模板 92 | 93 | 当前 preset 模板暂只有 `default` 默认模板,对于 `ts`、`egg`、`nuxt` 模板添加时间待定。 94 | 95 | ### UI 框架 96 | 97 | 本 preset 支持 `element-ui` 和 `iview`(默认)两种。 98 | 99 | ![iview](./screenshot/iview.png) 100 | 101 | iView 102 | 103 | ![element-ui](./screenshot/element-ui.png) 104 | 105 | element-ui 106 | 107 | ### I18n 多语言 108 | 109 | 多语言采用模块异步延迟加载方式,首先检测语言环境及用户上次使用的语言。在切换语言后,如果尚未加载的语言包将从服务器中加载,达到项目按需加载资源优化。 110 | 111 | ``` 112 | src 113 | i18n 114 | index.js 115 | zh-CN.js 116 | en-US.js 117 | ``` 118 | 119 | ![英文版页面](./screenshot/iview-en.png) 120 | 121 | 英文版页面 122 | 123 | ### 多页模式 124 | 125 | 通过配置`vue.config.js`的`pages`参数,默认读取 `src/pages`下的各个目录 126 | 127 | ``` 128 | - src 129 | - pages 130 | - index 131 | - components 132 | - routes 133 | - store 134 | - views 135 | App.vue 136 | index.html 137 | main.js 138 | - about 139 | ``` 140 | 141 | 每个单页基本包含3个文件 142 | 143 | ``` 144 | App.vue 145 | index.html 146 | main.js 147 | ``` 148 | 149 | # 150 | copyright (c) www.kuaizi.ai -------------------------------------------------------------------------------- /generator/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | module.exports = (api, opts, rootOpts) => { 4 | 5 | // 添加 npm 命令 6 | api.extendPackage({ 7 | scripts: { 8 | dev: 'vue-cli-service serve --copy', 9 | build: 'vue-cli-service build', 10 | review: 'serve -s dist', 11 | lint: 'vue-cli-service lint', 12 | serve: 'vue-cli-service serve' 13 | } 14 | }) 15 | 16 | // 开发依赖包 17 | api.extendPackage({ 18 | devDependencies: { 19 | 'serve': '^10.0.1', 20 | 'style-resources-loader': '1.2.1' 21 | } 22 | }) 23 | 24 | api.extendPackage({ 25 | dependencies: { 26 | 'axios': '^0.18.0', 27 | 'babel-polyfill': '^6.22.0', 28 | 'lodash': '^4.17.11', 29 | 'normalize.css': '^8.0.0', 30 | 'nprogress': '^0.2.0', 31 | 'vue-i18n': '^8.1.0', 32 | 'countup': '^1.8.2', 33 | "echarts": "^4.2.0-rc.1", 34 | [opts['ui-framework']]: opts['ui-framework'] === 'element-ui' ? '^2.4.7' : '^3.1.1' 35 | } 36 | }) 37 | 38 | // # less 39 | if (opts['cssPreprocessor'] === 'less') { 40 | api.extendPackage({ 41 | devDependencies: { 42 | "less": "^2.7.2", 43 | "less-loader": "^3.0.0" 44 | } 45 | }) 46 | } 47 | 48 | // # sass 49 | if (opts['cssPreprocessor'] === 'sass') { 50 | api.extendPackage({ 51 | devDependencies: { 52 | "node-sass": "^4.9.3", 53 | "sass-loader": "^7.1.0" 54 | } 55 | }) 56 | } 57 | 58 | // 扩展.babelrc 配置 59 | // api.extendPackage({ 60 | // babel: { 61 | // env: { 62 | // test: { 63 | // plugins: ["babel-plugin-transform-es2015-modules-commonjs"] 64 | // } 65 | // } 66 | // } 67 | // }) 68 | 69 | // 扩展 .eslintrc 配置 70 | api.extendPackage({ 71 | eslintConfig: { 72 | "rules": { 73 | "vue/no-parsing-error": [ 74 | 2, 75 | { "x-invalid-end-tag": false } 76 | ] 77 | } 78 | } 79 | }) 80 | 81 | // 删除多余的模板 82 | api.render(files => { 83 | Object.keys(files) 84 | .filter(path => path.startsWith('src/') || path.startsWith('public/')) 85 | .forEach(path => delete files[path]) 86 | }) 87 | 88 | 89 | 90 | // 选择生成的模板 91 | // if (opts.Typescript) { 92 | // api.render("./templates/ts") 93 | // } else 94 | if(opts.SSR === 'nuxt') { 95 | api.render("./templates/nuxt") 96 | // } else if (opts.SSR === 'egg') { 97 | // api.render("./templates/egg") 98 | } else { 99 | api.render("./templates/default") 100 | } 101 | 102 | // 删除多余目录 103 | const pwaFiles = [ 104 | 'public/robots.txt', 105 | 'public/manifest.json', 106 | 'src/registerServiceWorker.js', 107 | 'public/icons/android-chrome-192x192.png', 108 | 'public/icons/apple-touch-icon-152x152.png', 109 | 'public/icons/msapplication-icon-144x144.png', 110 | 'public/icons/safari-pinned-tab.svg' 111 | ] 112 | 113 | if (opts.pwa) { 114 | api.extendPackage({ 115 | dependencies: { 116 | "register-service-worker": "^1.0.0", 117 | "sass-loader": "^7.1.0" 118 | }, 119 | devDependencies: { 120 | "@vue/cli-plugin-pwa": "^3.0.3" 121 | } 122 | }) 123 | } 124 | 125 | api.render(files => { 126 | Object.keys(files) 127 | .filter(path => path.includes(`/${opts.cssPreprocessor === 'sass' ? 'less' : 'sass' }/`)) 128 | .forEach(path => delete files[path]) 129 | 130 | if (!opts.pwa) { 131 | Object.keys(files) 132 | .filter(path => { 133 | return pwaFiles.find(file => path.includes(file)) 134 | }) 135 | .forEach(path => delete files[path]) 136 | } 137 | }) 138 | } -------------------------------------------------------------------------------- /generator/templates/default/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /generator/templates/default/.env.local: -------------------------------------------------------------------------------- 1 | # 只允许访问的路由 2 | # VUE_APP_ALLOW_ROUTES=manage 3 | # 只允许访问的单页 4 | # VUE_APP_ALLOW_ENTRY=index 5 | -------------------------------------------------------------------------------- /generator/templates/default/.eslintignore: -------------------------------------------------------------------------------- 1 | # src/lib/ajax.js -------------------------------------------------------------------------------- /generator/templates/default/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/generator/templates/default/public/favicon.ico -------------------------------------------------------------------------------- /generator/templates/default/public/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/generator/templates/default/public/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /generator/templates/default/public/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/generator/templates/default/public/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /generator/templates/default/public/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/generator/templates/default/public/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /generator/templates/default/public/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /generator/templates/default/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pwa", 3 | "short_name": "pwa", 4 | "icons": [ 5 | { 6 | "src": "/img/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/img/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/index.html", 17 | "display": "standalone", 18 | "background_color": "#000000", 19 | "theme_color": "#4DBA87" 20 | } 21 | -------------------------------------------------------------------------------- /generator/templates/default/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: -------------------------------------------------------------------------------- /generator/templates/default/src/assets/less/var.less: -------------------------------------------------------------------------------- 1 | @color: #2c3e50; 2 | -------------------------------------------------------------------------------- /generator/templates/default/src/assets/sass/var.scss: -------------------------------------------------------------------------------- 1 | $color: #2c3e50; 2 | -------------------------------------------------------------------------------- /generator/templates/default/src/bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 页面初始化函数 3 | * by www.kuaizi.ai 4 | * http://www.kuaizi.ai 5 | */ 6 | 7 | // css reset 8 | import 'normalize.css' 9 | import Vue from 'vue' 10 | import i18n from '@/i18n' 11 | 12 | <% if (options['ui-framework'] === 'element-ui') {%> 13 | // 使用ElementUI 14 | import ElementUI from 'element-ui' 15 | import 'element-ui/lib/theme-chalk/index.css' 16 | Vue.use(ElementUI) 17 | <% } %> 18 | 19 | <% if (options['ui-framework'] === 'iview') {%> 20 | // 使用iView 21 | import iView from 'iview'; 22 | import 'iview/dist/styles/iview.css'; 23 | Vue.use(iView) 24 | <% } %> 25 | 26 | import Store from './store' 27 | import components from './components' 28 | 29 | <% if (options.pwa) {%> 30 | import './registerServiceWorker' 31 | <% } %> 32 | 33 | export default ({ Router, Component, routes, states = {}, options }, resolve = () => {}) => { 34 | // 批量注册组件 35 | Object.values(components) 36 | .forEach(component => { 37 | Vue.component(component.name, component) 38 | }) 39 | 40 | const store = Store(states) 41 | 42 | // 绑定路由 43 | const router = Router ? Router(store, routes, options) : {} 44 | 45 | // 动态加载当前语言包 46 | store.dispatch('setSystemLanguage', Vue.config.lang) 47 | .then(res => { 48 | // 创建单页实例 49 | const app = new Vue({ 50 | el: '#app', 51 | render: h => h(Component), 52 | store, 53 | router, 54 | i18n 55 | }) 56 | 57 | // 回调函数 58 | resolve(app) 59 | }) 60 | 61 | // const app = new Vue({ 62 | // el: '#app', 63 | // render: h => h(Component), 64 | // store, 65 | // router, 66 | // i18n 67 | // }) 68 | 69 | // // 回调函数 70 | // resolve(app) 71 | } 72 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/charts/bar.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 66 | 67 | 72 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/charts/index.js: -------------------------------------------------------------------------------- 1 | import ChartPie from './pie.vue' 2 | import ChartBar from './bar.vue' 3 | 4 | export const requireEcharts = () => import(/* webpackChunkName: "echarts" */ 'echarts') 5 | 6 | export { 7 | ChartPie, 8 | ChartBar 9 | } 10 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/charts/pie.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 78 | 83 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/charts/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | "#2d8cf0", 4 | "#19be6b", 5 | "#ff9900", 6 | "#E46CBB", 7 | "#9A66E4", 8 | "#ed3f14" 9 | ], 10 | "backgroundColor": "rgba(0,0,0,0)", 11 | "textStyle": {}, 12 | "title": { 13 | "textStyle": { 14 | "color": "#516b91" 15 | }, 16 | "subtextStyle": { 17 | "color": "#93b7e3" 18 | } 19 | }, 20 | "line": { 21 | "itemStyle": { 22 | "normal": { 23 | "borderWidth": "2" 24 | } 25 | }, 26 | "lineStyle": { 27 | "normal": { 28 | "width": "2" 29 | } 30 | }, 31 | "symbolSize": "6", 32 | "symbol": "emptyCircle", 33 | "smooth": true 34 | }, 35 | "radar": { 36 | "itemStyle": { 37 | "normal": { 38 | "borderWidth": "2" 39 | } 40 | }, 41 | "lineStyle": { 42 | "normal": { 43 | "width": "2" 44 | } 45 | }, 46 | "symbolSize": "6", 47 | "symbol": "emptyCircle", 48 | "smooth": true 49 | }, 50 | "bar": { 51 | "itemStyle": { 52 | "normal": { 53 | "barBorderWidth": 0, 54 | "barBorderColor": "#ccc" 55 | }, 56 | "emphasis": { 57 | "barBorderWidth": 0, 58 | "barBorderColor": "#ccc" 59 | } 60 | } 61 | }, 62 | "pie": { 63 | "itemStyle": { 64 | "normal": { 65 | "borderWidth": 0, 66 | "borderColor": "#ccc" 67 | }, 68 | "emphasis": { 69 | "borderWidth": 0, 70 | "borderColor": "#ccc" 71 | } 72 | } 73 | }, 74 | "scatter": { 75 | "itemStyle": { 76 | "normal": { 77 | "borderWidth": 0, 78 | "borderColor": "#ccc" 79 | }, 80 | "emphasis": { 81 | "borderWidth": 0, 82 | "borderColor": "#ccc" 83 | } 84 | } 85 | }, 86 | "boxplot": { 87 | "itemStyle": { 88 | "normal": { 89 | "borderWidth": 0, 90 | "borderColor": "#ccc" 91 | }, 92 | "emphasis": { 93 | "borderWidth": 0, 94 | "borderColor": "#ccc" 95 | } 96 | } 97 | }, 98 | "parallel": { 99 | "itemStyle": { 100 | "normal": { 101 | "borderWidth": 0, 102 | "borderColor": "#ccc" 103 | }, 104 | "emphasis": { 105 | "borderWidth": 0, 106 | "borderColor": "#ccc" 107 | } 108 | } 109 | }, 110 | "sankey": { 111 | "itemStyle": { 112 | "normal": { 113 | "borderWidth": 0, 114 | "borderColor": "#ccc" 115 | }, 116 | "emphasis": { 117 | "borderWidth": 0, 118 | "borderColor": "#ccc" 119 | } 120 | } 121 | }, 122 | "funnel": { 123 | "itemStyle": { 124 | "normal": { 125 | "borderWidth": 0, 126 | "borderColor": "#ccc" 127 | }, 128 | "emphasis": { 129 | "borderWidth": 0, 130 | "borderColor": "#ccc" 131 | } 132 | } 133 | }, 134 | "gauge": { 135 | "itemStyle": { 136 | "normal": { 137 | "borderWidth": 0, 138 | "borderColor": "#ccc" 139 | }, 140 | "emphasis": { 141 | "borderWidth": 0, 142 | "borderColor": "#ccc" 143 | } 144 | } 145 | }, 146 | "candlestick": { 147 | "itemStyle": { 148 | "normal": { 149 | "color": "#edafda", 150 | "color0": "transparent", 151 | "borderColor": "#d680bc", 152 | "borderColor0": "#8fd3e8", 153 | "borderWidth": "2" 154 | } 155 | } 156 | }, 157 | "graph": { 158 | "itemStyle": { 159 | "normal": { 160 | "borderWidth": 0, 161 | "borderColor": "#ccc" 162 | } 163 | }, 164 | "lineStyle": { 165 | "normal": { 166 | "width": 1, 167 | "color": "#aaa" 168 | } 169 | }, 170 | "symbolSize": "6", 171 | "symbol": "emptyCircle", 172 | "smooth": true, 173 | "color": [ 174 | "#2d8cf0", 175 | "#19be6b", 176 | "#f5ae4a", 177 | "#9189d5", 178 | "#56cae2", 179 | "#cbb0e3" 180 | ], 181 | "label": { 182 | "normal": { 183 | "textStyle": { 184 | "color": "#eee" 185 | } 186 | } 187 | } 188 | }, 189 | "map": { 190 | "itemStyle": { 191 | "normal": { 192 | "areaColor": "#f3f3f3", 193 | "borderColor": "#516b91", 194 | "borderWidth": 0.5 195 | }, 196 | "emphasis": { 197 | "areaColor": "rgba(165,231,240,1)", 198 | "borderColor": "#516b91", 199 | "borderWidth": 1 200 | } 201 | }, 202 | "label": { 203 | "normal": { 204 | "textStyle": { 205 | "color": "#000" 206 | } 207 | }, 208 | "emphasis": { 209 | "textStyle": { 210 | "color": "rgb(81,107,145)" 211 | } 212 | } 213 | } 214 | }, 215 | "geo": { 216 | "itemStyle": { 217 | "normal": { 218 | "areaColor": "#f3f3f3", 219 | "borderColor": "#516b91", 220 | "borderWidth": 0.5 221 | }, 222 | "emphasis": { 223 | "areaColor": "rgba(165,231,240,1)", 224 | "borderColor": "#516b91", 225 | "borderWidth": 1 226 | } 227 | }, 228 | "label": { 229 | "normal": { 230 | "textStyle": { 231 | "color": "#000" 232 | } 233 | }, 234 | "emphasis": { 235 | "textStyle": { 236 | "color": "rgb(81,107,145)" 237 | } 238 | } 239 | } 240 | }, 241 | "categoryAxis": { 242 | "axisLine": { 243 | "show": true, 244 | "lineStyle": { 245 | "color": "#cccccc" 246 | } 247 | }, 248 | "axisTick": { 249 | "show": false, 250 | "lineStyle": { 251 | "color": "#333" 252 | } 253 | }, 254 | "axisLabel": { 255 | "show": true, 256 | "textStyle": { 257 | "color": "#999999" 258 | } 259 | }, 260 | "splitLine": { 261 | "show": true, 262 | "lineStyle": { 263 | "color": [ 264 | "#eeeeee" 265 | ] 266 | } 267 | }, 268 | "splitArea": { 269 | "show": false, 270 | "areaStyle": { 271 | "color": [ 272 | "rgba(250,250,250,0.05)", 273 | "rgba(200,200,200,0.02)" 274 | ] 275 | } 276 | } 277 | }, 278 | "valueAxis": { 279 | "axisLine": { 280 | "show": true, 281 | "lineStyle": { 282 | "color": "#cccccc" 283 | } 284 | }, 285 | "axisTick": { 286 | "show": false, 287 | "lineStyle": { 288 | "color": "#333" 289 | } 290 | }, 291 | "axisLabel": { 292 | "show": true, 293 | "textStyle": { 294 | "color": "#999999" 295 | } 296 | }, 297 | "splitLine": { 298 | "show": true, 299 | "lineStyle": { 300 | "color": [ 301 | "#eeeeee" 302 | ] 303 | } 304 | }, 305 | "splitArea": { 306 | "show": false, 307 | "areaStyle": { 308 | "color": [ 309 | "rgba(250,250,250,0.05)", 310 | "rgba(200,200,200,0.02)" 311 | ] 312 | } 313 | } 314 | }, 315 | "logAxis": { 316 | "axisLine": { 317 | "show": true, 318 | "lineStyle": { 319 | "color": "#cccccc" 320 | } 321 | }, 322 | "axisTick": { 323 | "show": false, 324 | "lineStyle": { 325 | "color": "#333" 326 | } 327 | }, 328 | "axisLabel": { 329 | "show": true, 330 | "textStyle": { 331 | "color": "#999999" 332 | } 333 | }, 334 | "splitLine": { 335 | "show": true, 336 | "lineStyle": { 337 | "color": [ 338 | "#eeeeee" 339 | ] 340 | } 341 | }, 342 | "splitArea": { 343 | "show": false, 344 | "areaStyle": { 345 | "color": [ 346 | "rgba(250,250,250,0.05)", 347 | "rgba(200,200,200,0.02)" 348 | ] 349 | } 350 | } 351 | }, 352 | "timeAxis": { 353 | "axisLine": { 354 | "show": true, 355 | "lineStyle": { 356 | "color": "#cccccc" 357 | } 358 | }, 359 | "axisTick": { 360 | "show": false, 361 | "lineStyle": { 362 | "color": "#333" 363 | } 364 | }, 365 | "axisLabel": { 366 | "show": true, 367 | "textStyle": { 368 | "color": "#999999" 369 | } 370 | }, 371 | "splitLine": { 372 | "show": true, 373 | "lineStyle": { 374 | "color": [ 375 | "#eeeeee" 376 | ] 377 | } 378 | }, 379 | "splitArea": { 380 | "show": false, 381 | "areaStyle": { 382 | "color": [ 383 | "rgba(250,250,250,0.05)", 384 | "rgba(200,200,200,0.02)" 385 | ] 386 | } 387 | } 388 | }, 389 | "toolbox": { 390 | "iconStyle": { 391 | "normal": { 392 | "borderColor": "#999" 393 | }, 394 | "emphasis": { 395 | "borderColor": "#666" 396 | } 397 | } 398 | }, 399 | "legend": { 400 | "textStyle": { 401 | "color": "#999999" 402 | } 403 | }, 404 | "tooltip": { 405 | "axisPointer": { 406 | "lineStyle": { 407 | "color": "#ccc", 408 | "width": 1 409 | }, 410 | "crossStyle": { 411 | "color": "#ccc", 412 | "width": 1 413 | } 414 | } 415 | }, 416 | "timeline": { 417 | "lineStyle": { 418 | "color": "#8fd3e8", 419 | "width": 1 420 | }, 421 | "itemStyle": { 422 | "normal": { 423 | "color": "#8fd3e8", 424 | "borderWidth": 1 425 | }, 426 | "emphasis": { 427 | "color": "#8fd3e8" 428 | } 429 | }, 430 | "controlStyle": { 431 | "normal": { 432 | "color": "#8fd3e8", 433 | "borderColor": "#8fd3e8", 434 | "borderWidth": 0.5 435 | }, 436 | "emphasis": { 437 | "color": "#8fd3e8", 438 | "borderColor": "#8fd3e8", 439 | "borderWidth": 0.5 440 | } 441 | }, 442 | "checkpointStyle": { 443 | "color": "#8fd3e8", 444 | "borderColor": "rgba(138,124,168,0.37)" 445 | }, 446 | "label": { 447 | "normal": { 448 | "textStyle": { 449 | "color": "#8fd3e8" 450 | } 451 | }, 452 | "emphasis": { 453 | "textStyle": { 454 | "color": "#8fd3e8" 455 | } 456 | } 457 | } 458 | }, 459 | "visualMap": { 460 | "color": [ 461 | "#516b91", 462 | "#59c4e6", 463 | "#a5e7f0" 464 | ] 465 | }, 466 | "dataZoom": { 467 | "backgroundColor": "rgba(0,0,0,0)", 468 | "dataBackgroundColor": "rgba(255,255,255,0.3)", 469 | "fillerColor": "rgba(167,183,204,0.4)", 470 | "handleColor": "#a7b7cc", 471 | "handleSize": "100%", 472 | "textStyle": { 473 | "color": "#333" 474 | } 475 | }, 476 | "markPoint": { 477 | "label": { 478 | "normal": { 479 | "textStyle": { 480 | "color": "#eee" 481 | } 482 | }, 483 | "emphasis": { 484 | "textStyle": { 485 | "color": "#eee" 486 | } 487 | } 488 | } 489 | } 490 | } 491 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/common-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/count-to/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 175 | 176 | 184 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/icons.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/index.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /generator/templates/default/src/components/info-card/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 55 | 56 | 103 | -------------------------------------------------------------------------------- /generator/templates/default/src/config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | webConfig: { 3 | title: 'Kuaizi™ - 领先的人工智能创意平台', 4 | copyright: 'Copyright © 2013-2018 All Rights Reserved 广州筷子信息科技有限公司' 5 | }, 6 | dev: { 7 | baseURL: '/mock' 8 | }, 9 | prod: { 10 | baseURL: '/' 11 | } 12 | } 13 | 14 | /** 15 | * 获取导航配置数组 16 | * @param {Array} arr 导航配置数组 17 | * @return [{ name: '首页', link: '/', route: true }, ...] 18 | */ 19 | const getNavArr = arr => arr.map(name => ({ 20 | name: `header.nav.${name}`, 21 | // name: name.charAt(0).toUpperCase() + name.substr(1, name.length), 22 | link: `/${name === 'home' ? '' : name}`, 23 | icon: `nav-icon-${name}`, 24 | route: true 25 | })) 26 | 27 | const navigators = ['home', 'manage', 'report', 'system', 'tag', 'content', 'account'] 28 | export const navList = getNavArr(navigators) 29 | 30 | export const webConfig = config.webConfig 31 | export default process.env.NODE_ENV === 'production' ? config.prod : config.dev 32 | -------------------------------------------------------------------------------- /generator/templates/default/src/i18n/en-US.js: -------------------------------------------------------------------------------- 1 | // ^_^,有道翻译!!! 2 | <% if (options['ui-framework'] === 'element-ui') {%> 3 | import en from 'element-ui/lib/locale/lang/en' 4 | <% } %> 5 | <% if (options['ui-framework'] === 'iview') {%> 6 | import en from 'iview/dist/locale/en-US' 7 | <% } %> 8 | export default Object.assign({ 9 | // 站点配置信息 10 | webconfig: { 11 | title: 'Kuaizi™ - Leading artificial intelligence creative platform in real time', 12 | copyright: 'Copyright © 2013-2018 All Rights Reserved by www.kuaiz.ai' 13 | }, 14 | 15 | // 页面头部 16 | header: { 17 | nav: { 18 | home: 'Home', 19 | manage: 'Manage', 20 | report: 'Report', 21 | system: 'System', 22 | tag: 'Tag', 23 | partner: 'Partner', 24 | content: 'Content', 25 | account: 'Account' 26 | }, 27 | profile: { 28 | menu: { 29 | logout: 'Logout' 30 | } 31 | } 32 | }, 33 | 34 | // 首页面板 35 | dashboard: { 36 | newCreation: 'New Creation', 37 | clickTotal: 'Click Total', 38 | newTag: 'New Tag', 39 | shareTotal: 'Share Total', 40 | userAccess: 'User Access', 41 | weekAmountCreation: 'A week on the amount of creativity', 42 | sysLog: 'System Update Log' 43 | }, 44 | 45 | // 按钮 46 | btn: { 47 | login: 'Login', 48 | reset: 'Rest', 49 | logout: 'Logout' 50 | }, 51 | 52 | // 消息 53 | messages: { 54 | loginSuccess: 'Success!', 55 | loginFailed: 'Failed', 56 | logoutSuccess: 'Success!', 57 | logoutFailed: 'Failed!' 58 | }, 59 | 60 | // 登录页 61 | pages: { 62 | login: { 63 | title: 'Advertisers Account', 64 | user: 'User', 65 | password: 'Password' 66 | } 67 | } 68 | }, en) 69 | -------------------------------------------------------------------------------- /generator/templates/default/src/i18n/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | 4 | Vue.use(VueI18n) 5 | 6 | const navLang = navigator.language 7 | const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false 8 | let lang = window.localStorage.lang || localLang || 'zh-CN' 9 | 10 | // 小技巧,定义Vue.config.lang为用户语言环境 11 | Vue.config.lang = lang 12 | 13 | export default new VueI18n({ 14 | // 默认已加载 15 | // locale: 'zh-CN', 16 | fallbackLocale: lang 17 | }) 18 | -------------------------------------------------------------------------------- /generator/templates/default/src/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | <% if (options['ui-framework'] === 'element-ui') {%> 2 | import zh from 'element-ui/lib/locale/lang/zh-CN' 3 | <% } %> 4 | <% if (options['ui-framework'] === 'iview') {%> 5 | import zh from 'iview/dist/locale/zh-CN' 6 | <% } %> 7 | 8 | export default Object.assign({ 9 | // 站点配置信息 10 | webconfig: { 11 | title: 'Kuaizi™ - 领先的人工智能创意平台', 12 | copyright: 'Copyright © 2013-2018 All Rights Reserved 广州筷子信息科技有限公司' 13 | }, 14 | 15 | // 页面头部 16 | header: { 17 | nav: { 18 | home: '首页', 19 | manage: '广告管理', 20 | report: '广告报告', 21 | system: '系统管理', 22 | tag: '分类管理', 23 | partner: '客户管理', 24 | content: '内容管理', 25 | account: '账户中心' 26 | }, 27 | profile: { 28 | menu: { 29 | logout: '退出登录' 30 | } 31 | } 32 | }, 33 | 34 | // 首页面板 35 | dashboard: { 36 | newCreation: '新增创意', 37 | clickTotal: '累计点击', 38 | newTag: '新增标签', 39 | shareTotal: '分享统计', 40 | userAccess: '用户访问来源', 41 | weekAmountCreation: '每周投放创意量', 42 | sysLog: '系统更新日志' 43 | }, 44 | 45 | // 按钮 46 | btn: { 47 | login: '登录', 48 | reset: '重置', 49 | logout: '注销' 50 | }, 51 | 52 | // 消息 53 | messages: { 54 | loginSuccess: '登录成功,欢迎回来!', 55 | loginFailed: '登录失败', 56 | logoutSuccess: '成功注销!', 57 | logoutFailed: '注销失败!' 58 | }, 59 | 60 | // 登录页 61 | pages: { 62 | login: { 63 | title: '广 告 主 账 号', 64 | user: '用户名', 65 | password: '密码' 66 | } 67 | } 68 | }, zh) 69 | -------------------------------------------------------------------------------- /generator/templates/default/src/lib/services/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | import config from '@/config' 4 | 5 | const api = axios.create({ 6 | baseURL: config.baseURL 7 | }) 8 | 9 | api.interceptors.request.use(config => config, err => Promise.reject(err)) 10 | api.interceptors.response.use(({ data: { data, code, message } }) => { 11 | if (code === 0) return data 12 | const failData = { code, message } 13 | return Promise.reject(failData) 14 | }, err => Promise.reject(err)) 15 | 16 | /** 17 | * GET method 18 | * @param {*} url 请求地址 19 | * @param {*} data 查询参数 20 | */ 21 | api.fetch = async config => { 22 | const result = await api(config) 23 | return result 24 | } 25 | 26 | if (!Vue.$http) Vue.$http = api 27 | 28 | export default api 29 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | 28 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/components/common/footer.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/components/common/header.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 116 | 117 | <% if (options['ui-framework'] === 'iview') {%> 118 | 160 | <% } %> 161 | 162 | <% if (options['ui-framework'] === 'element-ui') {%> 163 | 201 | <% } %> 202 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/components/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 需要自动注册组件 3 | */ 4 | 5 | export default {} 6 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/components/language.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 41 | 42 | 56 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/components/layout.vue: -------------------------------------------------------------------------------- 1 | 93 | 94 | 116 | 117 | 185 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 首页 | <%= rootOptions.projectName %> 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import bootstrap from '@/bootstrap' 3 | import Router from '@/router' 4 | import routes from './routes' 5 | import store from './store' 6 | import App from './App' 7 | 8 | // 单页组件 9 | import components from './components' 10 | 11 | // 单页语言配置 12 | import '@/i18n' 13 | 14 | bootstrap({ Router, Component: App, routes, states: store }, app => { 15 | // 批量注册单页全局组件 16 | Object.values(components) 17 | .forEach(component => { 18 | Vue.component(component.name, component) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/routes/index.js: -------------------------------------------------------------------------------- 1 | import { generateRoutes } from '@/router' 2 | const lazyLoader = (path) => () => import(/* webpackChunkName: "view-[request]" */ `../views/${path}`) 3 | 4 | // 一级子路由名称,对应 `./routes/子路由配置.js` 5 | // 确定`./routes`目录存在对应文件,否则require报错 6 | const childRoutesName = ['manage', 'report', 'system'] 7 | // 通过`kz serve --route 子路由1,子路由2` 或 `.env.local` 来定义只访问指定的子路由 8 | // eslint-disable-next-line 9 | const allowRoutes = (process.env.VUE_APP_ALLOW_ROUTES || '').split(',') 10 | const childRoutes = allowRoutes.length && allowRoutes[0] !== '' ? 11 | childRoutesName.filter(route => allowRoutes.includes(route)) 12 | : childRoutesName 13 | // 生成子路由配置 14 | const childRoutesConf = childRoutes.map(name => generateRoutes(require(`./${name}`).default, lazyLoader)).filter(route => route) 15 | 16 | export default [ 17 | '', 18 | 'login', 19 | '*' 20 | ].map(router => { 21 | return { 22 | path: router === '*' ? router : `/${router}`, 23 | component: lazyLoader(router === '' ? 'home': (router === '*' ? '404' : router)), 24 | meta: { 25 | sidebar: ['*', 'login'].includes(router) ? 0 : 1 26 | } 27 | } 28 | }).concat(childRoutesConf) 29 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/routes/manage.js: -------------------------------------------------------------------------------- 1 | export default { 2 | path: 'manage', 3 | name: 'manage', 4 | redirect: '/manage/hello', 5 | children: [ 6 | { 7 | path: 'hello', 8 | name: 'hello', 9 | template: 'manage/hello', 10 | meta: { 11 | title: 'xxxx', 12 | keepAlive: false 13 | }, 14 | children: [ 15 | { 16 | path: 'world', 17 | name: 'world', 18 | redirect: '/manage/hello' 19 | }, 20 | { 21 | path: 'world/:id', 22 | name: 'world', 23 | routeName: 'world', 24 | template: 'manage/world' 25 | } 26 | ] 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/routes/report.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'report', 3 | path: 'report', 4 | meta: { 5 | sidebar: 0 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/routes/system.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'system' 3 | } 4 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/store/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 单页 vuex 配置 3 | */ 4 | 5 | export default {} 6 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/404.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/account.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/home.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 132 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/login.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 109 | 110 | 150 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/manage/hello.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 40 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/manage/index.vue: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/manage/world.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/report.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 130 | -------------------------------------------------------------------------------- /generator/templates/default/src/pages/index/views/system.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /generator/templates/default/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from 'register-service-worker' 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready () { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ) 12 | }, 13 | cached () { 14 | console.log('Content has been cached for offline use.') 15 | }, 16 | updated () { 17 | console.log('New content is available; please refresh.') 18 | }, 19 | offline () { 20 | console.log('No internet connection found. App is running in offline mode.') 21 | }, 22 | error (error) { 23 | console.error('Error during service worker registration:', error) 24 | } 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /generator/templates/default/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import NProgress from 'nprogress' 4 | import 'nprogress/nprogress.css' 5 | 6 | /** 7 | * 生成路由函数 8 | * @param {*} conf 路由配置 9 | * @param {*} parent 父路由名称 10 | */ 11 | export const generateRoutes = (conf, lazyLoader, parent) => { 12 | let result 13 | let path 14 | let name 15 | let componentPath 16 | if (conf) { 17 | path = (parent || '') + '/' + (conf.path || conf.name) 18 | name = parent ? parent + '_' + conf.name : conf.name 19 | componentPath = conf.template ? conf.template : path.replace(/^\//g, '') + (conf.children && conf.children.length > 0 ? '/index' : '') 20 | 21 | result = { 22 | path, 23 | name: conf.routeName || name, 24 | redirect: conf.redirect, 25 | alias: conf.alias, 26 | props: conf.props, 27 | meta: conf.meta, 28 | children: conf.children && conf.children.length > 0 ? conf.children.map(c => generateRoutes(c, lazyLoader, path)) : [], 29 | component: lazyLoader(componentPath) 30 | } 31 | } 32 | return result 33 | } 34 | 35 | export default (store, routes = [], options = {}) => { 36 | Vue.use(VueRouter) 37 | // 默认对路由不验证 38 | options = Object.assign({ validate: true }, options) 39 | 40 | const router = new VueRouter({ 41 | // H5 history 42 | 43 | routes 44 | }) 45 | 46 | // 切换路由之前 47 | router.beforeEach(({ meta, path }, from, next) => { 48 | // 判断是否登录 49 | const { auth = options.validate } = meta 50 | const isLogin = Boolean(store.state.User.uid) 51 | 52 | NProgress.start() 53 | 54 | // 进入下一个路由 55 | if (auth) { 56 | if (!isLogin && path !== '/login') return next({ path: '/login' }) 57 | if (isLogin && path === '/login') return next({ path: '/' }) 58 | next() 59 | } else { 60 | next() 61 | } 62 | }) 63 | 64 | // 切换路由完成 65 | router.afterEach(route => { 66 | NProgress.done() 67 | }) 68 | 69 | return router 70 | } 71 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import plugins from './plugins' 4 | import modules from './modules' 5 | 6 | Vue.use(Vuex) 7 | 8 | const strict = process.env.NODE_ENV !== 'production' 9 | 10 | export default pageModules => { 11 | return new Vuex.Store({ 12 | modules: { 13 | ...modules, 14 | ...pageModules 15 | }, 16 | plugins, 17 | strict 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/modules/Language.js: -------------------------------------------------------------------------------- 1 | import i18n from '@/i18n' 2 | import * as types from '../mutation-type' 3 | 4 | const state = { 5 | locale: '', 6 | loadedLanguages: [] 7 | } 8 | 9 | const actions = { 10 | setSystemLanguage ({ commit, state }, lang) { 11 | if (state.locale !== lang) { 12 | if (!state.loadedLanguages.includes(lang)) { 13 | return import(/* webpackChunkName: "lang-[request]" */ `@/i18n/${lang}`).then(msgs => { 14 | i18n.setLocaleMessage(lang, msgs.default) 15 | commit(types.LANG_CHANGE, lang) 16 | commit(types.LANG_ADD_NEW, lang) 17 | }) 18 | } 19 | commit(types.LANG_CHANGE, lang) 20 | return Promise.resolve(lang) 21 | } 22 | commit(types.LANG_CHANGE, lang) 23 | return Promise.resolve(lang) 24 | } 25 | } 26 | 27 | const mutations = { 28 | [types.LANG_CHANGE] (state, lang) { 29 | i18n.locale = lang 30 | window.localStorage.lang = lang 31 | state.locale = lang 32 | }, 33 | [types.LANG_ADD_NEW] (state, lang) { 34 | state.loadedLanguages.push(lang) 35 | } 36 | } 37 | 38 | export default { 39 | state, 40 | actions, 41 | mutations 42 | } 43 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/modules/User.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import api from 'API' 3 | import * as types from '../mutation-type' 4 | 5 | const state = JSON.parse(window.localStorage.getItem('User')) || {} 6 | 7 | const actions = { 8 | userSignIn ({ commit }, user) { 9 | return api.fetch({ 10 | method: 'post', 11 | url: '/login', 12 | data: user 13 | }).then(data => { 14 | commit(types.USER_SIGN_IN, data) 15 | }) 16 | }, 17 | userSignOut ({ commit }) { 18 | commit(types.USER_SIGN_OUT) 19 | return Promise.resolve(true) 20 | } 21 | } 22 | 23 | const mutations = { 24 | async [types.USER_SIGN_IN] (state, user) { 25 | window.localStorage.setItem('User', JSON.stringify(user)) 26 | Object.assign(state, user) 27 | }, 28 | [types.USER_SIGN_OUT] (state) { 29 | window.localStorage.removeItem('User') 30 | Object.keys(state) 31 | .forEach(item => Vue.delete(state, item)) 32 | } 33 | } 34 | 35 | export default { state, mutations, actions } 36 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/modules/Webconfig.js: -------------------------------------------------------------------------------- 1 | import { webConfig } from '@/config' 2 | 3 | const state = { 4 | ...webConfig 5 | } 6 | 7 | export default { state } 8 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | import User from './User' 2 | import Webconfig from './Webconfig' 3 | import Language from './Language' 4 | 5 | export default { 6 | User, 7 | Webconfig, 8 | Language 9 | } 10 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/mutation-type.js: -------------------------------------------------------------------------------- 1 | // 用户相关 2 | export const USER_SIGN_IN = 'USER_SIGN_IN' 3 | export const USER_SIGN_OUT = 'USER_SIGN_OUT' 4 | 5 | // 语言相关 6 | export const LANG_CHANGE = 'LANG_CHANGE' 7 | export const LANG_ADD_NEW = 'LANG_ADD_NEW' 8 | -------------------------------------------------------------------------------- /generator/templates/default/src/store/plugins.js: -------------------------------------------------------------------------------- 1 | /** 2 | * vuex 日志插件 3 | * by Vincent1993 4 | * https://github.com/Vincent1993/V2EX-mobile/blob/master/src/store/plugins.js 5 | */ 6 | 7 | const plugins = [] 8 | 9 | if (process.env.NODE_ENV !== 'production') { 10 | const createLogger = require('vuex/dist/logger') 11 | 12 | plugins.push(createLogger({ 13 | collapsed: true 14 | })) 15 | } 16 | 17 | export default plugins 18 | -------------------------------------------------------------------------------- /generator/templates/default/vue.config.js: -------------------------------------------------------------------------------- 1 | const glob = require('glob') 2 | const path = require('path') 3 | const resolve = folder => path.resolve(__dirname, folder) 4 | const VUE_APP_ALLOW_ENTRY = process.env.VUE_APP_ALLOW_ENTRY || '' 5 | // 多页面入口路径 6 | const PAGE_PATH = resolve('src/pages') 7 | 8 | /** 9 | * 获取多页面配置对象 10 | */ 11 | function getPagesConfig(entry) { 12 | const pages = {} 13 | // 规范中定义每个单页文件结构 14 | // index.html,main.js,App.vue 15 | glob.sync(PAGE_PATH + '/*/main.js') 16 | .forEach(filePath => { 17 | const pageName = path.basename(path.dirname(filePath)) 18 | if (entry && entry !== pageName) return 19 | pages[pageName] = { 20 | entry: filePath, 21 | // 除了首页,其他按第二级目录输出 22 | // 浏览器中直接访问/news,省去/news.html 23 | fileName: `${pageName === 'index' ? '' : pageName + '/'}index.html`, 24 | template: path.dirname(filePath) + '/index.html', 25 | chunks: ['vue-common', '<%= options['ui-framework'] %>', 'echarts', 'vendors', 'manifest', pageName] 26 | } 27 | }) 28 | return pages 29 | } 30 | 31 | /** 32 | * 样式预处理器全局变量资源插件 33 | * @param {String} rule webpack 规则 34 | */ 35 | function addStyleResource (rule) { 36 | rule.use('style-resource') 37 | .loader('style-resources-loader') 38 | .options({ 39 | patterns: [ 40 | resolve('./src/assets/<%= options.cssPreprocessor%>/var.<%= options.cssPreprocessor%>'), 41 | ], 42 | }) 43 | } 44 | 45 | const pages = getPagesConfig(VUE_APP_ALLOW_ENTRY) 46 | 47 | module.exports = { 48 | 49 | // 多页配置 50 | pages: { 51 | ...pages 52 | // , 53 | // 手动设置单页 54 | // about: 'src/pages/about/main.js' 55 | }, 56 | 57 | // 自定义webpack配置 58 | configureWebpack: { 59 | cache: true, 60 | plugins: [], 61 | performance: { 62 | hints: false 63 | }, 64 | optimization: { 65 | runtimeChunk: process.env.NODE_ENV === 'production' ? { name: 'manifest' } : false, 66 | splitChunks: { 67 | automaticNameDelimiter: '--', 68 | cacheGroups: { 69 | vendors: { 70 | name: 'vendors', 71 | chunks: 'initial', 72 | test: /[\\/]node_modules[\\/]/, 73 | priority: 2 74 | }, 75 | vue: { 76 | name: 'vue-common', 77 | test: (module) => { 78 | return /vue|axios/g.test(module.context) 79 | }, 80 | chunks: 'initial', 81 | priority: 10 82 | }, 83 | '<%= options['ui-framework'] %>': { 84 | name: '<%= options['ui-framework'] %>', 85 | test: module => /<%= options['ui-framework'] %>/g.test(module.context), 86 | chunks: 'initial', 87 | priority: 10 88 | }, 89 | echarts: { 90 | name: 'echarts', 91 | test: module => /echarts/g.test(module.context), 92 | chunks: 'initial', 93 | priority: 10 94 | } 95 | } 96 | } 97 | } 98 | }, 99 | 100 | // 扩展webpack配置 101 | chainWebpack: config => { 102 | // 移除 prefetch 插件 103 | config.plugins.delete('prefetch') 104 | config.plugins.delete('preload') 105 | Object.keys(pages).forEach(page => { 106 | config.plugins.delete(`preload-${page}`) 107 | config.plugins.delete(`prefetch-${page}`) 108 | }) 109 | 110 | config.resolve 111 | .alias 112 | .set('vue$', resolve('./node_modules/vue/dist/vue.common.js')) 113 | .set('assets', resolve('src/assets')) 114 | .set('components', resolve('src/components')) 115 | .set('I18n', resolve('src/i18n')) 116 | .set('View', resolve('src/view')) 117 | .set('Lib', resolve('src/lib')) 118 | .set('API', resolve('src/lib/services')) 119 | 120 | // 添加 css 全局变量资源插件 121 | const types = ['vue-modules', 'vue', 'normal-modules', 'normal'] 122 | types.forEach( 123 | type => addStyleResource(config.module.rule('<%= options.cssPreprocessor%>').oneOf(type)) 124 | ) 125 | }, 126 | 127 | // 开发服务器配置 128 | devServer: { 129 | port: `<%= options['Server Port'] %>`, 130 | proxy: { 131 | '/mock': { 132 | target: 'https://easy-mock.com/mock/5ba83adde786c911a33a5090', 133 | changeOrigin: true, 134 | secure: false, 135 | pathRewrite: { 136 | '/mock': '' 137 | } 138 | } 139 | } 140 | }, 141 | 142 | // 样式 143 | // css: { 144 | // loaderOptions: {} 145 | // } 146 | 147 | // 插件配置 148 | pluginOptions: { 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli-preset-kz", 3 | "version": "0.2.0", 4 | "description": "kuaizi vue app preset with vue-cli-preset", 5 | "main": "preset.json", 6 | "repository": "https://github.com/kuaizi-co/vue-cli-preset-kz.git", 7 | "author": "tomieric ", 8 | "license": "MIT" 9 | } 10 | -------------------------------------------------------------------------------- /preset.json: -------------------------------------------------------------------------------- 1 | { 2 | "useTaobaoRegistry": true, 3 | "git": false, 4 | "useConfigFiles": false, 5 | "plugins": { 6 | "@vue/cli-plugin-babel": {}, 7 | "@vue/cli-plugin-eslint": { 8 | "prompts": true 9 | }, 10 | "@vue/cli-plugin-e2e-nightwatch": {}, 11 | "@vue/cli-plugin-unit-mocha": {} 12 | }, 13 | "router": true, 14 | "vuex": true, 15 | "configs": { 16 | "vue": { 17 | "baseUrl": "./", 18 | "lintOnSave": true, 19 | "productionSourceMap": false 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /prompts.js: -------------------------------------------------------------------------------- 1 | // https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli/lib/promptModules/vuex.js 2 | // module.exports = cli => { 3 | // cli.injectFeature({ 4 | // name: 'cssPreprocessor', 5 | // type: 'list', 6 | // ... 7 | // }) 8 | 9 | // cli.injectPrompt({ 10 | // name: 'routerHistoryMode', 11 | // when: answers => answers.features.includes('router'), 12 | // type: 'confirm', 13 | // ... 14 | // }) 15 | 16 | // cli.onPromptComplete((answers, options) => { 17 | // if (answers.features.includes('router')) { 18 | // options.router = true 19 | // options.routerHistoryMode = answers.routerHistoryMode 20 | // } 21 | // }) 22 | // } 23 | 24 | module.exports = [ 25 | { 26 | name: 'cssPreprocessor', 27 | type: 'list', 28 | message: 'Add support for CSS pre-processors like Sass or Less', 29 | choices: [ 30 | { 31 | name: 'Less', 32 | value: 'less' 33 | }, 34 | { 35 | name: 'Sass/SCSS', 36 | value: 'sass' 37 | } 38 | ], 39 | default: 'less' 40 | }, 41 | { 42 | name: 'Vue Router mode', 43 | type: 'list', 44 | message: 'Choice Vue Router History mode', 45 | choices: [ 46 | { 47 | name: 'Hash', 48 | value: 'hash' 49 | }, 50 | { 51 | name: 'history', 52 | value: 'history' 53 | } 54 | ], 55 | default: 'hash' 56 | }, 57 | { 58 | name: 'Typescript', 59 | type: 'confirm', 60 | message: 'Add support for the TypeScript language (default: None)', 61 | default: false 62 | }, 63 | { 64 | name: 'pwa', 65 | type: 'confirm', 66 | message: 'Progressive Web App (PWA) Support (default: None)', 67 | default: false 68 | }, 69 | { 70 | name: 'SSR', 71 | type: 'list', 72 | message: 'Add support for Server-Side Rendering', 73 | choices: [ 74 | { 75 | name: 'None', 76 | value: 'none' 77 | }, 78 | { 79 | name: 'Nuxt', 80 | value: 'nuxt' 81 | } 82 | // , 83 | // { 84 | // name: 'egg.js', 85 | // value: 'egg' 86 | // } 87 | ], 88 | default: 'none' 89 | }, 90 | { 91 | name: 'ui-framework', 92 | type: 'list', 93 | message: 'choice UI Framework', 94 | choices: [ 95 | { 96 | name: 'iView', 97 | value: 'iview' 98 | }, 99 | { 100 | name: 'Element UI', 101 | value: 'element-ui' 102 | } 103 | ], 104 | default: 'iview' 105 | }, 106 | { 107 | name: 'Mock Server', 108 | type: 'list', 109 | message: 'choice mock server', 110 | choices: [ 111 | { 112 | name: 'Easy Mock', 113 | value: 'easymock' 114 | }, 115 | { 116 | name: 'Kuaizi db', 117 | value: 'kzdb' 118 | } 119 | ], 120 | default: 'easymock' 121 | }, 122 | { 123 | name: 'Server Port', 124 | type: 'input', 125 | message: 'Input DevServer Port(default: 8081)', 126 | default: '8081', 127 | validate: (n) => { 128 | return !isNaN(+n) 129 | } 130 | } 131 | ] 132 | -------------------------------------------------------------------------------- /screenshot/element-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/screenshot/element-ui.png -------------------------------------------------------------------------------- /screenshot/iview-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/screenshot/iview-en.png -------------------------------------------------------------------------------- /screenshot/iview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kuaizi-co/vue-cli-preset-kz/a6b2e54c03901993487c80b55e2a35cb2e65e725/screenshot/iview.png --------------------------------------------------------------------------------