├── static
└── .gitkeep
├── src
├── assets
│ ├── scss
│ │ ├── main.scss
│ │ ├── mixin.scss
│ │ └── base.scss
│ └── images
│ │ └── start_loading.svg
├── api
│ ├── constant
│ │ ├── file.js
│ │ ├── user.js
│ │ └── table.js
│ ├── modules
│ │ ├── file.js
│ │ ├── user.js
│ │ └── table.js
│ └── index.js
├── pages
│ ├── error
│ │ ├── images
│ │ │ └── 404.png
│ │ └── index.vue
│ ├── user
│ │ └── login
│ │ │ ├── images
│ │ │ ├── login_body.jpg
│ │ │ └── login_logo.png
│ │ │ └── index.vue
│ ├── charts
│ │ └── bar
│ │ │ └── index.vue
│ ├── table
│ │ ├── base
│ │ │ └── index.vue
│ │ └── sort
│ │ │ └── index.vue
│ └── home
│ │ └── index.vue
├── layouts
│ ├── default
│ │ ├── components
│ │ │ ├── images
│ │ │ │ └── logo.png
│ │ │ ├── header.vue
│ │ │ └── menu.vue
│ │ └── index.vue
│ └── full
│ │ └── index.vue
├── store
│ ├── actions
│ │ ├── type.js
│ │ └── index.js
│ ├── mutations
│ │ ├── type.js
│ │ └── index.js
│ ├── states
│ │ └── index.js
│ ├── getters
│ │ ├── type.js
│ │ └── index.js
│ └── index.js
├── App.vue
├── common
│ ├── setting.js
│ ├── storage
│ │ ├── index.js
│ │ ├── storage.js
│ │ └── cookie.js
│ ├── queryString.js
│ └── verify.js
├── router
│ ├── routes.js
│ └── index.js
├── plugin
│ └── index.js
├── components
│ ├── index.js
│ ├── pagination
│ │ └── index.js
│ └── container
│ │ └── index.vue
├── main.js
├── element-ui
│ └── index.js
└── fetch
│ └── index.js
├── favicon.ico
├── .eslintignore
├── .env.development
├── .env.production
├── .editorconfig
├── .postcssrc.js
├── .babelrc
├── .gitignore
├── .eslintrc.js
├── index.ejs
├── LICENSE
├── README.md
└── package.json
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/scss/main.scss:
--------------------------------------------------------------------------------
1 | @import "./base";
2 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imingdev/vue-admin/HEAD/favicon.ico
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 | src/router/auto-routes.js
6 |
--------------------------------------------------------------------------------
/src/api/constant/file.js:
--------------------------------------------------------------------------------
1 | // 图片上传
2 | export const imageUpload = '/api/post/image/upload'
3 |
--------------------------------------------------------------------------------
/.env.development:
--------------------------------------------------------------------------------
1 | WEB_APP_API=https://www.easy-mock.com/mock/5c95c746747db1013e6e1cc4/vue-admin
2 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | WEB_APP_API=https://www.easy-mock.com/mock/5c95c746747db1013e6e1cc4/vue-admin
2 |
--------------------------------------------------------------------------------
/src/pages/error/images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imingdev/vue-admin/HEAD/src/pages/error/images/404.png
--------------------------------------------------------------------------------
/src/pages/user/login/images/login_body.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imingdev/vue-admin/HEAD/src/pages/user/login/images/login_body.jpg
--------------------------------------------------------------------------------
/src/pages/user/login/images/login_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imingdev/vue-admin/HEAD/src/pages/user/login/images/login_logo.png
--------------------------------------------------------------------------------
/src/api/constant/user.js:
--------------------------------------------------------------------------------
1 | // 用户登录
2 | export const login = '/api/post/user/login'
3 | // 用户登出
4 | export const logout = '/api/post/user/logout'
5 |
--------------------------------------------------------------------------------
/src/layouts/default/components/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/imingdev/vue-admin/HEAD/src/layouts/default/components/images/logo.png
--------------------------------------------------------------------------------
/src/store/actions/type.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: action的类型管理.
3 | *
4 | */
5 |
6 | // 设置用户信息和登录
7 | export const SET_USER_INFO = 'SET_USER_INFO'
8 |
--------------------------------------------------------------------------------
/src/store/mutations/type.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: mutation类型管理.
3 | *
4 | */
5 |
6 | // 设置用户信息和是否登录
7 | export const SET_USER_INFO = 'SET_USER_INFO'
8 |
--------------------------------------------------------------------------------
/src/store/states/index.js:
--------------------------------------------------------------------------------
1 | import {sessionStorage} from 'src/common/storage'
2 |
3 | export default {
4 | // 用户信息和是否登录
5 | userInfo: sessionStorage.get('user_info')
6 | }
7 |
--------------------------------------------------------------------------------
/.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/store/getters/type.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: getters的类型管理.
3 | *
4 | */
5 |
6 | // 获取用户信息
7 | export const GET_USER_INFO = 'GET_USER_INFO'
8 | // 判断是否登录
9 | export const GET_IS_LOGIN = 'GET_IS_LOGIN'
10 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
11 |
--------------------------------------------------------------------------------
/src/common/setting.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 一些配置.
3 | */
4 | // 主页
5 | export const homePage = '/home'
6 | // 本地存储的前缀
7 | export const storagePrefix = 'adming_storage_'
8 | // 接入服务器接口地址根目录
9 | export const serverBaseUrl = process.env.WEB_APP_API
10 |
--------------------------------------------------------------------------------
/src/router/routes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 路由.
3 | *
4 | */
5 | import routes, {Error, Home} from './auto-routes'
6 |
7 | export default [{
8 | path: '*',
9 | redirect: Error.path
10 | }, {
11 | path: '/',
12 | redirect: Home.path
13 | }].concat(routes)
14 |
--------------------------------------------------------------------------------
/src/api/modules/file.js:
--------------------------------------------------------------------------------
1 | import fetch from 'src/fetch'
2 | import * as fileUrl from '../constant/file'
3 |
4 | // 图片上传
5 | export const imageUpload = data => {
6 | return fetch({
7 | url: fileUrl.imageUpload,
8 | method: 'post',
9 | data
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/src/common/storage/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: storage存储.
3 | *
4 | */
5 |
6 | import {localStorage, sessionStorage} from './storage'
7 | import cookieStorage from './cookie'
8 |
9 | export {
10 | localStorage,
11 | sessionStorage,
12 | cookieStorage
13 | }
14 |
--------------------------------------------------------------------------------
/.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/store/actions/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from 'src/store/actions/type'
2 | import * as mutations from 'src/store/mutations/type'
3 |
4 | export default {
5 | // 设置用户信息和登录
6 | [actions.SET_USER_INFO] ({commit}, userInfo) {
7 | commit(mutations.SET_USER_INFO, userInfo)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/layouts/full/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
14 |
17 |
--------------------------------------------------------------------------------
/src/store/getters/index.js:
--------------------------------------------------------------------------------
1 | import {GET_USER_INFO, GET_IS_LOGIN} from 'src/store/getters/type'
2 |
3 | export default {
4 | // 获取用户信息
5 | [GET_USER_INFO]: state => {
6 | return state.userInfo || {}
7 | },
8 | // 判断是否登录
9 | [GET_IS_LOGIN]: state => !!state.userInfo && JSON.stringify(state.userInfo) !== '{}'
10 | }
11 |
--------------------------------------------------------------------------------
/src/api/constant/table.js:
--------------------------------------------------------------------------------
1 | // 数据列表
2 | export const list = '/api/get/table/list'
3 | // 根据id查询数据
4 | export const get = '/api/get/table/get'
5 | // 根据id删除数据
6 | export const del = '/api/post/table/del'
7 | // 添加或修改数据
8 | export const save = '/api/post/table/save'
9 | // 批量删除
10 | export const batchDel = '/api/post/table/batch/del'
11 |
--------------------------------------------------------------------------------
/src/pages/charts/bar/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 柱状图表
9 |
10 |
11 |
16 |
18 |
--------------------------------------------------------------------------------
/src/pages/table/base/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 基本表格
9 |
10 |
11 |
16 |
18 |
--------------------------------------------------------------------------------
/src/pages/table/sort/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 排序表格
9 |
10 |
11 |
16 |
18 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-0"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime", ["component", {"libraryName": "element-ui", "styleLibraryName": "theme-chalk"}]]
12 | }
13 |
--------------------------------------------------------------------------------
/src/pages/home/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | header
4 | home page
5 |
6 |
7 |
14 |
17 |
--------------------------------------------------------------------------------
/src/api/modules/user.js:
--------------------------------------------------------------------------------
1 | import fetch from 'src/fetch'
2 | import * as userUrl from '../constant/user'
3 |
4 | // 登录
5 | export const login = (data) => {
6 | return fetch({
7 | url: userUrl.login,
8 | method: 'post',
9 | data
10 | })
11 | }
12 | // 登出
13 | export const logout = () => {
14 | return fetch({
15 | url: userUrl.logout,
16 | method: 'post'
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * 状态管理器
4 | *
5 | */
6 |
7 | import Vue from 'vue'
8 | import Vuex from 'vuex'
9 |
10 | // 引入模块
11 | import actions from './actions'
12 | import getters from './getters'
13 | import mutations from './mutations'
14 | import state from './states'
15 |
16 | Vue.use(Vuex)
17 |
18 | export default new Vuex.Store({
19 | state,
20 | getters,
21 | actions,
22 | mutations
23 | })
24 |
--------------------------------------------------------------------------------
/src/store/mutations/index.js:
--------------------------------------------------------------------------------
1 | import * as type from 'src/store/mutations/type'
2 | import {sessionStorage} from 'src/common/storage'
3 |
4 | export default {
5 | // 设置用户信息和是否登录
6 | [type.SET_USER_INFO] (state, userInfo) {
7 | state.userInfo = userInfo
8 | if (!userInfo) {
9 | sessionStorage.remove('user_info')
10 | } else {
11 | sessionStorage.set('user_info', userInfo)
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/plugin/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 插件.
3 | */
4 | import * as verify from 'src/common/verify'
5 | import api from 'src/api'
6 |
7 | const install = Vue => {
8 | if (install.installed) return false
9 |
10 | // 添加到Vue的原型链上
11 | Object.defineProperties(Vue.prototype, {
12 | $valid: {value: verify},
13 | $api: {value: api}
14 | })
15 |
16 | install.installed = true
17 | }
18 |
19 | export default install
20 |
--------------------------------------------------------------------------------
/src/api/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: api集合,将扫描modules下面的所有接口,并且根据路径生成驼峰命名为key.
3 | */
4 | let _result = {}
5 | // 驼峰命名转换
6 | const camelCaseChange = (str, separator = '/') => str.replace(new RegExp(`${separator}(\\w)`, 'g'), str => str.slice(1).toUpperCase())
7 | const context = require.context('./modules', true, /\.js$/)
8 | context.keys().map(item => {
9 | const k = camelCaseChange(item.match(/\.\/(\S*)\.js$/)[1])
10 | _result[k] = context(item)
11 | })
12 |
13 | export default _result
14 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import container from './container'
2 | import pagination from './pagination'
3 |
4 | const components = [
5 | container,
6 | pagination
7 | ]
8 |
9 | const install = Vue => {
10 | if (install.installed) return false
11 |
12 | for (let i = 0, len = components.length; i < len; i++) {
13 | const component = components[i]
14 | Vue.component(component.name, component)
15 | }
16 |
17 | install.installed = true
18 | }
19 |
20 | export default install
21 |
--------------------------------------------------------------------------------
/src/common/queryString.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 将对象解析成key=value&key2=value2模式.
3 | * @param obj 对象
4 | * @returns {string}
5 | */
6 | export default obj => {
7 | obj = obj || {}
8 | let _result = ''
9 | for (let key in obj) {
10 | let value = obj[key]
11 | if (typeof value !== 'undefined' && value !== null && value !== '') {
12 | // 有时候数值型0会转成false
13 | if (_result) {
14 | _result += '&'
15 | }
16 | _result += `${key}=${value}`
17 | }
18 | }
19 | return _result
20 | }
21 |
--------------------------------------------------------------------------------
/src/assets/scss/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin defaultBackgroundImage(
2 | $url,
3 | $size:cover,
4 | $color:transparent,
5 | $position:center,
6 | $repeat:no-repeat
7 | ) {
8 | @if ($url) {
9 | background: url($url) $repeat $position $color;
10 | } @else {
11 | background: $repeat $position $color;
12 | }
13 | @if ($size) {
14 | background-size: $size;
15 | }
16 | }
17 |
18 | @mixin defaultBackgroundAttr {
19 | background-repeat: no-repeat;
20 | background-position: center;
21 | background-size: cover;
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 |
4 | # eclipse ignore
5 | .settings/
6 | .project
7 | .classpath
8 |
9 | # idea ignore
10 | .idea/
11 | *.ipr
12 | *.iml
13 | *.iws
14 |
15 | # temp ignore
16 | *.log
17 | *.cache
18 | *.diff
19 | *.patch
20 | *.tmp
21 |
22 | # system ignore
23 | .DS_Store
24 | Thumbs.db
25 |
26 | # project ignore
27 | **/tmp
28 | pom.xml.versionsBackup
29 |
30 | # node ignore
31 | node_modules/
32 | dist/
33 | package-lock.json
34 | yarn.lock
35 | auto-routes.js
36 |
37 | # local env files
38 | .env.local
39 | .env.*.local
40 |
--------------------------------------------------------------------------------
/src/common/verify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 常用验证工具类.
3 | *
4 | */
5 | /**
6 | * //验证url是否正确
7 | * @param url
8 | * @returns {boolean}
9 | */
10 | // eslint-disable-next-line
11 | export const isUrl = url => (/(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/i).test(url)
12 | /**
13 | * 验证手机号码是否正确
14 | * @param tel
15 | * @returns {boolean}
16 | */
17 | export const isTel = tel => (/^1[3|4|5|8][0-9]\d{4,8}$/).test(tel)
18 |
19 | /**
20 | * 判断是否是object对象
21 | * @param obj
22 | * @returns {boolean}
23 | */
24 | export const isObject = obj => !!obj && Object.prototype.toString.call(obj) === '[object Object]'
25 | /**
26 | * 判断是否是数组
27 | * @param array
28 | * @returns {boolean}
29 | */
30 | export const isArray = array => !!array && Object.prototype.toString.call(array) === '[object Array]'
31 |
--------------------------------------------------------------------------------
/src/components/pagination/index.js:
--------------------------------------------------------------------------------
1 | import Pagination from 'element-ui/lib/pagination'
2 |
3 | /**
4 | * 重写element-ui的组件,在原有的基础上新增两个prop,top和align
5 | * @param {String} top 距离顶部的距离
6 | * @param {String} align 对齐方式
7 | */
8 | export default {
9 | ...Pagination,
10 | name: 'UiPagination',
11 | props: {
12 | ...Pagination.props || {},
13 | top: {
14 | type: String,
15 | default: '20px'
16 | },
17 | align: {
18 | type: String,
19 | default: 'right',
20 | validator: align => ['left', 'center', 'right'].indexOf(align) !== -1
21 | }
22 | },
23 | render (createdElement) {
24 | const {top, align} = this
25 | const template = Pagination.render.call(this, createdElement)
26 | return createdElement('div', {style: {marginTop: top, textAlign: align}}, [template])
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/api/modules/table.js:
--------------------------------------------------------------------------------
1 | import fetch from 'src/fetch'
2 | import * as tableUrl from '../constant/table'
3 |
4 | // 数据列表
5 | export const list = params => {
6 | return fetch({
7 | url: tableUrl.list,
8 | params
9 | })
10 | }
11 |
12 | // 根据id查询数据
13 | export const get = (params) => {
14 | return fetch({
15 | url: tableUrl.get,
16 | params
17 | })
18 | }
19 |
20 | // 根据id删除数据
21 | export const del = (data) => {
22 | return fetch({
23 | url: tableUrl.del,
24 | method: 'delete',
25 | data
26 | })
27 | }
28 | // 添加或修改数据
29 | export const save = (data) => {
30 | return fetch({
31 | url: tableUrl.save,
32 | method: 'post',
33 | data
34 | })
35 | }
36 | // 批量删除
37 | export const batchDel = (data) => {
38 | return fetch({
39 | url: tableUrl.batchDel,
40 | method: 'delete',
41 | data
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 主程序入口.
3 | */
4 |
5 | // 导入样式
6 | import 'normalize.css'
7 | import 'font-awesome/scss/font-awesome.scss'
8 | import 'src/assets/scss/main.scss'
9 | // 导入Vue框架
10 | import Vue from 'vue'
11 | // 导入element组件
12 | import ElementUI from './element-ui'
13 | // 导入组件
14 | import components from './components'
15 | // 导入路由
16 | import router from './router'
17 | // 导入状态管理器
18 | import store from 'src/store'
19 | // 导入请求框架
20 | // import api from './api'
21 | // 导入自定义插件
22 | import plugin from './plugin'
23 | // 导入主视图文件
24 | import App from './App'
25 |
26 | // 注册
27 | Vue.use(ElementUI)
28 | Vue.use(components)
29 | Vue.use(plugin)
30 |
31 | // 发布后是否显示提示
32 | Vue.config.productionTip = false
33 | // 只有开发时才开启工具
34 | Vue.config.devtools = process.env.NODE_ENV === 'development'
35 |
36 | new Vue({
37 | router,
38 | store,
39 | render: h => h(App)
40 | }).$mount('mainbody')
41 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parserOptions: {
6 | parser: 'babel-eslint'
7 | },
8 | env: {
9 | browser: true,
10 | },
11 | extends: [
12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
14 | 'plugin:vue/essential',
15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md
16 | 'standard'
17 | ],
18 | // required to lint *.vue files
19 | plugins: [
20 | 'vue'
21 | ],
22 | // add your custom rules here
23 | rules: {
24 | // allow async-await
25 | 'generator-star-spacing': 'off',
26 | // allow debugger during development
27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | AdminX
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/layouts/default/index.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
31 |
42 |
--------------------------------------------------------------------------------
/src/components/container/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 mingdev
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/router/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: 路由配置.
3 | */
4 | import Vue from 'vue'
5 | import VueRouter from 'vue-router'
6 | import routes from './routes'
7 | import NProgress from 'nprogress'
8 | import 'nprogress/nprogress.css'
9 | import Store from 'src/store'
10 | import {GET_IS_LOGIN} from 'src/store/getters/type'
11 | import {UserLogin} from './auto-routes'
12 |
13 | Vue.use(VueRouter)
14 |
15 | const router = new VueRouter({
16 | routes,
17 | mode: 'hash', // default: hash ,history
18 | scrollBehavior (to, from, savedPosition) {
19 | if (savedPosition) {
20 | return savedPosition
21 | } else {
22 | return {x: 0, y: 0}
23 | }
24 | }
25 | })
26 |
27 | // 全局路由配置
28 | // 路由开始之前的操作
29 | router.beforeEach((to, from, next) => {
30 | if (from.path !== '/') {
31 | NProgress.done().start()
32 | }
33 |
34 | const isLogin = Store.getters[GET_IS_LOGIN]
35 | const auth = to.meta.auth
36 |
37 | if (auth === false || auth === 'false') {
38 | // 不需要验证的
39 | next()
40 | } else {
41 | // 已经登录的继续执行,没登录就跑到登录页面中去
42 | isLogin ? next() : router.replace(UserLogin.path)
43 | }
44 | })
45 |
46 | // 路由完成之后的操作
47 | router.afterEach(route => {
48 | NProgress.done()
49 | })
50 |
51 | export default router
52 |
--------------------------------------------------------------------------------
/src/common/storage/storage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: Storage工具类.
3 | *
4 | */
5 |
6 | // 存储前缀
7 | import {storagePrefix} from 'src/common/setting'
8 |
9 | class Storage {
10 | constructor (type) {
11 | if (type === 'local') {
12 | this.store = window.localStorage
13 | } else if (type === 'session') {
14 | this.store = window.sessionStorage
15 | }
16 | this.prefix = storagePrefix
17 | }
18 |
19 | set (key, value) {
20 | try {
21 | value = JSON.stringify(value)
22 | this.store.setItem(this.prefix + key, value)
23 | } catch (e) {
24 | // eslint-disable-next-line
25 | }
26 |
27 | return this
28 | }
29 |
30 | get (key) {
31 | if (!key) {
32 | throw new Error('没有找到key。')
33 | }
34 | if (typeof key === 'object') {
35 | throw new Error('key不能是一个对象。')
36 | }
37 | let value = this.store.getItem(this.prefix + key)
38 |
39 | if (value === null) {
40 | return {}
41 | }
42 |
43 | try {
44 | value = JSON.parse(value)
45 | } catch (e) {
46 | value = {}
47 | }
48 | return value
49 | }
50 |
51 | remove (key) {
52 | this.store.removeItem(this.prefix + key)
53 | return this
54 | }
55 | }
56 |
57 | export const localStorage = new Storage('local')
58 | export const sessionStorage = new Storage('session')
59 |
--------------------------------------------------------------------------------
/src/element-ui/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: element-ui组件.
3 | */
4 | import {
5 | // plugin
6 | Loading,
7 | MessageBox,
8 | Notification,
9 | Message,
10 |
11 | // component
12 | Input,
13 | Button,
14 | Dropdown,
15 | DropdownMenu,
16 | DropdownItem,
17 | Form,
18 | FormItem,
19 | Dialog,
20 | Table,
21 | TableColumn,
22 | Pagination,
23 | Main,
24 | Container,
25 | Menu,
26 | MenuItem,
27 | Submenu,
28 | Aside
29 | } from 'element-ui'
30 | // 按道理来说可以导入进来,但是提示没有这个,所以直接单独导入进来吧
31 | import Scrollbar from 'element-ui/lib/scrollbar'
32 |
33 | const components = [
34 | Input,
35 | Button,
36 | Dropdown,
37 | DropdownMenu,
38 | DropdownItem,
39 | Form,
40 | FormItem,
41 | Dialog,
42 | Option,
43 | Table,
44 | TableColumn,
45 | Pagination,
46 | Main,
47 | Container,
48 | Menu,
49 | MenuItem,
50 | Submenu,
51 | Aside,
52 | Scrollbar
53 | ]
54 |
55 | const install = Vue => {
56 | if (install.installed) return false
57 |
58 | components.forEach(component => {
59 | Vue.component(component.name, component)
60 | })
61 |
62 | Vue.use(Loading.directive)
63 |
64 | Vue.prototype.$loading = Loading.service
65 | Vue.prototype.$msgbox = MessageBox
66 | Vue.prototype.$alert = MessageBox.alert
67 | Vue.prototype.$confirm = MessageBox.confirm
68 | Vue.prototype.$prompt = MessageBox.prompt
69 | Vue.prototype.$notify = Notification
70 | Vue.prototype.$message = Message
71 |
72 | install.installed = true
73 | }
74 |
75 | export default install
76 |
--------------------------------------------------------------------------------
/src/assets/images/start_loading.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/error/index.vue:
--------------------------------------------------------------------------------
1 |
2 | {
3 | layoutName:'full',
4 | meta:{
5 | auth: false
6 | }
7 | }
8 |
9 |
10 |
11 |
12 |
13 |
![]()
14 |
15 |
16 |
17 |
返回首页
18 |
19 |
20 |
21 |
36 |
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-admin [Live Demo](http://vue-admin.js.org)
2 |
3 | ### 安装
4 |
5 | ***
6 | 项目地址: (`git clone`)
7 | ```shell
8 | git clone https://github.com/imingdev/vue-admin.git
9 | ```
10 | 通过`npm`安装本地服务第三方依赖模块(需要已安装[Node.js](https://nodejs.org/))
11 |
12 | ```
13 | npm install
14 | ```
15 | 启动服务: (http://localhost:3001)
16 |
17 | ```
18 | npm run dev
19 | ```
20 | 发布代码
21 |
22 | ```
23 | npm run build
24 | ```
25 | ***
26 | ### 目录结构
27 |
28 | ├── build // 项目的 Webpack 配置文件
29 | ├── src // 开发目录
30 | │ ├── api // 请求接口
31 | │ ├── assets // 一些资源文件
32 | │ ├── common // 通用文件、如工具类、状态码
33 | │ ├── components // 各种组件
34 | │ ├── element-ui // element-ui动态注册组件
35 | │ ├── fetch // axios 封装
36 | │ ├── layout // 布局文件
37 | │ ├── pages // 各种页面
38 | │ ├── plugin // 各种插件
39 | │ ├── router // 路由配置及map
40 | │ ├── store // Vuex 状态管理器
41 | │ ├── App.vue // 根组件
42 | │ ├── main.js // Webpack 编译入口文件,入口js
43 | ├── static // 静态资源,一般把不需要处理的文件可以放这里
44 | ├── .babelrc // babelrc配置文件
45 | ├── .editorconfig // 代码风格文件,前提是要你的编辑器支持
46 | ├── .env.development // 开发环境的一些属性
47 | ├── .env.production // 生产环境的一些属性
48 | ├── .eslintignore // eslint 的忽略配置
49 | ├── .eslintrc.js // eslint 的配置
50 | ├── .gitignore // 用于Git配置不需要加入版本管理的文件
51 | ├── .postcssrc.js // autoprefixer的配置文件
52 | ├── favicon.ico // ico小图标
53 | ├── index.ejs // 项目入口文件
54 | ├── package.json // 项目配置文件
55 |
56 |
57 | 
58 |
59 | 
60 |
61 | 
62 | ***
63 | ##### 捐赠
64 | 
65 |
66 | 喜欢这个项目?捐助一杯咖啡支持下(¥28)
67 | ***
68 | ### 结束
69 |
70 | 有什么想交流的请联系我:[mingdev@163.com](mailto:mingdev@163.com),QQ群:[307914534](https://jq.qq.com/?_wv=1027&k=46l9UkQ)
71 |
--------------------------------------------------------------------------------
/src/fetch/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: http统一封装,同时支持callback模式调用.
3 | */
4 | import axios from 'axios'
5 | import {serverBaseUrl} from 'src/common/setting'
6 | import queryString from 'src/common/queryString'
7 |
8 | // 默认get请求
9 | const DEFAULT_METHOD = 'get'
10 |
11 | const Http = async options => {
12 | // eslint-disable-next-line
13 | if (!options) throw '请求参数不能为空!'
14 | if (typeof options === 'string') options = {url: options}
15 |
16 | const {
17 | before, // 请求开始之前的函数
18 | success, // 请求成功的函数
19 | error, // 请求失败,如果是系统错误(500,400)则type为system,其他为business
20 | complete, // 请求完成,这里不管成功还是失败都会执行
21 | method = DEFAULT_METHOD, // 请求方式,默认为get
22 | // params = {}, // get请求参数
23 | data = {} // 非get请求参数
24 | } = options
25 |
26 | // 请求之前调用一次
27 | before && before(options)
28 |
29 | if (method.toLowerCase() !== DEFAULT_METHOD) {
30 | // 将参数转成form表单的形式
31 | options.data = queryString(data)
32 | }
33 |
34 | // https://github.com/mzabriskie/axios
35 | // 创建一个axios实例
36 | const instance = axios.create({
37 | // 设置全局默认的headers
38 | headers: {
39 | 'Content-Type': 'application/x-www-form-urlencoded'
40 | },
41 | // 设置默认根地址
42 | baseURL: serverBaseUrl,
43 | // 设置请求超时设置
44 | timeout: 30000,
45 | // 返回类型json
46 | responseType: 'json'
47 | })
48 |
49 | try {
50 | // 开始请求
51 | const response = await instance(options)
52 |
53 | /**
54 | * code非0是抛错
55 | */
56 | console.log('http: response', response)
57 | const data = response.data
58 | if (+data.code === 0) {
59 | // 请求成功
60 | console.log('http: response success', data)
61 | success && success(data)
62 | return Promise.resolve(data)
63 | } else {
64 | // 失败(这里可以做未登录或者其他权限处理)
65 | if (data.code === -2) {
66 | // 用户登录失效
67 | }
68 | const errorObj = {type: 'business', ...data}
69 | console.log('http: response error', errorObj)
70 | // 失败
71 | error && error(errorObj)
72 | return Promise.reject(errorObj)
73 | }
74 | } catch (err) {
75 | console.log('err', err)
76 | let resError = err.response || {}
77 | let resCode = resError.status || '500'
78 | let resMsg = err.message || '操作失败,请稍后重试!'
79 | const errorObj = {code: resCode, message: resMsg, type: 'system'}
80 | console.log('http: response error', errorObj)
81 | error && error(errorObj)
82 | return Promise.reject(errorObj)
83 | } finally {
84 | console.log('http: complete')
85 | complete && complete()
86 | }
87 | }
88 |
89 | export default Http
90 |
--------------------------------------------------------------------------------
/src/assets/scss/base.scss:
--------------------------------------------------------------------------------
1 | @import "./mixin";
2 |
3 | * {
4 | word-break: break-all;
5 | word-wrap: break-word;
6 | padding: 0;
7 | margin: 0;
8 | outline: 0;
9 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
10 | box-sizing: border-box;
11 | }
12 |
13 | html, body {
14 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
15 | height: 100%;
16 | }
17 |
18 | ol, ul, li {
19 | list-style-type: none;
20 | }
21 |
22 | a {
23 | text-decoration: none;
24 |
25 | &:hover {
26 | text-decoration: underline;
27 | }
28 | }
29 |
30 | /************ Embedded content ************/
31 | img {
32 | border: 0;
33 | width: auto;
34 | height: auto;
35 | max-width: 100% !important;
36 | max-height: 100%;
37 | vertical-align: top;
38 | -ms-interpolation-mode: bicubic;
39 | }
40 |
41 | img:not([src*="/"]) {
42 | display: none !important;
43 | }
44 |
45 | svg:not(:root) {
46 | overflow: hidden;
47 | }
48 |
49 | /************ Grouping content ************/
50 | figure {
51 | margin: 1em 40px;
52 | }
53 |
54 | hr {
55 | box-sizing: content-box;
56 | height: 0;
57 | }
58 |
59 | pre {
60 | overflow: auto;
61 | }
62 |
63 | code, kbd, pre, samp {
64 | font-family: monospace, monospace;
65 | font-size: 1em;
66 | }
67 |
68 | h1, h2, h3, h4, h5, h6 {
69 | font-size: 100%;
70 | font-weight: normal;
71 | }
72 |
73 | table {
74 | border-collapse: collapse;
75 | border-spacing: 0;
76 | }
77 |
78 | .block {
79 | display: block;
80 | }
81 |
82 | .inline_block {
83 | display: inline-block;
84 | }
85 |
86 | .hide {
87 | display: none;
88 | }
89 |
90 | .ofh {
91 | overflow: hidden;
92 | }
93 |
94 | .relative {
95 | position: relative;
96 | }
97 |
98 | .absolute {
99 | position: absolute;
100 | }
101 |
102 | .fl {
103 | float: left;
104 | }
105 |
106 | .fr {
107 | float: right;
108 | }
109 |
110 | .align_left {
111 | text-align: left;
112 | }
113 |
114 | .align_center {
115 | text-align: center;
116 | }
117 |
118 | .align_right {
119 | text-align: right;
120 | }
121 |
122 | .height_100 {
123 | height: 100%;
124 | }
125 |
126 | .width_100 {
127 | width: 100%;
128 | }
129 |
130 | .nowrap {
131 | white-space: nowrap;
132 | overflow: hidden;
133 | text-overflow: ellipsis;
134 | }
135 |
136 | .flex {
137 | display: flex;
138 | }
139 |
140 | .flex__item {
141 | flex: 1;
142 | }
143 |
144 | .pointer {
145 | cursor: pointer;
146 | }
147 |
148 | .backgroundCover {
149 | @include defaultBackgroundAttr;
150 | }
151 |
--------------------------------------------------------------------------------
/src/layouts/default/components/header.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
27 |
28 |
60 |
102 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "admin-vue",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "adming ",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node_modules/.bin/webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "lint": "eslint --ext .js,.vue src",
11 | "build": "node build/build.js"
12 | },
13 | "dependencies": {
14 | "axios": "^0.18.0",
15 | "element-ui": "^2.6.3",
16 | "font-awesome": "^4.7.0",
17 | "normalize.css": "^8.0.1",
18 | "nprogress": "^0.2.0",
19 | "vue": "^2.5.2",
20 | "vue-router": "^3.0.1",
21 | "vuex": "^3.1.0"
22 | },
23 | "devDependencies": {
24 | "autoprefixer": "^7.1.2",
25 | "babel-core": "^6.22.1",
26 | "babel-eslint": "^8.2.1",
27 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
28 | "babel-loader": "^7.1.1",
29 | "babel-plugin-component": "^1.1.1",
30 | "babel-plugin-syntax-jsx": "^6.18.0",
31 | "babel-plugin-transform-runtime": "^6.22.0",
32 | "babel-plugin-transform-vue-jsx": "^3.5.0",
33 | "babel-preset-env": "^1.3.2",
34 | "babel-preset-stage-0": "^6.24.1",
35 | "chalk": "^2.0.1",
36 | "cheerio": "^1.0.0-rc.2",
37 | "copy-webpack-plugin": "^4.0.1",
38 | "css-loader": "^0.28.0",
39 | "dotenv-webpack": "^1.7.0",
40 | "eslint": "^4.15.0",
41 | "eslint-config-standard": "^10.2.1",
42 | "eslint-friendly-formatter": "^3.0.0",
43 | "eslint-loader": "^1.7.1",
44 | "eslint-plugin-import": "^2.7.0",
45 | "eslint-plugin-node": "^5.2.0",
46 | "eslint-plugin-promise": "^3.4.0",
47 | "eslint-plugin-standard": "^3.0.1",
48 | "eslint-plugin-vue": "^4.0.0",
49 | "extract-text-webpack-plugin": "^3.0.0",
50 | "file-loader": "^1.1.4",
51 | "friendly-errors-webpack-plugin": "^1.6.1",
52 | "html-webpack-plugin": "^2.30.1",
53 | "ip": "^1.1.5",
54 | "node-notifier": "^5.1.2",
55 | "node-sass": "^4.11.0",
56 | "optimize-css-assets-webpack-plugin": "^3.2.0",
57 | "ora": "^1.2.0",
58 | "portfinder": "^1.0.13",
59 | "postcss-import": "^11.0.0",
60 | "postcss-loader": "^2.0.8",
61 | "postcss-url": "^7.2.1",
62 | "rimraf": "^2.6.0",
63 | "sass-loader": "^7.1.0",
64 | "semver": "^5.3.0",
65 | "shelljs": "^0.7.6",
66 | "uglifyjs-webpack-plugin": "^1.1.1",
67 | "url-loader": "^0.5.8",
68 | "vue-loader": "^13.3.0",
69 | "vue-routes-auto-webpack": "^1.1.0",
70 | "vue-style-loader": "^3.0.1",
71 | "vue-template-compiler": "^2.5.2",
72 | "webpack": "^3.6.0",
73 | "webpack-bundle-analyzer": "^3.6.0",
74 | "webpack-dev-server": "^2.9.1",
75 | "webpack-merge": "^4.1.0"
76 | },
77 | "engines": {
78 | "node": ">= 6.0.0",
79 | "npm": ">= 3.0.0"
80 | },
81 | "browserslist": [
82 | "> 1%",
83 | "last 2 versions",
84 | "not ie <= 8"
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/src/pages/user/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 | {
3 | layoutName:'full',
4 | meta:{
5 | auth: false
6 | }
7 | }
8 |
9 |
10 |
11 |
12 |
13 |

14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
77 |
96 |
--------------------------------------------------------------------------------
/src/common/storage/cookie.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @intro: cookie存储类.
3 | *
4 | */
5 |
6 | import {storagePrefix} from 'src/common/setting'
7 | import {isArray, isObject} from 'src/common/verify'
8 |
9 | /**
10 | * cookies操作类
11 | */
12 | class Cookie {
13 | /**
14 | * 构造函数
15 | */
16 | constructor () {
17 | this.defaults = {}
18 | this.expiresMultiplier = 60 * 60 * 24
19 | this.prefix = storagePrefix
20 | }
21 |
22 | /**
23 | * 根据key获取cookie的值
24 | * @param {string} key 键
25 | * @returns {object} 值
26 | */
27 | get (key) {
28 | if (!key) {
29 | throw new Error('没有找到key。')
30 | }
31 | if (typeof key === 'object') {
32 | throw new Error('key不能是一个对象。')
33 | }
34 | let cookies = this.all()
35 | let value = cookies[this.prefix + key]
36 | try {
37 | value = JSON.parse(value)
38 | } catch (e) {
39 | value = null
40 | }
41 | return value
42 | }
43 |
44 | /**
45 | * 设置cookies
46 | * @param key 键
47 | * @param value 值
48 | * @param options 选项
49 | * @returns {Cookie}
50 | */
51 | set (key, value, options) {
52 | options = isObject(options) ? options : {expires: options}
53 | // 如果expires为空的话那么就设置为session.
54 | let expires = options.expires !== undefined ? options.expires : (this.defaults.expires || '')
55 | let expiresType = typeof (expires)
56 | if (expiresType === 'string' && expires !== '') {
57 | expires = new Date(expires)
58 | } else if (expiresType === 'number') {
59 | expires = new Date(+new Date() + 1000 * this.expiresMultiplier * expires)
60 | }
61 | if (expires !== '' && 'toGMTString' in expires) {
62 | expires = ';expires=' + expires.toGMTString()
63 | }
64 | // 设置path
65 | let path = options.path || this.defaults.path
66 | path = path ? ';path=' + path : ''
67 | // 设置domain
68 | let domain = options.domain || this.defaults.domain
69 | domain = domain ? ';domain=' + domain : ''
70 | // 设置secure
71 | let secure = options.secure || this.defaults.secure ? ';secure' : ''
72 | if (options.secure === false) secure = ''
73 | // 设置cookie
74 | document.cookie = this.prefix + key + '=' + JSON.stringify(value) + expires + path + domain + secure
75 | return this
76 | }
77 |
78 | /**
79 | * 删除cookie
80 | * @param {string||array} keys 删除cookie的key
81 | * @returns {Cookie}
82 | */
83 | remove (keys) {
84 | keys = isArray(keys) ? keys : [keys]
85 | for (let i = 0, l = keys.length; i < l; i++) {
86 | this.set(keys[i], '', -1)
87 | }
88 | return this
89 | }
90 |
91 | /**
92 | * 获取所有的cookie
93 | * @returns {object} cookie对象
94 | */
95 | all () {
96 | let cookie = document.cookie
97 | if (cookie === '') return {}
98 | let cookieArr = cookie.split('; ')
99 | let result = {}
100 | for (let i = 0, l = cookieArr.length; i < l; i++) {
101 | let item = cookieArr[i].split('=')
102 | // arr.shift()把第一个数组删除并得到删除的值
103 | let key = item.shift()
104 | let value = item.join('')
105 | result[key] = value
106 | }
107 | return result
108 | }
109 | }
110 |
111 | export default new Cookie()
112 |
--------------------------------------------------------------------------------
/src/layouts/default/components/menu.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
56 |
57 |
103 |
142 |
--------------------------------------------------------------------------------