├── static ├── .gitkeep └── image │ ├── iphonex.png │ └── screen │ ├── index.png │ ├── login.png │ ├── article-edit.png │ └── article-list.png ├── src ├── libs │ ├── url.js │ ├── api │ │ ├── index.js │ │ ├── info.js │ │ ├── user.js │ │ └── list.js │ ├── toaster.js │ ├── http.js │ ├── utils.js │ └── mockdata.js ├── assets │ ├── logo.png │ └── css │ │ ├── global.styl │ │ ├── func.styl │ │ └── common.styl ├── views │ ├── list │ │ ├── table-list2.vue │ │ ├── card-list.vue │ │ ├── tree.vue │ │ └── table-list.vue │ ├── app │ │ ├── empty-page.vue │ │ ├── main-content.vue │ │ ├── main-nav.vue │ │ └── login.vue │ ├── article │ │ ├── article-info.vue │ │ ├── article-list.vue │ │ └── article-edit.vue │ ├── map │ │ └── amap.vue │ └── index │ │ └── index.vue ├── main.js ├── components │ ├── app │ │ └── event-calendar.vue │ └── HelloWorld.vue ├── router │ └── index.js └── App.vue ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── .gitignore ├── .editorconfig ├── .prettierrc.json ├── .babelrc ├── .postcssrc.js ├── index.html ├── LICENSE ├── package.json └── README.md /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/libs/url.js: -------------------------------------------------------------------------------- 1 | export default { 2 | apiurl: 'http://127.0.0.1/', 3 | } 4 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/css/global.styl: -------------------------------------------------------------------------------- 1 | @import 'func.styl' 2 | body 3 | font-size f-md 4 | [cloak] 5 | display none -------------------------------------------------------------------------------- /static/image/iphonex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/static/image/iphonex.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | _temp -------------------------------------------------------------------------------- /static/image/screen/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/static/image/screen/index.png -------------------------------------------------------------------------------- /static/image/screen/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/static/image/screen/login.png -------------------------------------------------------------------------------- /static/image/screen/article-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/static/image/screen/article-edit.png -------------------------------------------------------------------------------- /static/image/screen/article-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvgao2012/vue-simple-admin/HEAD/static/image/screen/article-list.png -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/libs/api/index.js: -------------------------------------------------------------------------------- 1 | //引入各种业务的js 2 | import list from "./list.js" 3 | import info from "./info.js" 4 | import user from "./user.js" 5 | export default { 6 | list, 7 | info, 8 | user 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "semi": false, 5 | "tabWidth": 2, 6 | "bracketSpacing": true, 7 | "arrowParens": "always", 8 | "proseWrap": "never" 9 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"] 12 | } 13 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/views/list/table-list2.vue: -------------------------------------------------------------------------------- 1 | 5 | 15 | -------------------------------------------------------------------------------- /src/views/app/empty-page.vue: -------------------------------------------------------------------------------- 1 | 5 | 15 | 18 | -------------------------------------------------------------------------------- /src/libs/api/info.js: -------------------------------------------------------------------------------- 1 | import http from '@/libs/http.js' 2 | const apis = { 3 | getInfo() { 4 | 5 | }, 6 | getInfoB() { 7 | 8 | }, 9 | getArticleInfo() { 10 | return http.get({ 11 | url: 'article/info', 12 | data: { 13 | id: 1 14 | } 15 | }) 16 | } 17 | } 18 | export default apis 19 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-simple-admin 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/css/func.styl: -------------------------------------------------------------------------------- 1 | // 字体颜色 2 | t-white = #fff // 字体 - 白 3 | t-blue = #5093FF // 字体 - 蓝 4 | t-red = #ff3b30 // 字体 - 红 5 | t-green = #15be31 // 字体 - 绿 6 | t-black = #333 // 字体 - 主黑 7 | t-gray = #c1c1c1 // 字体 - 副标题灰 8 | t-border = #e6e6e6 // 默认边框颜色 9 | // 圆角 10 | b-r-xs = 2px 11 | b-r-xs = 3px 12 | b-r = 5px 13 | b-r-xl = 10px 14 | // 字体大小 15 | f-sm = 12px 16 | f-md = 14px 17 | f-xl = 18px 18 | f-lg = 24px 19 | // margin padding 20 | len-mg = 20px 21 | len-pd = 20px -------------------------------------------------------------------------------- /src/libs/api/user.js: -------------------------------------------------------------------------------- 1 | import http from '@/libs/http.js' 2 | const apis = { 3 | getTelCode() { 4 | return http.get({ 5 | url: 'user/getcode', 6 | }) 7 | }, 8 | register(tel, pwd, code) { 9 | return http.post({ 10 | url: 'user/register', 11 | data: { 12 | tel: tel, 13 | pwd: pwd, 14 | code: code 15 | } 16 | }) 17 | }, 18 | login(tel, pwd) { 19 | return http.post({ 20 | url: 'user/login', 21 | data: { 22 | tel: tel, 23 | pwd: pwd, 24 | } 25 | }) 26 | }, 27 | getUserInfo() { 28 | return http.get({ 29 | url: 'user/info', 30 | }) 31 | }, 32 | checkLogin() { 33 | return http.get({ 34 | url: 'user/checklogin', 35 | }) 36 | }, 37 | } 38 | export default apis 39 | -------------------------------------------------------------------------------- /src/views/app/main-content.vue: -------------------------------------------------------------------------------- 1 | 18 | 28 | 37 | -------------------------------------------------------------------------------- /src/libs/api/list.js: -------------------------------------------------------------------------------- 1 | import http from '@/libs/http.js' 2 | const apis = { 3 | getList(psize, pidx) { 4 | return http.get({ 5 | url: 'list/table', 6 | data: { 7 | pageSize: 10, 8 | pageIndex: 1 9 | } 10 | }) 11 | }, 12 | getListB(psize, pidx) { 13 | return http.get({ 14 | url: 'list/b', 15 | data: { 16 | pageSize: 10, 17 | pageIndex: 1 18 | } 19 | }) 20 | }, 21 | getListCard(psize, pidx) { 22 | return http.get({ 23 | url: 'list/card', 24 | data: { 25 | pageSize: 10, 26 | pageIndex: 1 27 | } 28 | }) 29 | }, 30 | getListArticle(psize, pidx) { 31 | return http.get({ 32 | url: 'list/article', 33 | data: { 34 | pageSize: 10, 35 | pageIndex: 1 36 | } 37 | }) 38 | }, 39 | } 40 | export default apis -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 LGGGGG 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 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import router from './router' 4 | import ElementUI from 'element-ui' 5 | import 'element-ui/lib/theme-chalk/index.css' 6 | import 'reset-css' 7 | import '@/assets/css/global.styl' 8 | import '@/assets/css/common.styl' 9 | 10 | 11 | import '@/libs/mockdata.js' 12 | import utils from '@/libs/utils.js' 13 | import api from '@/libs/api/index.js' 14 | import toaster from '@/libs/toaster' 15 | Vue.prototype.$utils = utils 16 | Vue.prototype.$api = api 17 | Vue.prototype.$toaster = toaster 18 | 19 | Vue.use(ElementUI) 20 | 21 | 22 | // 引入vue-amap 23 | import VueAMap from 'vue-amap'; 24 | Vue.use(VueAMap); 25 | // 初始化vue-amap 26 | VueAMap.initAMapApiLoader({ 27 | // 高德的key 28 | key: '7b7631ed1ef64991f5f49156f73a7daf', 29 | // 插件集合 30 | plugin: ['AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar', 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor', 31 | 'AMap.Geocoder', 32 | 'AMap.Geolocation' 33 | ], 34 | // 高德 sdk 版本,默认为 1.4.4 35 | v: '1.4.4' 36 | }); 37 | 38 | 39 | 40 | Vue.config.productionTip = false 41 | /* eslint-disable no-new */ 42 | new Vue({ 43 | el: '#app', 44 | router, 45 | render: (h) => h(App) 46 | }) -------------------------------------------------------------------------------- /src/views/list/card-list.vue: -------------------------------------------------------------------------------- 1 | 19 | 47 | -------------------------------------------------------------------------------- /src/components/app/event-calendar.vue: -------------------------------------------------------------------------------- 1 | 9 | 44 | -------------------------------------------------------------------------------- /src/libs/toaster.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | export default { 3 | message: function (t, m, d, data, cb) { 4 | var options = { 5 | customClass: 'toaster toaster-success', 6 | title: t || '成功', 7 | message: m || '操作成功', 8 | duration: d || 1500, 9 | type: 'success', 10 | onClick: cb, 11 | } 12 | Vue.prototype.$message.success(options) 13 | }, 14 | error: function (t, m, d) { 15 | var options = { 16 | title: t || '错误', 17 | message: `${t} ${m||''}` || '错误消息', 18 | duration: d || 1500, 19 | offset: 120, 20 | type: 'error', 21 | showClose: true, 22 | } 23 | Vue.prototype.$message.error(options) 24 | }, 25 | info: function (t, m, d) { 26 | var options = { 27 | title: t || '操作提示', 28 | message: m || '提示消息', 29 | duration: d || 1500, 30 | type: 'info', 31 | showClose: true, 32 | } 33 | Vue.prototype.$message.info(options) 34 | }, 35 | warn: function (t, m, d) { 36 | var options = { 37 | // customClass: 'toaster toaster-warn', 38 | title: t || '警告', 39 | message: t || '警告消息', 40 | duration: d || 1500, 41 | type: 'warning', 42 | showClose: true, 43 | } 44 | Vue.prototype.$message.warning(options) 45 | }, 46 | ok: function (t, m, d) { 47 | var options = { 48 | title: t || '成功', 49 | message: t || '操作成功', 50 | duration: d || 1500, 51 | type: 'success', 52 | showClose: true, 53 | } 54 | Vue.prototype.$message.success(options) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/assets/css/common.styl: -------------------------------------------------------------------------------- 1 | @import "func.styl" 2 | /* 分页条 */ 3 | .page-bar 4 | text-align right 5 | margin-top len-mg 6 | /* 设置滚动条的样式 */ 7 | /* vue2-scrollbar */ 8 | .vue-scrollbar-transition, .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__scrollbar-horizontal 9 | border-radius 5px 10 | transition all 0.5s ease 11 | -moz-transition all 0.5s ease 12 | -webkit-transition all 0.5s ease 13 | -o-transition all 0.5s ease 14 | .vue-scrollbar-transition--scrollbar 15 | transition opacity 0.5s linear 16 | -moz-transition opacity 0.5s linear 17 | -webkit-transition opacity 0.5s linear 18 | -o-transition opacity 0.5s linear 19 | .vue-scrollbar__wrapper 20 | margin 0 auto 21 | overflow hidden 22 | position relative 23 | height 100% 24 | // background: white; 25 | .vue-scrollbar__wrapper:hover .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__wrapper:hover .vue-scrollbar__scrollbar-horizontal 26 | opacity 1 27 | .vue-scrollbar__scrollbar-vertical, .vue-scrollbar__scrollbar-horizontal 28 | opacity 0.5 29 | position absolute 30 | background transparent 31 | .vue-scrollbar__scrollbar-vertical:hover, .vue-scrollbar__scrollbar-horizontal:hover 32 | background rgba(0, 0, 0, 0.3) 33 | .vue-scrollbar__scrollbar-vertical .scrollbar, .vue-scrollbar__scrollbar-horizontal .scrollbar 34 | position relative 35 | background rgba(0, 0, 0, 0.5) 36 | cursor default 37 | .vue-scrollbar__scrollbar-vertical 38 | width 5px 39 | height 100% 40 | top 0 41 | right 0 42 | .vue-scrollbar__scrollbar-vertical .scrollbar 43 | width 5px 44 | .vue-scrollbar__scrollbar-horizontal 45 | height 10px 46 | width 100% 47 | bottom 0 48 | right 0 49 | .vue-scrollbar__scrollbar-horizontal .scrollbar 50 | height 10px -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import emptyPage from '@/views/app/empty-page' 4 | import index from '@/views/index/index' 5 | 6 | //列表 7 | import tableList from '@/views/list/table-list' 8 | import tableList2 from '@/views/list/table-list2' 9 | import cardList from '@/views/list/card-list' 10 | //文章 11 | import articleList from '@/views/article/article-list' 12 | import articleInfo from '@/views/article/article-info' 13 | import articleEdit from '@/views/article/article-edit' 14 | 15 | //地图 16 | import vueamap from '@/views/map/amap.vue' 17 | 18 | Vue.use(Router) 19 | //github-pages 无法使用history模式,开发可使用 20 | export default new Router({ 21 | // mode: 'history', 22 | routes: [{ 23 | path: '/', 24 | base: __dirname, 25 | component: index 26 | }, 27 | { 28 | path: '/index', 29 | component: index 30 | }, 31 | { 32 | path: '/list/table', 33 | component: tableList 34 | }, 35 | { 36 | path: '/list/table2', 37 | component: tableList2 38 | }, 39 | { 40 | path: '/list/card', 41 | component: cardList 42 | }, 43 | { 44 | path: '/article/list', 45 | component: articleList 46 | }, 47 | { 48 | path: '/article/edit/:id', 49 | component: articleEdit 50 | }, 51 | { 52 | path: '/article/info/:id', 53 | component: articleInfo 54 | }, 55 | { 56 | path: '/map/amap', 57 | component: vueamap 58 | }, 59 | { 60 | path: '*', 61 | component: emptyPage 62 | } 63 | ] 64 | }) -------------------------------------------------------------------------------- /src/views/list/tree.vue: -------------------------------------------------------------------------------- 1 | 6 | 82 | -------------------------------------------------------------------------------- /src/views/article/article-info.vue: -------------------------------------------------------------------------------- 1 | 29 | 56 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8088, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | 24 | /** 25 | * Source Maps 26 | */ 27 | 28 | // https://webpack.js.org/configuration/devtool/#development 29 | devtool: 'cheap-module-eval-source-map', 30 | 31 | // If you have problems debugging vue-files in devtools, 32 | // set this to false - it *may* help 33 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 34 | cacheBusting: true, 35 | 36 | cssSourceMap: true 37 | }, 38 | 39 | build: { 40 | // Template for index.html 41 | index: path.resolve(__dirname, '../dist/index.html'), 42 | 43 | // Paths 44 | assetsRoot: path.resolve(__dirname, '../dist'), 45 | assetsSubDirectory: 'static', 46 | assetsPublicPath: './', 47 | 48 | /** 49 | * Source Maps 50 | */ 51 | 52 | productionSourceMap: false, 53 | // https://webpack.js.org/configuration/devtool/#production 54 | devtool: '#source-map', 55 | 56 | // Gzip off by default as many popular static hosts such as 57 | // Surge or Netlify already gzip all static assets for you. 58 | // Before setting to `true`, make sure to: 59 | // npm install --save-dev compression-webpack-plugin 60 | productionGzip: true, 61 | productionGzipExtensions: ['js', 'css'], 62 | 63 | // Run the build command with an extra argument to 64 | // View the bundle analyzer report after build finishes: 65 | // `npm run build --report` 66 | // Set to `true` or `false` to always turn it on or off 67 | bundleAnalyzerReport: process.env.npm_config_report 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/libs/http.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import QS from 'qs' 3 | import Axios from 'axios' 4 | import url from '@/libs/url' 5 | import toaster from '@/libs/toaster' 6 | import utils from '@/libs/utils' 7 | const baseurl = url.apiurl 8 | 9 | // http request 拦截器 10 | Axios.interceptors.request.use( 11 | (config) => { 12 | config.baseURL = baseurl 13 | if (!config['params']) { 14 | config['params'] = {} 15 | } 16 | config.params['token'] = utils.getkey() 17 | config.headers['token'] = utils.getkey() 18 | return config 19 | }, 20 | (err) => { 21 | return Promise.reject(err) 22 | } 23 | ) 24 | 25 | // 添加响应拦截器 26 | Axios.interceptors.response.use( 27 | (res) => { 28 | // 对响应数据做点什么 29 | switch (res.data.code) { 30 | case 200: 31 | return res.data 32 | break 33 | case -100: 34 | Vue.prototype.loginout() 35 | toaster.error('未登录', res.data.msg, 1500) 36 | return Promise.reject(res.data) 37 | break 38 | default: 39 | toaster.error('', res.data.msg, 1500) 40 | return Promise.reject(res.data) 41 | break 42 | } 43 | }, 44 | (error) => { 45 | // 对响应错误做点什么 46 | toaster.error('接口异常', '', 1500) 47 | return Promise.reject(error); 48 | } 49 | ) 50 | export default { 51 | get: (option) => { 52 | var options = { 53 | url: option.url, 54 | timeout: 10000, 55 | method: option.method || 'get', 56 | params: option.data || {}, 57 | success: option.succ || function (res) {}, 58 | error: option.error || function (res) {}, 59 | } 60 | return Axios.request(options) 61 | }, 62 | post: (option) => { 63 | var options = { 64 | url: option.url, 65 | timeout: 10000, 66 | headers: { 67 | 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' 68 | }, 69 | method: option.method || 'post', 70 | data: option.data, 71 | success: option.succ || function (res) {}, 72 | error: option.error || function (res) {} 73 | } 74 | if (option.data && option.data.constructor == FormData) { 75 | options['onUploadProgress'] = option.progress || function (progressEvent) {} 76 | options.headers['Content-Type'] = 'multipart/form-data; charset=utf-8' 77 | } else { 78 | options.data = QS.stringify(options.data) 79 | } 80 | return Axios.request(options) 81 | }, 82 | } 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-simple-admin", 3 | "version": "1.0.0", 4 | "description": "vue-simpole-admin", 5 | "author": "lg <384652119@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.18.0", 14 | "compression-webpack-plugin": "^1.1.11", 15 | "element-ui": "^2.4.5", 16 | "mockjs": "^1.0.1-beta3", 17 | "reset-css": "^4.0.1", 18 | "stylus": "^0.54.5", 19 | "stylus-loader": "^3.0.2", 20 | "vue": "^2.5.2", 21 | "vue-amap": "^0.5.8", 22 | "vue-echarts": "^3.0.9", 23 | "vue-event-calendar": "^1.5.2", 24 | "vue-quill-editor": "^3.0.6", 25 | "vue-router": "^3.0.1", 26 | "vue2-scrollbar": "^0.0.3" 27 | }, 28 | "devDependencies": { 29 | "autoprefixer": "^7.1.2", 30 | "babel-core": "^6.22.1", 31 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 32 | "babel-loader": "^7.1.1", 33 | "babel-plugin-syntax-jsx": "^6.18.0", 34 | "babel-plugin-transform-runtime": "^6.22.0", 35 | "babel-plugin-transform-vue-jsx": "^3.5.0", 36 | "babel-preset-env": "^1.3.2", 37 | "babel-preset-stage-2": "^6.22.0", 38 | "chalk": "^2.0.1", 39 | "copy-webpack-plugin": "^4.0.1", 40 | "css-loader": "^0.28.0", 41 | "extract-text-webpack-plugin": "^3.0.0", 42 | "file-loader": "^1.1.4", 43 | "friendly-errors-webpack-plugin": "^1.6.1", 44 | "html-webpack-plugin": "^2.30.1", 45 | "node-notifier": "^5.1.2", 46 | "optimize-css-assets-webpack-plugin": "^3.2.0", 47 | "ora": "^1.2.0", 48 | "portfinder": "^1.0.13", 49 | "postcss-import": "^11.0.0", 50 | "postcss-loader": "^2.0.8", 51 | "postcss-url": "^7.2.1", 52 | "rimraf": "^2.6.0", 53 | "semver": "^5.3.0", 54 | "shelljs": "^0.7.6", 55 | "uglifyjs-webpack-plugin": "^1.1.1", 56 | "url-loader": "^0.5.8", 57 | "vue-loader": "^13.3.0", 58 | "vue-style-loader": "^3.0.1", 59 | "vue-template-compiler": "^2.5.2", 60 | "webpack": "^3.6.0", 61 | "webpack-bundle-analyzer": "^2.9.0", 62 | "webpack-dev-server": "^2.9.1", 63 | "webpack-merge": "^4.1.0" 64 | }, 65 | "engines": { 66 | "node": ">= 6.0.0", 67 | "npm": ">= 3.0.0" 68 | }, 69 | "browserslist": [ 70 | "> 1%", 71 | "last 2 versions", 72 | "not ie <= 8" 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 76 | 77 | 98 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 85 | 86 | 96 | 97 | 98 | 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-simple-admin 2 | 3 | ## 简介 4 | vue-simple-admin,如其名,做一个简单易上手的后台管理系统。将结合各种组件模拟各种实战场景页面,如登录、富文本、地图、图表、列表展示、详情展示、滚动条、无限加载、轮播、弹窗等等。 5 | 6 | 从简单到复杂,后期将会逐渐提升难度,体验真实战,自己造组件、复杂场景实现、权限控制等等 7 | 8 | mockjs拦截api请求,真实模拟api返回值 9 | 10 | 项目为自由发挥,想到哪做到哪,界面也是随意出比较粗糙,莫嫌丑,从无到有,从有到优,希望小伙伴一起玩耍 11 | 12 | 项目预览:https://lvgao2012.github.io/vue-simple-admin/ 13 | 14 | ## 开发 15 | 个人使用vscode进行开发,配置 editorconfig、prettierrc.json 美化代码缩进、stylus样式、以及js格式,保证风格统一 16 |

