├── static
└── .gitkeep
├── Dockerfile
├── .eslintignore
├── test
├── unit
│ ├── setup.js
│ ├── .eslintrc
│ ├── specs
│ │ └── HelloWorld.spec.js
│ └── jest.conf.js
└── e2e
│ ├── specs
│ └── test.js
│ ├── custom-assertions
│ └── elementCount.js
│ ├── nightwatch.conf.js
│ └── runner.js
├── src
├── router
│ ├── import_production.js
│ └── import_development.js
├── assets
│ ├── logo.png
│ ├── 401_images
│ │ └── 401.gif
│ ├── 404_images
│ │ ├── 404.png
│ │ └── 404_cloud.png
│ └── custom-theme
│ │ └── fonts
│ │ ├── element-icons.ttf
│ │ └── element-icons.woff
├── api
│ ├── base
│ │ ├── logs.js
│ │ ├── frame.js
│ │ ├── users.js
│ │ ├── permissions.js
│ │ └── menus.js
│ └── example
│ │ ├── detail.js
│ │ ├── form.js
│ │ ├── table.js
│ │ └── articles.js
├── module-dashboard
│ ├── assets
│ │ ├── logo-64.png
│ │ ├── banner-64.png
│ │ └── bigUserHeader.png
│ ├── router
│ │ └── index.js
│ ├── components
│ │ ├── layoutIndex.js
│ │ ├── layoutAppMain.vue
│ │ ├── pageTool.vue
│ │ ├── layoutSidebar.vue
│ │ ├── layoutSidebarItem.vue
│ │ ├── dashboardPieChart.vue
│ │ ├── loginSocialSignin.vue
│ │ ├── dashboardBarChart.vue
│ │ ├── dashboardRaddarChart.vue
│ │ └── dashboardLineChart.vue
│ ├── pages
│ │ ├── authredirect.vue
│ │ ├── layout.vue
│ │ └── 401.vue
│ ├── store
│ │ ├── errorLog.js
│ │ ├── app.js
│ │ ├── permission.js
│ │ ├── tagsView.js
│ │ └── user.js
│ └── index.js
├── App.vue
├── icons
│ ├── generateIconsView.js
│ ├── index.js
│ └── svg
│ │ ├── chart.svg
│ │ ├── money.svg
│ │ ├── email.svg
│ │ ├── component.svg
│ │ ├── menu-fold.svg
│ │ ├── menu-unfold.svg
│ │ ├── documentation.svg
│ │ ├── user.svg
│ │ ├── excel.svg
│ │ ├── message.svg
│ │ ├── drag.svg
│ │ ├── icon.svg
│ │ ├── example.svg
│ │ ├── lock.svg
│ │ ├── theme.svg
│ │ ├── tab.svg
│ │ ├── star.svg
│ │ ├── password.svg
│ │ ├── clipboard.svg
│ │ ├── peoples.svg
│ │ ├── github.svg
│ │ ├── language.svg
│ │ ├── 404.svg
│ │ ├── copyright.svg
│ │ ├── shoppingCard.svg
│ │ ├── bug.svg
│ │ ├── people.svg
│ │ ├── table.svg
│ │ ├── eye.svg
│ │ ├── international.svg
│ │ ├── dashboard.svg
│ │ ├── wechat.svg
│ │ ├── zip.svg
│ │ └── form.svg
├── styles
│ ├── variables.scss
│ ├── transition.scss
│ ├── element-ui.scss
│ ├── mixin.scss
│ ├── btn.scss
│ └── sidebar.scss
├── utils
│ ├── auth.js
│ ├── i18n.js
│ ├── permission.js
│ ├── validate.js
│ ├── openWindow.js
│ └── request.js
├── mock
│ ├── index.js
│ ├── table.js
│ ├── articles.js
│ └── detailTable.js
├── components
│ ├── Charts
│ │ ├── mixins
│ │ │ └── resize.js
│ │ └── keyboard.vue
│ ├── TreeTable
│ │ ├── utils
│ │ │ ├── expand.vue
│ │ │ └── dataTranslate.js
│ │ └── index.vue
│ ├── Hamburger
│ │ └── index.vue
│ ├── SvgIcon
│ │ └── index.vue
│ ├── LangSelect
│ │ └── index.vue
│ ├── Breadcrumb
│ │ └── index.vue
│ ├── ScrollBar
│ │ └── index.vue
│ ├── Screenfull
│ │ └── index.vue
│ ├── ScrollPane
│ │ └── index.vue
│ └── ErrorLog
│ │ └── index.vue
├── module-form
│ ├── index.js
│ ├── store
│ │ ├── app.js
│ │ └── store.js
│ ├── router
│ │ └── step.js
│ ├── pages
│ │ ├── activePublic
│ │ │ ├── step3.vue
│ │ │ └── index.vue
│ │ └── step-form.vue
│ └── components
│ │ └── address.vue
├── module-list
│ ├── index.js
│ ├── store
│ │ └── app.js
│ └── router
│ │ └── index.js
├── module-details
│ ├── index.js
│ ├── store
│ │ └── app.js
│ └── router
│ │ └── index.js
├── module-manage
│ ├── index.js
│ ├── store
│ │ └── app.js
│ ├── components
│ │ ├── page-tool.vue
│ │ └── user-add.vue
│ └── router
│ │ └── index.js
├── errorLog.js
├── lang
│ ├── index.js
│ ├── zh.js
│ └── en.js
├── store
│ ├── index.js
│ └── getters.js
├── main.js
└── filters
│ └── index.js
├── assets
└── img
│ ├── itheima.png
│ └── vue-element-admin-itheima logo.psd
├── config
├── prod.env.js
├── test.env.js
├── dev.env.js
└── index.js
├── ci
├── deploy.sh
├── sonar_analyze.sh
├── build.sh
└── sonar_preview.sh
├── .editorconfig
├── .postcssrc.js
├── .gitignore
├── index.html
├── .babelrc
├── .gitlab-ci.yml
├── script
└── module-add
│ ├── template
│ ├── index.js
│ ├── store
│ │ └── app.js
│ └── router
│ │ └── index.js
│ └── index.js
├── LICENSE
├── sonar-project.properties
├── .eslintrc.js
├── README.md
├── package.json
└── _package.json
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx
2 |
3 | COPY ./dist /usr/share/nginx/html
4 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 | /test/unit/coverage/
6 |
--------------------------------------------------------------------------------
/test/unit/setup.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 |
3 | Vue.config.productionTip = false
4 |
--------------------------------------------------------------------------------
/src/router/import_production.js:
--------------------------------------------------------------------------------
1 | module.exports = file => () => import('@/module-' + file + '.vue')
2 |
--------------------------------------------------------------------------------
/test/unit/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "jest": true
4 | },
5 | "globals": {
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/assets/img/itheima.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/assets/img/itheima.png
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"',
4 | BASE_API: '"api"'
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/401_images/401.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/401_images/401.gif
--------------------------------------------------------------------------------
/src/assets/404_images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/404_images/404.png
--------------------------------------------------------------------------------
/src/router/import_development.js:
--------------------------------------------------------------------------------
1 | module.exports = file => require('@/module-' + file + '.vue').default // vue-loader at least v13.0.0+
2 |
--------------------------------------------------------------------------------
/src/api/base/logs.js:
--------------------------------------------------------------------------------
1 | import {createAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/base/logs/', 'get', data)
4 |
--------------------------------------------------------------------------------
/src/assets/404_images/404_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/404_images/404_cloud.png
--------------------------------------------------------------------------------
/ci/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pwd
4 | ls -la
5 |
6 | ssh root@172.17.0.120 'cd /home/hmadmin && docker-compose down && docker-compose up -d'
--------------------------------------------------------------------------------
/src/module-dashboard/assets/logo-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/module-dashboard/assets/logo-64.png
--------------------------------------------------------------------------------
/src/module-dashboard/assets/banner-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/module-dashboard/assets/banner-64.png
--------------------------------------------------------------------------------
/assets/img/vue-element-admin-itheima logo.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/assets/img/vue-element-admin-itheima logo.psd
--------------------------------------------------------------------------------
/src/api/example/detail.js:
--------------------------------------------------------------------------------
1 | import {createAPI, createFormAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/details/list', 'get', data)
4 |
--------------------------------------------------------------------------------
/src/api/example/form.js:
--------------------------------------------------------------------------------
1 | import {createAPI, createFormAPI} from '@/utils/request'
2 |
3 | export const form = data => createAPI('/form/user', 'post', data)
4 |
--------------------------------------------------------------------------------
/src/api/example/table.js:
--------------------------------------------------------------------------------
1 | import {createAPI, createFormAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/table/list', 'get', data)
4 |
--------------------------------------------------------------------------------
/src/module-dashboard/assets/bigUserHeader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/module-dashboard/assets/bigUserHeader.png
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/custom-theme/fonts/element-icons.ttf
--------------------------------------------------------------------------------
/src/assets/custom-theme/fonts/element-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/itheima2017/vue-element-admin-itheima/HEAD/src/assets/custom-theme/fonts/element-icons.woff
--------------------------------------------------------------------------------
/src/module-dashboard/router/index.js:
--------------------------------------------------------------------------------
1 | // import Layout from '@/module-dashboard/pages/layout'
2 | // const _import = require('@/router/import_' + process.env.NODE_ENV)
3 |
--------------------------------------------------------------------------------
/config/test.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const devEnv = require('./dev.env')
4 |
5 | module.exports = merge(devEnv, {
6 | NODE_ENV: '"testing"'
7 | })
8 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/.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/icons/generateIconsView.js:
--------------------------------------------------------------------------------
1 | const data = {
2 | state: {
3 | iconsMap: []
4 | },
5 | generate(iconsMap) {
6 | this.state.iconsMap = iconsMap
7 | }
8 | }
9 |
10 | export default data
11 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"',
7 | BASE_API: '"api"'
8 | })
9 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/layoutIndex.js:
--------------------------------------------------------------------------------
1 | export { default as Navbar } from './layoutNavbar'
2 | export { default as Sidebar } from './layoutSidebar'
3 | export { default as TagsView } from './layoutTags'
4 | export { default as AppMain } from './layoutAppMain'
5 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | $blue:#324157;
2 | $light-blue:#3A71A8;
3 | $red:#C03639;
4 | $pink: #E65D6E;
5 | $green: #30B08F;
6 | $tiffany: #4AB7BD;
7 | $yellow:#FEC171;
8 | $panGreen: #30B08F;
9 |
10 | //sidebar
11 | $menuBg:#001529;
12 | $subMenuBg:#001529;
13 | $menuHover:#001529;
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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | /test/unit/coverage/
8 | /test/e2e/reports/
9 | selenium-debug.log
10 |
11 | # Editor directories and files
12 | .idea
13 | .vscode
14 | *.suo
15 | *.ntvs*
16 | *.njsproj
17 | *.sln
18 | *.zip
19 | img
--------------------------------------------------------------------------------
/src/module-dashboard/pages/authredirect.vue:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/ci/sonar_analyze.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sonar-scanner \
4 | -Dsonar.projectKey=gitlab:$CI_COMMIT_REF_NAME:$CI_PROJECT_NAME \
5 | -Dsonar.projectName=gitlab:$CI_COMMIT_REF_NAME:$CI_PROJECT_NAME \
6 | -Dsonar.projectVersion=1.0.$CI_PIPELINE_ID
7 |
8 | if [ $? -eq 0 ]; then
9 | echo "sonarqube code-publish over."
10 | fi
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 黑马Admin
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/utils/auth.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const TokenKey = 'Admin-Token-Itheima'
4 |
5 | export function getToken () {
6 | return Cookies.get(TokenKey)
7 | }
8 |
9 | export function setToken (token) {
10 | return Cookies.set(TokenKey, token)
11 | }
12 |
13 | export function removeToken () {
14 | return Cookies.remove(TokenKey)
15 | }
16 |
--------------------------------------------------------------------------------
/src/module-dashboard/store/errorLog.js:
--------------------------------------------------------------------------------
1 | const errorLog = {
2 | state: {
3 | logs: []
4 | },
5 | mutations: {
6 | ADD_ERROR_LOG: (state, log) => {
7 | state.logs.push(log)
8 | }
9 | },
10 | actions: {
11 | addErrorLog({ commit }, log) {
12 | commit('ADD_ERROR_LOG', log)
13 | }
14 | }
15 | }
16 |
17 | export default errorLog
18 |
--------------------------------------------------------------------------------
/src/utils/i18n.js:
--------------------------------------------------------------------------------
1 | // translate router.meta.title, be used in breadcrumb sidebar tagsview
2 | export function generateTitle(title) {
3 | const hasKey = this.$te('route.' + title)
4 | const translatedTitle = this.$t('route.' + title) // $t :this method from vue-i18n, inject in @/lang/index.js
5 |
6 | if (hasKey) {
7 | return translatedTitle
8 | }
9 | return title
10 | }
11 |
--------------------------------------------------------------------------------
/src/mock/index.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import TableAPI from './table'
3 | import ArticlesAPI from './articles'
4 | import DetailAPI from './detailTable'
5 |
6 | Mock.setup({
7 | timeout: '1000'
8 | })
9 |
10 | Mock.mock(/\/table\/list\.*/, 'get', TableAPI.list)
11 | Mock.mock(/\/articles\/list\.*/, 'get', ArticlesAPI.list)
12 | Mock.mock(/\/details\/list\.*/, 'get', DetailAPI.list)
13 |
--------------------------------------------------------------------------------
/src/api/example/articles.js:
--------------------------------------------------------------------------------
1 | import {createAPI, createFormAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/articles/list', 'get', data)
4 | export const types = [
5 | '类型一',
6 | '类型二',
7 | '类型三',
8 | '类型四',
9 | '类型五',
10 | '类型六',
11 | '类型七',
12 | '类型八',
13 | '类型九',
14 | '类型十',
15 | '类型十一',
16 | '类型十二',
17 | '类型十三',
18 | '类型十四',
19 | '类型十五',
20 | '类型十六'
21 | ]
22 |
--------------------------------------------------------------------------------
/test/unit/specs/HelloWorld.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import HelloWorld from '@/components/HelloWorld'
3 |
4 | describe('HelloWorld.vue', () => {
5 | it('should render correct contents', () => {
6 | const Constructor = Vue.extend(HelloWorld)
7 | const vm = new Constructor().$mount()
8 | expect(vm.$el.querySelector('.hello h1').textContent)
9 | .toEqual('Welcome to Your Vue.js App')
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/src/components/Charts/mixins/resize.js:
--------------------------------------------------------------------------------
1 | import { debounce } from '@/utils'
2 |
3 | export default {
4 | mounted() {
5 | this.__resizeHanlder = debounce(() => {
6 | if (this.chart) {
7 | this.chart.resize()
8 | }
9 | }, 100)
10 | window.addEventListener('resize', this.__resizeHanlder)
11 | },
12 | beforeDestroy() {
13 | window.removeEventListener('resize', this.__resizeHanlder)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/api/base/frame.js:
--------------------------------------------------------------------------------
1 | import {createAPI, createFormAPI} from '@/utils/request'
2 |
3 | export const login = data => createFormAPI('/base/frame/login', 'post', data)
4 | export const register = data => createAPI('/base/frame/register', 'post', data)
5 | export const logout = data => createAPI('/base/frame/logout', 'post', data)
6 | export const passwd = data => createAPI('/base/frame/passwd', 'post', data)
7 | export const profile = data => createAPI('/base/frame/profile', 'post', data)
8 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"],
12 | "env": {
13 | "test": {
14 | "presets": ["env", "stage-2"],
15 | "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ci/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pwd
4 | ls -la
5 |
6 | cnpm i
7 | npm run build
8 |
9 | docker build -t 172.17.0.57:5000/hmadmin-vue:1.0.$CI_PIPELINE_ID .
10 | docker tag 172.17.0.57:5000/hmadmin-vue:1.0.$CI_PIPELINE_ID 172.17.0.57:5000/hmadmin-vue:latest
11 | docker push 172.17.0.57:5000/hmadmin-vue:latest
12 |
13 | docker rmi 172.17.0.57:5000/hmadmin-vue:1.0.$CI_PIPELINE_ID
14 | docker rmi 172.17.0.57:5000/hmadmin-vue:latest
15 |
16 | # docker rmi -f $(docker images | grep hmadmin-vue)
--------------------------------------------------------------------------------
/src/api/base/users.js:
--------------------------------------------------------------------------------
1 | import {createAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/base/users/', 'get', data)
4 | export const simple = data => createAPI('/base/users/simple', 'get', data)
5 | export const add = data => createAPI('/base/users', 'post', data)
6 | export const update = data => createAPI(`/base/users/${data.id}`, 'put', data)
7 | export const remove = data => createAPI(`/base/users/${data.id}`, 'delete', data)
8 | export const detail = data => createAPI(`/base/users/${data.id}`, 'get', data)
9 |
--------------------------------------------------------------------------------
/src/icons/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import SvgIcon from '@/components/SvgIcon'// svg组件
3 | import generateIconsView from './generateIconsView.js'// just for @/views/icons , you can delete it
4 |
5 | // register globally
6 | Vue.component('svg-icon', SvgIcon)
7 |
8 | const requireAll = requireContext => requireContext.keys().map(requireContext)
9 | const req = require.context('./svg', false, /\.svg$/)
10 | const iconMap = requireAll(req)
11 |
12 | generateIconsView.generate(iconMap) // just for @/views/icons , you can delete it
13 |
--------------------------------------------------------------------------------
/src/icons/svg/chart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/TreeTable/utils/expand.vue:
--------------------------------------------------------------------------------
1 |
24 |
--------------------------------------------------------------------------------
/src/api/base/permissions.js:
--------------------------------------------------------------------------------
1 | import {createAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/base/permissions', 'get', data)
4 | export const simple = data => createAPI('/base/permissions/simple', 'get', data)
5 | export const add = data => createAPI('/base/permissions', 'post', data)
6 | export const update = data => createAPI(`/base/permissions/${data.id}`, 'put', data)
7 | export const remove = data => createAPI(`/base/permissions/${data.id}`, 'delete', data)
8 | export const detail = data => createAPI(`/base/permissions/${data.id}`, 'get', data)
9 |
--------------------------------------------------------------------------------
/src/utils/permission.js:
--------------------------------------------------------------------------------
1 | import store from '@/store'
2 |
3 | // 检查是否有权限
4 | export function hasPermission(roles, route) {
5 | if (roles.menus && route.name) {
6 | return roles.menus.some(role => route.name.toLowerCase() === role.toLowerCase())
7 | } else {
8 | return false
9 | }
10 | }
11 |
12 | // 检查是否有权限点
13 | export function hasPermissionPoint(point) {
14 | let points = store.getters.roles.points
15 | if (points) {
16 | return points.some(it => it.toLowerCase() === point.toLowerCase())
17 | } else {
18 | return false
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/styles/transition.scss:
--------------------------------------------------------------------------------
1 | //globl transition css
2 |
3 | /*fade*/
4 | .fade-enter-active,
5 | .fade-leave-active {
6 | transition: opacity 0.28s;
7 | }
8 |
9 | .fade-enter,
10 | .fade-leave-active {
11 | opacity: 0;
12 | }
13 |
14 | /*fade*/
15 | .breadcrumb-enter-active,
16 | .breadcrumb-leave-active {
17 | transition: all .5s;
18 | }
19 |
20 | .breadcrumb-enter,
21 | .breadcrumb-leave-active {
22 | opacity: 0;
23 | transform: translateX(20px);
24 | }
25 |
26 | .breadcrumb-move {
27 | transition: all .5s;
28 | }
29 |
30 | .breadcrumb-leave-active {
31 | position: absolute;
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | stages:
2 | - test
3 | - build
4 | - deploy
5 |
6 | sonar_analyze:
7 | stage: test
8 | script:
9 | - ci/sonar_analyze.sh
10 | tags:
11 | - hmadmin-vue
12 |
13 | sonar_preview:
14 | stage: test
15 | script:
16 | - ci/sonar_preview.sh
17 | tags:
18 | - hmadmin-vue
19 |
20 | build_image:
21 | stage: build
22 | # services:
23 | # - node:8
24 | script:
25 | - ci/build.sh
26 | tags:
27 | - hmadmin-vue
28 |
29 | deploy_image:
30 | stage: deploy
31 | # services:
32 | # - node:8
33 | script:
34 | - ci/deploy.sh
35 | tags:
36 | - hmadmin-vue
37 |
--------------------------------------------------------------------------------
/src/module-form/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 表单页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:04
7 | */
8 |
9 | // vue-router
10 | import {asyncRouterMap} from '@/router'
11 | import routerMaps from './router'
12 | // vuex
13 | import app from './store/app'
14 |
15 | export default {
16 | install(module, store) {
17 | // 注册路由
18 | asyncRouterMap.push(routerMaps[0])
19 | // 注册状态管理
20 | if (store !== undefined) {
21 | // store.registerModule('app', app)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/module-list/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 列表页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:04
7 | */
8 |
9 | // vue-router
10 | import {asyncRouterMap} from '@/router'
11 | import routerMaps from './router'
12 | // vuex
13 | import app from './store/app'
14 |
15 | export default {
16 | install(module, store) {
17 | // 注册路由
18 | asyncRouterMap.push(routerMaps[0])
19 | // 注册状态管理
20 | if (store !== undefined) {
21 | // store.registerModule('app', app)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/script/module-add/template/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: {{author}}
3 | * @Description: {{description}}
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:04
7 | */
8 |
9 | // vue-router
10 | import {asyncRouterMap} from '@/router'
11 | import routerMaps from './router'
12 | // vuex
13 | import app from './store/app'
14 |
15 | export default {
16 | install(module, store) {
17 | // 注册路由
18 | asyncRouterMap.push(routerMaps[0])
19 | // 注册状态管理
20 | if (store !== undefined) {
21 | // store.registerModule('app', app)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/icons/svg/money.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-details/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description:详情页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:04
7 | */
8 |
9 | // vue-router
10 | import {asyncRouterMap} from '@/router'
11 | import routerMaps from './router'
12 | // vuex
13 | import app from './store/app'
14 |
15 | export default {
16 | install(module, store) {
17 | // 注册路由
18 | asyncRouterMap.push(routerMaps[0])
19 | // 注册状态管理
20 | if (store !== undefined) {
21 | // store.registerModule('app', app)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/module-manage/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description:详情页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:04
7 | */
8 |
9 | // vue-router
10 | import {asyncRouterMap} from '@/router'
11 | import routerMaps from './router'
12 | // vuex
13 | import app from './store/app'
14 |
15 | export default {
16 | install(module, store) {
17 | // 注册路由
18 | asyncRouterMap.push(routerMaps[0])
19 | // 注册状态管理
20 | if (store !== undefined) {
21 | // store.registerModule('app', app)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/errorLog.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import store from './store'
3 |
4 | // you can set only in production env show the error-log
5 | // if (process.env.NODE_ENV === 'production') {
6 |
7 | Vue.config.errorHandler = function(err, vm, info, a) {
8 | // Don't ask me why I use Vue.nextTick, it just a hack.
9 | // detail see https://forum.vuejs.org/t/dispatch-in-vue-config-errorhandler-has-some-problem/23500
10 | Vue.nextTick(() => {
11 | store.dispatch('addErrorLog', {
12 | err,
13 | vm,
14 | info,
15 | url: window.location.href
16 | })
17 | console.error(err, info)
18 | })
19 | }
20 |
21 | // }
22 |
--------------------------------------------------------------------------------
/test/e2e/specs/test.js:
--------------------------------------------------------------------------------
1 | // For authoring Nightwatch tests, see
2 | // http://nightwatchjs.org/guide#usage
3 |
4 | module.exports = {
5 | 'default e2e tests': function (browser) {
6 | // automatically uses dev Server port from /config.index.js
7 | // default: http://localhost:8080
8 | // see nightwatch.conf.js
9 | const devServer = browser.globals.devServerURL
10 |
11 | browser
12 | .url(devServer)
13 | .waitForElementVisible('#app', 5000)
14 | .assert.elementPresent('.hello')
15 | .assert.containsText('h1', 'Welcome to Your Vue.js App')
16 | .assert.elementCount('img', 1)
17 | .end()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/icons/svg/email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/layoutAppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
24 |
--------------------------------------------------------------------------------
/src/icons/svg/component.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-form/store/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 表单页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:33
7 | */
8 |
9 | const app = {
10 | state: {
11 | name: ''
12 | },
13 | mutations: {
14 | SET_NAME: (state, name) => {
15 | state.name = name
16 | }
17 | },
18 | actions: {
19 | setName({ commit }, userInfo) {
20 | const username = userInfo.username.trim()
21 | return new Promise((resolve, reject) => {
22 | commit('SET_NAME', username)
23 | resolve()
24 | })
25 | }
26 | }
27 | }
28 |
29 | export default app
30 |
--------------------------------------------------------------------------------
/src/module-list/store/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 列表页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:33
7 | */
8 |
9 | const app = {
10 | state: {
11 | name: ''
12 | },
13 | mutations: {
14 | SET_NAME: (state, name) => {
15 | state.name = name
16 | }
17 | },
18 | actions: {
19 | setName({ commit }, userInfo) {
20 | const username = userInfo.username.trim()
21 | return new Promise((resolve, reject) => {
22 | commit('SET_NAME', username)
23 | resolve()
24 | })
25 | }
26 | }
27 | }
28 |
29 | export default app
30 |
--------------------------------------------------------------------------------
/script/module-add/template/store/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: {{author}}
3 | * @Description: {{description}}
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:33
7 | */
8 |
9 | const app = {
10 | state: {
11 | name: ''
12 | },
13 | mutations: {
14 | SET_NAME: (state, name) => {
15 | state.name = name
16 | }
17 | },
18 | actions: {
19 | setName({ commit }, userInfo) {
20 | const username = userInfo.username.trim()
21 | return new Promise((resolve, reject) => {
22 | commit('SET_NAME', username)
23 | resolve()
24 | })
25 | }
26 | }
27 | }
28 |
29 | export default app
30 |
--------------------------------------------------------------------------------
/src/module-details/store/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 详情页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:33
7 | */
8 |
9 | const app = {
10 | state: {
11 | name: ''
12 | },
13 | mutations: {
14 | SET_NAME: (state, name) => {
15 | state.name = name
16 | }
17 | },
18 | actions: {
19 | setName({ commit }, userInfo) {
20 | const username = userInfo.username.trim()
21 | return new Promise((resolve, reject) => {
22 | commit('SET_NAME', username)
23 | resolve()
24 | })
25 | }
26 | }
27 | }
28 |
29 | export default app
30 |
--------------------------------------------------------------------------------
/src/module-manage/store/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 列表页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 16:15:33
7 | */
8 |
9 | const app = {
10 | state: {
11 | name: ''
12 | },
13 | mutations: {
14 | SET_NAME: (state, name) => {
15 | state.name = name
16 | }
17 | },
18 | actions: {
19 | setName({ commit }, userInfo) {
20 | const username = userInfo.username.trim()
21 | return new Promise((resolve, reject) => {
22 | commit('SET_NAME', username)
23 | resolve()
24 | })
25 | }
26 | }
27 | }
28 |
29 | export default app
30 |
--------------------------------------------------------------------------------
/src/icons/svg/menu-fold.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/lang/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueI18n from 'vue-i18n'
3 | import Cookies from 'js-cookie'
4 | import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
5 | import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
6 | import enLocale from './en'
7 | import zhLocale from './zh'
8 |
9 | Vue.use(VueI18n)
10 |
11 | const messages = {
12 | en: {
13 | ...enLocale,
14 | ...elementEnLocale
15 | },
16 | zh: {
17 | ...zhLocale,
18 | ...elementZhLocale
19 | }
20 | }
21 |
22 | const i18n = new VueI18n({
23 | locale: Cookies.get('language') || 'zh', // set locale
24 | messages // set locale messages
25 | })
26 |
27 | export default i18n
28 |
--------------------------------------------------------------------------------
/script/module-add/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: hans.taozhiwei
3 | * @Description: 模块安装 itheima-moduleAdd
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-13 17:26:52
7 | */
8 |
9 | module.exports = {
10 | prompts: {
11 | name: {
12 | type: 'string',
13 | required: true,
14 | message: '模块名称'
15 | },
16 | author: {
17 | type: 'string',
18 | required: false,
19 | message: '作者',
20 | default: 'yourname '
21 | },
22 | description: {
23 | type: 'string',
24 | required: false,
25 | message: '说明',
26 | default: 'xxx业务模块'
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/icons/svg/menu-unfold.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | // import app from '@/module-dashboard/store/app'
4 | // import errorLog from '@/module-dashboard/store/errorLog'
5 | // import permission from '@/module-dashboard/store/permission'
6 | // import tagsView from '@/module-dashboard/store/tagsView'
7 | // import user from '@/module-dashboard/store/user'
8 | import getters from './getters'
9 |
10 | Vue.use(Vuex)
11 |
12 | const store = new Vuex.Store({
13 | getters
14 | })
15 |
16 | // const store = new Vuex.Store({
17 | // modules: {
18 | // app,
19 | // errorLog,
20 | // permission,
21 | // tagsView,
22 | // user
23 | // },
24 | // getters
25 | // })
26 |
27 | export default store
28 |
--------------------------------------------------------------------------------
/src/icons/svg/documentation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | // 手动添加需要的 快捷 getters
2 | const getters = {
3 | sidebar: state => state.app.sidebar,
4 | language: state => state.app.language,
5 | visitedViews: state => state.tagsView.visitedViews,
6 | cachedViews: state => state.tagsView.cachedViews,
7 | token: state => state.user.token,
8 | avatar: state => state.user.avatar,
9 | name: state => state.user.name,
10 | introduction: state => state.user.introduction,
11 | status: state => state.user.status,
12 | roles: state => state.user.roles,
13 | setting: state => state.user.setting,
14 | permission_routers: state => state.permission.routers,
15 | addRouters: state => state.permission.addRouters,
16 | errorLogs: state => state.errorLog.logs
17 | }
18 |
19 | export default getters
20 |
--------------------------------------------------------------------------------
/src/icons/svg/user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/src/module-dashboard/index.js:
--------------------------------------------------------------------------------
1 | // vue-router
2 | import {asyncRouterMap} from '@/router'
3 | import routerMaps from './router'
4 | // vuex
5 | import app from './store/app'
6 | import errorLog from './store/errorLog'
7 | import permission from './store/permission'
8 | import tagsView from './store/tagsView'
9 | import user from './store/user'
10 |
11 | export default {
12 | install(module, store) {
13 | // 注册路由
14 | // asyncRouterMap.push(routerMaps[0])
15 | // 注册状态管理
16 | if (store !== undefined) {
17 | store.registerModule('app', app)
18 | store.registerModule('errorLog', errorLog)
19 | store.registerModule('permission', permission)
20 | store.registerModule('tagsView', tagsView)
21 | store.registerModule('user', user)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/script/module-add/template/router/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: {{author}}
3 | * @Description: {{description}}
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-05-22 17:04:36
7 | */
8 |
9 | import Layout from '@/module-dashboard/pages/layout'
10 | const _import = require('@/router/import_' + process.env.NODE_ENV)
11 |
12 | export default [
13 | {
14 | path: '/{{name}}',
15 | component: Layout,
16 | redirect: 'noredirect',
17 | name: '{{name}}',
18 | meta: {
19 | title: '{{name}}管理',
20 | icon: 'component'
21 | },
22 | children: [
23 | {
24 | path: 'table',
25 | component: _import('{{name}}/pages/index'),
26 | name: '{{name}}-table',
27 | meta: {title: '列表模块'}
28 | }
29 | ]
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/src/icons/svg/excel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/unit/jest.conf.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | rootDir: path.resolve(__dirname, '../../'),
5 | moduleFileExtensions: [
6 | 'js',
7 | 'json',
8 | 'vue'
9 | ],
10 | moduleNameMapper: {
11 | '^@/(.*)$': '/src/$1'
12 | },
13 | transform: {
14 | '^.+\\.js$': '/node_modules/babel-jest',
15 | '.*\\.(vue)$': '/node_modules/vue-jest'
16 | },
17 | testPathIgnorePatterns: [
18 | '/test/e2e'
19 | ],
20 | snapshotSerializers: ['/node_modules/jest-serializer-vue'],
21 | setupFiles: ['/test/unit/setup'],
22 | mapCoverage: true,
23 | coverageDirectory: '/test/unit/coverage',
24 | collectCoverageFrom: [
25 | 'src/**/*.{js,vue}',
26 | '!src/main.js',
27 | '!src/router/index.js',
28 | '!**/node_modules/**'
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/SvgIcon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
33 |
34 |
43 |
--------------------------------------------------------------------------------
/src/icons/svg/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/store/app.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 |
3 | const app = {
4 | state: {
5 | sidebar: {
6 | opened: !+Cookies.get('sidebarStatus')
7 | },
8 | language: Cookies.get('language') || 'en'
9 | },
10 | mutations: {
11 | TOGGLE_SIDEBAR: state => {
12 | if (state.sidebar.opened) {
13 | Cookies.set('sidebarStatus', 1)
14 | } else {
15 | Cookies.set('sidebarStatus', 0)
16 | }
17 | state.sidebar.opened = !state.sidebar.opened
18 | },
19 | SET_LANGUAGE: (state, language) => {
20 | state.language = language
21 | Cookies.set('language', language)
22 | }
23 | },
24 | actions: {
25 | toggleSideBar({ commit }) {
26 | commit('TOGGLE_SIDEBAR')
27 | },
28 | setLanguage({ commit }, language) {
29 | commit('SET_LANGUAGE', language)
30 | }
31 | }
32 | }
33 |
34 | export default app
35 |
--------------------------------------------------------------------------------
/test/e2e/custom-assertions/elementCount.js:
--------------------------------------------------------------------------------
1 | // A custom Nightwatch assertion.
2 | // The assertion name is the filename.
3 | // Example usage:
4 | //
5 | // browser.assert.elementCount(selector, count)
6 | //
7 | // For more information on custom assertions see:
8 | // http://nightwatchjs.org/guide#writing-custom-assertions
9 |
10 | exports.assertion = function (selector, count) {
11 | this.message = 'Testing if element <' + selector + '> has count: ' + count
12 | this.expected = count
13 | this.pass = function (val) {
14 | return val === this.expected
15 | }
16 | this.value = function (res) {
17 | return res.value
18 | }
19 | this.command = function (cb) {
20 | var self = this
21 | return this.api.execute(function (selector) {
22 | return document.querySelectorAll(selector).length
23 | }, [selector], function (res) {
24 | cb.call(self, res)
25 | })
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/icons/svg/drag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/pageTool.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
35 |
38 |
--------------------------------------------------------------------------------
/src/module-manage/components/page-tool.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
35 |
38 |
--------------------------------------------------------------------------------
/src/icons/svg/icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/example.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ci/sonar_preview.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sonar-scanner -X \
4 | -Dsonar.analysis.mode=preview \
5 | -Dsonar.projectKey=gitlab:$CI_COMMIT_REF_NAME:$CI_PROJECT_NAME \
6 | -Dsonar.projectName=gitlab:$CI_COMMIT_REF_NAME:$CI_PROJECT_NAME \
7 | -Dsonar.projectVersion=1.0.$CI_PIPELINE_ID \
8 | -Dsonar.issuesReport.html.enable=true \
9 | -Dsonar.gitlab.project_id=$CI_PROJECT_ID \
10 | -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA \
11 | -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
12 |
13 | # -Dsonar.gitlab.ignore_certificate=true \
14 | # -Dsonar.gitlab.disable_global_comment=true \
15 | # -Dsonar.gitlab.unique_issue_per_inline=true
16 | # -Dsonar.gitlab.failure_notification_mode=exit-code
17 | # -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA \
18 | # -Dsonar.gitlab.disable_global_comment=true \
19 | # -Dsonar.gitlab.unique_issue_per_inline=true \
20 | # -Dsonar.gitlab.failure_notification_mode=exit-code \
21 | # -Dsonar.gitlab.only_issue_from_commit_file=false
22 |
23 | if [ $? -eq 0 ]; then
24 | echo "sonarqube code-publish over."
25 | fi
--------------------------------------------------------------------------------
/src/module-details/router/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 列表页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-17 09:48:44
7 | */
8 |
9 | import Layout from '@/module-dashboard/pages/layout'
10 | const _import = require('@/router/import_' + process.env.NODE_ENV)
11 |
12 | export default [
13 | {
14 | path: '/details',
15 | component: Layout,
16 | redirect: 'noredirect',
17 | name: 'details',
18 | meta: {
19 | title: 'details',
20 | icon: 'tab'
21 | },
22 | children: [
23 | {
24 | path: 'basics-details',
25 | component: _import('details/pages/basicsDetails'),
26 | name: 'basics-details',
27 | meta: {title: 'BasicsDetails'}
28 | },
29 | {
30 | path: 'senior-details',
31 | component: _import('details/pages/seniorDetails'),
32 | name: 'senior-details',
33 | meta: {title: 'seniorDetails'}
34 | }
35 | ]
36 | }
37 | ]
38 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/layoutSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
35 |
--------------------------------------------------------------------------------
/src/icons/svg/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/theme.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/module-manage/router/index.js:
--------------------------------------------------------------------------------
1 | import Layout from '@/module-dashboard/pages/layout'
2 | const _import = require('@/router/import_' + process.env.NODE_ENV)
3 |
4 | export default [
5 | {
6 | path: '/base',
7 | component: Layout,
8 | redirect: 'noredirect',
9 | name: 'base',
10 | meta: {
11 | title: 'manage',
12 | icon: 'component'
13 | },
14 | children: [
15 | {
16 | path: 'users',
17 | component: _import('manage/pages/users'),
18 | name: 'base-users',
19 | meta: {title: 'users'}
20 | },
21 | {
22 | path: 'menus',
23 | name: 'base-menus',
24 | component: _import('manage/pages/menus'),
25 | meta: {title: 'menus'}
26 | },
27 | {
28 | path: 'permissions',
29 | name: 'base-permissions',
30 | component: _import('manage/pages/permissions'),
31 | meta: {title: 'permissions'}
32 | },
33 | {
34 | path: 'logs',
35 | name: 'base-logs',
36 | component: _import('manage/pages/logs'),
37 | meta: {title: 'logs'}
38 | }
39 | ]
40 | }
41 | ]
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-present itheima
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/icons/svg/tab.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.host.url=http://sonar.itcast.cn
2 | sonar.login=b45c1cfb006d1d5c359d5b101eef867dfe0f5e91
3 | sonar.sourceEncoding=UTF-8
4 | sonar.modules=javascript-module
5 | # sonar.modules=java-module,javascript-module,html-module,css-module
6 |
7 | # sonar.sources=.
8 | # sonar.tests=test
9 | # sonar.language=js
10 | # sonar.exclusions=test
11 |
12 | # # Java module
13 | # java-module.sonar.projectName=java-module
14 | # java-module.sonar.language=java
15 | # # .表示projectBaseDir指定的目录
16 | # java-module.sonar.sources=.
17 | # java-module.sonar.projectBaseDir=src
18 | # sonar.binaries=classes
19 |
20 | # JavaScript module
21 | javascript-module.sonar.projectName=javascript-module
22 | javascript-module.sonar.language=js
23 | javascript-module.sonar.sources=.
24 | javascript-module.sonar.projectBaseDir=src
25 |
26 | # Html module
27 | # html-module.sonar.projectName=html-module
28 | # html-module.sonar.language=web
29 | # html-module.sonar.sources=.
30 | # html-module.sonar.projectBaseDir=web
31 |
32 | # CSS module
33 | # css-module.sonar.projectName=css-module
34 | # css-module.sonar.language=css
35 | # css-module.sonar.sources=.
36 | # css-module.sonar.projectBaseDir=web
37 |
--------------------------------------------------------------------------------
/src/module-list/router/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 列表页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-17 09:48:44
7 | */
8 |
9 | import Layout from '@/module-dashboard/pages/layout'
10 | const _import = require('@/router/import_' + process.env.NODE_ENV)
11 |
12 | export default [
13 | {
14 | path: '/list',
15 | component: Layout,
16 | redirect: 'noredirect',
17 | name: 'list',
18 | meta: {
19 | title: 'list',
20 | icon: 'table'
21 | },
22 | children: [
23 | {
24 | path: 'table-list',
25 | component: _import('list/pages/table-list'),
26 | name: 'table-list',
27 | meta: {title: 'tableList'}
28 | },
29 | {
30 | path: 'basic-list',
31 | component: _import('list/pages/basic-list'),
32 | name: 'basic-list',
33 | meta: {title: 'basicList'}
34 | },
35 | {
36 | path: 'card-list',
37 | component: _import('list/pages/card-list'),
38 | name: 'card-list',
39 | meta: {title: 'cardList'}
40 | }
41 | ]
42 | }
43 | ]
44 |
--------------------------------------------------------------------------------
/src/icons/svg/star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/e2e/nightwatch.conf.js:
--------------------------------------------------------------------------------
1 | require('babel-register')
2 | var config = require('../../config')
3 |
4 | // http://nightwatchjs.org/gettingstarted#settings-file
5 | module.exports = {
6 | src_folders: ['test/e2e/specs'],
7 | output_folder: 'test/e2e/reports',
8 | custom_assertions_path: ['test/e2e/custom-assertions'],
9 |
10 | selenium: {
11 | start_process: true,
12 | server_path: require('selenium-server').path,
13 | host: '127.0.0.1',
14 | port: 4444,
15 | cli_args: {
16 | 'webdriver.chrome.driver': require('chromedriver').path
17 | }
18 | },
19 |
20 | test_settings: {
21 | default: {
22 | selenium_port: 4444,
23 | selenium_host: 'localhost',
24 | silent: true,
25 | globals: {
26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
27 | }
28 | },
29 |
30 | chrome: {
31 | desiredCapabilities: {
32 | browserName: 'chrome',
33 | javascriptEnabled: true,
34 | acceptSslCerts: true
35 | }
36 | },
37 |
38 | firefox: {
39 | desiredCapabilities: {
40 | browserName: 'firefox',
41 | javascriptEnabled: true,
42 | acceptSslCerts: true
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/components/LangSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 中文
10 | English
11 |
12 |
13 |
14 |
15 |
34 |
35 |
43 |
--------------------------------------------------------------------------------
/src/mock/table.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { param2Obj } from '@/utils'
3 |
4 | const List = []
5 | const count = 100
6 |
7 | for (let i = 0; i < count; i++) {
8 | List.push(Mock.mock({
9 | id: '@increment',
10 | timestamp: +Mock.Random.date('T'),
11 | author: '@cname',
12 | reviewer: '@cname',
13 | title: '@csentence(15, 45)',
14 | forecast: '@float(0, 100, 2, 2)',
15 | importance: '@integer(1, 3)',
16 | 'type|1': ['CN', 'US', 'JP', 'EU'],
17 | 'status|1': ['published', 'draft', 'deleted'],
18 | display_time: '@datetime',
19 | pageviews: '@integer(300, 5000)'
20 | }))
21 | }
22 |
23 | export default {
24 | list: config => {
25 | const { type, title, page = 1, limit = 20, sort } = param2Obj(config.url)
26 |
27 | let mockList = List.filter(item => {
28 | if (type && item.type !== type) return false
29 | if (title && item.title.indexOf(title) < 0) return false
30 | return true
31 | })
32 |
33 | if (sort === '-id') {
34 | mockList = mockList.reverse()
35 | }
36 |
37 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
38 |
39 | return {
40 | total: mockList.length,
41 | items: pageList
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/icons/svg/clipboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/TreeTable/utils/dataTranslate.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: sunlandong
3 | * @Date: 2017-03-11 12:06:49
4 | * @Last Modified by: sunlandong
5 | * @Last Modified time: 2017-03-11 16:30:03
6 | */
7 |
8 | import Vue from 'vue'
9 | function DataTransfer (data) {
10 | if (!(this instanceof DataTransfer)) {
11 | return new DataTransfer(data, null, null)
12 | }
13 | }
14 |
15 | DataTransfer.treeToArray = function (data, parent, level, expandedAll) {
16 | let tmp = []
17 | Array.from(data).forEach(function (record) {
18 | if (record._expanded === undefined) {
19 | Vue.set(record, '_expanded', expandedAll)
20 | }
21 | if (parent) {
22 | Vue.set(record, '_parent', parent)
23 | }
24 | let _level = 0
25 | if (level !== undefined && level !== null) {
26 | _level = level + 1
27 | }
28 | Vue.set(record, '_level', _level)
29 | tmp.push(record)
30 | if (record.childs && record.childs.length > 0) {
31 | let childs = DataTransfer.treeToArray(record.childs, record, _level, expandedAll)
32 | tmp = tmp.concat(childs)
33 | }
34 | if (record.points && record.points.length > 0) {
35 | let points = DataTransfer.treeToArray(record.points, record, _level, expandedAll)
36 | tmp = tmp.concat(points)
37 | }
38 | })
39 | return tmp
40 | }
41 |
42 | export default DataTransfer
43 |
--------------------------------------------------------------------------------
/.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 | "no-undef": 0, //不允许未声明的变量
25 | "no-unused-vars": [0, {"vars": "all", "args": "after-used"}], //不允许有声明后未使用的变量或者参数
26 | "no-tabs": 0, //不允许tabs
27 |
28 | "no-trailing-spaces": 0,
29 | "padded-blocks": 0,
30 | "no-control-regex": 0,
31 |
32 | // allow async-await
33 | 'generator-star-spacing': 'off',
34 |
35 | "indent": [0, 2],//缩进风格
36 | // "camelcase": [0, {"properties": "never"}], //强制驼峰命名规则
37 | "space-before-function-paren": [0, {"anonymous": "always", "named": "never"}], //函数定义时括号前的空格
38 | // allow debugger during development
39 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
40 | }
41 | }
--------------------------------------------------------------------------------
/src/icons/svg/peoples.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/store/permission.js:
--------------------------------------------------------------------------------
1 | import { asyncRouterMap, constantRouterMap } from '@/router'
2 | import { hasPermission } from '@/utils/permission'
3 |
4 | /**
5 | * 递归过滤异步路由表,返回符合用户角色权限的路由表
6 | * @param asyncRouterMap
7 | * @param roles
8 | */
9 | function filterAsyncRouter(asyncRouterMap, roles) {
10 | const accessedRouters = asyncRouterMap.filter(route => {
11 | if (hasPermission(roles, route)) {
12 | if (route.children && route.children.length) {
13 | route.children = filterAsyncRouter(route.children, roles)
14 | }
15 | return true
16 | }
17 | return false
18 | })
19 | return accessedRouters
20 | }
21 |
22 | const permission = {
23 | state: {
24 | routers: constantRouterMap,
25 | addRouters: []
26 | },
27 | mutations: {
28 | SET_ROUTERS: (state, routers) => {
29 | state.addRouters = routers
30 | state.routers = constantRouterMap.concat(routers)
31 | }
32 | },
33 | actions: {
34 | GenerateRoutes({ commit }, data) {
35 | return new Promise(resolve => {
36 | // const { roles } = data
37 | // let accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
38 | // commit('SET_ROUTERS', accessedRouters)
39 | commit('SET_ROUTERS', asyncRouterMap)
40 | resolve()
41 | })
42 | }
43 | }
44 | }
45 |
46 | export default permission
47 |
--------------------------------------------------------------------------------
/src/module-form/router/step.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: taoshiwei
3 | * @Description: 表单页
4 | * @Date: 2018-04-13 16:13:27
5 | * @Last Modified by: hans.taozhiwei
6 | * @Last Modified time: 2018-04-17 09:29:01
7 | */
8 | import activePublic from '../pages/activePublic/index'
9 | import Layout from '@/module-dashboard/pages/layout'
10 | const _import = require('@/router/import_' + process.env.NODE_ENV)
11 |
12 | export default [
13 | {
14 | path: '/activePublic',
15 | component: activePublic,
16 | children: [
17 | {
18 | path: '/',
19 | component: _import('form/pages/activePublic/step1'),
20 | name: 'step0',
21 | meta: {
22 | title: 'step'
23 | }
24 | },
25 | {
26 | path: 'step1',
27 | component: _import('form/pages/activePublic/step1'),
28 | name: 'step1',
29 | meta: {
30 | title: 'step'
31 | }
32 | },
33 | {
34 | path: 'step2',
35 | component: _import('form/pages/activePublic/step2'),
36 | name: 'step2',
37 | meta: {
38 | title: 'step'
39 | }
40 | },
41 | {
42 | path: 'step3',
43 | component: _import('form/pages/activePublic/step3'),
44 | name: 'step3',
45 | meta: {
46 | title: 'step'
47 | }
48 | }
49 | ]
50 | }
51 | ]
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/vuejs/vue)
2 | [](https://github.com/itheima2017/vue-element-admin-itheima/blob/master/LICENSE)
3 | [](https://github.com/itheima2017/vue-element-admin-itheima/releases)
4 | [](https://github.com/itheima2017/vue-element-admin-itheima)
5 |
6 | # 说明
7 |
8 | `黑马Admin` 的前端项目
9 |
10 | [安装及快速开始 go!](http://itheimaadmin.itcast.cn/book/help/#/getting-started)
11 |
12 | * [在线演示](http://itheimaadmin.itcast.cn/preview/vue/dist)
13 | * 代码
14 | * [前端 Vue](https://github.com/itheima2017/vue-element-admin-itheima)
15 | * [后端 Java](https://github.com/itheima2017/vue-element-admin-api-java-itheima)
16 | * 文档
17 | * [API 接口文档](http://itheimaadmin.itcast.cn/book/api/_book/)
18 | * [使用帮助文档](http://itheimaadmin.itcast.cn/book/help/)
19 |
20 | # 版权
21 |
22 | [MIT](https://github.com/itheima2017/vue-element-admin-itheima/blob/master/LICENSE) license.
23 |
24 | @传智研究院-研发部
25 |
26 | 江苏传智播客教育科技股份有限公司 版权所有 Copyright 2006-2018, All Rights Reserved
27 |
--------------------------------------------------------------------------------
/src/utils/validate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by jiachenpan on 16/11/18.
3 | */
4 |
5 | export function isvalidUsername(str) {
6 | const validMap = ['admin', 'editor']
7 | return validMap.indexOf(str.trim()) >= 0
8 | }
9 |
10 | /* 合法uri */
11 | export function validateURL(textval) {
12 | const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
13 | return urlregex.test(textval)
14 | }
15 |
16 | /* 小写字母 */
17 | export function validateLowerCase(str) {
18 | const reg = /^[a-z]+$/
19 | return reg.test(str)
20 | }
21 |
22 | /* 大写字母 */
23 | export function validateUpperCase(str) {
24 | const reg = /^[A-Z]+$/
25 | return reg.test(str)
26 | }
27 |
28 | /* 大小写字母 */
29 | export function validatAlphabets(str) {
30 | const reg = /^[A-Za-z]+$/
31 | return reg.test(str)
32 | }
33 |
34 | /**
35 | * validate email
36 | * @param email
37 | * @returns {boolean}
38 | */
39 | export function validateEmail(email) {
40 | // eslint-disable-next-line
41 | const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
42 | return re.test(email)
43 | }
44 |
--------------------------------------------------------------------------------
/src/styles/element-ui.scss:
--------------------------------------------------------------------------------
1 | //覆盖一些element-ui样式
2 |
3 | .el-breadcrumb__inner, .el-breadcrumb__inner a{
4 | font-weight: 400!important;
5 | }
6 |
7 | .el-upload {
8 | input[type="file"] {
9 | display: none !important;
10 | }
11 | }
12 |
13 | .el-upload__input {
14 | display: none;
15 | }
16 |
17 | .cell {
18 | .el-tag {
19 | margin-right: 0px;
20 | }
21 | }
22 |
23 | .small-padding {
24 | .cell {
25 | padding-left: 5px;
26 | padding-right: 5px;
27 | }
28 | }
29 |
30 | .fixed-width{
31 | .el-button--mini{
32 | padding: 7px 10px;
33 | width: 60px;
34 | }
35 | }
36 |
37 | .status-col {
38 | .cell {
39 | padding: 0 10px;
40 | text-align: center;
41 | .el-tag {
42 | margin-right: 0px;
43 | }
44 | }
45 | }
46 |
47 | //暂时性解决dialog 问题 https://github.com/ElemeFE/element/issues/2461
48 | .el-dialog {
49 | transform: none;
50 | left: 0;
51 | position: relative;
52 | margin: 0 auto;
53 | }
54 |
55 | //文章页textarea修改样式
56 | .article-textarea {
57 | textarea {
58 | padding-right: 40px;
59 | resize: none;
60 | border: none;
61 | border-radius: 0px;
62 | border-bottom: 1px solid #bfcbd9;
63 | }
64 | }
65 |
66 | //element ui upload
67 | .upload-container {
68 | .el-upload {
69 | width: 100%;
70 | .el-upload-dragger {
71 | width: 100%;
72 | height: 200px;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/utils/openWindow.js:
--------------------------------------------------------------------------------
1 | /**
2 | *Created by jiachenpan on 16/11/29.
3 | * @param {Sting} url
4 | * @param {Sting} title
5 | * @param {Number} w
6 | * @param {Number} h
7 | */
8 |
9 | export default function openWindow(url, title, w, h) {
10 | // Fixes dual-screen position Most browsers Firefox
11 | const dualScreenLeft =
12 | window.screenLeft !== undefined ? window.screenLeft : screen.left
13 | const dualScreenTop =
14 | window.screenTop !== undefined ? window.screenTop : screen.top
15 |
16 | const width = window.innerWidth
17 | ? window.innerWidth
18 | : document.documentElement.clientWidth
19 | ? document.documentElement.clientWidth
20 | : screen.width
21 | const height = window.innerHeight
22 | ? window.innerHeight
23 | : document.documentElement.clientHeight
24 | ? document.documentElement.clientHeight
25 | : screen.height
26 |
27 | const left = width / 2 - w / 2 + dualScreenLeft
28 | const top = height / 2 - h / 2 + dualScreenTop
29 | const newWindow = window.open(
30 | url,
31 | title,
32 | 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' +
33 | w +
34 | ', height=' +
35 | h +
36 | ', top=' +
37 | top +
38 | ', left=' +
39 | left
40 | )
41 |
42 | // Puts focus on the newWindow
43 | if (window.focus) {
44 | newWindow.focus()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/mock/articles.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import {
3 | param2Obj
4 | } from '@/utils'
5 | const List = []
6 | const count = 100
7 | for (let i = 0; i < count; i++) {
8 | List.push(Mock.mock({
9 | id: '@increment',
10 | title: '@ctitle',
11 | author: '@cname',
12 | 'icon|1': ['alipay', 'angular', 'antDesign', 'antDesignPro', 'bootstrap', 'vue', 'webpack'],
13 | tags: ['html', 'javascript', 'css'],
14 | description: '@csentence(50, 350)',
15 | url: '@url',
16 | timestamp: +Mock.Random.date('T'),
17 | displayTime: '@datetime',
18 | stars: '@integer(300, 5000)',
19 | likes: '@integer(300, 5000)',
20 | messages: '@integer(300, 5000)'
21 | }))
22 | }
23 | export default {
24 | list: config => {
25 | const {
26 | title,
27 | type,
28 | owner,
29 | page = 1,
30 | limit = 20,
31 | sort
32 | } = param2Obj(config.url)
33 | let mockList
34 | mockList = List.filter(item => {
35 | if (type && item.type !== type) return false
36 | if (owner && item.owner !== owner) return false
37 | if (title && item.title.indexOf(title) < 0) return false
38 | return true
39 | })
40 | if (sort === '-id') {
41 | mockList = mockList.reverse()
42 | }
43 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
44 | return {
45 | total: mockList.length,
46 | items: pageList
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/icons/svg/github.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import 'normalize.css/normalize.css'// A modern alternative to CSS resets
3 | import Element from 'element-ui'
4 | import 'element-ui/lib/theme-chalk/index.css'
5 | import '@/styles/index.scss' // global css
6 | import App from './App'
7 | import router from './router'
8 | import store from './store'
9 | import i18n from './lang' // Internationalization
10 | import './icons' // icon
11 | import './errorLog'// error log
12 | import * as filters from './filters' // global filters
13 | import './mock' // simulation data
14 | // font-awesome
15 | import 'font-awesome/css/font-awesome.css'
16 | /*
17 | * 注册 - 业务模块
18 | */
19 | import dashboard from '@/module-dashboard/' // 面板
20 | import base from '@/module-manage/' // 用户管理
21 | import list from '@/module-list/' // 列表页
22 | import form from '@/module-form/' // 表单页
23 | import details from '@/module-details/' // 表单页
24 |
25 | Vue.use(dashboard, store)
26 | Vue.use(base, store)
27 | Vue.use(list, store)
28 | Vue.use(form, store)
29 | Vue.use(details, store)
30 |
31 | /*
32 | * 注册 - 组件
33 | */
34 |
35 | // 饿了么
36 | Vue.use(Element, {
37 | size: 'medium', // set element-ui default size
38 | i18n: (key, value) => i18n.t(key, value)
39 | })
40 | // 过滤器
41 | Object.keys(filters).forEach(key => {
42 | Vue.filter(key, filters[key])
43 | })
44 |
45 | Vue.config.productionTip = false
46 |
47 | /* eslint-disable */
48 | new Vue({
49 | el: '#app',
50 | router,
51 | store,
52 | i18n,
53 | template: '',
54 | components: { App }
55 | })
56 |
--------------------------------------------------------------------------------
/src/icons/svg/language.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/mock/detailTable.js:
--------------------------------------------------------------------------------
1 | import Mock from 'mockjs'
2 | import { param2Obj } from '@/utils'
3 |
4 | const List = []
5 | const count = 100
6 |
7 | for (let i = 0; i < count; i++) {
8 | List.push(Mock.mock({
9 | id: '@increment',
10 | timestamp: +Mock.Random.date('T'),
11 | author: '@cname',
12 | reviewer: '@cname',
13 | 'name|1': ['HUAWEI', 'apple', 'Lenovo', 'DELL'],
14 | 'barcode|1': ['123456789', '987654321', '456987123', '896532147'],
15 | 'price|1': ['2', '2.5', '3', '8'],
16 | moneyall: '',
17 | 'step|1': ['取货员接单', ' 联系客户', '取货员接单', '申请审批通过', '发起退货申请'],
18 | 'number|1': ['2', '3', '5', '2'],
19 | 'status|1': ['进行中', '成功', '失败'],
20 | display_time: '@datetime',
21 | 'nameId|1': ['取货员 ID6666', '系统', '用户'],
22 | 'time|1': ['1h', '10mins', '5mins'],
23 | 'type|1': ['创建订单', '提交订单', '部门初审', '财务复审'],
24 | 'remarks|1': ['--', '暂无']
25 | }))
26 | }
27 |
28 | export default {
29 | list: config => {
30 | const { type, title, page = 1, limit = 20, sort } = param2Obj(config.url)
31 |
32 | let mockList = List.filter(item => {
33 | if (type && item.type !== type) return false
34 | if (title && item.title.indexOf(title) < 0) return false
35 | return true
36 | })
37 |
38 | if (sort === '-id') {
39 | mockList = mockList.reverse()
40 | }
41 |
42 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
43 |
44 | return {
45 | total: mockList.length,
46 | items: pageList
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/icons/svg/404.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | @mixin clearfix {
2 | &:after {
3 | content: "";
4 | display: table;
5 | clear: both;
6 | }
7 | }
8 |
9 | @mixin scrollBar {
10 | &::-webkit-scrollbar-track-piece {
11 | background: #d3dce6;
12 | }
13 | &::-webkit-scrollbar {
14 | width: 6px;
15 | }
16 | &::-webkit-scrollbar-thumb {
17 | background: #99a9bf;
18 | border-radius: 20px;
19 | }
20 | }
21 |
22 | @mixin relative {
23 | position: relative;
24 | width: 100%;
25 | height: 100%;
26 | }
27 |
28 | @mixin pct($pct) {
29 | width: #{$pct};
30 | position: relative;
31 | margin: 0 auto;
32 | }
33 |
34 | @mixin triangle($width, $height, $color, $direction) {
35 | $width: $width/2;
36 | $color-border-style: $height solid $color;
37 | $transparent-border-style: $width solid transparent;
38 | height: 0;
39 | width: 0;
40 | @if $direction==up {
41 | border-bottom: $color-border-style;
42 | border-left: $transparent-border-style;
43 | border-right: $transparent-border-style;
44 | }
45 | @else if $direction==right {
46 | border-left: $color-border-style;
47 | border-top: $transparent-border-style;
48 | border-bottom: $transparent-border-style;
49 | }
50 | @else if $direction==down {
51 | border-top: $color-border-style;
52 | border-left: $transparent-border-style;
53 | border-right: $transparent-border-style;
54 | }
55 | @else if $direction==left {
56 | border-right: $color-border-style;
57 | border-top: $transparent-border-style;
58 | border-bottom: $transparent-border-style;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/icons/svg/copyright.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/pages/layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Copyright 2018 传智研究院出品
15 |
16 |
17 |
18 |
19 |
20 |
41 |
42 |
58 |
--------------------------------------------------------------------------------
/src/icons/svg/shoppingCard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Breadcrumb/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{generateTitle(item.meta.title)}}
6 | {{generateTitle(item.meta.title)}}
7 |
8 |
9 |
10 |
11 |
12 |
44 |
45 |
57 |
--------------------------------------------------------------------------------
/src/components/ScrollBar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
46 |
47 |
61 |
--------------------------------------------------------------------------------
/src/icons/svg/bug.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/people.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/e2e/runner.js:
--------------------------------------------------------------------------------
1 | // 1. start the dev server using production config
2 | process.env.NODE_ENV = 'testing'
3 |
4 | const webpack = require('webpack')
5 | const DevServer = require('webpack-dev-server')
6 |
7 | const webpackConfig = require('../../build/webpack.prod.conf')
8 | const devConfigPromise = require('../../build/webpack.dev.conf')
9 |
10 | let server
11 |
12 | devConfigPromise.then(devConfig => {
13 | const devServerOptions = devConfig.devServer
14 | const compiler = webpack(webpackConfig)
15 | server = new DevServer(compiler, devServerOptions)
16 | const port = devServerOptions.port
17 | const host = devServerOptions.host
18 | return server.listen(port, host)
19 | })
20 | .then(() => {
21 | // 2. run the nightwatch test suite against it
22 | // to run in additional browsers:
23 | // 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings"
24 | // 2. add it to the --env flag below
25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
26 | // For more information on Nightwatch's config file, see
27 | // http://nightwatchjs.org/guide#settings-file
28 | let opts = process.argv.slice(2)
29 | if (opts.indexOf('--config') === -1) {
30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
31 | }
32 | if (opts.indexOf('--env') === -1) {
33 | opts = opts.concat(['--env', 'chrome'])
34 | }
35 |
36 | const spawn = require('cross-spawn')
37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
38 |
39 | runner.on('exit', function (code) {
40 | server.close()
41 | process.exit(code)
42 | })
43 |
44 | runner.on('error', function (err) {
45 | server.close()
46 | throw err
47 | })
48 | })
49 |
--------------------------------------------------------------------------------
/src/icons/svg/table.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/styles/btn.scss:
--------------------------------------------------------------------------------
1 | @import './variables.scss';
2 |
3 | @mixin colorBtn($color) {
4 | background: $color;
5 | &:hover {
6 | color: $color;
7 | &:before,
8 | &:after {
9 | background: $color;
10 | }
11 | }
12 | }
13 |
14 | .blue-btn {
15 | @include colorBtn($blue)
16 | }
17 |
18 | .light-blue-btn {
19 | @include colorBtn($light-blue)
20 | }
21 |
22 | .red-btn {
23 | @include colorBtn($red)
24 | }
25 |
26 | .pink-btn {
27 | @include colorBtn($pink)
28 | }
29 |
30 | .green-btn {
31 | @include colorBtn($green)
32 | }
33 |
34 | .tiffany-btn {
35 | @include colorBtn($tiffany)
36 | }
37 |
38 | .yellow-btn {
39 | @include colorBtn($yellow)
40 | }
41 |
42 | .pan-btn {
43 | font-size: 14px;
44 | color: #fff;
45 | padding: 14px 36px;
46 | border-radius: 8px;
47 | border: none;
48 | outline: none;
49 | margin-right: 25px;
50 | transition: 600ms ease all;
51 | position: relative;
52 | display: inline-block;
53 | &:hover {
54 | background: #fff;
55 | &:before,
56 | &:after {
57 | width: 100%;
58 | transition: 600ms ease all;
59 | }
60 | }
61 | &:before,
62 | &:after {
63 | content: '';
64 | position: absolute;
65 | top: 0;
66 | right: 0;
67 | height: 2px;
68 | width: 0;
69 | transition: 400ms ease all;
70 | }
71 | &::after {
72 | right: inherit;
73 | top: inherit;
74 | left: 0;
75 | bottom: 0;
76 | }
77 | }
78 |
79 | .custom-button {
80 | display: inline-block;
81 | line-height: 1;
82 | white-space: nowrap;
83 | cursor: pointer;
84 | background: #fff;
85 | color: #fff;
86 | -webkit-appearance: none;
87 | text-align: center;
88 | box-sizing: border-box;
89 | outline: 0;
90 | margin: 0;
91 | padding: 10px 15px;
92 | font-size: 14px;
93 | border-radius: 4px;
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/src/icons/svg/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/icons/svg/international.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-form/pages/activePublic/step3.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 | 将文件拖到此处,或点击上传
23 | 图片尺寸建议比例1:1,如160*160像素,图片不能大于2M
24 |
25 |
26 |
27 |
28 |
29 |
30 |
64 |
72 |
--------------------------------------------------------------------------------
/src/lang/zh.js:
--------------------------------------------------------------------------------
1 | export default {
2 | route: {
3 | dashboard: '首页',
4 | manage: '后台管理',
5 | users: '用户管理',
6 | menus: '菜单管理',
7 | permissions: '权限管理',
8 | logs: '日志管理',
9 | example: '示例',
10 | table: '数据列表',
11 |
12 | list: '列表页',
13 | tableList: '查询表格',
14 | basicList: '标准列表',
15 | cardList: '卡片列表',
16 |
17 | form: '表单页',
18 | basicForm: '基础表单',
19 | stepForm: '分步表单',
20 | advancedList: '高级表单',
21 | step: '步骤',
22 |
23 | details: '详情页',
24 | BasicsDetails: '基础详情页',
25 | seniorDetails: '高级详情页'
26 | },
27 | navbar: {
28 | search: '站内搜索',
29 | logOut: '退出登录',
30 | dashboard: '首页',
31 | github: '项目地址',
32 | screenfull: '全屏',
33 | theme: '换肤',
34 | lang: '多语言',
35 | error: '错误日志'
36 | },
37 | login: {
38 | title: '黑马Admin',
39 | logIn: '登录',
40 | username: '账号',
41 | password: '密码',
42 | any: '随便填',
43 | thirdparty: '第三方登录',
44 | thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
45 | },
46 | tagsView: {
47 | close: '关闭',
48 | closeOthers: '关闭其它',
49 | closeAll: '关闭所有'
50 | },
51 | table: {
52 | title: '请输入用户',
53 | search: '搜索',
54 | add: '添加',
55 | addUser: '新增用户',
56 | id: '序号',
57 | email: '邮箱',
58 | phone: '联系电话',
59 | username: '用户名',
60 | permissionNew: '新增权限组',
61 | permissionUser: '权限组名称',
62 | imdsAi: '高级接口授权',
63 | avatar: '头像',
64 | introduction: '介绍',
65 | paddword: '密码',
66 | powerCode: '权限代码',
67 | powerDistriB: '权限分配',
68 | powerTitle: '权限标题',
69 | powerNav: '主导航',
70 | actions: '操作',
71 | edit: '编辑',
72 | delete: '删除',
73 | cancel: '取 消',
74 | confirm: '确 定',
75 | operationType: '操作类型',
76 | operationDate: '操作时间',
77 | date: '日期',
78 | operator: '操作人',
79 | results: '执行结果',
80 | describe: '描述',
81 | preserve: '保存',
82 | signOut: '退出'
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/icons/svg/dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Screenfull/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
55 |
56 |
67 |
--------------------------------------------------------------------------------
/src/icons/svg/wechat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/layoutSidebarItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
53 |
--------------------------------------------------------------------------------
/src/lang/en.js:
--------------------------------------------------------------------------------
1 | export default {
2 | route: {
3 | dashboard: 'Dashboard',
4 | manage: 'manage',
5 | users: 'users',
6 | menus: 'menus',
7 | permissions: 'permissions',
8 | logs: 'logs',
9 | example: 'example',
10 | table: 'table',
11 |
12 | list: 'list',
13 | tableList: 'table list',
14 | basicList: 'basic list',
15 | cardList: 'card list',
16 |
17 | form: 'form',
18 | basicForm: 'basic form',
19 | stepForm: 'step form',
20 | advancedList: 'advanced form',
21 | step: 'step',
22 |
23 | details: 'details',
24 | BasicsDetails: 'Basic details page',
25 | seniorDetails: 'Advanced details page'
26 | },
27 | navbar: {
28 | search: 'search',
29 | logOut: 'Log Out',
30 | dashboard: 'Dashboard',
31 | github: 'Github',
32 | screenfull: 'screenfull',
33 | theme: 'theme',
34 | lang: 'i18n',
35 | error: 'error log'
36 | },
37 | login: {
38 | title: 'itheima login',
39 | logIn: 'Log in',
40 | username: 'Username',
41 | password: 'Password',
42 | any: 'any',
43 | thirdparty: 'Third',
44 | thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !'
45 | },
46 | tagsView: {
47 | close: 'Close',
48 | closeOthers: 'Close Others',
49 | closeAll: 'Close All'
50 | },
51 | table: {
52 | title: 'Title',
53 | search: 'Search',
54 | add: 'add',
55 | addUser: 'addUser',
56 | id: 'ID',
57 | email: 'Email',
58 | phone: 'Phone',
59 | username: 'User',
60 | permissionNew: 'permissionNew',
61 | permissionUser: 'Permission',
62 | imdsAi: 'Advanced interface authorization',
63 | avatar: 'Avatar',
64 | introduction: 'Introduction',
65 | paddword: 'paddWord',
66 | powerCode: 'Permission code',
67 | powerTitle: 'Permission title',
68 | actions: 'Actions',
69 | edit: 'Edit',
70 | delete: 'Delete',
71 | cancel: 'Cancel',
72 | confirm: 'Confirm',
73 | operationType: 'operationType',
74 | operationDate: 'operationDate',
75 | date: 'Date',
76 | operator: 'operator',
77 | results: 'results of enforcement',
78 | describe: 'Pedagogical operation',
79 | preserve: 'preserve',
80 | signOut: 'sign out'
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/dashboardPieChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
85 |
--------------------------------------------------------------------------------
/src/components/ScrollPane/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
67 |
68 |
79 |
--------------------------------------------------------------------------------
/src/module-dashboard/store/tagsView.js:
--------------------------------------------------------------------------------
1 | const tagsView = {
2 | state: {
3 | visitedViews: [],
4 | cachedViews: []
5 | },
6 | mutations: {
7 | ADD_VISITED_VIEWS: (state, view) => {
8 | if (state.visitedViews.some(v => v.path === view.path)) return
9 | state.visitedViews.push({
10 | name: view.name,
11 | path: view.path,
12 | title: view.meta.title || 'no-name'
13 | })
14 | if (!view.meta.noCache) {
15 | state.cachedViews.push(view.name)
16 | }
17 | },
18 | DEL_VISITED_VIEWS: (state, view) => {
19 | for (const [i, v] of state.visitedViews.entries()) {
20 | if (v.path === view.path) {
21 | state.visitedViews.splice(i, 1)
22 | break
23 | }
24 | }
25 | for (const i of state.cachedViews) {
26 | if (i === view.name) {
27 | const index = state.cachedViews.indexOf(i)
28 | state.cachedViews.splice(index, 1)
29 | break
30 | }
31 | }
32 | },
33 | DEL_OTHERS_VIEWS: (state, view) => {
34 | for (const [i, v] of state.visitedViews.entries()) {
35 | if (v.path === view.path) {
36 | state.visitedViews = state.visitedViews.slice(i, i + 1)
37 | break
38 | }
39 | }
40 | for (const i of state.cachedViews) {
41 | if (i === view.name) {
42 | const index = state.cachedViews.indexOf(i)
43 | state.cachedViews = state.cachedViews.slice(index, i + 1)
44 | break
45 | }
46 | }
47 | },
48 | DEL_ALL_VIEWS: (state) => {
49 | state.visitedViews = []
50 | state.cachedViews = []
51 | }
52 | },
53 | actions: {
54 | addVisitedViews({ commit }, view) {
55 | commit('ADD_VISITED_VIEWS', view)
56 | },
57 | delVisitedViews({ commit, state }, view) {
58 | return new Promise((resolve) => {
59 | commit('DEL_VISITED_VIEWS', view)
60 | resolve([...state.visitedViews])
61 | })
62 | },
63 | delOthersViews({ commit, state }, view) {
64 | return new Promise((resolve) => {
65 | commit('DEL_OTHERS_VIEWS', view)
66 | resolve([...state.visitedViews])
67 | })
68 | },
69 | delAllViews({ commit, state }) {
70 | return new Promise((resolve) => {
71 | commit('DEL_ALL_VIEWS')
72 | resolve([...state.visitedViews])
73 | })
74 | }
75 | }
76 | }
77 |
78 | export default tagsView
79 |
--------------------------------------------------------------------------------
/src/icons/svg/zip.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/module-dashboard/pages/401.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
返回
4 |
5 |
6 | Oops!
7 | gif来源airbnb 页面
8 | 你没有权限去该页面
9 | 如有不满请联系你领导
10 |
11 | - 或者你可以去:
12 | -
13 | 回首页
14 |
15 | - 随便看看
16 | - 点我看图
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
52 |
53 |
89 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/loginSocialSignin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Wechat
5 |
6 |
7 | QQ
8 |
9 |
10 |
11 |
12 |
48 |
49 |
82 |
--------------------------------------------------------------------------------
/src/icons/svg/form.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/dashboardBarChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
107 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 | // Paths
10 | assetsSubDirectory: 'static',
11 | assetsPublicPath: '',
12 | proxyTable: {
13 | '/api': {
14 | // target: 'https://www.easy-mock.com/mock/5ab213e33666166110a94928/admin',
15 | // target: 'http://172.17.0.58:7999',
16 | // target: 'http://127.0.0.1:7001',
17 | target: 'http://172.17.0.120:8090',
18 | changeOrigin: true,
19 | pathRewrite: {
20 | '^/api': ''
21 | }
22 | }
23 | },
24 |
25 | // Various Dev Server settings
26 | host: 'localhost', // can be overwritten by process.env.HOST
27 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
28 | autoOpenBrowser: false,
29 | errorOverlay: true,
30 | notifyOnErrors: true,
31 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
32 |
33 | // Use Eslint Loader?
34 | // If true, your code will be linted during bundling and
35 | // linting errors and warnings will be shown in the console.
36 | useEslint: true,
37 | // If true, eslint errors and warnings will also be shown in the error overlay
38 | // in the browser.
39 | showEslintErrorsInOverlay: false,
40 |
41 | /**
42 | * Source Maps
43 | */
44 |
45 | // https://webpack.js.org/configuration/devtool/#development
46 | devtool: 'cheap-module-eval-source-map',
47 |
48 | // If you have problems debugging vue-files in devtools,
49 | // set this to false - it *may* help
50 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
51 | cacheBusting: true,
52 |
53 | cssSourceMap: true
54 | },
55 |
56 | build: {
57 | // Template for index.html
58 | index: path.resolve(__dirname, '../dist/index.html'),
59 |
60 | // Paths
61 | assetsRoot: path.resolve(__dirname, '../dist'),
62 | assetsSubDirectory: 'static',
63 | assetsPublicPath: '',
64 |
65 | /**
66 | * Source Maps
67 | */
68 |
69 | productionSourceMap: true,
70 | // https://webpack.js.org/configuration/devtool/#production
71 | devtool: '#source-map',
72 |
73 | // Gzip off by default as many popular static hosts such as
74 | // Surge or Netlify already gzip all static assets for you.
75 | // Before setting to `true`, make sure to:
76 | // npm install --save-dev compression-webpack-plugin
77 | productionGzip: false,
78 | productionGzipExtensions: ['js', 'css'],
79 |
80 | // Run the build command with an extra argument to
81 | // View the bundle analyzer report after build finishes:
82 | // `npm run build --report`
83 | // Set to `true` or `false` to always turn it on or off
84 | bundleAnalyzerReport: process.env.npm_config_report
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/module-form/pages/step-form.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 上一步
17 | 下一步
18 |
19 |
20 |
21 |
22 |
23 |
24 |
95 |
103 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import {Message} from 'element-ui'
3 | import store from '@/store'
4 | import {getToken} from '@/utils/auth'
5 |
6 | // create an axios instance
7 | const instance = axios.create({
8 | baseURL: process.env.BASE_API, // api的base_url
9 | timeout: 5000 // request timeout
10 | })
11 |
12 | // request interceptor
13 | instance.interceptors.request.use(
14 | config => {
15 | // Do something before request is sent
16 | if (store.getters.token) {
17 | config.headers['Authorization'] = `VEA-ADMIN ${getToken()}` // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
18 | }
19 | return config
20 | },
21 | error => {
22 | // Do something with request error
23 | console.log(error) // for debug
24 | Promise.reject(error)
25 | }
26 | )
27 |
28 | // respone interceptor
29 | instance.interceptors.response.use(
30 | response => response,
31 | /**
32 | * 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
33 | * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
34 | */
35 | // const res = response.data;
36 | // if (res.code !== 20000) {
37 | // Message({
38 | // message: res.message,
39 | // type: 'error',
40 | // duration: 5 * 1000
41 | // });
42 | // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
43 | // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
44 | // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
45 | // confirmButtonText: '重新登录',
46 | // cancelButtonText: '取消',
47 | // type: 'warning'
48 | // }).then(() => {
49 | // store.dispatch('FedLogOut').then(() => {
50 | // location.reload();// 为了重新实例化vue-router对象 避免bug
51 | // });
52 | // })
53 | // }
54 | // return Promise.reject('error');
55 | // } else {
56 | // return response.data;
57 | // }
58 | error => {
59 | console.log('err' + error) // for debug
60 | Message({
61 | message: error.message,
62 | type: 'error',
63 | duration: 5 * 1000
64 | })
65 | return Promise.reject(error)
66 | }
67 | )
68 |
69 | export const createAPI = (url, method, data) => {
70 | let config = {}
71 | if (method === 'get') {
72 | config.params = data
73 | } else {
74 | config.data = data
75 | }
76 | return instance({
77 | url,
78 | method,
79 | ...config
80 | })
81 | }
82 |
83 | export const createFormAPI = (url, method, data) => {
84 | let config = {}
85 | config.data = data
86 | config.headers = {
87 | 'Cache-Control': 'no-cache',
88 | 'Content-Type': 'application/x-www-form-urlencoded'
89 | }
90 | config.responseType = 'json'
91 | config.transformRequest = [
92 | function(data) {
93 | let ret = ''
94 | for (let it in data) {
95 | ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
96 | }
97 | return ret
98 | }
99 | ]
100 | return instance({
101 | url,
102 | method,
103 | ...config
104 | })
105 | }
106 |
--------------------------------------------------------------------------------
/src/module-form/pages/activePublic/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | 上一步
16 | 下一步
17 |
18 |
19 |
20 |
21 |
22 |
23 |
89 |
129 |
--------------------------------------------------------------------------------
/src/filters/index.js:
--------------------------------------------------------------------------------
1 | function pluralize(time, label) {
2 | if (time === 1) {
3 | return time + label
4 | }
5 | return time + label + 's'
6 | }
7 |
8 | export function timeAgo(time) {
9 | const between = Date.now() / 1000 - Number(time)
10 | if (between < 3600) {
11 | return pluralize(~~(between / 60), ' minute')
12 | } else if (between < 86400) {
13 | return pluralize(~~(between / 3600), ' hour')
14 | } else {
15 | return pluralize(~~(between / 86400), ' day')
16 | }
17 | }
18 |
19 | export function parseTime(time, cFormat) {
20 | if (arguments.length === 0) {
21 | return null
22 | }
23 |
24 | if ((time + '').length === 10) {
25 | time = +time * 1000
26 | }
27 |
28 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
29 | let date
30 | if (typeof time === 'object') {
31 | date = time
32 | } else {
33 | date = new Date(parseInt(time))
34 | }
35 | const formatObj = {
36 | y: date.getFullYear(),
37 | m: date.getMonth() + 1,
38 | d: date.getDate(),
39 | h: date.getHours(),
40 | i: date.getMinutes(),
41 | s: date.getSeconds(),
42 | a: date.getDay()
43 | }
44 | const timeStr = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
45 | let value = formatObj[key]
46 | if (key === 'a') {
47 | return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
48 | }
49 | if (result.length > 0 && value < 10) {
50 | value = '0' + value
51 | }
52 | return value || 0
53 | })
54 | return timeStr
55 | }
56 |
57 | export function formatTime(time, option) {
58 | time = +time * 1000
59 | const d = new Date(time)
60 | const now = Date.now()
61 |
62 | const diff = (now - d) / 1000
63 |
64 | if (diff < 30) {
65 | return '刚刚'
66 | } else if (diff < 3600) {
67 | // less 1 hour
68 | return Math.ceil(diff / 60) + '分钟前'
69 | } else if (diff < 3600 * 24) {
70 | return Math.ceil(diff / 3600) + '小时前'
71 | } else if (diff < 3600 * 24 * 2) {
72 | return '1天前'
73 | }
74 | if (option) {
75 | return parseTime(time, option)
76 | } else {
77 | return (
78 | d.getMonth() +
79 | 1 +
80 | '月' +
81 | d.getDate() +
82 | '日' +
83 | d.getHours() +
84 | '时' +
85 | d.getMinutes() +
86 | '分'
87 | )
88 | }
89 | }
90 |
91 | /* 数字 格式化 */
92 | export function nFormatter(num, digits) {
93 | const si = [
94 | {value: 1e18, symbol: 'E'},
95 | {value: 1e15, symbol: 'P'},
96 | {value: 1e12, symbol: 'T'},
97 | {value: 1e9, symbol: 'G'},
98 | {value: 1e6, symbol: 'M'},
99 | {value: 1e3, symbol: 'k'}
100 | ]
101 | for (let i = 0; i < si.length; i++) {
102 | if (num >= si[i].value) {
103 | return (
104 | (num / si[i].value + 0.1)
105 | .toFixed(digits)
106 | .replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1') + si[i].symbol
107 | )
108 | }
109 | }
110 | return num.toString()
111 | }
112 |
113 | export function html2Text(val) {
114 | const div = document.createElement('div')
115 | div.innerHTML = val
116 | return div.textContent || div.innerText
117 | }
118 |
119 | export function toThousandslsFilter(num) {
120 | return (+num || 0)
121 | .toString()
122 | .replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
123 | }
124 |
--------------------------------------------------------------------------------
/src/module-dashboard/store/user.js:
--------------------------------------------------------------------------------
1 | import { login, logout, profile } from '@/api/base/frame'
2 | import { getToken, setToken, removeToken } from '@/utils/auth'
3 |
4 | const user = {
5 | state: {
6 | user: '',
7 | status: '',
8 | code: '',
9 | token: getToken(),
10 | name: '',
11 | avatar: '',
12 | introduction: '',
13 | roles: [],
14 | setting: {
15 | articlePlatform: []
16 | }
17 | },
18 |
19 | mutations: {
20 | SET_CODE: (state, code) => {
21 | state.code = code
22 | },
23 | SET_TOKEN: (state, token) => {
24 | state.token = token
25 | },
26 | SET_INTRODUCTION: (state, introduction) => {
27 | state.introduction = introduction
28 | },
29 | SET_SETTING: (state, setting) => {
30 | state.setting = setting
31 | },
32 | SET_STATUS: (state, status) => {
33 | state.status = status
34 | },
35 | SET_NAME: (state, name) => {
36 | state.name = name
37 | },
38 | SET_AVATAR: (state, avatar) => {
39 | state.avatar = avatar || 'http://or45inefq.bkt.clouddn.com/itheima-avatar.png'
40 | },
41 | SET_ROLES: (state, roles) => {
42 | state.roles = roles
43 | }
44 | },
45 |
46 | actions: {
47 | // 用户名登录
48 | LoginByUsername({ commit }, userInfo) {
49 | const username = userInfo.username.trim()
50 | return new Promise((resolve, reject) => {
51 | login({
52 | username: username,
53 | password: userInfo.password
54 | }).then(response => {
55 | const data = response.data
56 | commit('SET_TOKEN', data.token)
57 | setToken(response.data.token)
58 | resolve()
59 | }).catch(error => {
60 | reject(error)
61 | })
62 | })
63 | },
64 |
65 | // 获取用户信息
66 | GetUserInfo({ commit, state }) {
67 | return new Promise((resolve, reject) => {
68 | profile().then(response => {
69 | const data = response.data
70 | commit('SET_ROLES', data.roles)
71 | commit('SET_NAME', data.name)
72 | commit('SET_AVATAR', data.avatar)
73 | commit('SET_INTRODUCTION', data.introduction)
74 | resolve(response)
75 | }).catch(error => {
76 | reject(error)
77 | })
78 | })
79 | },
80 |
81 | // 第三方验证登录
82 | // LoginByThirdparty({ commit, state }, code) {
83 | // return new Promise((resolve, reject) => {
84 | // commit('SET_CODE', code)
85 | // loginByThirdparty(state.status, state.email, state.code).then(response => {
86 | // commit('SET_TOKEN', response.data.token)
87 | // setToken(response.data.token)
88 | // resolve()
89 | // }).catch(error => {
90 | // reject(error)
91 | // })
92 | // })
93 | // },
94 |
95 | // 登出
96 | LogOut({ commit, state }) {
97 | return new Promise((resolve, reject) => {
98 | logout().then(() => {
99 | commit('SET_TOKEN', '')
100 | commit('SET_ROLES', [])
101 | removeToken()
102 | resolve()
103 | }).catch(error => {
104 | reject(error)
105 | })
106 | })
107 | },
108 |
109 | // 前端 登出
110 | FedLogOut({ commit }) {
111 | return new Promise(resolve => {
112 | commit('SET_TOKEN', '')
113 | removeToken()
114 | resolve()
115 | })
116 | }
117 |
118 | }
119 | }
120 |
121 | export default user
122 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/dashboardRaddarChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
121 |
--------------------------------------------------------------------------------
/src/module-form/components/address.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
124 |
130 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "itheima-admin",
3 | "version": "1.0.0",
4 | "description": "黑马Admin 管理系统基础模板",
5 | "author": "taoshiwei ",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "unit": "jest --config test/unit/jest.conf.js --coverage",
11 | "e2e": "node test/e2e/runner.js",
12 | "test": "npm run unit && npm run e2e",
13 | "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
14 | "build": "node build/build.js"
15 | },
16 | "dependencies": {
17 | "axios": "^0.18.0",
18 | "echarts": "^3.8.5",
19 | "element-ui": "^2.2.2",
20 | "font-awesome": "^4.7.0",
21 | "js-cookie": "^2.2.0",
22 | "normalize.css": "^8.0.0",
23 | "nprogress": "^0.2.0",
24 | "screenfull": "^3.3.2",
25 | "sha.js": "^2.4.11",
26 | "vue": "^2.5.2",
27 | "vue-i18n": "^7.6.0",
28 | "vue-router": "^3.0.1",
29 | "vuex": "^3.0.1"
30 | },
31 | "devDependencies": {
32 | "autoprefixer": "^7.1.2",
33 | "babel-core": "^6.22.1",
34 | "babel-eslint": "^8.2.1",
35 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
36 | "babel-jest": "^21.0.2",
37 | "babel-loader": "^7.1.1",
38 | "babel-plugin-dynamic-import-node": "^1.2.0",
39 | "babel-plugin-syntax-jsx": "^6.18.0",
40 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
41 | "babel-plugin-transform-runtime": "^6.22.0",
42 | "babel-plugin-transform-vue-jsx": "^3.5.0",
43 | "babel-preset-env": "^1.3.2",
44 | "babel-preset-stage-2": "^6.22.0",
45 | "babel-register": "^6.22.0",
46 | "chalk": "^2.0.1",
47 | "chromedriver": "^2.27.2",
48 | "copy-webpack-plugin": "^4.0.1",
49 | "cross-spawn": "^5.0.1",
50 | "css-loader": "^0.28.0",
51 | "eslint": "^4.15.0",
52 | "eslint-config-standard": "^10.2.1",
53 | "eslint-friendly-formatter": "^3.0.0",
54 | "eslint-loader": "^1.7.1",
55 | "eslint-plugin-import": "^2.7.0",
56 | "eslint-plugin-node": "^5.2.0",
57 | "eslint-plugin-promise": "^3.4.0",
58 | "eslint-plugin-standard": "^3.0.1",
59 | "eslint-plugin-vue": "^4.0.0",
60 | "extract-text-webpack-plugin": "^3.0.0",
61 | "file-loader": "^1.1.4",
62 | "font-awesome": "^4.7.0",
63 | "friendly-errors-webpack-plugin": "^1.6.1",
64 | "html-webpack-plugin": "^2.30.1",
65 | "jest": "^22.0.4",
66 | "jest-serializer-vue": "^0.3.0",
67 | "mockjs": "^1.0.1-beta3",
68 | "nightwatch": "^0.9.12",
69 | "node-notifier": "^5.1.2",
70 | "node-sass": "^4.7.2",
71 | "optimize-css-assets-webpack-plugin": "^3.2.0",
72 | "ora": "^1.2.0",
73 | "portfinder": "^1.0.13",
74 | "postcss-import": "^11.0.0",
75 | "postcss-loader": "^2.0.8",
76 | "postcss-url": "^7.2.1",
77 | "rimraf": "^2.6.0",
78 | "sass-loader": "^6.0.7",
79 | "selenium-server": "^3.0.1",
80 | "semver": "^5.3.0",
81 | "shelljs": "^0.7.6",
82 | "svg-sprite-loader": "^3.7.3",
83 | "uglifyjs-webpack-plugin": "^1.1.1",
84 | "url-loader": "^0.5.8",
85 | "vue-jest": "^1.0.2",
86 | "vue-loader": "^13.3.0",
87 | "vue-style-loader": "^3.0.1",
88 | "vue-template-compiler": "^2.5.2",
89 | "webpack": "^3.6.0",
90 | "webpack-bundle-analyzer": "^2.9.0",
91 | "webpack-dev-server": "^2.9.1",
92 | "webpack-merge": "^4.1.0"
93 | },
94 | "engines": {
95 | "node": ">= 6.0.0",
96 | "npm": ">= 3.0.0"
97 | },
98 | "browserslist": [
99 | "> 1%",
100 | "last 2 versions",
101 | "not ie <= 8"
102 | ]
103 | }
104 |
--------------------------------------------------------------------------------
/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{name}}",
3 | "version": "1.0.0",
4 | "description": "{{description}}",
5 | "author": "{{author}}",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "unit": "jest --config test/unit/jest.conf.js --coverage",
11 | "e2e": "node test/e2e/runner.js",
12 | "test": "npm run unit && npm run e2e",
13 | "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
14 | "build": "node build/build.js",
15 | "art:create": "mkdir src/module-${module} && mkdir src/module-${module}/assets && mkdir src/module-${module}/pages && mkdir src/module-${module}/components && mkdir src/module-${module}/router && mkdir src/module-${module}/store"
16 | },
17 | "dependencies": {
18 | "axios": "^0.18.0",
19 | "echarts": "^3.8.5",
20 | "element-ui": "^2.2.2",
21 | "font-awesome": "^4.7.0",
22 | "js-cookie": "^2.2.0",
23 | "normalize.css": "^8.0.0",
24 | "nprogress": "^0.2.0",
25 | "screenfull": "^3.3.2",
26 | "sha.js": "^2.4.11",
27 | "vue": "^2.5.2",
28 | "vue-i18n": "^7.6.0",
29 | "vue-router": "^3.0.1",
30 | "vuex": "^3.0.1"
31 | },
32 | "devDependencies": {
33 | "autoprefixer": "^7.1.2",
34 | "babel-core": "^6.22.1",
35 | "babel-eslint": "^8.2.1",
36 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
37 | "babel-jest": "^21.0.2",
38 | "babel-loader": "^7.1.1",
39 | "babel-plugin-dynamic-import-node": "^1.2.0",
40 | "babel-plugin-syntax-jsx": "^6.18.0",
41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
42 | "babel-plugin-transform-runtime": "^6.22.0",
43 | "babel-plugin-transform-vue-jsx": "^3.5.0",
44 | "babel-preset-env": "^1.3.2",
45 | "babel-preset-stage-2": "^6.22.0",
46 | "babel-register": "^6.22.0",
47 | "chalk": "^2.0.1",
48 | "chromedriver": "^2.27.2",
49 | "copy-webpack-plugin": "^4.0.1",
50 | "cross-spawn": "^5.0.1",
51 | "css-loader": "^0.28.0",
52 | "eslint": "^4.15.0",
53 | "eslint-config-standard": "^10.2.1",
54 | "eslint-friendly-formatter": "^3.0.0",
55 | "eslint-loader": "^1.7.1",
56 | "eslint-plugin-import": "^2.7.0",
57 | "eslint-plugin-node": "^5.2.0",
58 | "eslint-plugin-promise": "^3.4.0",
59 | "eslint-plugin-standard": "^3.0.1",
60 | "eslint-plugin-vue": "^4.0.0",
61 | "extract-text-webpack-plugin": "^3.0.0",
62 | "file-loader": "^1.1.4",
63 | "friendly-errors-webpack-plugin": "^1.6.1",
64 | "html-webpack-plugin": "^2.30.1",
65 | "jest": "^22.0.4",
66 | "jest-serializer-vue": "^0.3.0",
67 | "nightwatch": "^0.9.12",
68 | "node-notifier": "^5.1.2",
69 | "node-sass": "^4.7.2",
70 | "optimize-css-assets-webpack-plugin": "^3.2.0",
71 | "ora": "^1.2.0",
72 | "portfinder": "^1.0.13",
73 | "postcss-import": "^11.0.0",
74 | "postcss-loader": "^2.0.8",
75 | "postcss-url": "^7.2.1",
76 | "rimraf": "^2.6.0",
77 | "sass-loader": "^6.0.7",
78 | "selenium-server": "^3.0.1",
79 | "semver": "^5.3.0",
80 | "shelljs": "^0.7.6",
81 | "svg-sprite-loader": "^3.7.3",
82 | "uglifyjs-webpack-plugin": "^1.1.1",
83 | "url-loader": "^0.5.8",
84 | "vue-jest": "^1.0.2",
85 | "vue-loader": "^13.3.0",
86 | "vue-style-loader": "^3.0.1",
87 | "vue-template-compiler": "^2.5.2",
88 | "webpack": "^3.6.0",
89 | "webpack-bundle-analyzer": "^2.9.0",
90 | "webpack-dev-server": "^2.9.1",
91 | "webpack-merge": "^4.1.0"
92 | },
93 | "engines": {
94 | "node": ">= 6.0.0",
95 | "npm": ">= 3.0.0"
96 | },
97 | "browserslist": [
98 | "> 1%",
99 | "last 2 versions",
100 | "not ie <= 8"
101 | ]
102 | }
103 |
--------------------------------------------------------------------------------
/src/components/ErrorLog/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Msg:
21 | {{ scope.row.err.message }}
22 |
23 |
24 |
25 | Info:
26 | {{scope.row.vm.$vnode.tag}} error in {{scope.row.info}}
27 |
28 |
29 |
30 | Url:
31 | {{scope.row.url}}
32 |
33 |
34 |
35 |
36 |
37 | {{ scope.row.err.stack}}
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
61 |
62 |
80 |
--------------------------------------------------------------------------------
/src/components/TreeTable/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
14 |
15 |
16 | {{scope.row[column.value]}}
17 |
18 |
19 |
20 |
21 |
22 |
26 | 修改
27 |
28 |
32 | 删除
33 |
34 |
35 |
36 |
37 |
38 |
39 |
102 |
123 |
124 |
155 |
--------------------------------------------------------------------------------
/src/api/base/menus.js:
--------------------------------------------------------------------------------
1 | import {createAPI} from '@/utils/request'
2 |
3 | export const list = data => createAPI('/base/menus', 'get', data)
4 | export const add = data => createAPI('/base/menus', 'post', data)
5 | export const update = data => createAPI(`/base/menus/${data.id}`, 'put', data)
6 | export const remove = data => createAPI(`/base/menus/${data.id}`, 'delete', data)
7 | export const detail = data => createAPI(`/base/menus/${data.id}`, 'get', data)
8 |
9 | export const search = data => {
10 | return [
11 | {value: '三全鲜食(北新泾店)', address: '长宁区新渔路144号'},
12 | {value: 'Hot honey 首尔炸鸡(仙霞路)', address: '上海市长宁区淞虹路661号'},
13 | {
14 | value: '新旺角茶餐厅',
15 | address: '上海市普陀区真北路988号创邑金沙谷6号楼113'
16 | },
17 | {value: '泷千家(天山西路店)', address: '天山西路438号'},
18 | {
19 | value: '胖仙女纸杯蛋糕(上海凌空店)',
20 | address: '上海市长宁区金钟路968号1幢18号楼一层商铺18-101'
21 | },
22 | {value: '贡茶', address: '上海市长宁区金钟路633号'},
23 | {
24 | value: '豪大大香鸡排超级奶爸',
25 | address: '上海市嘉定区曹安公路曹安路1685号'
26 | },
27 | {value: '茶芝兰(奶茶,手抓饼)', address: '上海市普陀区同普路1435号'},
28 | {value: '十二泷町', address: '上海市北翟路1444弄81号B幢-107'},
29 | {value: '星移浓缩咖啡', address: '上海市嘉定区新郁路817号'},
30 | {value: '阿姨奶茶/豪大大', address: '嘉定区曹安路1611号'},
31 | {value: '新麦甜四季甜品炸鸡', address: '嘉定区曹安公路2383弄55号'},
32 | {
33 | value: 'Monica摩托主题咖啡店',
34 | address: '嘉定区江桥镇曹安公路2409号1F,2383弄62号1F'
35 | },
36 | {
37 | value: '浮生若茶(凌空soho店)',
38 | address: '上海长宁区金钟路968号9号楼地下一层'
39 | },
40 | {value: 'NONO JUICE 鲜榨果汁', address: '上海市长宁区天山西路119号'},
41 | {value: 'CoCo都可(北新泾店)', address: '上海市长宁区仙霞西路'},
42 | {
43 | value: '快乐柠檬(神州智慧店)',
44 | address: '上海市长宁区天山西路567号1层R117号店铺'
45 | },
46 | {
47 | value: 'Merci Paul cafe',
48 | address: '上海市普陀区光复西路丹巴路28弄6号楼819'
49 | },
50 | {
51 | value: '猫山王(西郊百联店)',
52 | address: '上海市长宁区仙霞西路88号第一层G05-F01-1-306'
53 | },
54 | {value: '枪会山', address: '上海市普陀区棕榈路'},
55 | {value: '纵食', address: '元丰天山花园(东门) 双流路267号'},
56 | {value: '钱记', address: '上海市长宁区天山西路'},
57 | {value: '壹杯加', address: '上海市长宁区通协路'},
58 | {
59 | value: '唦哇嘀咖',
60 | address: '上海市长宁区新泾镇金钟路999号2幢(B幢)第01层第1-02A单元'
61 | },
62 | {value: '爱茜茜里(西郊百联)', address: '长宁区仙霞西路88号1305室'},
63 | {
64 | value: '爱茜茜里(近铁广场)',
65 | address: '上海市普陀区真北路818号近铁城市广场北区地下二楼N-B2-O2-C商铺'
66 | },
67 | {
68 | value: '鲜果榨汁(金沙江路和美广店)',
69 | address: '普陀区金沙江路2239号金沙和美广场B1-10-6'
70 | },
71 | {value: '开心丽果(缤谷店)', address: '上海市长宁区威宁路天山路341号'},
72 | {value: '超级鸡车(丰庄路店)', address: '上海市嘉定区丰庄路240号'},
73 | {value: '妙生活果园(北新泾店)', address: '长宁区新渔路144号'},
74 | {value: '香宜度麻辣香锅', address: '长宁区淞虹路148号'},
75 | {value: '凡仔汉堡(老真北路店)', address: '上海市普陀区老真北路160号'},
76 | {value: '港式小铺', address: '上海市长宁区金钟路968号15楼15-105室'},
77 | {value: '蜀香源麻辣香锅(剑河路店)', address: '剑河路443-1'},
78 | {value: '北京饺子馆', address: '长宁区北新泾街道天山西路490-1号'},
79 | {
80 | value: '饭典*新简餐(凌空SOHO店)',
81 | address: '上海市长宁区金钟路968号9号楼地下一层9-83室'
82 | },
83 | {
84 | value: '焦耳·川式快餐(金钟路店)',
85 | address: '上海市金钟路633号地下一层甲部'
86 | },
87 | {value: '动力鸡车', address: '长宁区仙霞西路299弄3号101B'},
88 | {value: '浏阳蒸菜', address: '天山西路430号'},
89 | {value: '四海游龙(天山西路店)', address: '上海市长宁区天山西路'},
90 | {
91 | value: '樱花食堂(凌空店)',
92 | address: '上海市长宁区金钟路968号15楼15-105室'
93 | },
94 | {value: '壹分米客家传统调制米粉(天山店)', address: '天山西路428号'},
95 | {
96 | value: '福荣祥烧腊(平溪路店)',
97 | address: '上海市长宁区协和路福泉路255弄57-73号'
98 | },
99 | {
100 | value: '速记黄焖鸡米饭',
101 | address: '上海市长宁区北新泾街道金钟路180号1层01号摊位'
102 | },
103 | {value: '红辣椒麻辣烫', address: '上海市长宁区天山西路492号'},
104 | {value: '(小杨生煎)西郊百联餐厅', address: '长宁区仙霞西路88号百联2楼'},
105 | {value: '阳阳麻辣烫', address: '天山西路389号'},
106 | {
107 | value: '南拳妈妈龙虾盖浇饭',
108 | address: '普陀区金沙江路1699号鑫乐惠美食广场A13'
109 | }
110 | ]
111 | }
112 |
--------------------------------------------------------------------------------
/src/components/Charts/keyboard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
153 |
--------------------------------------------------------------------------------
/src/module-form/store/store.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | /* 测试数据 */
7 | const date = 'Mon Oct 17 2016 00:00:00 GMT+0800 (中国标准时间)'
8 | const ruleForm = {
9 | name: '活动名称',
10 | fenLeis: [{
11 | name: '测试1'
12 | },
13 | {
14 | name: '测试2'
15 | },
16 | {
17 | name: '测试3'
18 | }
19 | ],
20 | fenLei: '未发布',
21 | tags: [{
22 | name: '标签1'
23 | }],
24 | activeStartTimeDate: date,
25 | activeStartTimeTime: '00:45',
26 | activeEndTimeDate: date,
27 | activeEndTimeTime: '00:45',
28 | signStartTimeDate: date,
29 | signStartTimeTime: '00:45',
30 | signEndTimeDate: date,
31 | signEndTimeTime: '00:45',
32 | activePerson: '',
33 | activePersonNum: '',
34 | activeDescribe: '',
35 | UseMsgShow: '',
36 | evaluate: '',
37 | adTitle: '',
38 | adContent: '',
39 | adLink: '',
40 | province: '北京市',
41 | city: '北京市',
42 | detail: '海淀区'
43 | }
44 |
45 | const signForm = {
46 | signUpLimit: '无限制',
47 | numLimit: '无限制',
48 | numLimitDetail: '',
49 | cost: '免费',
50 | costDetail: '',
51 | cancel: '不允许',
52 | audit: '不需要',
53 | needName: true,
54 | needTel: true,
55 | sign: '必须报名',
56 | signType: '签到二维码',
57 | secretCode: '',
58 | signFormList: []
59 | }
60 |
61 | const shareForm = {
62 | title: '分享Allen的祖传链接',
63 | describe: '这个链接很吊!'
64 | }
65 |
66 | const selfForm = {
67 | signUpSuccess: true, // 报名成功
68 | signUpSuccessText: '您已成功报名***(默认活动标题名)活动',
69 | auditSuccess: true,
70 | auditSuccessText: '您报名的***(默认活动标题名)活动,已审核通过',
71 | auditFailed: true,
72 | auditFailedText: '您报名的***(默认活动标题名)活动,审核不通过',
73 | signInSuccess: true,
74 | signInSuccessText: '***(默认用户名)您好!恭喜您签到成功!',
75 | signInFailed: true,
76 | signInFailedText: '抱歉,签到失败',
77 | signInDouble: true,
78 | signInDoubleText: '请勿重复签到!',
79 | remind: '不提醒',
80 | remindTime: '',
81 | remindText: '',
82 | useScore: '不使用',
83 | useScoreNum: '',
84 | signUpScore: '无积分',
85 | signUpScoreNum: '',
86 | shareScore: '无积分',
87 | shareScoreNum: '',
88 | shareReadScore: '无积分',
89 | shareReadScoreNum: '',
90 | shareReadScoreNumMax: '',
91 | shareSignUp: '无积分',
92 | shareSignUpNum: '',
93 | shareSignUpNumMax: '',
94 | afterShare: '',
95 | afterShareLink: '',
96 | afterSingUp: '',
97 | afterSingUpLink: '',
98 | shareImg: '',
99 | shareImgUrl: ''
100 | }
101 | const data = [{
102 | id: '1111',
103 | name: 'Allen',
104 | type: '测试活动',
105 | status: '未开始',
106 | readNum: 200,
107 | signUpNum: 100,
108 | auditNum: 5,
109 | activeMessage: {}
110 | },
111 | {
112 | id: '2222',
113 | name: '王小虎',
114 | type: '测试活动',
115 | status: '已结束',
116 | readNum: 200,
117 | signUpNum: 100,
118 | auditNum: 8,
119 | activeMessage: {}
120 | }
121 | ]
122 | /* 活动管理测试数据 */
123 | /*
124 | * ruleForm 1、活动信息的表单
125 | * signFrom 2、报名的表单
126 | * shareFrom 3、报名的表单
127 | * selfFrom 4、个性设置的表单
128 | * activeList 活动列表
129 | * */
130 | const state = {
131 | ruleForm: ruleForm,
132 | signForm: {},
133 | shareForm: {},
134 | selfForm: {},
135 | activeList: data
136 | }
137 |
138 | /* 从本地存储读取数据 */
139 | // for (var item in state) {
140 | // localStorage.getItem(item)
141 | // ? state[item] = JSON.parse(localStorage.getItem(item)) : false
142 | // }
143 |
144 | const mutations = {
145 | setRuleForm(state, payload) {
146 | Object.assign(state.ruleForm, payload)
147 | localStorage.setItem('ruleForm', JSON.stringify(payload))
148 | },
149 | setSignForm(state, payload) {
150 | Object.assign(state.signForm, payload)
151 | localStorage.setItem('signForm', JSON.stringify(payload))
152 |
153 | },
154 | setShareForm(state, payload) {
155 | Object.assign(state.shareForm, payload)
156 | localStorage.setItem('shareForm', JSON.stringify(payload))
157 | },
158 | setSelfForm(state, payload) {
159 | Object.assign(state.selfForm, payload)
160 | localStorage.setItem('selfForm', JSON.stringify(payload))
161 | }
162 | }
163 |
164 | export default new Vuex.Store({
165 | state,
166 | mutations
167 | })
168 |
--------------------------------------------------------------------------------
/src/module-dashboard/components/dashboardLineChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
154 |
--------------------------------------------------------------------------------
/src/styles/sidebar.scss:
--------------------------------------------------------------------------------
1 | #app {
2 | // 主体区域
3 | .main-container {
4 | min-height: 100%;
5 | transition: margin-left 0.28s;
6 | margin-left: 180px;
7 | } // 侧边栏
8 | .sidebar-container {
9 | -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
10 | box-shadow: 2px 0 6px rgba(0,21,41,.35);
11 | transition: width 0.28s;
12 | background-color: #001529;
13 | width: 180px!important;
14 | height: 100%;
15 | position: fixed;
16 | top: 0;
17 | bottom: 0;
18 | left: 0;
19 | z-index: 1001;
20 | a {
21 | display: inline-block;
22 | width: 100%;
23 | }
24 | .svg-icon {
25 | margin-right: 16px;
26 | }
27 | .el-menu {
28 | border: none;
29 | width: 100%;
30 | }
31 | }
32 | .hideSidebar {
33 | .sidebar-container,.sidebar-container .el-menu {
34 | width: 36px!important;
35 | overflow: inherit;
36 | }
37 | .main-container {
38 | margin-left: 36px;
39 | }
40 | }
41 | .hideSidebar {
42 | .submenu-title-noDropdown {
43 | padding-left: 10px!important;
44 | position: relative;
45 | span {
46 | height: 0;
47 | width: 0;
48 | overflow: hidden;
49 | visibility: hidden;
50 | transition: opacity .3s cubic-bezier(.55, 0, .1, 1);
51 | opacity: 0;
52 | display: inline-block;
53 | }
54 | .svg-icon {
55 | margin-left: -10px;
56 | }
57 | &:hover {
58 | span {
59 | display: block;
60 | border-radius: 3px;
61 | z-index: 1002;
62 | width: 140px;
63 | height: 56px;
64 | visibility: visible;
65 | position: absolute;
66 | right: -145px;
67 | text-align: left;
68 | text-indent: 20px;
69 | top: 0px;
70 | background-color: $subMenuBg!important;
71 | opacity: 1;
72 | }
73 | }
74 | }
75 | .el-menu-item {
76 | padding-left: 10px!important;
77 | &>.el-tooltip {
78 | padding-left: 10px!important;
79 | }
80 | }
81 | .el-submenu {
82 | &>.el-submenu__title {
83 | padding-left: 10px!important;
84 | &>span {
85 | display: none;
86 | }
87 | .el-submenu__icon-arrow {
88 | display: none;
89 | }
90 | }
91 | .nest-menu {
92 | .el-submenu__icon-arrow {
93 | display: block!important;
94 | }
95 | span {
96 | display: inline-block!important;
97 | }
98 | }
99 | }
100 | }
101 | .nest-menu .el-submenu>.el-submenu__title,
102 | .el-submenu .el-menu-item {
103 | min-width: 180px!important;
104 | background-color: $subMenuBg!important;
105 | &:hover {
106 | background-color: $menuHover!important;
107 | span {
108 | color: #fff;
109 | }
110 | }
111 | }
112 | .el-menu--collapse .el-menu .el-submenu{
113 | min-width: 180px!important;
114 | }
115 | // logo标志
116 | .sidebar-logo ,.sidebar-logo-mini {
117 | font-size: 20px;
118 | text-align: center;
119 | line-height: 56px;
120 | margin: 0px;
121 | padding: 0px;
122 | background-color: #002140;
123 | color: #fff;
124 | font-weight: 600;
125 | font-family: "Myriad Pro","Helvetica Neue",Arial,Helvetica,sans-serif;
126 | img {
127 | width: 160px;
128 | padding: 0px;
129 | margin: 5px;
130 | }
131 | }
132 | .sidebar-logo {
133 | width:180px;
134 | height:56px;
135 | }
136 | .sidebar-logo-mini {
137 | display: none;
138 | width:36px;
139 | height:56px;
140 | img {
141 | width: 32px;
142 | padding: 0px;
143 | margin: 10px 0px;
144 | }
145 | }
146 | .hideSidebar {
147 | .sidebar-logo {
148 | display: none;
149 | }
150 | .sidebar-logo-mini {
151 | display: block;
152 | }
153 | }
154 | .el-menu-item.is-active {
155 | background-color: #1890ff!important;
156 | &:hover {
157 | background-color: #1890ff!important;
158 | }
159 | }
160 | .el-submenu.is-active .el-submenu__title {
161 | color: #fff!important;
162 | .el-submenu__icon-arrow {
163 | color: #fff!important;
164 | }
165 | }
166 | .el-submenu__icon-arrow {
167 | font-weight: 600;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/module-manage/components/user-add.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
48 |
49 |
114 |
123 |
--------------------------------------------------------------------------------