├── static ├── .gitkeep └── assets │ └── img │ ├── logo.png │ └── background-1.jpg ├── src ├── store │ ├── getters.js │ ├── actions.js │ ├── index.js │ ├── mutation-types.js │ └── modules │ │ ├── storage.js │ │ ├── user.js │ │ └── layout.js ├── assets │ └── logo.png ├── views │ ├── layout │ │ ├── abstract.vue │ │ ├── breadcrumb.vue │ │ ├── tabs.vue │ │ ├── ceiling.vue │ │ ├── css │ │ │ └── layout.css │ │ └── sidebar.vue │ ├── index.vue │ ├── home │ │ └── home.vue │ ├── profile │ │ └── profile.vue │ ├── login.vue │ ├── table │ │ └── table.vue │ └── user │ │ ├── user-list.vue │ │ └── new-user-list.vue ├── components │ ├── form-type │ │ ├── index.js │ │ └── image.vue │ ├── table │ │ ├── expandRow.vue │ │ ├── operation.vue │ │ └── searchCriteria.vue │ ├── info-card │ │ └── infoCard.vue │ ├── Hello.vue │ ├── echarts │ │ ├── pieChart.vue │ │ ├── shadowChart.vue │ │ ├── gaugeChart.vue │ │ └── lineChart.vue │ ├── edit-modal │ │ ├── editModal.vue │ │ └── editFormItem.vue │ └── base │ │ ├── baseView.vue │ │ └── baseView.js ├── styles │ ├── common.less │ └── dark.theme.css ├── App.vue ├── api │ ├── shop.js │ └── user.api.js ├── libs │ ├── qiniu.js │ ├── util.js │ └── httpUtil.js ├── main.js ├── plugins │ └── logger.js └── router │ └── index.js ├── .eslintignore ├── gifs └── iadmin.gif ├── config ├── prod.env.js ├── dev.env.js └── index.js ├── docs ├── static │ ├── assets │ │ └── img │ │ │ ├── logo.png │ │ │ └── background-1.jpg │ ├── fonts │ │ ├── ionicons.05acfdb.woff │ │ ├── ionicons.24712f6.ttf │ │ └── ionicons.2c2ae06.eot │ └── js │ │ ├── manifest.d02a66532530d0778726.js │ │ └── app.913abfd9f36004fe6b4f.js └── index.html ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── index.html ├── .babelrc ├── README.md ├── .eslintrc.js ├── LICENSE └── package.json /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/store/getters.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /gifs/iadmin.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/gifs/iadmin.gif -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /static/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/static/assets/img/logo.png -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"', 3 | BASE_URL: '"http://localhost:8090"' 4 | } 5 | -------------------------------------------------------------------------------- /docs/static/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/docs/static/assets/img/logo.png -------------------------------------------------------------------------------- /static/assets/img/background-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/static/assets/img/background-1.jpg -------------------------------------------------------------------------------- /docs/static/assets/img/background-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/docs/static/assets/img/background-1.jpg -------------------------------------------------------------------------------- /docs/static/fonts/ionicons.05acfdb.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/docs/static/fonts/ionicons.05acfdb.woff -------------------------------------------------------------------------------- /docs/static/fonts/ionicons.24712f6.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/docs/static/fonts/ionicons.24712f6.ttf -------------------------------------------------------------------------------- /docs/static/fonts/ionicons.2c2ae06.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TonyLuo/iview-vue-admin/HEAD/docs/static/fonts/ionicons.2c2ae06.eot -------------------------------------------------------------------------------- /.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/views/layout/abstract.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | *.sln 14 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"', 6 | BASE_URL: '"http://localhost:8090"' 7 | }) 8 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | // to edit target browsers: use "browserslist" field in package.json 6 | "autoprefixer": {} 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/store/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | 3 | export const addToCart = ({commit}, product) => { 4 | if (product.inventory > 0) { 5 | commit(types.ADD_TO_CART, { 6 | id: product.id 7 | }) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iview-vue-admin 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/form-type/index.js: -------------------------------------------------------------------------------- 1 | import ImageItem from './image.vue' 2 | 3 | const formType = { 4 | install: function (Vue) { //核心部分,在我们使用Vue.use()时,自动调用的是install,而install导出的必须是的组件 5 | Vue.component('imageItem', ImageItem); 6 | } 7 | }; 8 | export default formType; 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-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/styles/common.less: -------------------------------------------------------------------------------- 1 | @import '~iview/src/styles/index.less'; 2 | 3 | @font-size-base: 14px; 4 | @font-size-small: 14px; 5 | //@background-color-base: #fbfdff; // base 6 | //@table-td-stripe-bg: #fbfdff; 7 | .align-middle { 8 | position: relative; 9 | top: 50%; 10 | text-align: center; 11 | -webkit-transform: translateY(-50%); 12 | -ms-transform: translateY(-50%); 13 | transform: translateY(-50%); 14 | } 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | iview-vue-admin 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import * as actions from './actions' 4 | import * as getters from './getters' 5 | import createLogger from '../plugins/logger' 6 | 7 | import storage from './modules/storage' 8 | import layout from './modules/layout' 9 | import user from './modules/user' 10 | 11 | Vue.use(Vuex) 12 | 13 | const debug = process.env.NODE_ENV !== 'production' 14 | export default new Vuex.Store({ 15 | actions, 16 | getters, 17 | modules: { 18 | storage, 19 | layout, 20 | user 21 | }, 22 | strict: debug, 23 | plugins: debug ? [createLogger()] : [] 24 | }) 25 | -------------------------------------------------------------------------------- /src/views/layout/breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 15 | 19 | 34 | -------------------------------------------------------------------------------- /src/api/shop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Mocking client-server processing 3 | */ 4 | const _products = [ 5 | {'id': 1, 'title': 'iPad 4 Mini', 'price': 500.01, 'inventory': 2}, 6 | {'id': 2, 'title': 'H&M T-Shirt White', 'price': 10.99, 'inventory': 10}, 7 | {'id': 3, 'title': 'Charli XCX - Sucker CD', 'price': 19.99, 'inventory': 5} 8 | ] 9 | 10 | export default { 11 | getProducts (cb) { 12 | setTimeout(() => cb(_products), 100) 13 | }, 14 | 15 | buyProducts (products, cb, errorCb) { 16 | setTimeout(() => { 17 | // simulate random checkout failure. 18 | (Math.random() > 0.5 || navigator.userAgent.indexOf('PhantomJS') > -1) 19 | ? cb() 20 | : errorCb() 21 | }, 100) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = 'ADD_TO_CART' 2 | 3 | 4 | //util 5 | export const SET_STORAGE = 'SET_STORAGE' 6 | 7 | // layout 8 | export const INIT_LAYOUT = 'INIT_LAYOUT' 9 | export const SET_LAYOUT_STATUS = 'SET_LAYOUT_STATUS' 10 | export const SET_MENU_LIST = 'SET_MENU_LIST' 11 | export const SET_TAB_LIST = 'SET_TAB_LIST' 12 | export const ADD_TAB = 'ADD_TAB' 13 | export const OPEN_TAB = 'OPEN_TAB' 14 | export const REMOVE_TAB = 'REMOVE_TAB' 15 | export const SET_OPENED_TAB_LIST = 'SET_OPENED_TAB_LIST' 16 | export const SET_CURRENT_PATH = 'SET_CURRENT_PATH' 17 | export const SET_OPENED_MENU_LIST = 'SET_OPENED_MENU_LIST' 18 | 19 | //user 20 | export const SET_USER = 'SET_USER' 21 | export const CLEAR_USER = 'CLEAR_USER' 22 | export const SET_USER_TOKEN = 'SET_USER_TOKEN' 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/store/modules/storage.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types'; 2 | const state = { 3 | storage: sessionStorage 4 | }; 5 | // getters 6 | const getters = { 7 | storage : state => { 8 | return state.storage 9 | } 10 | } 11 | const actions = { 12 | changeStorage: function({commit}, rememberMe) { 13 | localStorage.setItem('rememberMe', rememberMe); 14 | // localStorage.removeItem("rememberMe"); //undefined 15 | 16 | commit(types.SET_STORAGE, rememberMe); 17 | } 18 | }; 19 | 20 | const mutations = { 21 | [types.SET_STORAGE]: (state, rememberMe) => { 22 | if (rememberMe) { 23 | state.storage = localStorage; 24 | } else { 25 | state.storage = sessionStorage; 26 | } 27 | } 28 | }; 29 | export default { 30 | state, 31 | getters, 32 | mutations, 33 | actions 34 | }; 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iview-vue-admin 2 | 3 | > iView Vue Admin 4 | 5 | ## Live Demo: 6 | - [https://tonyluo.github.io/iview-vue-admin](https://tonyluo.github.io/iview-vue-admin) 7 | 8 | ![image](https://github.com/TonyLuo/iview-vue-admin/blob/master/gifs/iadmin.gif) 9 | 10 | 11 | 12 | ## Build Setup 13 | 14 | ``` bash 15 | # install dependencies 16 | npm install 17 | 18 | # serve with hot reload at localhost:8080 19 | npm run dev 20 | 21 | # build for production with minification 22 | npm run build 23 | 24 | # build for production and view the bundle analyzer report 25 | npm run build --report 26 | ``` 27 | 28 | ## Links 29 | 30 | - [Vue](https://github.com/vuejs/vue) 31 | - [Webpack](https://github.com/webpack/webpack) 32 | - [iView](https://github.com/iview/) 33 | 34 | ## License 35 | [MIT](http://opensource.org/licenses/MIT) 36 | 37 | This project is built base on iview@2.x, some code is from the iview official demo 38 | 39 | Copyright (c) 2017-present, Tony Luo 40 | -------------------------------------------------------------------------------- /src/components/table/expandRow.vue: -------------------------------------------------------------------------------- 1 | 6 | 26 | 41 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | module.exports = { 3 | "root": true, 4 | extends: [ 5 | // 'eslint:recommended', 6 | 'plugin:vue/recommended' // or 'plugin:vue/base' 7 | ], 8 | rules: { 9 | // override/add rules' settings here 10 | // 'vue/valid-v-if': 'error' 11 | } 12 | } 13 | 14 | // 15 | // module.exports = { 16 | // root: true, 17 | // parser: 'babel-eslint', 18 | // parserOptions: { 19 | // sourceType: 'module' 20 | // }, 21 | // env: { 22 | // browser: true, 23 | // }, 24 | // // https://github.com/standard/standard/blob/master/docs/RULES-en.md 25 | // extends: 'standard', 26 | // // required to lint *.vue files 27 | // plugins: [ 28 | // 'html' 29 | // ], 30 | // // add your custom rules here 31 | // 'rules': { 32 | // // allow paren-less arrow functions 33 | // 'arrow-parens': 0, 34 | // // allow async-await 35 | // 'generator-star-spacing': 0, 36 | // // allow debugger during development 37 | // 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 38 | // } 39 | // } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 TonyLuo 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/libs/qiniu.js: -------------------------------------------------------------------------------- 1 | import httpUtil from './httpUtil' 2 | 3 | export default 4 | { 5 | getToken () { 6 | return JSON.parse(localStorage.getItem('upload_token')) 7 | }, 8 | hasValidToken () { 9 | const token = this.getToken(); 10 | return token && token.expires_at && token.expires_at > new Date().getTime() 11 | }, 12 | getUploadToken () { 13 | if (this.hasValidToken()) { 14 | return Promise.resolve(this.getToken()) 15 | } 16 | return new Promise((resolve, reject) => { 17 | httpUtil.fetch({ 18 | url: '/qiniu/get-upload-token', 19 | method: 'get' 20 | }).then(response => { 21 | const token = response.data.upload_token; 22 | const domainName = response.data.domain_name; 23 | let expiredAt = new Date(); 24 | expiredAt.setSeconds(expiredAt.getSeconds() + response.data.expires_in); 25 | const uploadToken = {token: token, domain_name: domainName, expires_at: expiredAt.getTime()}; 26 | localStorage.setItem('upload_token', JSON.stringify(uploadToken)); 27 | resolve(uploadToken) 28 | }).catch(err => { 29 | reject(err) 30 | }) 31 | }) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/components/info-card/infoCard.vue: -------------------------------------------------------------------------------- 1 | 19 | 46 | 61 | -------------------------------------------------------------------------------- /docs/static/js/manifest.d02a66532530d0778726.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,i){for(var u,a,f,s=0,l=[];s 2 | @import "../../styles/common.less"; 3 | 4 | .operation-icon { 5 | color: @primary-color; 6 | padding: 5px; 7 | text-align: center; 8 | cursor: pointer; 9 | } 10 | 11 | .operation-icon:hover { 12 | color: @warning-color; 13 | } 14 | 15 | 36 | 60 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: './', 11 | productionSourceMap: false, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | autoOpenBrowser: true, 28 | assetsSubDirectory: 'static', 29 | assetsPublicPath: '/', 30 | proxyTable: {}, 31 | // CSS Sourcemaps off by default because relative paths are "buggy" 32 | // with this option, according to the CSS-Loader README 33 | // (https://github.com/webpack/css-loader#sourcemaps) 34 | // In our experience, they generally work as expected, 35 | // just be aware of this issue when enabling this option. 36 | cssSourceMap: false 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | 34 | 35 | 54 | -------------------------------------------------------------------------------- /src/api/user.api.js: -------------------------------------------------------------------------------- 1 | import httpUtil from '../libs/httpUtil' 2 | 3 | export default { 4 | url: '/users/', 5 | list (params) { 6 | let options = httpUtil.createQueryOption(params); 7 | return httpUtil.fetch({ 8 | url: this.url + 'all' + options, 9 | method: 'get' 10 | }); 11 | }, 12 | fetchData (params) { 13 | let options = httpUtil.createQueryOption(params); 14 | return httpUtil.fetch({ 15 | url: this.url + 'all' + options, 16 | method: 'get' 17 | }); 18 | }, 19 | create (data) { 20 | return httpUtil.fetch({ 21 | url: `${this.url}/register`, 22 | method: 'post', 23 | data 24 | }); 25 | }, 26 | update (data) { 27 | return httpUtil.fetch({ 28 | url: this.url, 29 | method: 'put', 30 | data 31 | }); 32 | }, 33 | find (id) { 34 | return httpUtil.fetch({ 35 | url: this.url + encodeURIComponent(id), 36 | method: 'get' 37 | }); 38 | }, 39 | delete (id) { 40 | return httpUtil.fetch({ 41 | url: `${this.url}/delete/${id}`, 42 | method: 'delete' 43 | }); 44 | }, 45 | advancedSearch(searchStr, params) { 46 | let options = httpUtil.createQueryOption(params); 47 | return httpUtil.fetch({ 48 | url: this.url + 'adv/' + encodeURIComponent(searchStr) + options, 49 | method: 'get' 50 | }); 51 | }, 52 | login (data) { 53 | return httpUtil.fetch({ 54 | url: '/authenticate', 55 | method: 'post', 56 | data 57 | }) 58 | }, 59 | getUserInfo(){ 60 | return httpUtil.fetch({ 61 | url: '/account', 62 | method: 'get' 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/views/layout/tabs.vue: -------------------------------------------------------------------------------- 1 | 14 | 21 | 70 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import VueRouter from 'vue-router' 5 | import Vuex from 'vuex' 6 | 7 | import iView from 'iview' 8 | import 'iview/dist/styles/iview.css' 9 | import App from './App' 10 | import store from './store' 11 | // import util from './libs/util' 12 | import {checkPermission} from './libs/util' 13 | 14 | import {routers} from './router' 15 | 16 | import formType from './components/form-type' 17 | 18 | Vue.use(VueRouter) 19 | Vue.use(Vuex) 20 | Vue.use(iView) 21 | Vue.use(formType) 22 | 23 | Vue.config.productionTip = false 24 | 25 | 26 | function guardRoute(route, redirect, next) { 27 | if (store.getters.token) { 28 | next() 29 | } else { 30 | next({path: '/login', query: {redirect: redirect.fullPath}}); 31 | } 32 | // if(checkPermission(route)){ 33 | // next() 34 | // }else{ 35 | // redirect('/login') 36 | // } 37 | // if (window.confirm(`Navigate to ${route.path}?`)) { 38 | // next() 39 | // } else if (window.confirm(`Redirect to /baz?`)) { 40 | // redirect('/baz') 41 | // } 42 | } 43 | 44 | // 路由配置 45 | const RouterConfig = { 46 | mode: 'hash', 47 | routes: routers 48 | } 49 | const router = new VueRouter(RouterConfig) 50 | 51 | router.beforeEach((route, redirect, next) => { 52 | iView.LoadingBar.start() 53 | // util.title(route.meta.title) 54 | 55 | if (route.matched.some(m => m.meta.auth)) { 56 | guardRoute(route, redirect, next) 57 | } else { 58 | next() 59 | } 60 | }) 61 | 62 | router.afterEach((to, from, next) => { 63 | iView.LoadingBar.finish() 64 | window.scrollTo(0, 0) 65 | }) 66 | 67 | /* eslint-disable no-new */ 68 | new Vue({ 69 | el: '#app', 70 | store, 71 | router, 72 | template: '', 73 | components: {App} 74 | }) 75 | -------------------------------------------------------------------------------- /src/components/echarts/pieChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 68 | -------------------------------------------------------------------------------- /src/plugins/logger.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | // Credits: borrowed code from fcomb/redux-logger 3 | 4 | import { deepCopy } from '../libs/util' 5 | 6 | export default function createLogger ({ 7 | collapsed = true, 8 | filter = (mutation, stateBefore, stateAfter) => true, 9 | transformer = state => state, 10 | mutationTransformer = mut => mut 11 | } = {}) { 12 | return store => { 13 | let prevState = deepCopy(store.state) 14 | 15 | store.subscribe((mutation, state) => { 16 | if (typeof console === 'undefined') { 17 | return 18 | } 19 | const nextState = deepCopy(state) 20 | 21 | if (filter(mutation, prevState, nextState)) { 22 | const time = new Date() 23 | const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}` 24 | const formattedMutation = mutationTransformer(mutation) 25 | const message = `mutation ${mutation.type}${formattedTime}` 26 | const startMessage = collapsed 27 | ? console.groupCollapsed 28 | : console.group 29 | 30 | // render 31 | try { 32 | startMessage.call(console, message) 33 | } catch (e) { 34 | console.log(message) 35 | } 36 | 37 | console.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState)) 38 | console.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation) 39 | console.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState)) 40 | 41 | try { 42 | console.groupEnd() 43 | } catch (e) { 44 | console.log('—— log end ——') 45 | } 46 | } 47 | 48 | prevState = nextState 49 | }) 50 | } 51 | } 52 | 53 | function repeat (str, times) { 54 | return (new Array(times + 1)).join(str) 55 | } 56 | 57 | function pad (num, maxLength) { 58 | return repeat('0', maxLength - num.toString().length) + num 59 | } 60 | -------------------------------------------------------------------------------- /src/views/layout/ceiling.vue: -------------------------------------------------------------------------------- 1 | 25 | 58 | 80 | -------------------------------------------------------------------------------- /src/views/layout/css/layout.css: -------------------------------------------------------------------------------- 1 | /* Generic layout rules 2 | */ 3 | body { 4 | margin: 0; 5 | -webkit-text-size-adjust: 100%; 6 | } 7 | 8 | .page { 9 | left: 0; 10 | right: 0; 11 | top: 0; 12 | bottom: 0; 13 | } 14 | 15 | .row, .col, .page { 16 | overflow: hidden; 17 | position: absolute; 18 | } 19 | 20 | .row { 21 | left: 0; 22 | right: 0; 23 | } 24 | 25 | .col { 26 | top: 0; 27 | bottom: 0; 28 | } 29 | .left.col { 30 | width: 200px; 31 | } 32 | 33 | .right.col { 34 | left: 200px; 35 | right: 0; 36 | } 37 | 38 | .header.row { 39 | height: 40px; 40 | line-height: 40px; 41 | } 42 | .header { 43 | font-size: 1.4em; 44 | } 45 | 46 | .body.row { 47 | top: 75px; 48 | bottom: 0; 49 | } 50 | 51 | /*.footer.row {*/ 52 | /*height: 40px;*/ 53 | /*bottom: 0;*/ 54 | /*line-height: 40px;*/ 55 | /*!*opacity:0.7;*!*/ 56 | /*!*filter:Alpha(opacity=70); !* IE8 以及更早的浏览器 *!*!*/ 57 | /*}*/ 58 | .floating-right { 59 | float: right; 60 | transform: rotate(90deg); 61 | } 62 | 63 | .text-alight-left { 64 | text-align: left; 65 | } 66 | 67 | .text-alight-center { 68 | float: none; 69 | text-align: center; 70 | } 71 | 72 | .layout-tabs { 73 | float: left; 74 | padding: 5px 5px 0px 1em; 75 | } 76 | 77 | .layout-breadcrumb { 78 | float: right; 79 | padding: 5px 15px 0; 80 | } 81 | 82 | .scroll-x { 83 | overflow-x: auto; 84 | -webkit-overflow-scrolling: touch; 85 | } 86 | 87 | .scroll-y { 88 | overflow-y: auto; 89 | -webkit-overflow-scrolling: touch; 90 | } 91 | 92 | .fill, .pane { 93 | position: absolute; 94 | left: 0; 95 | top: 0; 96 | right: 0; 97 | bottom: 0; 98 | width: 100%; 99 | height: 100% 100 | } 101 | 102 | .pane { 103 | display: none; 104 | } 105 | 106 | /* Workaround: in landscape mode, IEMobile makes bottom toolbar overlap the page, so shorten the page by 75px to compensate */ 107 | .iemobile .page { 108 | bottom: -6px; 109 | } 110 | 111 | @media screen and (orientation: landscape) { 112 | .iemobile .page { 113 | bottom: 75px; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/components/echarts/shadowChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 71 | -------------------------------------------------------------------------------- /src/views/index.vue: -------------------------------------------------------------------------------- 1 | 36 | 40 | 41 | 74 | -------------------------------------------------------------------------------- /src/styles/dark.theme.css: -------------------------------------------------------------------------------- 1 | /* 2 | refer to http://stevesanderson.github.io/fixed-height-layouts-demo/two-columns.html 3 | */ 4 | 5 | body { 6 | font-family: 'Helvetica Neue', Arial, Sans-Serif; 7 | } 8 | 9 | .header, .footer { 10 | color: #eee; 11 | background: #464c5b; 12 | text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); 13 | padding: 0 0.5em; 14 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #696f77), color-stop(100%, #28343b)); 15 | background: -webkit-linear-gradient(top, #696f77 0%, #28343b 100%); 16 | background: -ms-linear-gradient(top, #696f77 0%, #28343b 100%); 17 | } 18 | 19 | 20 | 21 | .body, .pane { 22 | background: #ddd 23 | } 24 | 25 | /*.right.col { border-left: 1px solid black; }*/ 26 | .right.col .body { 27 | padding: 0 1em; 28 | background: #fff 29 | } 30 | 31 | .left.col .body { 32 | background: #495060; 33 | } 34 | 35 | .listview { 36 | padding: 0; 37 | margin: 0; 38 | font-weight: bold; 39 | color: #444; 40 | } 41 | 42 | .listview li { 43 | list-style-type: none; 44 | background: #eee; 45 | padding: 1em; 46 | border-top: 1px solid #aaa; 47 | border-bottom: 1px solid #fff; 48 | cursor: pointer; 49 | } 50 | 51 | .listview li.selected { 52 | background-color: #37F; 53 | color: White; 54 | } 55 | 56 | .listview.inset { 57 | margin: 1em 0; 58 | } 59 | 60 | .listview.inset li { 61 | background: white; 62 | border: 2px solid #aaa; 63 | border-bottom-width: 0; 64 | } 65 | 66 | .listview.inset li:first-child { 67 | border-radius: 1em 1em 0em 0em 68 | } 69 | 70 | .listview.inset li:last-child { 71 | border-radius: 0em 0em 1em 1em; 72 | border-bottom-width: 2px; 73 | } 74 | 75 | .tiles { 76 | overflow-y: hidden; 77 | } 78 | 79 | .tiles > ul { 80 | width: 1175px; 81 | } 82 | 83 | .tiles ul { 84 | margin: 0; 85 | padding: 0; 86 | white-space: nowrap; 87 | } 88 | 89 | .tiles li { 90 | list-style-type: none; 91 | display: inline-block; 92 | background-color: #080; 93 | width: 150px; 94 | height: 150px; 95 | padding: 1em; 96 | color: White; 97 | margin: 5px; 98 | font-weight: bold; 99 | zoom: 1; 100 | *display: inline; 101 | } 102 | 103 | button { 104 | display: block; 105 | border: 2px solid #aaa; 106 | line-height: normal; 107 | background-color: White; 108 | border-radius: 8px; 109 | margin: 8px 0; 110 | cursor: pointer; 111 | padding: 5px 20px; 112 | font-weight: bold; 113 | color: #333; 114 | } 115 | -------------------------------------------------------------------------------- /src/components/edit-modal/editModal.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 99 | -------------------------------------------------------------------------------- /src/components/echarts/gaugeChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 97 | -------------------------------------------------------------------------------- /src/components/edit-modal/editFormItem.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 89 | -------------------------------------------------------------------------------- /src/components/base/baseView.vue: -------------------------------------------------------------------------------- 1 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iview-vue-admin", 3 | "version": "1.0.0", 4 | "description": "Vue Admin Template bases on iView", 5 | "author": "Tony ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js", 11 | "lint": "eslint --ext .js,.vue src" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git@github.com:TonyLuo/iview-vue-admin.git" 16 | }, 17 | "homepage": "https://github.com/TonyLuo/iview-vue-admin", 18 | "keywords": [ 19 | "vue", 20 | "iview", 21 | "element", 22 | "ui", 23 | "admin", 24 | "vue admin", 25 | "管理", 26 | "后台", 27 | "管理后台", 28 | "后台模板" 29 | ], 30 | "license": "MIT", 31 | "dependencies": { 32 | "axios": "^0.16.2", 33 | "echarts": "^3.7.2", 34 | "iview": "^2.4.0", 35 | "vue": "^2.4.4", 36 | "vue-router": "^2.7.0", 37 | "vuex": "^2.4.1" 38 | }, 39 | "devDependencies": { 40 | "autoprefixer": "^7.1.2", 41 | "babel-core": "^6.22.1", 42 | "babel-eslint": "^7.1.1", 43 | "babel-loader": "^7.1.1", 44 | "babel-plugin-transform-runtime": "^6.22.0", 45 | "babel-preset-env": "^1.3.2", 46 | "babel-preset-es2015": "^6.24.1", 47 | "babel-preset-stage-2": "^6.22.0", 48 | "babel-register": "^6.22.0", 49 | "babel-webpack-plugin": "^0.1.1", 50 | "chalk": "^2.0.1", 51 | "connect-history-api-fallback": "^1.3.0", 52 | "copy-webpack-plugin": "^4.0.1", 53 | "css-loader": "^0.28.0", 54 | "cssnano": "^3.10.0", 55 | "eslint": "^3.19.0", 56 | "eslint-config-standard": "^6.2.1", 57 | "eslint-friendly-formatter": "^3.0.0", 58 | "eslint-loader": "^1.7.1", 59 | "eslint-plugin-html": "^3.0.0", 60 | "eslint-plugin-promise": "^3.4.0", 61 | "eslint-plugin-standard": "^2.0.1", 62 | "eslint-plugin-vue": "^3.13.0", 63 | "eslint-plugin-vuefix": "^0.2.1", 64 | "eventsource-polyfill": "^0.9.6", 65 | "express": "^4.14.1", 66 | "extract-text-webpack-plugin": "^2.0.0", 67 | "file-loader": "^0.11.1", 68 | "friendly-errors-webpack-plugin": "^1.1.3", 69 | "html-webpack-plugin": "^2.28.0", 70 | "http-proxy-middleware": "^0.17.3", 71 | "iview-loader": "^1.0.0-beta.4", 72 | "less": "^2.7.2", 73 | "less-loader": "^4.0.5", 74 | "opn": "^5.1.0", 75 | "optimize-css-assets-webpack-plugin": "^2.0.0", 76 | "ora": "^1.2.0", 77 | "rimraf": "^2.6.0", 78 | "semver": "^5.3.0", 79 | "shelljs": "^0.7.6", 80 | "url-loader": "^0.5.8", 81 | "vue-loader": "^13.0.4", 82 | "vue-style-loader": "^3.0.1", 83 | "vue-template-compiler": "^2.4.2", 84 | "webpack": "^2.6.1", 85 | "webpack-bundle-analyzer": "^2.2.1", 86 | "webpack-dev-middleware": "^1.10.0", 87 | "webpack-hot-middleware": "^2.18.0", 88 | "webpack-merge": "^4.1.0" 89 | }, 90 | "engines": { 91 | "node": ">= 4.0.0", 92 | "npm": ">= 3.0.0" 93 | }, 94 | "browserslist": [ 95 | "> 1%", 96 | "last 2 versions", 97 | "not ie <= 8" 98 | ] 99 | } 100 | -------------------------------------------------------------------------------- /src/views/home/home.vue: -------------------------------------------------------------------------------- 1 | 90 | 91 | 108 | 109 | 114 | -------------------------------------------------------------------------------- /src/components/echarts/lineChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 113 | -------------------------------------------------------------------------------- /src/store/modules/user.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import storage from './storage' 3 | import user from '../../api/user.api' 4 | 5 | const state = { 6 | userDetail: {}, 7 | token: {}, 8 | userId: null 9 | } 10 | // getters 11 | const getters = { 12 | token: state => { 13 | // check whether the token still valid 14 | let strToken = storage.state.storage.getItem('userToken') 15 | let localToken = null 16 | if (strToken) { 17 | localToken = JSON.parse(strToken) 18 | } 19 | let token = localToken || state.token 20 | if (token.expiresTime) { 21 | if (token.expiresTime > new Date().getTime()) { 22 | return token.userToken 23 | } else { 24 | return null 25 | } 26 | } 27 | }, 28 | userDetail: state => { 29 | return state.userDetail 30 | }, 31 | roles: state => { 32 | return state.userDetail.authorities 33 | } 34 | } 35 | 36 | const mutations = { 37 | 38 | [types.SET_USER]: (state, user) => { 39 | if (user) { 40 | state.userDetail = user 41 | state.userId = user.id 42 | storage.state.storage.setItem('userId', user.id) 43 | } 44 | }, 45 | [types.SET_USER_TOKEN]: (state, token) => { 46 | if (token && token.userToken) { 47 | state.token = token 48 | } 49 | 50 | }, 51 | [types.CLEAR_USER]: (state) => { 52 | state.userDetail = {} 53 | state.userId = null 54 | localStorage.clear() 55 | sessionStorage.clear() 56 | } 57 | } 58 | const actions = { 59 | initApp({dispatch, commit}, data) { 60 | dispatch('initUser') 61 | 62 | }, 63 | initUser({dispatch, commit}, data) { 64 | dispatch('initUserToken', data).then(() => { 65 | dispatch('setUser') 66 | }) 67 | }, 68 | setUser({dispatch, commit, state}) { 69 | if (state.token.userToken) { 70 | user.getUserInfo().then(res => { 71 | commit(types.SET_USER, res.data) 72 | 73 | }) 74 | } 75 | 76 | }, 77 | initUserToken({dispatch, commit}, token) { 78 | // get token through backend api 79 | if (token && token.id_token) { 80 | 81 | let now = new Date() 82 | var nowTime = now.getTime()//转化为时间戳毫秒数 83 | let expiresTime = now.setTime(nowTime + 1000 * token.expires_in - 1000 * 60 * 10)//set expires time 10 minutes advanced 设置比真实失效时间提前十分钟 84 | let userToken = {userToken: token.id_token, expiresTime: expiresTime} //转成失效时间 85 | let strToken = JSON.stringify(userToken) //转化为JSON字符串 86 | storage.state.storage.setItem('userToken', strToken) 87 | 88 | commit(types.SET_USER_TOKEN, userToken) 89 | } 90 | else { 91 | // get token from localStorage/sessionStorage 92 | let strToken = storage.state.storage.getItem('userToken') 93 | if (strToken) { 94 | let localToken = JSON.parse(strToken) 95 | if (localToken.expiresTime > new Date().getTime()) { 96 | commit(types.SET_USER_TOKEN, localToken) 97 | 98 | } else { 99 | commit(types.CLEAR_USER) 100 | } 101 | } 102 | 103 | } 104 | }, 105 | 106 | logout({dispatch, commit}) { 107 | commit(types.CLEAR_USER) 108 | 109 | } 110 | 111 | } 112 | 113 | export default { 114 | state, 115 | getters, 116 | mutations, 117 | actions 118 | } 119 | -------------------------------------------------------------------------------- /src/libs/util.js: -------------------------------------------------------------------------------- 1 | import store from '../store' 2 | 3 | /** 4 | * Get the first item that pass the test 5 | * by second argument function 6 | * 7 | * @param {Array} list 8 | * @param {Function} f 9 | * @return {*} 10 | */ 11 | function find (list, f) { 12 | return list.filter(f)[0] 13 | } 14 | 15 | /** 16 | * Deep copy the given object considering circular structure. 17 | * This function caches all nested objects and its copies. 18 | * If it detects circular structure, use cached copy to avoid infinite loop. 19 | * 20 | * @param {*} obj 21 | * @param {Array} cache 22 | * @return {*} 23 | */ 24 | export function deepCopy (obj, cache = []) { 25 | // just return if obj is immutable value 26 | if (obj === null || typeof obj !== 'object') { 27 | return obj 28 | } 29 | 30 | // if obj is hit, it is in circular structure 31 | const hit = find(cache, c => c.original === obj) 32 | if (hit) { 33 | return hit.copy 34 | } 35 | 36 | const copy = Array.isArray(obj) ? [] : {} 37 | // put the copy into cache at first 38 | // because we want to refer it in recursive deepCopy 39 | cache.push({ 40 | original: obj, 41 | copy 42 | }) 43 | 44 | Object.keys(obj).forEach(key => { 45 | copy[key] = deepCopy(obj[key], cache) 46 | }) 47 | 48 | return copy 49 | } 50 | 51 | /** 52 | * forEach for object 53 | */ 54 | export function forEachValue (obj, fn) { 55 | Object.keys(obj).forEach(key => fn(obj[key], key)) 56 | } 57 | 58 | export function isObject (obj) { 59 | return obj !== null && typeof obj === 'object' 60 | } 61 | 62 | export function isPromise (val) { 63 | return val && typeof val.then === 'function' 64 | } 65 | 66 | export function assert (condition, msg) { 67 | if (!condition) throw new Error(`[vuex] ${msg}`) 68 | } 69 | 70 | export function warn (condition, msg) { 71 | if (process.env.NODE_ENV !== 'production'){ 72 | if (condition) console.error(`[Application warn]: ${msg}`) 73 | } 74 | } 75 | 76 | export function formatDate (date) { 77 | if (!date || date === '') return '' 78 | if (typeof date === 'string') { 79 | date = new Date(date) 80 | } 81 | const y = date.getFullYear() 82 | let m = date.getMonth() + 1 83 | m = m < 10 ? '0' + m : m 84 | let d = date.getDate() 85 | d = d < 10 ? ('0' + d) : d 86 | return y + '-' + m + '-' + d 87 | } 88 | 89 | export function checkPermission (item) { 90 | 91 | if (!item.meta || !item.meta.auth) return true // return true if the menu has no access control 92 | 93 | let userRoles = store.getters.roles 94 | if (!(userRoles instanceof Array) || userRoles.length === 0) return false // return false if the user has no role 95 | 96 | if (userRoles && userRoles.indexOf('ROLE_ADMIN') >= 0) return true // administrator has full access 97 | if (item.meta && item.meta.auth) { 98 | if (item.meta.auth instanceof Array) { 99 | return userRoles && userRoles.some(role => item.meta.auth.indexOf(role) > -1) 100 | } else { 101 | return userRoles && userRoles.indexOf(item.meta.auth) > -1 102 | } 103 | } else { 104 | return true 105 | } 106 | } 107 | 108 | let util = {} 109 | 110 | util.title = function (title) { 111 | title = title ? title + ' - Home' : 'iView Admin' 112 | window.document.title = title 113 | } 114 | 115 | export default util 116 | -------------------------------------------------------------------------------- /src/views/layout/sidebar.vue: -------------------------------------------------------------------------------- 1 | 32 | 41 | 106 | -------------------------------------------------------------------------------- /src/views/profile/profile.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 121 | 122 | 127 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Main from '../views/index.vue' 2 | import Abstract from '../views/layout/abstract.vue' 3 | import Home from '../views/home/home.vue' 4 | import Login from '../views/login.vue' 5 | import Profile from '../views/profile/profile.vue' 6 | import UserList from '../views/user/user-list.vue' 7 | import NewUserList from '../views/user/new-user-list.vue' 8 | import Table from '../views/table/table.vue' 9 | 10 | export const loginRouter = { 11 | path: '/login', 12 | name: 'login', 13 | meta: { 14 | title: '登录' 15 | }, 16 | component: Login 17 | } 18 | 19 | export const profileRouter = { 20 | title: '个人设置', 21 | path: '/profile', 22 | name: 'profile', 23 | meta: { 24 | hidden: true, 25 | auth: ['ROLE_USER'] 26 | }, 27 | component: Profile 28 | } 29 | 30 | export const appRouter = [ 31 | { 32 | title: '首页', 33 | path: '/home', 34 | name: 'home', 35 | icon: 'ios-home', 36 | component: Home 37 | }, 38 | { 39 | title: '个人设置', 40 | path: '/profile', 41 | name: 'profile', 42 | meta: { 43 | hidden: true, // set it invisible on sidebar 44 | auth: ['ROLE_USER'] 45 | }, 46 | component: Profile 47 | }, 48 | { 49 | title: '用户管理', 50 | path: '/user', 51 | name: 'user', 52 | icon: 'person', 53 | component: Abstract, 54 | children: [ 55 | { 56 | title: '用户列表', 57 | name: 'usr_list', 58 | path: 'list', 59 | icon: 'ios-people', 60 | component: UserList, 61 | meta: { 62 | auth: ['ROLE_USER'] 63 | } 64 | }, 65 | { 66 | title: '新增用户', 67 | name: 'usr_new', 68 | path: 'new', 69 | icon: 'person-add', 70 | component: NewUserList, 71 | meta: { 72 | auth: ['ROLE_USER'] 73 | } 74 | }, 75 | { 76 | title: '活跃用户', 77 | name: 'usr_activated', 78 | path: 'activated', 79 | icon: 'ios-body', 80 | component: Table 81 | } 82 | ] 83 | }, 84 | { 85 | title: '内容管理', 86 | path: '/content', 87 | name: 'content', 88 | icon: 'ios-paper', 89 | component: Abstract, 90 | meta: { 91 | auth: ['ROLE_ADMIN'] 92 | }, 93 | children: [ 94 | { 95 | title: '文章管理', 96 | name: 'article', 97 | path: 'article', 98 | icon: 'ios-paper', 99 | component: Login 100 | }, 101 | { 102 | title: '评论管理', 103 | name: 'comment', 104 | path: 'comment', 105 | icon: 'images', 106 | component: Table 107 | }, 108 | { 109 | title: '举报管理', 110 | name: 'report', 111 | path: 'report', 112 | icon: 'images', 113 | component: Table 114 | } 115 | ] 116 | 117 | }, 118 | 119 | { 120 | title: '统计分析', 121 | path: '/statistics', 122 | name: 'statistics', 123 | icon: 'stats-bars', 124 | component: Abstract, 125 | children: [ 126 | { 127 | title: '新增和启动', 128 | name: 'stats_new', 129 | path: 'new', 130 | icon: 'ios-paper', 131 | component: Login 132 | }, 133 | { 134 | title: '活跃分析', 135 | name: 'stats_activated', 136 | path: 'activated', 137 | icon: 'images', 138 | component: Table 139 | }, 140 | { 141 | title: '时段分析', 142 | name: 'stats_time', 143 | path: 'time', 144 | icon: 'images', 145 | component: Table 146 | }, 147 | { 148 | title: '用户留存', 149 | name: 'retention', 150 | path: 'retention', 151 | icon: 'images', 152 | component: Table 153 | }, 154 | { 155 | title: '流失用户', 156 | name: 'churn', 157 | path: 'churn', 158 | icon: 'images', 159 | component: Table 160 | } 161 | ] 162 | 163 | } 164 | 165 | ] 166 | 167 | export const mainRouter = { 168 | path: '/', 169 | redirect: '/home', 170 | name: 'index', 171 | component: Main, 172 | children: appRouter 173 | } 174 | 175 | export const routers = [ 176 | loginRouter, 177 | mainRouter, 178 | // catch all redirect 179 | {path: '*', redirect: '/home'} 180 | 181 | ] 182 | 183 | -------------------------------------------------------------------------------- /src/libs/httpUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Tony on 14/06/2017. 3 | */ 4 | import axios from 'axios'; 5 | import store from '../store' 6 | import Notice from 'iview/src/components/notice'; 7 | 8 | axios.defaults.baseURL = `${process.env.BASE_URL}/api` 9 | // http request 拦截器 10 | axios.interceptors.request.use( 11 | config => { 12 | if (store.getters.token) { 13 | config.headers['Authorization'] = `Bearer ${store.getters.token}`; 14 | config.headers['Content-Type'] = 'application/json' 15 | } 16 | return config; 17 | }, 18 | err => { 19 | return Promise.reject(err); 20 | }); 21 | 22 | // http response 拦截器 23 | axios.interceptors.response.use( 24 | response => { 25 | return response; 26 | }, 27 | error => { 28 | if (error.response) { 29 | switch (error.response.status) { 30 | case 400: 31 | if (error.response && error.response.data && error.response.data.message) { 32 | Notice.error( 33 | { 34 | title: error.response.data.message, 35 | duration: 5, 36 | closable: true 37 | } 38 | ) 39 | } 40 | break; 41 | case 401: 42 | // 401 清除token信息 43 | store.dispatch('logout'); 44 | break; 45 | case 403: 46 | Notice.error( 47 | { 48 | title: '没有操作权限', 49 | duration: 5, 50 | closable: true 51 | } 52 | ) 53 | break; 54 | case 500: 55 | Notice.error( 56 | { 57 | title: '服务器出了小问题', 58 | duration: 5, 59 | closable: true 60 | } 61 | ) 62 | break; 63 | 64 | } 65 | } 66 | return Promise.reject(error) 67 | }); 68 | const httpUtil = 69 | { 70 | fetch: axios, 71 | cleanArray: function (actual) { 72 | const newArray = []; 73 | for (let i = 0; i < actual.length; i++) { 74 | if (actual[i]) { 75 | newArray.push(actual[i]); 76 | } 77 | } 78 | return newArray; 79 | }, 80 | createRequestOption: function (params) { 81 | if (!params || params === 'undefined' || params === undefined) return ''; 82 | return this.cleanArray(Object.keys(params).map(key => { 83 | if (!params[key] || params[key] === undefined || params[key] === 'undefined') return ''; 84 | if (key === 'page') { 85 | return encodeURIComponent(key) + '=' + 86 | encodeURIComponent(params[key] - 1); 87 | } 88 | return encodeURIComponent(key) + '=' + 89 | encodeURIComponent(params[key]); 90 | })).join('&'); 91 | }, 92 | createQueryOption: function (params) { 93 | if (!params) { 94 | return '' 95 | } 96 | let options = '?'; 97 | 98 | let {page, size, sortWay} = params; 99 | 100 | if (page && size) { 101 | page--; 102 | options = options + 'page=' + parseInt(page, 10) + '&size=' + parseInt(size, 10); 103 | } 104 | 105 | let sort = null; 106 | if (sortWay) { 107 | let {prop, order} = sortWay; 108 | 109 | if (prop) { 110 | if (order === 'desc') { 111 | order = 'desc'; 112 | sort = prop + ',' + order; 113 | } else if (order === 'asc') { 114 | order = 'asc'; 115 | sort = prop + ',' + order; 116 | } 117 | } 118 | } 119 | if (sort) { 120 | options = options + '&sort=' + sort; 121 | } 122 | return options; 123 | }, 124 | createSearchOption: function (params) { 125 | let options = '?'; 126 | 127 | let {page, size, sortWay} = params; 128 | 129 | if (page && size) { 130 | page--; 131 | options = options + 'page=' + parseInt(page, 10) + '&size=' + parseInt(size, 10); 132 | } 133 | 134 | let sort = null; 135 | if (sortWay) { 136 | let {prop, order} = sortWay; 137 | 138 | if (prop) { 139 | if (order === 'descending') { 140 | order = 'desc'; 141 | } else { 142 | order = 'asc'; 143 | } 144 | sort = prop + ',' + order; 145 | } 146 | } 147 | if (sort) { 148 | options = options + '&sort=' + sort; 149 | } 150 | return options; 151 | } 152 | }; 153 | 154 | export default httpUtil; 155 | -------------------------------------------------------------------------------- /src/views/login.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 68 | 146 | -------------------------------------------------------------------------------- /src/store/modules/layout.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import { checkPermission } from '../../libs/util' 3 | import * as types from '../mutation-types' 4 | import { appRouter } from '../../router' 5 | 6 | // initial state 7 | 8 | const state = { 9 | ready: false, 10 | routers: [], 11 | openedMenuNameList: [], 12 | menuList: [], 13 | tabList: [], 14 | pageOpenedList: [], 15 | currentPath: [], // 面包屑数组 16 | menuTheme: null, // 主题 17 | theme: null 18 | } 19 | 20 | // getters 21 | const getters = { 22 | // TODO filter menuList according to the user role 23 | sidebarMenuList: (state, getters) => { 24 | let menuList = state.menuList.filter(menu => { 25 | 26 | return !(menu.meta && menu.meta.hidden) && checkPermission(menu) 27 | }) 28 | let temMenuList = [] 29 | menuList.forEach(item => { 30 | let menu = Object.assign({}, item) 31 | if (item && item.children) { 32 | menu.children = item.children.filter(child => { 33 | return checkPermission(child) 34 | }) 35 | } 36 | temMenuList.push(menu) 37 | }) 38 | return temMenuList 39 | }, 40 | openedTabList : (state, getters) =>{ 41 | return state.pageOpenedList 42 | } 43 | 44 | } 45 | 46 | // actions 47 | const actions = { 48 | initApp ({dispatch, commit, state}, data) { 49 | dispatch('initLayout').then(() => { 50 | dispatch('setMenuList').then(() => { 51 | dispatch('setTabList').then(() => { 52 | commit(types.SET_LAYOUT_STATUS, true) 53 | }) 54 | }) 55 | }) 56 | }, 57 | 58 | initLayout ({dispatch, commit, state}, data) { 59 | commit(types.INIT_LAYOUT) 60 | }, 61 | setMenuList ({dispatch, commit, state}, data) { 62 | 63 | commit(types.SET_MENU_LIST, appRouter.slice()) 64 | }, 65 | setTabList ({dispatch, commit, state}, data) { 66 | let tabList = [] 67 | state.menuList.map((item) => { 68 | if (item.children) { 69 | tabList.push(...item.children) 70 | } else { 71 | tabList.push(item) 72 | } 73 | }) 74 | commit(types.SET_TAB_LIST, tabList) 75 | }, 76 | setCurrentPath ({dispatch, commit, state}, currentPageName) { 77 | let currentPath = [] 78 | let openedMenuList = state.menuList.filter(menu => { 79 | if (!menu.children) { 80 | return menu.name === currentPageName 81 | } 82 | else { 83 | return menu.children.some((child) => { 84 | if (child.name === currentPageName) { 85 | currentPath.push(child) 86 | } 87 | 88 | return child.name === currentPageName 89 | }) 90 | } 91 | }) 92 | 93 | if (openedMenuList[0] && openedMenuList[0].name !== 'home') { 94 | let currentNode = { 95 | title: openedMenuList[0].title, 96 | // breadcrumb should not show hyperlink if the current node is the parent node 97 | path: openedMenuList[0].children ? '' : openedMenuList[0].path, 98 | name: openedMenuList[0].name 99 | } 100 | currentPath.push(currentNode) 101 | } 102 | 103 | commit(types.SET_CURRENT_PATH, currentPath.reverse()) 104 | 105 | let openedMenuNameList = openedMenuList.map(item => { 106 | return item.name 107 | }) 108 | 109 | commit(types.SET_OPENED_MENU_LIST, openedMenuNameList) 110 | }, 111 | 112 | openTab ({dispatch, commit, state}, menuName) { 113 | let tabOpened = state.pageOpenedList.some(item => { 114 | return item.name === menuName 115 | }) 116 | if (!tabOpened) { 117 | let tab = state.tabList.filter((item) => { 118 | return menuName === item.name 119 | })[0] 120 | commit(types.OPEN_TAB, tab) 121 | 122 | } 123 | }, 124 | removeTab ({dispatch, commit, state}, name) { 125 | let pageOpenedList = state.pageOpenedList.filter(item => { 126 | return item.name !== name 127 | }) 128 | commit(types.SET_OPENED_TAB_LIST, pageOpenedList) 129 | } 130 | } 131 | 132 | // mutations 133 | const mutations = { 134 | [types.SET_MENU_LIST] (state, list) { 135 | state.menuList = list 136 | }, 137 | [types.SET_TAB_LIST] (state, tabList) { 138 | state.tabList.push(...tabList) 139 | 140 | }, 141 | [types.SET_CURRENT_PATH] (state, currentPath) { 142 | state.currentPath = currentPath 143 | }, 144 | 145 | [types.SET_OPENED_MENU_LIST] (state, openedMenuNameList) { 146 | state.openedMenuNameList = openedMenuNameList 147 | }, 148 | [types.OPEN_TAB] (state, tab) { 149 | state.pageOpenedList.push(tab) 150 | 151 | }, 152 | 153 | [types.SET_OPENED_TAB_LIST] (state, pageOpenedList) { 154 | state.pageOpenedList = pageOpenedList 155 | }, 156 | [types.SET_LAYOUT_STATUS] (state, status) { 157 | state.ready = status 158 | 159 | }, 160 | [types.INIT_LAYOUT] (state, name) { 161 | state.pageOpenedList = [appRouter[0]] 162 | state.currentPath = [ 163 | { 164 | title: '首页', 165 | path: '', 166 | name: 'home_index' 167 | } 168 | ] 169 | state.menuTheme = localStorage.menuTheme ? localStorage.menuTheme : 'dark' // 主题 170 | state.theme = localStorage.theme ? localStorage.theme : 'b' 171 | }, 172 | 173 | changeTheme (state, theme) { 174 | state.menuTheme = theme 175 | } 176 | } 177 | 178 | export default { 179 | state, 180 | getters, 181 | actions, 182 | mutations 183 | } 184 | -------------------------------------------------------------------------------- /src/views/table/table.vue: -------------------------------------------------------------------------------- 1 | 16 | 19 | 174 | -------------------------------------------------------------------------------- /src/components/table/searchCriteria.vue: -------------------------------------------------------------------------------- 1 | 86 | 105 | 191 | -------------------------------------------------------------------------------- /src/components/form-type/image.vue: -------------------------------------------------------------------------------- 1 | 44 | 177 | 178 | 250 | -------------------------------------------------------------------------------- /src/views/user/user-list.vue: -------------------------------------------------------------------------------- 1 | 351 | -------------------------------------------------------------------------------- /src/components/base/baseView.js: -------------------------------------------------------------------------------- 1 | import expandRow from '../../components/table/expandRow.vue' 2 | import operation from '../../components/table/operation.vue' 3 | import editModal from '../../components/edit-modal/editModal.vue' 4 | import searchCriteria from '../../components/table/searchCriteria.vue' 5 | import {checkPermission, warn} from '../../libs/util' 6 | 7 | export default { 8 | name: 'baseView', 9 | components: {expandRow, operation, editModal, searchCriteria}, 10 | data() { 11 | return { 12 | //TODO override api, operations, fields, searchOptions in child page 13 | showSelection: false, 14 | showExpand: true, 15 | showOperation: true, 16 | expandColNum: 2, 17 | 18 | api: null, 19 | fields: null, 20 | buttonList: [ 21 | { 22 | name: '创建', 23 | meta: { 24 | type: 'ghost', 25 | iconName: 'plus', 26 | operation: this.onCreate 27 | } 28 | }, 29 | { 30 | name: '删除', 31 | meta: { 32 | type: 'warning', 33 | iconName: 'close', 34 | operation: this.onDeleteSelection 35 | } 36 | }, 37 | ], 38 | operations: { 39 | width: 80, 40 | list: [ 41 | { 42 | name: '编辑', 43 | meta: { 44 | iconName: 'edit', 45 | operation: this.onUpdate 46 | } 47 | }, 48 | { 49 | name: '删除', 50 | meta: { 51 | auth: ['ROLE_ADMIN'], 52 | iconName: 'trash-b', 53 | operation: this.onDelete 54 | } 55 | }] 56 | 57 | }, 58 | searchOptions: { 59 | 60 | simpleSearchOptions: [ 61 | { 62 | name: 'ID', 63 | meta: { 64 | value: '', 65 | type: 'input', 66 | size: 'small', 67 | operation: this.searchById 68 | } 69 | } 70 | ], 71 | advancedSearchOptions: { 72 | operation: this.advancedSearch, 73 | onCancel: this.onRefresh, 74 | list: [ 75 | { 76 | name: '帐号', 77 | field: 'id', 78 | meta: { 79 | value: '', 80 | type: 'input', 81 | size: 'small' 82 | } 83 | } 84 | ] 85 | } 86 | 87 | }, 88 | 89 | //table options 90 | loading: false, 91 | tableData: [], 92 | total: 0, 93 | multipleSelection: null, 94 | 95 | //query options 96 | queryOptions: { 97 | page: 1, 98 | size: 10, 99 | sortWay: null, 100 | queryMethod: null, 101 | queryValue: null 102 | }, 103 | 104 | //edit modal options 105 | editModalStatus: '', 106 | editModalTitleMap: { 107 | update: '编辑', 108 | create: '创建' 109 | }, 110 | editForm: {}, 111 | showEditModal: false, 112 | 113 | deleteOperation: null, 114 | deleteData: null, 115 | deleteConfirmModal: false, 116 | deleteConfirmModalLoading: false, 117 | 118 | } 119 | }, 120 | computed: { 121 | //dynamic generate the table columns based on the user role 122 | tableColumns: function () { 123 | 124 | let preColumns = [] 125 | if (this.showSelection) { 126 | preColumns.push({ 127 | type: 'selection', 128 | width: 60, 129 | align: 'center' 130 | }) 131 | } 132 | if (this.showExpand) { 133 | preColumns.push({ 134 | type: 'expand', 135 | width: 30, 136 | render: (h, params) => { 137 | return h(expandRow, { 138 | props: { 139 | row: params.row, 140 | fields: this.fields, 141 | colNum: this.expandColNum 142 | } 143 | }) 144 | } 145 | }) 146 | } 147 | if (this.showOperation) { 148 | preColumns.push( 149 | { 150 | title: '操作', 151 | key: 'action', 152 | width: this.operations.width, 153 | align: 'center', 154 | render: (h, params) => { 155 | return h(operation, { 156 | props: { 157 | row: params.row, 158 | options: this.operations 159 | } 160 | }) 161 | } 162 | } 163 | ) 164 | } 165 | 166 | this.fields = this.fields.filter(item => { 167 | return checkPermission(item) 168 | }) 169 | let columns = [ 170 | ...preColumns, 171 | ...this.fields.filter(item => { 172 | return !(item.meta && item.meta.hidden) 173 | }) 174 | ] 175 | return columns 176 | }, 177 | }, 178 | methods: { 179 | 180 | checkHideCondition(btn){ 181 | if(typeof btn.meta.hideCondition === 'function'){ 182 | 183 | return btn.meta.hideCondition.call() 184 | }else{ 185 | return btn.meta.hideCondition 186 | } 187 | }, 188 | checkPermit(btn) { 189 | return checkPermission(btn) 190 | }, 191 | checkInitialization() { 192 | warn(this.api === null, '[baseView] api is not initialized properly') 193 | warn(this.fields === null, '[baseView] fields is not initialized properly') 194 | 195 | }, 196 | // table operation 197 | 198 | 199 | onPageChange(page) { 200 | this.queryOptions.page = page 201 | this.fetchData() 202 | }, 203 | 204 | onPageSizeChange(size) { 205 | this.queryOptions.page = 1 206 | this.queryOptions.size = size 207 | this.fetchData() 208 | }, 209 | onFilterChange(value, row) { 210 | return row.activated === value 211 | }, 212 | onSortChange(sortWay) { 213 | this.queryOptions.sortWay = { 214 | prop: sortWay.key, 215 | order: sortWay.order 216 | } 217 | this.fetchData() 218 | }, 219 | onSelectAll(selection) { 220 | 221 | }, 222 | onSelectionChange(selection) { 223 | this.multipleSelection = selection 224 | }, 225 | 226 | // end table operation 227 | 228 | handleResponseData(responseDataPromise) { 229 | 230 | responseDataPromise.then((res) => { 231 | this.tableData = [] 232 | this.total = 0 233 | if (res.data && res.data.content) { 234 | this.tableData = res.data.content 235 | this.total = parseInt(res.data.totalElements, 10) 236 | } 237 | this.loading = false 238 | }).catch(() => { 239 | this.loading = false 240 | this.tableData = [] 241 | this.total = 0 242 | }) 243 | }, 244 | onRefresh() { 245 | this.refresh() 246 | }, 247 | refresh() { 248 | 249 | this.queryOptions.queryMethod = null 250 | this.queryOptions.queryValue = null 251 | this.queryOptions = { 252 | page: 1, 253 | size: 10, 254 | sortWay: null, 255 | queryMethod: null, 256 | queryValue: null 257 | 258 | } 259 | this.fetchData() 260 | }, 261 | 262 | // search criteria operation end 263 | 264 | // row operation 265 | onCreate() { 266 | this.editForm = {} 267 | this.editModalStatus = 'create' 268 | this.openEditModal() 269 | }, 270 | onUpdate(row) { 271 | this.editForm = Object.assign({}, row) // 把clone对象付给editForm,避免editForm未提交form时就已经修改了row的值 272 | this.editModalStatus = 'update' 273 | this.openEditModal() 274 | }, 275 | onDelete(row) { 276 | this.deleteConfirmModal = true 277 | this.deleteOperation = this.delete 278 | this.deleteData = row 279 | 280 | }, 281 | onDeleteSelection() { 282 | if (this.multipleSelection && this.multipleSelection.length > 0) { 283 | this.deleteConfirmModal = true 284 | this.deleteOperation = this.deleteSelection 285 | this.deleteData = this.multipleSelection 286 | } 287 | 288 | 289 | }, 290 | 291 | //row operation end 292 | 293 | // editModal operation 294 | onOK() { 295 | console.log('ok') 296 | if (this.editModalStatus === 'create') { 297 | this.create(this.editForm) 298 | } else { 299 | this.update(this.editForm) 300 | } 301 | }, 302 | onClose() { 303 | console.log('close') 304 | 305 | this.closeEditModal() 306 | }, 307 | onViewModelClose() { 308 | this.showViewModal = false 309 | }, 310 | openEditModal() { 311 | this.showEditModal = true 312 | }, 313 | closeEditModal() { 314 | // console.log('closeEditModal') 315 | this.showEditModal = false 316 | }, 317 | // end editModal operation 318 | onSearchBtnClick() { 319 | this.$set(this.queryOptions, "page", 1) // reset the page to first page which click search button 320 | }, 321 | searchById(value) { 322 | console.log('searchById', value) 323 | }, 324 | advancedSearch(searchStr) { 325 | if (this.api) { 326 | this.queryOptions.queryMethod = this.advancedSearch 327 | this.queryOptions.queryValue = searchStr 328 | this.handleResponseData(this.api.advancedSearch(searchStr, this.queryOptions)) 329 | } 330 | }, 331 | fetchData() { 332 | if (this.api) { 333 | this.loading = true 334 | if (this.queryOptions.queryMethod) { 335 | this.queryOptions.queryMethod(this.queryOptions.queryValue) 336 | } else { 337 | this.handleResponseData(this.api.fetchData(this.queryOptions)) 338 | } 339 | } 340 | 341 | }, 342 | create(data) { 343 | if (this.api) { 344 | this.api.create(data).then((res) => { 345 | this.editForm.id = res.data.id // 新建操作时没有ID,需要把生成的ID传递到editModal,作为ownerId,用于保存图片列表 346 | this.fetchData() 347 | this.closeEditModal() 348 | this.afterCreate(data, res) 349 | this.$Message.info('创建成功') 350 | 351 | }) 352 | } 353 | }, 354 | afterCreate(data, res) { 355 | }, 356 | 357 | update(data) { 358 | if (this.api) { 359 | this.api.update(data).then((res) => { 360 | this.fetchData() 361 | this.closeEditModal() 362 | this.afterUpdate(data, res) 363 | this.$Message.info('编辑成功') 364 | 365 | }) 366 | } 367 | }, 368 | afterUpdate(data, res) { 369 | }, 370 | 371 | del(deleteOperation, deleteData) { 372 | if (deleteOperation) { 373 | this.deleteConfirmModalLoading = true; 374 | 375 | deleteOperation(deleteData).then((res) => { 376 | 377 | this.deleteConfirmModalLoading = false; 378 | this.deleteConfirmModal = false; 379 | this.fetchData() 380 | this.afterDelete(deleteData, res) 381 | this.$Message.info('删除成功') 382 | 383 | 384 | }).catch(error => { 385 | this.deleteConfirmModalLoading = false; 386 | this.deleteConfirmModal = false; 387 | this.$Message.error('删除失败') 388 | 389 | }) 390 | } 391 | else { 392 | this.deleteConfirmModalLoading = false; 393 | this.deleteConfirmModal = false; 394 | } 395 | 396 | }, 397 | delete(row) { 398 | if (this.api && this.api.delete) { 399 | return this.api.delete(row.id) 400 | } else { 401 | return new Promise((resolve, reject) => { 402 | resolve(true) 403 | }) 404 | } 405 | 406 | 407 | }, 408 | deleteSelection(selection) { 409 | if (this.api && this.api.deleteRecordList) { 410 | return this.api.deleteRecordList(selection) 411 | 412 | } else { 413 | return new Promise((resolve, reject) => { 414 | resolve(true) 415 | }) 416 | } 417 | }, 418 | afterDelete(id, res) { 419 | }, 420 | 421 | }, 422 | mounted() { 423 | this.checkInitialization() 424 | this.fetchData() 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /src/views/user/new-user-list.vue: -------------------------------------------------------------------------------- 1 | 72 | 433 | -------------------------------------------------------------------------------- /docs/static/js/app.913abfd9f36004fe6b4f.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{"+ote":function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("Card",{attrs:{padding:0}},[n("div",{staticClass:"info-card-con"},[n("Col",{staticClass:"info-card-icon-con",style:{backgroundColor:t.color,color:"white"},attrs:{span:"8"}},[n("div",{staticClass:"align-middle"},[n("Icon",{attrs:{type:t.iconType,size:t.iconSize}})],1)]),t._v(" "),n("Col",{staticClass:"height-100",attrs:{span:"16"}},[n("div",{staticClass:"align-middle"},[n("p",{staticClass:"info-num",style:{color:t.color}},[t._v(t._s(t.count))]),t._v(" "),n("p",{staticClass:"info-intro-text"},[t._v(t._s(t.message))])])])],1)])},i=[],r={render:a,staticRenderFns:i};e.a=r},"+skl":function(t,e){},"/HA2":function(t,e,n){"use strict";function a(t){n("mLkj")}var i=n("pf6Q"),r=n("rlnd"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,"data-v-a7efe9d0",null);e.a=c.exports},"0mGM":function(t,e,n){"use strict";var a=n("XLwt"),i=n.n(a);e.a={name:"lineChart",props:{chartOptions:Object,chartData:Object},methods:{init:function(){var t={tooltip:{trigger:"axis",axisPointer:{type:"shadow"}},grid:{top:0,left:"2%",right:"4%",bottom:"3%",containLabel:!0},xAxis:{type:"value",boundaryGap:[0,.01]},yAxis:{type:"category",data:["Mon","Tues","Wed","Thur","Fri","Sat","Sun"],nameTextStyle:{color:"#c3c3c3"}},series:[{name:"访问量",type:"bar",data:[{value:453682,name:"Mon",itemStyle:{normal:{color:"#2d8cf0"}}},{value:879545,name:"Tues",itemStyle:{normal:{color:"#2d8cf0"}}},{value:2354678,name:"Wed",itemStyle:{normal:{color:"#2d8cf0"}}},{value:1598403,name:"Thur",itemStyle:{normal:{color:"#2d8cf0"}}},{value:543250,name:"Fri",itemStyle:{normal:{color:"#2d8cf0"}}},{value:1305923,name:"Sat",itemStyle:{normal:{color:"#2d8cf0"}}},{value:1103456,name:"Sun",itemStyle:{normal:{color:"#2d8cf0"}}}]}]},e=i.a.init(document.getElementById("shadowChart"));e.setOption(t),window.addEventListener("resize",function(){e.resize()})}},mounted:function(){this.init()}}},"0qjf":function(t,e){},"1Cr7":function(t,e,n){"use strict";var a=n("EmyP"),i=n("kNo8"),r=n("VU/8"),o=r(a.a,i.a,null,null,null);e.a=o.exports},"2FpH":function(t,e,n){"use strict";function a(t){n("b+xI")}var i=n("E2ai"),r=n("qK4N"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},"35Pi":function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("Table",{attrs:{data:t.tableData1,columns:t.tableColumns1,stripe:""}},[n("div",{staticStyle:{"padding-left":"5px"},attrs:{slot:"footer"},slot:"footer"},[n("Page",{attrs:{total:100,current:1,size:"small",placement:"top","show-elevator":"","show-total":"","show-sizer":""},on:{"on-change":t.changePage,"on-page-size-change":t.changePageSize}})],1)])},i=[],r={render:a,staticRenderFns:i};e.a=r},"4U21":function(t,e){},"6Sia":function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"layout-ceiling"},[n("Dropdown",{staticStyle:{float:"right"},attrs:{placement:"bottom-end"}},[n("Button",{staticStyle:{"margin-top":"-3px","margin-right":"-10px"},attrs:{type:"text"}},[n("Avatar",{staticClass:"avatar",attrs:{shape:"square",src:"https://i.loli.net/2017/08/21/599a521472424.jpg"}})],1),t._v(" "),n("DropdownMenu",{attrs:{slot:"list"},slot:"list"},[n("DropdownItem",[t._v("个人设置")]),t._v(" "),n("DropdownItem",{attrs:{divided:""}},[t._v("退出登录")])],1)],1),t._v(" "),t._m(0)],1)},i=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"layout-ceiling-main align-middle"},[n("a",{attrs:{href:"#/login"}},[t._v("注册登录")]),t._v(" "),n("a",{attrs:{href:"#"}},[t._v("帮助中心")]),t._v(" "),n("a",{attrs:{href:"#"}},[t._v("安全中心")]),t._v(" "),n("a",{attrs:{href:"#"}},[t._v("服务大厅")])])}],r={render:a,staticRenderFns:i};e.a=r},"6f3y":function(t,e,n){"use strict";var a=n("olAT"),i=n("Yp+V"),r=n("VU/8"),o=r(a.a,i.a,null,null,null);e.a=o.exports},"7spQ":function(t,e,n){"use strict";var a=n("XLwt"),i=n.n(a);e.a={name:"lineChart",props:{chartOptions:Object,chartData:Object},methods:{init:function(){var t={title:{text:"",subtext:"",x:"center"},tooltip:{trigger:"item",formatter:"{a}
{b} : {c} ({d}%)"},legend:{orient:"vertical",left:"left",data:["直接访问","邮件营销","联盟广告","视频广告","搜索引擎"]},series:[{name:"访问来源",type:"pie",radius:"55%",center:["50%","60%"],data:[{value:335,name:"直接访问"},{value:310,name:"邮件营销"},{value:234,name:"联盟广告"},{value:135,name:"视频广告"},{value:1548,name:"搜索引擎"}],itemStyle:{emphasis:{shadowBlur:10,shadowOffsetX:0,shadowColor:"rgba(0, 0, 0, 0.5)"}}}]},e=i.a.init(document.getElementById("pieChart"));e.setOption(t),window.addEventListener("resize",function(){e.resize()})}},mounted:function(){this.init()}}},"8J+V":function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{attrs:{id:"app"}},[n("router-view")],1)},i=[],r={render:a,staticRenderFns:i};e.a=r},"8hXn":function(t,e,n){"use strict";function a(t){n("tP1M")}var i=n("Jtis"),r=n("gwrX"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},Ayzd:function(t,e,n){"use strict";var a,i=n("bOdI"),r=n.n(i),o=n("Gu7T"),s=n.n(o),c=n("Du/2"),l=n("YaEn"),u={ready:!1,routers:[],appRouter:[],openedMenuNameList:[],menuList:[],tabList:[],pageOpenedList:[],currentPath:[],menuTheme:null,theme:null},d={},m={initial:function(t,e){var n=t.dispatch,a=t.commit;t.state;n("initLayout").then(function(){n("setMenuList").then(function(){n("setTabList").then(function(){a(c.a,!0)})})})},initLayout:function(t,e){var n=(t.dispatch,t.commit);t.state;n(c.b)},setMenuList:function(t,e){var n=(t.dispatch,t.commit);t.state;n(c.c,l.b.slice())},setTabList:function(t,e){var n=(t.dispatch,t.commit),a=t.state,i=[];a.menuList.map(function(t){t.children?i.push.apply(i,s()(t.children)):i.push(t)}),n(c.d,i)},setCurrentPath:function(t,e){var n=(t.dispatch,t.commit),a=t.state,i=[],r=a.menuList.filter(function(t){return t.children?t.children.some(function(t){return t.name===e&&i.push(t),t.name===e}):t.name===e});if(r[0]&&"home"!==r[0].name){var o={title:r[0].title,path:r[0].children?"":r[0].path,name:r[0].name};i.push(o)}n(c.e,i.reverse());var s=r.map(function(t){return t.name});n(c.f,s)},openTab:function(t,e){var n=(t.dispatch,t.commit),a=t.state;if(!a.pageOpenedList.some(function(t){return t.name===e})){var i=a.tabList.filter(function(t){return e===t.name})[0];n(c.g,i)}},removeTab:function(t,e){var n=(t.dispatch,t.commit),a=t.state,i=a.pageOpenedList.filter(function(t){return t.name!==e});n(c.h,i)}},p=(a={},r()(a,c.c,function(t,e){t.menuList=e}),r()(a,c.d,function(t,e){var n;(n=t.tabList).push.apply(n,s()(e))}),r()(a,c.e,function(t,e){t.currentPath=e}),r()(a,c.f,function(t,e){t.openedMenuNameList=e}),r()(a,c.g,function(t,e){t.pageOpenedList.push(e)}),r()(a,c.h,function(t,e){t.pageOpenedList=e}),r()(a,c.a,function(t,e){t.ready=e}),r()(a,c.b,function(t,e){t.appRouter=l.b.slice(),t.pageOpenedList=[l.b[0]],t.currentPath=[{title:"首页",path:"",name:"home_index"}],t.menuTheme=localStorage.menuTheme?localStorage.menuTheme:"dark",t.theme=localStorage.theme?localStorage.theme:"b"}),r()(a,"changeTheme",function(t,e){t.menuTheme=e}),a);e.a={state:u,getters:d,actions:m,mutations:p}},Blda:function(t,e,n){"use strict";e.a={name:"tabs",props:{},data:function(){return{currentPageName:""}},computed:{itemList:function(){return this.$store.state.layout.pageOpenedList.slice()}},watch:{$route:function(t){this.currentPageName=t.name},currentPageName:function(){var t=this.currentPageName;-1===this.currentPageName&&(t="home"),this.$router.push({name:t})}},methods:{init:function(){this.currentPageName=this.$route.name},handleTabRemove:function(t){this.$store.dispatch("removeTab",t)},linkTo:function(t){this.$router.push({name:t})}},mounted:function(){this.init()}}},CMHJ:function(t,e){},D4CY:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("Tabs",{attrs:{type:"card",closable:"",id:"tabs-nav"},on:{"on-tab-remove":t.handleTabRemove,"on-click":t.linkTo},model:{value:t.currentPageName,callback:function(e){t.currentPageName=e},expression:"currentPageName"}},t._l(t.itemList,function(t,e){return n("TabPane",{key:t.name,attrs:{label:t.title,name:t.name}})}))},i=[],r={render:a,staticRenderFns:i};e.a=r},"Du/2":function(t,e,n){"use strict";n.d(e,"i",function(){return a}),n.d(e,"b",function(){return i}),n.d(e,"a",function(){return r}),n.d(e,"c",function(){return o}),n.d(e,"d",function(){return s}),n.d(e,"g",function(){return c}),n.d(e,"h",function(){return l}),n.d(e,"e",function(){return u}),n.d(e,"f",function(){return d});var a="ADD_TO_CART",i="INIT_LAYOUT",r="SET_LAYOUT_STATUS",o="SET_MENU_LIST",s="SET_TAB_LIST",c="OPEN_TAB",l="SET_OPENED_TAB_LIST",u="SET_CURRENT_PATH",d="SET_OPENED_MENU_LIST"},E2ai:function(t,e,n){"use strict";e.a={}},EmyP:function(t,e,n){"use strict";var a=n("XLwt"),i=n.n(a);e.a={name:"guageChart",props:{chartOptions:Object,chartData:Object},methods:{init:function(){var t=i.a.init(document.getElementById("guageChart"));window.addEventListener("resize",function(){t.resize()});var e={tooltip:{formatter:"{a}
{b} : {c}%"},series:[{name:"入流量",type:"gauge",min:0,max:1e3,detail:{formatter:"{value}Mb+",fontSize:18,offsetCenter:[0,"50px"]},data:[{value:50,name:"当前入流量"}],center:["25%","50%"],radius:"80%",title:{offsetCenter:[0,"80px"]},axisLine:{lineStyle:{width:20}},splitLine:{length:20}},{name:"出流量",type:"gauge",min:0,max:1e3,detail:{formatter:"{value}Mb+",fontSize:18,offsetCenter:[0,"50px"]},data:[{value:50,name:"当前出流量"}],center:["75%","50%"],radius:"80%",title:{offsetCenter:[0,"80px"]},axisLine:{lineStyle:{width:20}},splitLine:{length:20}}]};setInterval(function(){e.series[0].data[0].value=(1e3*Math.random()).toFixed(2)-0,e.series[1].data[0].value=(1e3*Math.random()).toFixed(2)-0,t.setOption(e)},2e3)}},mounted:function(){this.init()}}},GMSx:function(t,e,n){"use strict";function a(t){n("JhYJ")}var i=n("VBKy"),r=n("35Pi"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},"GW+A":function(t,e,n){"use strict";function a(t){n("KGuk")}var i=n("iIXo"),r=n("6Sia"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,"data-v-d3993010",null);e.a=c.exports},IcnI:function(t,e,n){"use strict";var a=n("7+uW"),i=n("NYxO"),r=n("mUbh"),o=n("UjVw"),s=(n("Q0qs"),n("Ayzd"));a.default.use(i.a);e.a=new i.a.Store({actions:r,getters:o,modules:{layout:s.a},strict:!1,plugins:[]})},JhYJ:function(t,e){},Jtis:function(t,e,n){"use strict";var a=n("GW+A"),i=n("jqh9"),r=n("/HA2"),o=n("TVfW");e.a={components:{ceiling:a.a,sidebar:i.a,breadcrumb:r.a,tabs:o.a},data:function(){return{hideSidebarText:!1}},methods:{init:function(){this.$store.dispatch("initial",{})},toggleClick:function(){this.hideSidebarText=!this.hideSidebarText}},watch:{},mounted:function(){this.init()}}},KGuk:function(t,e){},"L+ih":function(t,e){},M93x:function(t,e,n){"use strict";function a(t){n("0qjf")}var i=n("ZWVH"),r=n("8J+V"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},NHnr:function(t,e,n){"use strict";function a(t,e,n){window.confirm("Navigate to "+t.path+"?")?n():window.confirm("Redirect to /baz?")&&e("/baz")}Object.defineProperty(e,"__esModule",{value:!0});var i=n("7+uW"),r=n("/ocq"),o=n("NYxO"),s=n("BTaQ"),c=n.n(s),l=n("+skl"),u=(n.n(l),n("M93x")),d=n("IcnI"),m=n("TVG1"),p=n("YaEn");i.default.use(r.a),i.default.use(o.a),i.default.use(c.a),i.default.config.productionTip=!1;var f={mode:"hash",routes:p.a},h=new r.a(f);h.beforeEach(function(t,e,n){c.a.LoadingBar.start(),m.a.title(t.meta.title),t.matched.some(function(t){return t.meta.needGuard})?a(t,e,n):n()}),h.afterEach(function(t,e,n){c.a.LoadingBar.finish(),window.scrollTo(0,0)}),new i.default({el:"#app",store:d.a,router:h,template:"",components:{App:u.a}})},Q0qs:function(t,e,n){"use strict";function a(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.collapsed,a=void 0===e||e,i=t.filter,s=void 0===i?function(t,e,n){return!0}:i,c=t.transformer,l=void 0===c?function(t){return t}:c,u=t.mutationTransformer,d=void 0===u?function(t){return t}:u;return function(t){var e=n.i(o.b)(t.state);t.subscribe(function(t,i){if("undefined"!=typeof console){var c=n.i(o.b)(i);if(s(t,e,c)){var u=new Date,m=" @ "+r(u.getHours(),2)+":"+r(u.getMinutes(),2)+":"+r(u.getSeconds(),2)+"."+r(u.getMilliseconds(),3),p=d(t),f="mutation "+t.type+m,h=a?console.groupCollapsed:console.group;try{h.call(console,f)}catch(t){console.log(f)}console.log("%c prev state","color: #9E9E9E; font-weight: bold",l(e)),console.log("%c mutation","color: #03A9F4; font-weight: bold",p),console.log("%c next state","color: #4CAF50; font-weight: bold",l(c));try{console.groupEnd()}catch(t){console.log("—— log end ——")}}e=c}})}}function i(t,e){return new Array(e+1).join(t)}function r(t,e){return i("0",e-t.toString().length)+t}e.a=a;var o=n("TVG1")},Quw4:function(t,e,n){"use strict";function a(t){n("4U21")}var i=n("h4S4"),r=n("vMTs"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},TVG1:function(t,e,n){"use strict";function a(t,e){return t.filter(e)[0]}function i(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];if(null===t||"object"!==(void 0===t?"undefined":c()(t)))return t;var n=a(e,function(e){return e.original===t});if(n)return n.copy;var r=Array.isArray(t)?[]:{};return e.push({original:t,copy:r}),o()(t).forEach(function(n){r[n]=i(t[n],e)}),r}e.b=i;var r=n("fZjL"),o=n.n(r),s=n("pFYg"),c=n.n(s),l={};l.title=function(t){t=t?t+" - Home":"iView Admin",window.document.title=t},e.a=l},TVfW:function(t,e,n){"use strict";function a(t){n("pcJj")}var i=n("Blda"),r=n("D4CY"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports},UjVw:function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),n.d(e,"cartProducts",function(){return a});var a=function(t){return t.cart.added.map(function(e){var n=e.id,a=e.quantity,i=t.products.all.find(function(t){return t.id===n});return{title:i.title,price:i.price,quantity:a}})}},V7a7:function(t,e,n){"use strict";e.a={name:"sidebar",props:{theme:{type:String,default:"dark"},hideSidebarText:{type:Boolean,default:!1}},data:function(){return{currentPageName:null,openedMenuList:[]}},computed:{iconSize:function(){return 14},menuList:function(){return this.$store.state.layout.menuList.slice()}},watch:{$route:function(t){this.currentPageName=t.name},currentPageName:function(){var t=this;this.$store.state.layout.ready?this.setCurrentPath():setTimeout(function(){t.setCurrentPath()},100)}},methods:{init:function(){this.currentPageName=this.$route.name},setCurrentPath:function(){var t=this;this.$store.dispatch("openTab",this.currentPageName),this.$store.dispatch("setCurrentPath",this.currentPageName).then(function(){t.openedMenuList=t.$store.state.layout.openedMenuNameList.slice(),t.$nextTick(function(){t.$refs.sideMenu.updateOpened(),t.$refs.sideMenu.updateActiveName()})})},changeMenu:function(t){this.currentPageName=t,this.$router.push({name:t})}},mounted:function(){this.init()}}},VBKy:function(t,e,n){"use strict";e.a={data:function(){var t=this;return{page:1,pageSize:10,tableData1:this.mockTableData1(),tableColumns1:[{title:"名称",key:"name"},{title:"状态",key:"status",render:function(t,e){var n=e.row;return t("Tag",{props:{type:"dot",color:1===n.status?"blue":2===n.status?"green":"red"}},1===n.status?"构建中":2===n.status?"构建完成":"构建失败")}},{title:"画像内容",key:"portrayal",render:function(e,n){return e("Poptip",{props:{trigger:"hover",title:n.row.portrayal.length+"个画像",placement:"bottom"}},[e("Tag",n.row.portrayal.length),e("div",{slot:"content"},[e("ul",t.tableData1[n.index].portrayal.map(function(t){return e("li",{style:{textAlign:"center",padding:"4px"}},t)}))])])}},{title:"选定人群数",key:"people",render:function(e,n){return e("Poptip",{props:{trigger:"hover",title:n.row.people.length+"个客群",placement:"bottom"}},[e("Tag",n.row.people.length),e("div",{slot:"content"},[e("ul",t.tableData1[n.index].people.map(function(t){return e("li",{style:{textAlign:"center",padding:"4px"}},t.n+":"+t.c+"人")}))])])}},{title:"取样时段",key:"time",render:function(t,e){return t("div","近"+e.row.time+"天")}},{title:"更新时间",key:"update",render:function(e,n){return e("div",t.formatDate(t.tableData1[n.index].update))}}]}},methods:{mockTableData1:function(){console.log("mockTableData ",this.pageSize,this.page);for(var t=[],e=0;e0&&n(a.i,{id:e.id})}},nMAo:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",{staticStyle:{width:"100%",height:"100%"},attrs:{id:"shadowChart"}})},i=[],r={render:a,staticRenderFns:i};e.a=r},olAT:function(t,e,n){"use strict";var a=n("XLwt"),i=n.n(a);e.a={name:"lineChart",props:{chartOptions:Object,chartData:Object},methods:{init:function(){var t={title:{text:""},tooltip:{trigger:"axis",axisPointer:{type:"cross",label:{backgroundColor:"#6a7985"}}},legend:{data:["邮件营销","联盟广告","视频广告","直接访问","搜索引擎"]},toolbox:{feature:{saveAsImage:{}}},grid:{left:"3%",right:"4%",bottom:"3%",containLabel:!0},xAxis:[{type:"category",boundaryGap:!1,data:["周一","周二","周三","周四","周五","周六","周日"]}],yAxis:[{type:"value"}],series:[{name:"邮件营销",type:"line",stack:"总量",areaStyle:{normal:{}},data:[120,132,101,134,90,230,210]},{name:"联盟广告",type:"line",stack:"总量",areaStyle:{normal:{}},data:[220,182,191,234,290,330,310]},{name:"视频广告",type:"line",stack:"总量",areaStyle:{normal:{}},data:[150,232,201,154,190,330,410]},{name:"直接访问",type:"line",stack:"总量",areaStyle:{normal:{}},data:[320,332,301,334,390,330,320]},{name:"搜索引擎",type:"line",stack:"总量",label:{normal:{show:!0,position:"top"}},areaStyle:{normal:{}},data:[820,932,901,934,1290,1330,1320]}]},e=i.a.init(document.getElementById("lineChart"));e.setOption(t),window.addEventListener("resize",function(){e.resize()})}},mounted:function(){this.init()}}},pcJj:function(t,e){},pf6Q:function(t,e,n){"use strict";e.a={name:"breadcrumb",props:{},data:function(){return{}},computed:{currentPath:function(){return this.$store.state.layout.currentPath.slice()}}}},qK4N:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement;return(t._self._c||e)("router-view")},i=[],r={render:a,staticRenderFns:i};e.a=r},rlnd:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("Breadcrumb",[n("BreadcrumbItem",{attrs:{href:"/"}},[t._v("\n 首页\n ")]),t._v(" "),t._l(t.currentPath,function(e){return n("BreadcrumbItem",{key:e.name,attrs:{href:e.path}},[t._v("\n "+t._s(e.title)+"\n ")])})],2)},i=[],r={render:a,staticRenderFns:i};e.a=r},tP1M:function(t,e){},te0e:function(t,e){},vMTs:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"log-form"},[n("Card",{attrs:{bordered:!1}},[n("p",{staticStyle:{"text-align":"center"},attrs:{slot:"title"},slot:"title"},[t._v("请登录")]),t._v(" "),n("Form",{ref:"formInline",attrs:{model:t.formInline,rules:t.ruleInline}},[n("FormItem",{attrs:{prop:"user"}},[n("Input",{attrs:{type:"text",placeholder:"用户名"},model:{value:t.formInline.user,callback:function(e){t.formInline.user=e},expression:"formInline.user"}},[n("Icon",{attrs:{slot:"prepend",type:"ios-person-outline"},slot:"prepend"})],1)],1),t._v(" "),n("FormItem",{attrs:{prop:"password"}},[n("Input",{attrs:{type:"password",placeholder:"密码"},model:{value:t.formInline.password,callback:function(e){t.formInline.password=e},expression:"formInline.password"}},[n("Icon",{attrs:{slot:"prepend",type:"ios-locked-outline"},slot:"prepend"})],1)],1),t._v(" "),n("div",{staticStyle:{"text-align":"center"}},[n("Button",{attrs:{type:"primary"},on:{click:function(e){t.handleSubmit("formInline")}}},[t._v("登录")]),t._v(" "),n("Button",{staticStyle:{"margin-left":"8px"},attrs:{type:"ghost"}},[t._v("取消")])],1),t._v(" "),n("div",{staticStyle:{padding:"20px"}},[n("span",{staticStyle:{float:"left"}},[n("i-switch",{model:{value:t.rememberMe,callback:function(e){t.rememberMe=e},expression:"rememberMe"}}),t._v(" "),n("span",{on:{click:function(e){t.rememberMe=!t.rememberMe}}},[t._v(" 记住我")])],1),t._v(" "),n("a",{staticClass:"forgot",attrs:{href:"#"}},[t._v("忘记密码?")])])],1)],1)],1)},i=[],r={render:a,staticRenderFns:i};e.a=r},xBqg:function(t,e,n){"use strict";var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("span",[n("Menu",{ref:"sideMenu",class:{"hide-sidebard-text":t.hideSidebarText},attrs:{"active-name":t.currentPageName,"open-names":t.openedMenuList,width:"auto",theme:t.theme},on:{"on-select":t.changeMenu}},[t._t("top"),t._v(" "),t._l(t.menuList,function(e){return[e.children?t._e():n("MenuItem",{key:e.name,attrs:{name:e.name}},[n("Icon",{key:e.path,attrs:{type:e.icon,size:t.iconSize}}),t._v(" "),n("span",{key:e.name,staticClass:"sidebar-menu-text"},[t._v(t._s(e.title))])],1),t._v(" "),e.children&&e.children.length>0?n("Submenu",{key:e.path,attrs:{name:e.name}},[n("template",{attrs:{slot:"title"},slot:"title"},[n("Icon",{attrs:{type:e.icon,size:t.iconSize}}),t._v(" "),n("span",{staticClass:"sidebar-menu-text"},[t._v(t._s(e.title))])],1),t._v(" "),t._l(e.children,function(e){return n("MenuItem",{key:e.name,attrs:{name:e.name}},[n("Icon",{key:e.name,attrs:{type:e.icon,size:t.iconSize}}),t._v(" "),n("span",{key:e.name,staticClass:"sidebar-menu-text"},[t._v(t._s(e.title))])],1)})],2):t._e()]})],2)],1)},i=[],r={render:a,staticRenderFns:i};e.a=r},xElw:function(t,e,n){"use strict";e.a={name:"infoCard",props:{color:String,iconType:String,count:String,message:String,iconSize:{type:Number,default:40}}}},zKIK:function(t,e,n){"use strict";function a(t){n("L+ih")}var i=n("lM6M"),r=n("Yct/"),o=n("VU/8"),s=a,c=o(i.a,r.a,s,null,null);e.a=c.exports}},["NHnr"]); --------------------------------------------------------------------------------