17 | 18 |

19 |

20 | 21 |

22 |

23 | 24 |

25 |

26 | 27 |

28 | ## Build Setup 29 | 30 | ``` bash 31 | # install dependencies 32 | npm install 33 | 34 | # serve with hot reload at localhost:8088 35 | npm run dev 36 | 37 | # build for production with minification 38 | npm run build 39 | 40 | # build for production and view the bundle analyzer report 41 | npm run build --report 42 | ``` 43 | 44 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 45 | 46 | ### 文档目录划分 47 | ``` 48 | ├── build // 构建配置 Vue-cli *** 开发忽略 *** 49 | ├── config // 构建配置 Vue-cli *** 开发忽略 *** 50 | ├── dist // 构建命令生成静态资源 *** 开发忽略 *** 51 | ├── node_modules // node 包 *** 开发忽略 *** 52 | ├── index.html // App 首页 53 | ├─src 54 | │ ├── App.vue // 入口组件 55 | | ├── main.js // 入口配置文件 56 | │ ├─assets //文件资源 样式、图片、iconfont图标 57 | │ ├─components // 非View级别组件存放 58 | │ ├─filters // Vue filter 过滤 59 | │ ├─mixins // Vue mixin 混合 60 | │ ├─libs 61 | │ │ api //接口请求 62 | │ │ url.js //api请求地址 63 | │ │ mockdata.js //mock数据构造 64 | │ │ http.js //http请求封装 65 | │ │ toaster.js //弹窗信息 66 | │ │ utils.js //数据验证、公共函数封装 67 | │ ├─store //vuex 后期再用 68 | │ │ └─modules 69 | │ │ user.js //登录信息 70 | │ └─views // App views 路由页面 对应导航 页面级组件 71 | │ ├─app //修改密码、左导航、登录页、顶部条 页面全局使用 72 | │ ├─other //各种页面 73 | └─static //静态资源 不会被编辑 74 | │ update.html //IE浏览器升级提醒 75 | └─image //其他静态资源图片 76 | ``` 77 | -------------------------------------------------------------------------------- /src/libs/utils.js: -------------------------------------------------------------------------------- 1 | export default { 2 | isString: function (str) { 3 | if (typeof str !== 'string') return false 4 | if (str.trim().length < 1) return false 5 | return true 6 | }, 7 | isInt: function (num) { 8 | if (typeof num !== 'number') return false 9 | return /^[0-9]+$/.test(num) 10 | }, 11 | telphone: function (num) { 12 | return /^((\+?[0-9]{1,4})|(\(\+86\)))?(1[0-9])\d{9}$/.test(num) 13 | }, 14 | isEmail: function (str) { 15 | if (!this.isString(str)) return false 16 | return /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/.test(str) 17 | }, 18 | maxLength: function (str, len = 140) { 19 | if (!this.isString(str)) return false 20 | if (str.length >= ~~len) return false 21 | return true 22 | }, 23 | minLength: function (str, len = 1) { 24 | if (!this.isString(str)) return false 25 | if (str.length < ~~len) return false 26 | return true 27 | }, 28 | isMoney: function (num) { 29 | if (!num) return false 30 | return /^[0-9]+(.[0-9]{1,2})?$/.test(num) 31 | }, 32 | isZeroOrNum: function (num) { 33 | if (!num) return false 34 | return /^(0|[1-9][0-9]*)$/.test(num) 35 | }, 36 | isFloatNum: function (num) { 37 | if (!num) return false 38 | return /^(-?\d+)(\.\d+)?$/.test(num) 39 | }, 40 | isID: function (num) { 41 | if (!num) return false 42 | return /^\d{15}|\d{18}$/.test(num) 43 | }, 44 | isAccount: function (account) { 45 | if (!account) return false 46 | return /^[a-zA-Z][a-zA-Z0-9_]{5,13}$/.test(account) 47 | }, 48 | isName: function (str) { 49 | if (!str) return false 50 | return /^[\u4e00-\u9fa5]{0,}$/.test(str) 51 | }, 52 | setCookie(name, value, expireHours) { 53 | var cookieString = name + '=' + escape(value) + '; path=/' 54 | //判断是否设置过期时间 55 | if (expireHours > 0) { 56 | var date = new Date() 57 | date.setTime(date.getTime + expireHours * 3600 * 1000) 58 | cookieString = cookieString + '; expire=' + date.toGMTString() 59 | } 60 | document.cookie = cookieString 61 | }, 62 | getCookie(name) { 63 | var strcookie = document.cookie 64 | var arrcookie = strcookie.split('; ') 65 | for (var i = 0; i < arrcookie.length; i++) { 66 | var arr = arrcookie[i].split('=') 67 | if (arr[0] == name) { 68 | return unescape(arr[1]) 69 | } 70 | } 71 | return '' 72 | }, 73 | delCookie() { 74 | var cookies = document.cookie.split(';') 75 | for (var i = 0; i < cookies.length; i++) { 76 | var cookie = cookies[i] 77 | var eqPos = cookie.indexOf('=') 78 | var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie 79 | document.cookie = name + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT' 80 | } 81 | }, 82 | getuid() { 83 | return this.getCookie('lguid') 84 | }, 85 | getkey() { 86 | return this.getCookie('lgtoken') 87 | }, 88 | } 89 | -------------------------------------------------------------------------------- /src/views/list/table-list.vue: -------------------------------------------------------------------------------- 1 | 62 | 91 | -------------------------------------------------------------------------------- /src/views/app/main-nav.vue: -------------------------------------------------------------------------------- 1 | 55 | 88 | 91 | -------------------------------------------------------------------------------- /src/views/article/article-list.vue: -------------------------------------------------------------------------------- 1 | 68 | 94 | -------------------------------------------------------------------------------- /src/views/article/article-edit.vue: -------------------------------------------------------------------------------- 1 | 64 | 97 | -------------------------------------------------------------------------------- /src/views/app/login.vue: -------------------------------------------------------------------------------- 1 | 61 | 145 | -------------------------------------------------------------------------------- /src/libs/mockdata.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import { 3 | apiurl 4 | } from '@/libs/url.js' 5 | let article = [`

6 | 随着经济的不断发展,人们生活水平的不断提高,人们对物质、文化生活的要求也逐渐提高。越来越多的人在工作之余,和家人、朋友一起相约,走进农村、农田,体验休闲采摘的乐趣。我国幅员辽阔,大多数地区到了冬季,鲜果均已下市,此时只有大棚里的草莓春意盎然,红红的果子挂满“枝头”,不禁让人垂涎欲滴。可常规的地面栽培模式,垄面低,不仅农事操作花工、费时费力,也不适合休闲采摘,且与当前劳动力短缺和老龄化严重冲突;各种架式基质栽培模式确实省工省力,适合休闲观光采摘,但成本太高,广大草莓种植户望而却步。成本问题严重限制了草莓省力化栽培的规模化发展。经过多年的试验研究,我们研发出了一种低成本的省力化栽培架式——超高垄。这里,我就向大家介绍一下这种架式的具体搭建方法和注意事项。 7 |

`, 8 | `

9 | 一、明晰几个概念 10 |

`, 11 | `

12 | 1、什么是超高垄栽培? 13 |

`, 14 | `

15 | 超高垄栽培就是搭建栽培槽和挖深沟形成超高垄,然后将土壤、基质或两者混合物回填到栽培槽内,进行草莓生产的一种栽培方式。 16 |

`, 17 | `

18 | 2、什么是栽培槽? 19 |

`, 20 | `

21 | 栽培槽就是用于盛装土壤和基质的凹槽,由热镀锌钢管、螺纹钢、铁丝和控根器等搭建而成。 22 |

`, 23 | `

24 | 3、什么是过道? 25 |

`, 26 | `

27 | 过道就是两架栽培槽之间的地方,方便采摘或田间管理。 28 |

`, 29 | `

30 | 31 |

`, 32 | `

33 | (超高垄栽培) 34 |

`, 35 | `

36 | 二、搭建方法 37 |

`, 38 | `

39 | 第一步:放样 40 |

`, 41 | `

42 | 在大棚的两端放样,栽培槽宽度35cm,槽间距80~90cm。以草莓大棚宽度的中点作为栽培槽的中点,向两边各量出17.5cm,就是将来的栽培槽。在栽培槽两边分别留出80cm,就是将来的过道,以后依次放样。6米跨度大棚可以做5条栽培槽,过道80~90cm,8米跨度大棚可以做7条栽培槽,过道80cm。 43 |

`, 44 | `

45 | 第二步:做栽培槽 46 |

`, 47 | `

48 | 1、打边柱支撑 49 |

`, 50 | `

51 | 用1.3m长的6分镀锌管,平行对应固定2排立柱,横向间隔35cm,纵向间距25m,1.3m长的直径1cm钢筋棍或12mm直径的螺纹钢、6分镀锌钢管,纵向间距1m,分别垂直打入地下8cm,地上净高50cm,与6分镀锌管共同组成栽培槽边柱。 52 |

`, 53 | `

54 | 55 |

`, 56 | `

57 | (打边柱支撑) 58 |

`, 59 | `

60 | 2、拉热镀锌铁丝 61 |

`, 62 | `

63 | 用14#或16#热镀锌铁丝从立柱的一端拉到另一端,每排边柱拉4层14#或16#热镀锌铁丝,每层14#或16#热镀锌铁丝间隔10cm,底部和顶端的2层铁丝要各空出5cm,中间再平均分布2层铁丝。 64 |

`, 65 | `

66 | 67 |

`, 68 | `

69 | (拉铁丝) 70 |

`, 71 | `

72 | 第三步:埋置预埋件 73 |

`, 74 | `

75 | 在每排立柱的延长线上50cm处,挖50cm深坑,砖块上绑扎12#热镀锌铁丝埋入坑中,露出地面1cm,通过花蓝螺栓与栽培槽两端的立柱连接,以调节松紧;在预埋砖块的位置加1根钢管立柱,包住花蓝螺栓。 76 |

`, 77 | `

78 | 79 |

`, 80 | `

81 | 第四步:做控根器围挡 82 |

`, 83 | `

84 | 用规格为50cm高的控根器贴着边柱和铁丝的内壁围起来,两端分别将控根器折成直角,接头用控根器扣子扣起来,围成栽培槽;并让出花篮螺栓,方便调节。 85 |

`, 86 | `

87 | 88 |

`, 89 | `

90 | (做控根器围挡) 91 |

`, 92 | `

93 | 第五步:横向加固 94 |

`, 95 | `

96 | 栽培槽每根立柱上间距20cm横向加固两道12#热镀锌铁丝。 97 |

`, 98 | `

99 | 第六步:挖沟填土 100 |

`, 101 | `

102 | 过道的土挖出,回填到栽培槽;也可用土与基质混合填槽。视是否使用基质混合装填情况,向下挖20~30cm的土壤,与50cm高的栽培槽共同构成70~90cm超高垄。 103 |

`, 104 | `

105 | 106 |

`, 107 | `

108 | (挖沟填土) 109 |

`, 110 | `

111 | 第七步:安装滴水管 112 |

`, 113 | `

114 | 与地面安装地水管不同的是,每条栽培槽上要多加一根50cm长的主管,1个三通、1个弯头和1个堵头,把滴水管到抬高到垄面上。其他安装相同。 115 |

`, 116 | `

117 | 滴管安装好后超高垄架式已经搭建完成,下一步就可以栽苗了,其他管理与地面栽培管理大致相同,可参考地面管理技术。略有不同的是,亩用苗数5500~6000株,与常规栽培相比亩减少用苗840~1100株。 118 |

`, 119 | `

120 | 121 |

`, 122 | `

123 | (安装滴水管) 124 |

`, 125 | `

126 | 三、注意事项 127 |

`, 128 | `

129 | 草莓超高垄架式搭建简单,成本较低,根据当地市场价格不同,每亩成本在1~1.2万元,与搭建普通高架相比成本降低4~5万元; 130 |

`, 131 | `

132 | 搭建和田间管理操作简单、易学。但在搭建过程中,还有几点特别需要注意的事项,在这里跟大家唠叨唠叨,请务必注意! 133 |

`, 134 | `

135 | 1、这种架式适合在地势高燥、平整的土地搭建,易水淹的田块慎用! 136 |

`, 137 | `

138 | 2、搭建的时候垄的方向宜选择接受光照均匀的南北方向。 139 |

`, 140 | `

141 | 3、栽培槽不宜宽于或窄于35cm。过宽基质用量大,空间利用率低;过窄行间距小,植株密不透风,通风透光性差,植株易感病。 142 |

`, 143 | `

144 | 4、栽培槽不宜过长。每条栽培槽长度在50m以内为宜。过长易欠压而导致水分管理不便。 145 |

`, 146 | `

147 | 5、做栽培槽的铁丝不要粗,14#或16#热镀锌铁丝就足以,粗了反而收不紧,铁丝一定要收紧才有力。 148 |

`, 149 | `

150 | 6、横向加固的铁丝一定要略粗些才有劲。哪怕加固1道铁丝也要加固,否则易起鼓或向一边倾斜。 151 |

`, 152 | `

153 | 7、这条是最重要的一条,千万千万要注意的是:在挖土装填土壤或基质的时候, 154 | 一定要离开边柱10cm左右开挖,主要是考虑控根器是塑料制品,固定能力欠佳。如果紧贴柱脚开挖的话,土壤装填时会导致土壤垮塌; 155 | 土壤或基质填满后,切记要沉实!沉实!再沉实!最好结合菜籽饼、微生物菌肥等基肥一起施入。最终垄面要略高于架面,呈面包形。 156 |

` 157 | ] 158 | //使用正则表达式匹配,消除query参数拼接导致无法匹配到 159 | Mock.mock(new RegExp('list/table'), 'get', { 160 | code: 200, 161 | data: { 162 | 'list|10': [{ 163 | id: '@increment', 164 | name: '@cname', 165 | birthday: '@date', 166 | 'sex|1': ['男', '女'], 167 | address: '@county(true)', 168 | headurl: 'http://placekitten.com/g/100/100', 169 | }], 170 | total: '@integer(100,200)' 171 | } 172 | }) 173 | Mock.mock(new RegExp('list/card'), 'get', { 174 | code: 200, 175 | data: { 176 | 'list|20': [{ 177 | id: '@increment', 178 | name: '@cname', 179 | birthday: '@date', 180 | 'sex|1': ['男', '女'], 181 | address: '@county(true)', 182 | headurl: 'http://placekitten.com/g/300/400', 183 | }], 184 | total: '@integer(100,200)' 185 | } 186 | }) 187 | Mock.mock(new RegExp('list/article'), 'get', { 188 | code: 200, 189 | data: { 190 | 'list|10': [{ 191 | id: '@increment', 192 | title: '@ctitle(15,30)', 193 | context: '@cparagraph', 194 | createTime: '@date', 195 | 'sex|1': ['男', '女'], 196 | cover: 'http://placekitten.com/g/320/240', 197 | }], 198 | total: '@integer(100,200)' 199 | } 200 | }) 201 | Mock.mock(new RegExp('article/info'), 'get', { 202 | code: 200, 203 | data: { 204 | id: '@increment', 205 | title: '@ctitle(15,30)', 206 | content: () => { 207 | let idx = Mock.Random.integer(1, article.length - 15) 208 | return article.slice(idx, idx + 15).join('') 209 | }, 210 | 'type|1': [ 211 | '新闻', '生活', '社会', '娱乐', '财经' 212 | ], 213 | date: '@date', 214 | subtitle: '@cparagraph', 215 | author: '@cname', 216 | cover: 'http://placekitten.com/g/320/240', 217 | } 218 | }) 219 | 220 | //用户登录注册信息 221 | Mock.mock(new RegExp('user/getcode'), { 222 | code: 200, 223 | }) 224 | Mock.mock(new RegExp('user/register'), 'post', { 225 | code: 200, 226 | }) 227 | Mock.mock(new RegExp('user/login'), 'post', { 228 | code: 200, 229 | data: { 230 | token: 'faosifhoasfaslkdfaj' 231 | } 232 | }) 233 | Mock.mock(new RegExp('user/info'), { 234 | code: 200, 235 | data: { 236 | name: '@cname', 237 | } 238 | }) 239 | Mock.mock(new RegExp('user/checklogin'), { 240 | code: 200, 241 | data: { 242 | login: true 243 | } 244 | }) 245 | -------------------------------------------------------------------------------- /src/views/map/amap.vue: -------------------------------------------------------------------------------- 1 | 58 | 210 | -------------------------------------------------------------------------------- /src/views/index/index.vue: -------------------------------------------------------------------------------- 1 | 85 | 219 | 242 | --------------------------------------------------------------------------------