Commit 1172ebb79113b8a99000521190fdd9f936ea649f
1 parent
c44ba96f68
Exists in
master
auto commit the code by alias command
Showing
29 changed files
with
1834 additions
and
243 deletions
Show diff stats
.eslintrc.js
1 | module.exports = { | 1 | module.exports = { |
2 | root: true, | 2 | root: true, |
3 | parserOptions: { | 3 | parserOptions: { |
4 | parser: 'babel-eslint', | 4 | parser: 'babel-eslint', |
5 | sourceType: 'module' | 5 | sourceType: 'module' |
6 | }, | 6 | }, |
7 | env: { | 7 | env: { |
8 | browser: true, | 8 | browser: true, |
9 | node: true, | 9 | node: true, |
10 | es6: true, | 10 | es6: true, |
11 | }, | 11 | }, |
12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], | 12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], |
13 | 13 | ||
14 | // add your custom rules here | 14 | // add your custom rules here |
15 | //it is base on https://github.com/vuejs/eslint-config-vue | 15 | //it is base on https://github.com/vuejs/eslint-config-vue |
16 | rules: { | 16 | rules: { |
17 | "vue/max-attributes-per-line": [2, { | 17 | "vue/max-attributes-per-line": [2, { |
18 | "singleline": 10, | 18 | "singleline": 10, |
19 | "multiline": { | 19 | "multiline": { |
20 | "max": 1, | 20 | "max": 1, |
21 | "allowFirstLine": false | 21 | "allowFirstLine": false |
22 | } | 22 | } |
23 | }], | 23 | }], |
24 | "vue/singleline-html-element-content-newline": "off", | 24 | "vue/singleline-html-element-content-newline": "off", |
25 | "vue/multiline-html-element-content-newline":"off", | 25 | "vue/multiline-html-element-content-newline":"off", |
26 | "vue/name-property-casing": ["error", "PascalCase"], | 26 | "vue/name-property-casing": ["error", "PascalCase"], |
27 | "vue/no-v-html": "off", | 27 | "vue/no-v-html": "off", |
28 | 'accessor-pairs': 2, | 28 | 'accessor-pairs': 2, |
29 | 'arrow-spacing': [2, { | 29 | 'arrow-spacing': [2, { |
30 | 'before': true, | 30 | 'before': true, |
31 | 'after': true | 31 | 'after': true |
32 | }], | 32 | }], |
33 | 'block-spacing': [2, 'always'], | 33 | 'block-spacing': [2, 'always'], |
34 | 'brace-style': [2, '1tbs', { | 34 | 'brace-style': [2, '1tbs', { |
35 | 'allowSingleLine': true | 35 | 'allowSingleLine': true |
36 | }], | 36 | }], |
37 | 'camelcase': [0, { | 37 | 'camelcase': [0, { |
38 | 'properties': 'always' | 38 | 'properties': 'always' |
39 | }], | 39 | }], |
40 | 'comma-dangle': [2, 'never'], | 40 | 'comma-dangle': [2, 'never'], |
41 | 'comma-spacing': [2, { | 41 | 'comma-spacing': [2, { |
42 | 'before': false, | 42 | 'before': false, |
43 | 'after': true | 43 | 'after': true |
44 | }], | 44 | }], |
45 | 'comma-style': [2, 'last'], | 45 | 'comma-style': [2, 'last'], |
46 | 'constructor-super': 2, | 46 | 'constructor-super': 2, |
47 | 'curly': [2, 'multi-line'], | 47 | 'curly': [2, 'multi-line'], |
48 | 'dot-location': [2, 'property'], | 48 | 'dot-location': [2, 'property'], |
49 | 'eol-last': 2, | 49 | 'eol-last': 2, |
50 | 'eqeqeq': ["error", "always", {"null": "ignore"}], | 50 | 'eqeqeq': ["error", "always", {"null": "ignore"}], |
51 | 'generator-star-spacing': [2, { | 51 | 'generator-star-spacing': [2, { |
52 | 'before': true, | 52 | 'before': true, |
53 | 'after': true | 53 | 'after': true |
54 | }], | 54 | }], |
55 | 'handle-callback-err': [2, '^(err|error)$'], | 55 | 'handle-callback-err': [2, '^(err|error)$'], |
56 | 'indent': [2, 2, { | 56 | 'indent': [2, 2, { |
57 | 'SwitchCase': 1 | 57 | 'SwitchCase': 1 |
58 | }], | 58 | }], |
59 | 'jsx-quotes': [2, 'prefer-single'], | 59 | 'jsx-quotes': [2, 'prefer-single'], |
60 | 'key-spacing': [2, { | 60 | 'key-spacing': [2, { |
61 | 'beforeColon': false, | 61 | 'beforeColon': false, |
62 | 'afterColon': true | 62 | 'afterColon': true |
63 | }], | 63 | }], |
64 | 'keyword-spacing': [2, { | 64 | 'keyword-spacing': [2, { |
65 | 'before': true, | 65 | 'before': true, |
66 | 'after': true | 66 | 'after': true |
67 | }], | 67 | }], |
68 | 'new-cap': [2, { | 68 | 'new-cap': [2, { |
69 | 'newIsCap': true, | 69 | 'newIsCap': true, |
70 | 'capIsNew': false | 70 | 'capIsNew': false |
71 | }], | 71 | }], |
72 | 'new-parens': 2, | 72 | 'new-parens': 2, |
73 | 'no-array-constructor': 2, | 73 | 'no-array-constructor': 2, |
74 | 'no-caller': 2, | 74 | 'no-caller': 2, |
75 | 'no-console': 'off', | 75 | 'no-console': 'off', |
76 | 'no-class-assign': 2, | 76 | 'no-class-assign': 2, |
77 | 'no-cond-assign': 2, | 77 | 'no-cond-assign': 2, |
78 | 'no-const-assign': 2, | 78 | 'no-const-assign': 2, |
79 | 'no-control-regex': 0, | 79 | 'no-control-regex': 0, |
80 | 'no-delete-var': 2, | 80 | 'no-delete-var': 2, |
81 | 'no-dupe-args': 2, | 81 | 'no-dupe-args': 2, |
82 | 'no-dupe-class-members': 2, | 82 | 'no-dupe-class-members': 2, |
83 | 'no-dupe-keys': 2, | 83 | 'no-dupe-keys': 2, |
84 | 'no-duplicate-case': 2, | 84 | 'no-duplicate-case': 2, |
85 | 'no-empty-character-class': 2, | 85 | 'no-empty-character-class': 2, |
86 | 'no-empty-pattern': 2, | 86 | 'no-empty-pattern': 2, |
87 | 'no-eval': 2, | 87 | 'no-eval': 2, |
88 | 'no-ex-assign': 2, | 88 | 'no-ex-assign': 2, |
89 | 'no-extend-native': 2, | 89 | 'no-extend-native': 2, |
90 | 'no-extra-bind': 2, | 90 | 'no-extra-bind': 2, |
91 | 'no-extra-boolean-cast': 2, | 91 | 'no-extra-boolean-cast': 2, |
92 | 'no-extra-parens': [2, 'functions'], | 92 | 'no-extra-parens': [2, 'functions'], |
93 | 'no-fallthrough': 2, | 93 | 'no-fallthrough': 2, |
94 | 'no-floating-decimal': 2, | 94 | 'no-floating-decimal': 2, |
95 | 'no-func-assign': 2, | 95 | 'no-func-assign': 2, |
96 | 'no-implied-eval': 2, | 96 | 'no-implied-eval': 2, |
97 | 'no-inner-declarations': [2, 'functions'], | 97 | 'no-inner-declarations': [2, 'functions'], |
98 | 'no-invalid-regexp': 2, | 98 | 'no-invalid-regexp': 2, |
99 | 'no-irregular-whitespace': 2, | 99 | 'no-irregular-whitespace': 2, |
100 | 'no-iterator': 2, | 100 | 'no-iterator': 2, |
101 | 'no-label-var': 2, | 101 | 'no-label-var': 2, |
102 | 'no-labels': [2, { | 102 | 'no-labels': [2, { |
103 | 'allowLoop': false, | 103 | 'allowLoop': false, |
104 | 'allowSwitch': false | 104 | 'allowSwitch': false |
105 | }], | 105 | }], |
106 | 'no-lone-blocks': 2, | 106 | 'no-lone-blocks': 2, |
107 | 'no-mixed-spaces-and-tabs': 2, | 107 | 'no-mixed-spaces-and-tabs': 2, |
108 | 'no-multi-spaces': 2, | 108 | 'no-multi-spaces': 2, |
109 | 'no-multi-str': 2, | 109 | 'no-multi-str': 2, |
110 | 'no-multiple-empty-lines': [2, { | 110 | 'no-multiple-empty-lines': [2, { |
111 | 'max': 1 | 111 | 'max': 1 |
112 | }], | 112 | }], |
113 | 'no-native-reassign': 2, | 113 | 'no-native-reassign': 2, |
114 | 'no-negated-in-lhs': 2, | 114 | 'no-negated-in-lhs': 2, |
115 | 'no-new-object': 2, | 115 | 'no-new-object': 2, |
116 | 'no-new-require': 2, | 116 | 'no-new-require': 2, |
117 | 'no-new-symbol': 2, | 117 | 'no-new-symbol': 2, |
118 | 'no-new-wrappers': 2, | 118 | 'no-new-wrappers': 2, |
119 | 'no-obj-calls': 2, | 119 | 'no-obj-calls': 2, |
120 | 'no-octal': 2, | 120 | 'no-octal': 2, |
121 | 'no-octal-escape': 2, | 121 | 'no-octal-escape': 2, |
122 | 'no-path-concat': 2, | 122 | 'no-path-concat': 2, |
123 | 'no-proto': 2, | 123 | 'no-proto': 2, |
124 | 'no-redeclare': 2, | 124 | 'no-redeclare': 2, |
125 | 'no-regex-spaces': 2, | 125 | 'no-regex-spaces': 2, |
126 | 'no-return-assign': [2, 'except-parens'], | 126 | 'no-return-assign': [2, 'except-parens'], |
127 | 'no-self-assign': 2, | 127 | 'no-self-assign': 2, |
128 | 'no-self-compare': 2, | 128 | 'no-self-compare': 2, |
129 | 'no-sequences': 2, | 129 | 'no-sequences': 2, |
130 | 'no-shadow-restricted-names': 2, | 130 | 'no-shadow-restricted-names': 2, |
131 | 'no-spaced-func': 2, | 131 | 'no-spaced-func': 2, |
132 | 'no-sparse-arrays': 2, | 132 | 'no-sparse-arrays': 2, |
133 | 'no-this-before-super': 2, | 133 | 'no-this-before-super': 2, |
134 | 'no-throw-literal': 2, | 134 | 'no-throw-literal': 2, |
135 | 'no-trailing-spaces': 2, | 135 | 'no-trailing-spaces': 2, |
136 | 'no-undef': 2, | 136 | 'no-undef': 2, |
137 | 'no-undef-init': 2, | 137 | 'no-undef-init': 2, |
138 | 'no-unexpected-multiline': 2, | 138 | 'no-unexpected-multiline': 2, |
139 | 'no-unmodified-loop-condition': 2, | 139 | 'no-unmodified-loop-condition': 2, |
140 | 'no-unneeded-ternary': [2, { | 140 | 'no-unneeded-ternary': [2, { |
141 | 'defaultAssignment': false | 141 | 'defaultAssignment': false |
142 | }], | 142 | }], |
143 | 'no-unreachable': 2, | 143 | 'no-unreachable': 2, |
144 | 'no-unsafe-finally': 2, | 144 | 'no-unsafe-finally': 2, |
145 | 'no-unused-vars': [2, { | 145 | 'no-unused-vars': [2, { |
146 | 'vars': 'all', | 146 | 'vars': 'all', |
147 | 'args': 'none' | 147 | 'args': 'none' |
148 | }], | 148 | }], |
149 | 'no-useless-call': 2, | 149 | 'no-useless-call': 2, |
150 | 'no-useless-computed-key': 2, | 150 | 'no-useless-computed-key': 2, |
151 | 'no-useless-constructor': 2, | 151 | 'no-useless-constructor': 2, |
152 | 'no-useless-escape': 0, | 152 | 'no-useless-escape': 0, |
153 | 'no-whitespace-before-property': 2, | 153 | 'no-whitespace-before-property': 2, |
154 | 'no-with': 2, | 154 | 'no-with': 2, |
155 | 'one-var': [2, { | 155 | 'one-var': [2, { |
156 | 'initialized': 'never' | 156 | 'initialized': 'never' |
157 | }], | 157 | }], |
158 | 'operator-linebreak': [2, 'after', { | 158 | 'operator-linebreak': [2, 'after', { |
159 | 'overrides': { | 159 | 'overrides': { |
160 | '?': 'before', | 160 | '?': 'before', |
161 | ':': 'before' | 161 | ':': 'before' |
162 | } | 162 | } |
163 | }], | 163 | }], |
164 | 'padded-blocks': [2, 'never'], | 164 | 'padded-blocks': [2, 'never'], |
165 | 'quotes': [2, 'single', { | 165 | 'quotes': [2, 'single', { |
166 | 'avoidEscape': true, | 166 | 'avoidEscape': true, |
167 | 'allowTemplateLiterals': true | 167 | 'allowTemplateLiterals': true |
168 | }], | 168 | }], |
169 | 'semi': [2, 'never'], | 169 | 'semi': [2, 'never'], |
170 | // 'semi': 0, | ||
170 | 'semi-spacing': [2, { | 171 | 'semi-spacing': [2, { |
171 | 'before': false, | 172 | 'before': false, |
172 | 'after': true | 173 | 'after': true |
173 | }], | 174 | }], |
174 | 'space-before-blocks': [2, 'always'], | 175 | 'space-before-blocks': [2, 'always'], |
175 | 'space-before-function-paren': [2, 'never'], | 176 | 'space-before-function-paren': [2, 'never'], |
176 | 'space-in-parens': [2, 'never'], | 177 | 'space-in-parens': [2, 'never'], |
177 | 'space-infix-ops': 2, | 178 | 'space-infix-ops': 2, |
178 | 'space-unary-ops': [2, { | 179 | 'space-unary-ops': [2, { |
179 | 'words': true, | 180 | 'words': true, |
180 | 'nonwords': false | 181 | 'nonwords': false |
181 | }], | 182 | }], |
182 | 'spaced-comment': [2, 'always', { | 183 | 'spaced-comment': [2, 'always', { |
183 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] | 184 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] |
184 | }], | 185 | }], |
185 | 'template-curly-spacing': [2, 'never'], | 186 | 'template-curly-spacing': [2, 'never'], |
186 | 'use-isnan': 2, | 187 | 'use-isnan': 2, |
187 | 'valid-typeof': 2, | 188 | 'valid-typeof': 2, |
188 | 'wrap-iife': [2, 'any'], | 189 | 'wrap-iife': [2, 'any'], |
189 | 'yield-star-spacing': [2, 'both'], | 190 | 'yield-star-spacing': [2, 'both'], |
190 | 'yoda': [2, 'never'], | 191 | 'yoda': [2, 'never'], |
191 | 'prefer-const': 2, | 192 | 'prefer-const': 2, |
192 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, | 193 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, |
193 | 'object-curly-spacing': [2, 'always', { | 194 | 'object-curly-spacing': [2, 'always', { |
194 | objectsInObjects: false | 195 | objectsInObjects: false |
195 | }], | 196 | }], |
196 | 'array-bracket-spacing': [2, 'never'] | 197 | 'array-bracket-spacing': [2, 'never'] |
197 | } | 198 | } |
198 | } | 199 | } |
199 | 200 |
babel.config.js
1 | // module.exports = { | ||
2 | // presets: [ | ||
3 | // '@vue/app' | ||
4 | // ] | ||
5 | // } | ||
6 | // "@babel/preset-env", | ||
7 | // { | ||
8 | // "modules": false | ||
9 | // }, | ||
1 | module.exports = { | 10 | module.exports = { |
2 | presets: [ | 11 | "presets": [ |
3 | '@vue/app' | 12 | [ |
13 | '@vue/app', | ||
14 | // '@babel/preset-env', | ||
15 | { | ||
16 | // "modules": false, | ||
17 | // "targets": { // 配置代码的运行环境 | ||
18 | // "chrome": 64 | ||
19 | // }, | ||
20 | // "useBuiltIns": true // 开启对 babel-polyfill 的优化 | ||
21 | } | ||
22 | ] | ||
23 | ], | ||
24 | "plugins": [ | ||
25 | [ | ||
26 | "component", | ||
27 | { | ||
28 | "libraryName": "element-ui", | ||
29 | "styleLibraryName": "theme-chalk" | ||
30 | } | ||
31 | ] | ||
4 | ] | 32 | ] |
5 | } | 33 | } |
6 | 34 |
mock/index.js
1 | import Mock from 'mockjs' | 1 | import Mock from 'mockjs' |
2 | import { param2Obj } from '../src/utils' | 2 | import { |
3 | param2Obj | ||
4 | } from '../src/utils' | ||
3 | 5 | ||
4 | import user from './user' | 6 | import user from './user' |
5 | import table from './table' | 7 | import table from './table' |
6 | 8 | ||
7 | const mocks = [ | 9 | const mocks = [ |
8 | ...user, | 10 | ...user, |
9 | ...table | 11 | ...table |
10 | ] | 12 | ] |
11 | 13 | ||
12 | // for front mock | 14 | // for front mock |
13 | // please use it cautiously, it will redefine XMLHttpRequest, | 15 | // please use it cautiously, it will redefine XMLHttpRequest, |
14 | // which will cause many of your third-party libraries to be invalidated(like progress event). | 16 | // which will cause many of your third-party libraries to be invalidated(like progress event). |
15 | export function mockXHR() { | 17 | export function mockXHR() { |
16 | // mock patch | 18 | // mock patch |
17 | // https://github.com/nuysoft/Mock/issues/300 | 19 | // https://github.com/nuysoft/Mock/issues/300 |
18 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send | 20 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send |
19 | Mock.XHR.prototype.send = function() { | 21 | Mock.XHR.prototype.send = function () { |
20 | if (this.custom.xhr) { | 22 | if (this.custom.xhr) { |
21 | this.custom.xhr.withCredentials = this.withCredentials || false | 23 | this.custom.xhr.withCredentials = this.withCredentials || false |
22 | 24 | ||
23 | if (this.responseType) { | 25 | if (this.responseType) { |
24 | this.custom.xhr.responseType = this.responseType | 26 | this.custom.xhr.responseType = this.responseType |
25 | } | 27 | } |
26 | } | 28 | } |
27 | this.proxy_send(...arguments) | 29 | this.proxy_send(...arguments) |
28 | } | 30 | } |
29 | 31 | ||
30 | function XHR2ExpressReqWrap(respond) { | 32 | function XHR2ExpressReqWrap(respond) { |
31 | return function(options) { | 33 | return function (options) { |
32 | let result = null | 34 | let result = null |
33 | if (respond instanceof Function) { | 35 | if (respond instanceof Function) { |
34 | const { body, type, url } = options | 36 | const { |
37 | body, | ||
38 | type, | ||
39 | url | ||
40 | } = options | ||
35 | // https://expressjs.com/en/4x/api.html#req | 41 | // https://expressjs.com/en/4x/api.html#req |
36 | result = respond({ | 42 | result = respond({ |
37 | method: type, | 43 | method: type, |
38 | body: JSON.parse(body), | 44 | body: JSON.parse(body), |
39 | query: param2Obj(url) | 45 | query: param2Obj(url) |
40 | }) | 46 | }) |
41 | } else { | 47 | } else { |
42 | result = respond | 48 | result = respond |
43 | } | 49 | } |
44 | return Mock.mock(result) | 50 | return Mock.mock(result) |
45 | } | 51 | } |
46 | } | 52 | } |
47 | 53 | ||
48 | for (const i of mocks) { | 54 | for (const i of mocks) { |
49 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) | 55 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) |
50 | } | 56 | } |
51 | } | 57 | } |
52 | 58 | ||
53 | // for mock server | 59 | // for mock server |
54 | const responseFake = (url, type, respond) => { | 60 | const responseFake = (url, type, respond) => { |
55 | return { | 61 | return { |
56 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), | 62 | url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), |
57 | type: type || 'get', | 63 | type: type || 'get', |
58 | response(req, res) { | 64 | response(req, res) { |
59 | console.log('request invoke:' + req.path) | 65 | console.log('request invoke:' + req.path) |
60 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) | 66 | res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) |
61 | } | 67 | } |
62 | } | 68 | } |
63 | } | 69 | } |
64 | 70 | ||
65 | export default mocks.map(route => { | 71 | export default mocks.map(route => { |
66 | return responseFake(route.url, route.type, route.response) | 72 | return responseFake(route.url, route.type, route.response) |
67 | }) | 73 | }) |
68 | 74 |
mock/table.js
1 | import Mock from 'mockjs' | 1 | import Mock from 'mockjs' |
2 | 2 | ||
3 | const data = Mock.mock({ | 3 | const data = Mock.mock({ |
4 | 'items|10': [{ | 4 | 'items|10': [{ |
5 | id: '@id', | 5 | id: '@id', |
6 | title: '@sentence(3, 10)', | 6 | title: '@sentence(10, 10)', |
7 | 'status|1': ['published', 'draft', 'deleted'], | 7 | 'status|1': ['published', 'draft', 'deleted'], |
8 | author: 'name@integer(300, 5000)', | 8 | username: '@sentence(1, 2)', |
9 | display_time: '@datetime', | 9 | create_at: '@datetime', |
10 | pageviews: '@integer(300, 5000)' | 10 | pageviews: '@integer(10, 500)', |
11 | openid: '@sentence(1, 1)', | ||
12 | avatar:'----' | ||
11 | }] | 13 | }] |
12 | }) | 14 | }) |
13 | 15 | ||
14 | export default [ | 16 | export default [ |
15 | { | 17 | { |
16 | url: '/yp/table/list', | 18 | url: '/yp/table/list', |
17 | type: 'get', | 19 | type: 'get', |
18 | response: config => { | 20 | response: config => { |
19 | const items = data.items | 21 | const items = data.items |
20 | return { | 22 | return { |
21 | code: 20000, | 23 | code: 20000, |
22 | data: { | 24 | data: { |
23 | total: items.length, | 25 | total: items.length, |
24 | items: items | 26 | items: items |
25 | } | 27 | } |
26 | } | 28 | } |
27 | } | 29 | } |
28 | } | 30 | } |
29 | ] | 31 | ] |
30 | 32 |
package.json
1 | { | 1 | { |
2 | "name": "yp-plan", | 2 | "name": "yp-plan", |
3 | "version": "4.2.1", | 3 | "version": "4.2.1", |
4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", | 4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", |
5 | "author": "XYT==admin@xiuyetang.com", | 5 | "author": "XYT==admin@xiuyetang.com", |
6 | "license": "MIT", | 6 | "license": "MIT", |
7 | "scripts": { | 7 | "scripts": { |
8 | "dev": "vue-cli-service serve", | 8 | "dev": "vue-cli-service serve", |
9 | "build:prod": "vue-cli-service build", | 9 | "build:prod": "vue-cli-service build", |
10 | "build:stage": "vue-cli-service build --mode staging", | 10 | "build:stage": "vue-cli-service build --mode staging", |
11 | "preview": "node build/index.js --preview", | 11 | "preview": "node build/index.js --preview", |
12 | "lint": "eslint --ext .js,.vue src", | 12 | "lint": "eslint --ext .js,.vue src", |
13 | "test:unit": "jest --clearCache && vue-cli-service test:unit", | 13 | "test:unit": "jest --clearCache && vue-cli-service test:unit", |
14 | "test:ci": "npm run lint && npm run test:unit", | 14 | "test:ci": "npm run lint && npm run test:unit", |
15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" | 15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" |
16 | }, | 16 | }, |
17 | "dependencies": { | 17 | "dependencies": { |
18 | "axios": "0.18.1", | 18 | "axios": "0.18.1", |
19 | "babel-polyfill": "^6.26.0", | ||
19 | "echarts": "^4.7.0", | 20 | "echarts": "^4.7.0", |
20 | "element-ui": "2.13.0", | 21 | "element-ui": "2.13.0", |
21 | "js-cookie": "2.2.0", | 22 | "js-cookie": "2.2.0", |
22 | "normalize.css": "7.0.0", | 23 | "normalize.css": "7.0.0", |
23 | "nprogress": "0.2.0", | 24 | "nprogress": "0.2.0", |
24 | "path-to-regexp": "2.4.0", | 25 | "path-to-regexp": "2.4.0", |
25 | "plop": "^2.6.0", | 26 | "plop": "^2.6.0", |
26 | "vue": "2.6.10", | 27 | "vue": "2.6.10", |
27 | "vue-router": "3.0.6", | 28 | "vue-router": "3.0.6", |
28 | "vuex": "3.1.0" | 29 | "vuex": "3.1.0" |
29 | }, | 30 | }, |
30 | "devDependencies": { | 31 | "devDependencies": { |
31 | "@babel/core": "7.0.0", | 32 | "@babel/core": "7.0.0", |
33 | "@babel/preset-env": "^7.9.6", | ||
32 | "@babel/register": "7.0.0", | 34 | "@babel/register": "7.0.0", |
33 | "@vue/cli-plugin-babel": "3.6.0", | 35 | "@vue/cli-plugin-babel": "3.6.0", |
34 | "@vue/cli-plugin-eslint": "^3.9.1", | 36 | "@vue/cli-plugin-eslint": "^3.9.1", |
35 | "@vue/cli-plugin-unit-jest": "3.6.3", | 37 | "@vue/cli-plugin-unit-jest": "3.6.3", |
36 | "@vue/cli-service": "3.6.0", | 38 | "@vue/cli-service": "3.6.0", |
37 | "@vue/test-utils": "1.0.0-beta.29", | 39 | "@vue/test-utils": "1.0.0-beta.29", |
38 | "autoprefixer": "^9.5.1", | 40 | "autoprefixer": "^9.5.1", |
41 | "babel-cli": "^6.26.0", | ||
39 | "babel-core": "7.0.0-bridge.0", | 42 | "babel-core": "7.0.0-bridge.0", |
40 | "babel-eslint": "10.0.1", | 43 | "babel-eslint": "10.0.1", |
41 | "babel-jest": "23.6.0", | 44 | "babel-jest": "23.6.0", |
45 | "babel-plugin-component": "^1.1.1", | ||
46 | "babel-preset-env": "^1.7.0", | ||
42 | "chalk": "2.4.2", | 47 | "chalk": "2.4.2", |
43 | "connect": "3.6.6", | 48 | "connect": "3.6.6", |
44 | "eslint": "5.15.3", | 49 | "eslint": "5.15.3", |
45 | "eslint-plugin-vue": "5.2.2", | 50 | "eslint-plugin-vue": "5.2.2", |
46 | "html-webpack-plugin": "3.2.0", | 51 | "html-webpack-plugin": "3.2.0", |
47 | "mockjs": "1.0.1-beta3", | 52 | "mockjs": "1.0.1-beta3", |
48 | "node-sass": "^4.9.0", | 53 | "node-sass": "^4.9.0", |
49 | "runjs": "^4.3.2", | 54 | "runjs": "^4.3.2", |
50 | "sass-loader": "^7.1.0", | 55 | "sass-loader": "^7.1.0", |
51 | "script-ext-html-webpack-plugin": "2.1.3", | 56 | "script-ext-html-webpack-plugin": "2.1.3", |
52 | "script-loader": "0.7.2", | 57 | "script-loader": "0.7.2", |
53 | "serve-static": "^1.13.2", | 58 | "serve-static": "^1.13.2", |
54 | "svg-sprite-loader": "4.1.3", | 59 | "svg-sprite-loader": "4.1.3", |
55 | "svgo": "1.2.2", | 60 | "svgo": "1.2.2", |
61 | "vue-schart": "^2.0.0", | ||
56 | "vue-template-compiler": "2.6.10" | 62 | "vue-template-compiler": "2.6.10" |
57 | }, | 63 | }, |
58 | "engines": { | 64 | "engines": { |
59 | "node": ">=8.9", | 65 | "node": ">=8.9", |
60 | "npm": ">= 3.0.0" | 66 | "npm": ">= 3.0.0" |
61 | }, | 67 | }, |
62 | "browserslist": [ | 68 | "browserslist": [ |
63 | "> 1%", | 69 | "> 1%", |
64 | "last 2 versions" | 70 | "last 2 versions" |
65 | ] | 71 | ] |
66 | } | 72 | } |
67 | 73 |
src/api/admin.js
1 | import request from '@/utils/request' | 1 | // import request from '@/utils/request' |
2 | |||
3 | export function login(data) { | ||
4 | console.log('login....', data) | ||
5 | return request({ | ||
6 | url: '/yp/user/login', | ||
7 | method: 'post', | ||
8 | data | ||
9 | }) | ||
10 | } | ||
11 | |||
12 | export function getInfo(token) { | ||
13 | console.log('getInfo....', token) | ||
14 | return request({ | ||
15 | url: '/yp/user/info', | ||
16 | method: 'get', | ||
17 | params: { token } | ||
18 | }) | ||
19 | } | ||
20 | |||
21 | export function logout() { | ||
22 | console.log('logout....') | ||
23 | return request({ | ||
24 | url: '/yp/user/logout', | ||
25 | method: 'post' | ||
26 | }) | ||
27 | } | ||
28 | 2 |
src/api/meta.js
1 | import request from '@/utils/request' | ||
2 | |||
3 | export function listMeta(params) { | ||
4 | return request({ | ||
5 | url: '/yp/meta/list', | ||
6 | method: 'get', | ||
7 | params | ||
8 | }) | ||
9 | } | ||
10 | |||
11 | export function addMeta(params) { | ||
12 | return request({ | ||
13 | url: '/yp/meta/add', | ||
14 | method: 'get', | ||
15 | params | ||
16 | }) | ||
17 | } | ||
18 | |||
19 | export function delMeta(params) { | ||
20 | return request({ | ||
21 | url: '/yp/meta/del', | ||
22 | method: 'get', | ||
23 | params | ||
24 | }) | ||
25 | } | ||
26 | |||
27 | export function modiMeta(params) { | ||
28 | return request({ | ||
29 | url: '/yp/meta/modi', | ||
30 | method: 'get', | ||
31 | params | ||
32 | }) | ||
33 | } | ||
34 |
src/api/relation.js
File was created | 1 | import request from '@/utils/request' | |
2 | |||
3 | export function build(params) { | ||
4 | return request({ | ||
5 | url: '/yp/relation/build', | ||
6 | method: 'get', | ||
7 | params | ||
8 | }) | ||
9 | } | ||
10 | |||
11 | export function del(params) { | ||
12 | return request({ | ||
13 | url: '/yp/relation/del', | ||
14 | method: 'get', | ||
15 | params | ||
16 | }) | ||
17 | } | ||
18 |
src/api/user.js
1 | import request from '@/utils/request' | 1 | import request from '@/utils/request' |
2 | 2 | ||
3 | export function login(data) { | 3 | export function login(data) { |
4 | console.log('login....', data) | 4 | console.log('login....', data) |
5 | return request({ | 5 | return request({ |
6 | url: '/yp/user/login', | 6 | url: '/yp/user/login', |
7 | method: 'post', | 7 | method: 'post', |
8 | data | 8 | data |
9 | }) | 9 | }) |
10 | } | 10 | } |
11 | 11 | ||
12 | export function getInfo(token) { | 12 | export function getInfo(token) { |
13 | console.log('getInfo....', token) | 13 | console.log('getInfo....', token) |
14 | return request({ | 14 | return request({ |
15 | url: '/yp/user/info', | 15 | url: '/yp/user/info', |
16 | method: 'get', | 16 | method: 'get', |
17 | params: { token } | 17 | params: { token } |
18 | }) | 18 | }) |
19 | } | 19 | } |
20 | 20 | ||
21 | export function list(token) { | 21 | export function list(token) { |
22 | console.log('listUser....', token) | 22 | console.log('listUser....', token) |
23 | return request({ | 23 | return request({ |
24 | url: '/yp/user/list', | 24 | url: '/yp/user/list', |
25 | method: 'get', | 25 | method: 'get', |
26 | params: { token } | 26 | params: { token } |
27 | }) | 27 | }) |
28 | } | 28 | } |
29 | 29 | ||
30 | export function add(token) { | ||
31 | console.log('addUser....', token) | ||
32 | return request({ | ||
33 | url: '/yp/user/add', | ||
34 | method: 'get', | ||
35 | params: { token } | ||
36 | }) | ||
37 | } | ||
38 | |||
39 | export function modi(token) { | ||
40 | console.log('modiUser....', token) | ||
41 | return request({ | ||
42 | url: '/yp/user/modi', | ||
43 | method: 'get', | ||
44 | params: { token } | ||
45 | }) | ||
46 | } | ||
47 | |||
30 | export function logout() { | 48 | export function logout() { |
31 | console.log('logout....') | 49 | console.log('logout....') |
32 | return request({ | 50 | return request({ |
33 | url: '/yp/user/logout', | 51 | url: '/yp/user/logout', |
34 | method: 'post' | 52 | method: 'post' |
35 | }) | 53 | }) |
36 | } | 54 | } |
37 | 55 |
src/assets/img/img.jpg
6 KB
src/assets/img/login-bg.jpg
68.9 KB
src/common/Header.vue
File was created | 1 | <template> | |
2 | <div class="header"> | ||
3 | <!-- 折叠按钮 --> | ||
4 | <div class="collapse-btn" @click="collapseChage"> | ||
5 | <i v-if="!collapse" class="el-icon-s-fold"></i> | ||
6 | <i v-else class="el-icon-s-unfold"></i> | ||
7 | </div> | ||
8 | <div class="logo">后台管理系统</div> | ||
9 | <div class="header-right"> | ||
10 | <div class="header-user-con"> | ||
11 | <!-- 全屏显示 --> | ||
12 | <div class="btn-fullscreen" @click="handleFullScreen"> | ||
13 | <el-tooltip effect="dark" :content="fullscreen?`取消全屏`:`全屏`" placement="bottom"> | ||
14 | <i class="el-icon-rank"></i> | ||
15 | </el-tooltip> | ||
16 | </div> | ||
17 | <!-- 消息中心 --> | ||
18 | <div class="btn-bell"> | ||
19 | <el-tooltip | ||
20 | effect="dark" | ||
21 | :content="message?`有${message}条未读消息`:`消息中心`" | ||
22 | placement="bottom" | ||
23 | > | ||
24 | <router-link to="/tabs"> | ||
25 | <i class="el-icon-bell"></i> | ||
26 | </router-link> | ||
27 | </el-tooltip> | ||
28 | <span class="btn-bell-badge" v-if="message"></span> | ||
29 | </div> | ||
30 | <!-- 用户头像 --> | ||
31 | <div class="user-avator"> | ||
32 | <img src="../assets/img/img.jpg" /> | ||
33 | </div> | ||
34 | <!-- 用户名下拉菜单 --> | ||
35 | <el-dropdown class="user-name" trigger="click" @command="handleCommand"> | ||
36 | <span class="el-dropdown-link"> | ||
37 | {{username}} | ||
38 | <i class="el-icon-caret-bottom"></i> | ||
39 | </span> | ||
40 | <el-dropdown-menu slot="dropdown"> | ||
41 | <a href="https://github.com/lin-xin/vue-manage-system" target="_blank"> | ||
42 | <el-dropdown-item>项目仓库</el-dropdown-item> | ||
43 | </a> | ||
44 | <el-dropdown-item divided command="loginout">退出登录</el-dropdown-item> | ||
45 | </el-dropdown-menu> | ||
46 | </el-dropdown> | ||
47 | </div> | ||
48 | </div> | ||
49 | </div> | ||
50 | </template> | ||
51 | <script> | ||
52 | import bus from './bus'; | ||
53 | export default { | ||
54 | data() { | ||
55 | return { | ||
56 | collapse: false, | ||
57 | fullscreen: false, | ||
58 | name: 'linxin', | ||
59 | message: 2 | ||
60 | }; | ||
61 | }, | ||
62 | computed: { | ||
63 | username() { | ||
64 | let username = localStorage.getItem('ms_username'); | ||
65 | return username ? username : this.name; | ||
66 | } | ||
67 | }, | ||
68 | methods: { | ||
69 | // 用户名下拉菜单选择事件 | ||
70 | handleCommand(command) { | ||
71 | if (command == 'loginout') { | ||
72 | localStorage.removeItem('ms_username'); | ||
73 | this.$router.push('/login'); | ||
74 | } | ||
75 | }, | ||
76 | // 侧边栏折叠 | ||
77 | collapseChage() { | ||
78 | this.collapse = !this.collapse; | ||
79 | bus.$emit('collapse', this.collapse); | ||
80 | }, | ||
81 | // 全屏事件 | ||
82 | handleFullScreen() { | ||
83 | let element = document.documentElement; | ||
84 | if (this.fullscreen) { | ||
85 | if (document.exitFullscreen) { | ||
86 | document.exitFullscreen(); | ||
87 | } else if (document.webkitCancelFullScreen) { | ||
88 | document.webkitCancelFullScreen(); | ||
89 | } else if (document.mozCancelFullScreen) { | ||
90 | document.mozCancelFullScreen(); | ||
91 | } else if (document.msExitFullscreen) { | ||
92 | document.msExitFullscreen(); | ||
93 | } | ||
94 | } else { | ||
95 | if (element.requestFullscreen) { | ||
96 | element.requestFullscreen(); | ||
97 | } else if (element.webkitRequestFullScreen) { | ||
98 | element.webkitRequestFullScreen(); | ||
99 | } else if (element.mozRequestFullScreen) { | ||
100 | element.mozRequestFullScreen(); | ||
101 | } else if (element.msRequestFullscreen) { | ||
102 | // IE11 | ||
103 | element.msRequestFullscreen(); | ||
104 | } | ||
105 | } | ||
106 | this.fullscreen = !this.fullscreen; | ||
107 | } | ||
108 | }, | ||
109 | mounted() { | ||
110 | if (document.body.clientWidth < 1500) { | ||
111 | this.collapseChage(); | ||
112 | } | ||
113 | } | ||
114 | }; | ||
115 | </script> | ||
116 | <style scoped> | ||
117 | .header { | ||
118 | position: relative; | ||
119 | box-sizing: border-box; | ||
120 | width: 100%; | ||
121 | height: 70px; | ||
122 | font-size: 22px; | ||
123 | color: #fff; | ||
124 | } | ||
125 | .collapse-btn { | ||
126 | float: left; | ||
127 | padding: 0 21px; | ||
128 | cursor: pointer; | ||
129 | line-height: 70px; | ||
130 | } | ||
131 | .header .logo { | ||
132 | float: left; | ||
133 | width: 250px; | ||
134 | line-height: 70px; | ||
135 | } | ||
136 | .header-right { | ||
137 | float: right; | ||
138 | padding-right: 50px; | ||
139 | } | ||
140 | .header-user-con { | ||
141 | display: flex; | ||
142 | height: 70px; | ||
143 | align-items: center; | ||
144 | } | ||
145 | .btn-fullscreen { | ||
146 | transform: rotate(45deg); | ||
147 | margin-right: 5px; | ||
148 | font-size: 24px; | ||
149 | } | ||
150 | .btn-bell, | ||
151 | .btn-fullscreen { | ||
152 | position: relative; | ||
153 | width: 30px; | ||
154 | height: 30px; | ||
155 | text-align: center; | ||
156 | border-radius: 15px; | ||
157 | cursor: pointer; | ||
158 | } | ||
159 | .btn-bell-badge { | ||
160 | position: absolute; | ||
161 | right: 0; | ||
162 | top: -2px; | ||
163 | width: 8px; | ||
164 | height: 8px; | ||
165 | border-radius: 4px; | ||
166 | background: #f56c6c; | ||
167 | color: #fff; | ||
168 | } | ||
169 | .btn-bell .el-icon-bell { | ||
170 | color: #fff; | ||
171 | } | ||
172 | .user-name { | ||
173 | margin-left: 10px; | ||
174 | } | ||
175 | .user-avator { | ||
176 | margin-left: 20px; | ||
177 | } | ||
178 | .user-avator img { | ||
179 | display: block; | ||
180 | width: 40px; | ||
181 | height: 40px; | ||
182 | border-radius: 50%; | ||
183 | } | ||
184 | .el-dropdown-link { | ||
185 | color: #fff; | ||
186 | cursor: pointer; | ||
187 | } | ||
188 | .el-dropdown-menu__item { | ||
189 | text-align: center; | ||
190 | } | ||
191 | </style> |
src/common/Home.vue
File was created | 1 | <template> | |
2 | <div class="wrapper"> | ||
3 | <v-head></v-head> | ||
4 | <v-sidebar></v-sidebar> | ||
5 | <div class="content-box" :class="{'content-collapse':collapse}"> | ||
6 | <v-tags></v-tags> | ||
7 | <div class="content"> | ||
8 | <transition name="move" mode="out-in"> | ||
9 | <keep-alive :include="tagsList"> | ||
10 | <router-view></router-view> | ||
11 | </keep-alive> | ||
12 | </transition> | ||
13 | <el-backtop target=".content"></el-backtop> | ||
14 | </div> | ||
15 | </div> | ||
16 | </div> | ||
17 | </template> | ||
18 | |||
19 | <script> | ||
20 | import vHead from './Header.vue'; | ||
21 | import vSidebar from './Sidebar.vue'; | ||
22 | import vTags from './Tags.vue'; | ||
23 | import bus from './bus'; | ||
24 | export default { | ||
25 | data() { | ||
26 | return { | ||
27 | tagsList: [], | ||
28 | collapse: false | ||
29 | }; | ||
30 | }, | ||
31 | components: { | ||
32 | vHead, | ||
33 | vSidebar, | ||
34 | vTags | ||
35 | }, | ||
36 | created() { | ||
37 | bus.$on('collapse-content', msg => { | ||
38 | this.collapse = msg; | ||
39 | }); | ||
40 | // 只有在标签页列表里的页面才使用keep-alive,即关闭标签之后就不保存到内存中了。 | ||
41 | bus.$on('tags', msg => { | ||
42 | let arr = []; | ||
43 | for (let i = 0, len = msg.length; i < len; i++) { | ||
44 | msg[i].name && arr.push(msg[i].name); | ||
45 | } | ||
46 | this.tagsList = arr; | ||
47 | }); | ||
48 | } | ||
49 | }; | ||
50 | </script> |
src/common/Sidebar.vue
File was created | 1 | <template> | |
2 | <div class="sidebar"> | ||
3 | <el-menu | ||
4 | class="sidebar-el-menu" | ||
5 | :default-active="onRoutes" | ||
6 | :collapse="collapse" | ||
7 | background-color="#324157" | ||
8 | text-color="#bfcbd9" | ||
9 | active-text-color="#20a0ff" | ||
10 | unique-opened | ||
11 | router | ||
12 | > | ||
13 | <template v-for="item in items"> | ||
14 | <template v-if="item.subs"> | ||
15 | <el-submenu :index="item.index" :key="item.index"> | ||
16 | <template slot="title"> | ||
17 | <i :class="item.icon"></i> | ||
18 | <span slot="title">{{ item.title }}</span> | ||
19 | </template> | ||
20 | <template v-for="subItem in item.subs"> | ||
21 | <el-submenu | ||
22 | v-if="subItem.subs" | ||
23 | :index="subItem.index" | ||
24 | :key="subItem.index" | ||
25 | > | ||
26 | <template slot="title">{{ subItem.title }}</template> | ||
27 | <el-menu-item | ||
28 | v-for="(threeItem,i) in subItem.subs" | ||
29 | :key="i" | ||
30 | :index="threeItem.index" | ||
31 | >{{ threeItem.title }}</el-menu-item> | ||
32 | </el-submenu> | ||
33 | <el-menu-item | ||
34 | v-else | ||
35 | :index="subItem.index" | ||
36 | :key="subItem.index" | ||
37 | >{{ subItem.title }}</el-menu-item> | ||
38 | </template> | ||
39 | </el-submenu> | ||
40 | </template> | ||
41 | <template v-else> | ||
42 | <el-menu-item :index="item.index" :key="item.index"> | ||
43 | <i :class="item.icon"></i> | ||
44 | <span slot="title">{{ item.title }}</span> | ||
45 | </el-menu-item> | ||
46 | </template> | ||
47 | </template> | ||
48 | </el-menu> | ||
49 | </div> | ||
50 | </template> | ||
51 | |||
52 | <script> | ||
53 | import bus from './bus'; | ||
54 | export default { | ||
55 | data() { | ||
56 | return { | ||
57 | collapse: false, | ||
58 | items: [ | ||
59 | { | ||
60 | icon: 'el-icon-lx-home', | ||
61 | index: 'dashboard', | ||
62 | title: '系统首页' | ||
63 | }, | ||
64 | { | ||
65 | icon: 'el-icon-lx-cascades', | ||
66 | index: 'table', | ||
67 | title: '基础表格' | ||
68 | }, | ||
69 | { | ||
70 | icon: 'el-icon-lx-copy', | ||
71 | index: 'tabs', | ||
72 | title: 'tab选项卡' | ||
73 | }, | ||
74 | { | ||
75 | icon: 'el-icon-lx-calendar', | ||
76 | index: '3', | ||
77 | title: '表单相关', | ||
78 | subs: [ | ||
79 | { | ||
80 | index: 'form', | ||
81 | title: '基本表单' | ||
82 | }, | ||
83 | { | ||
84 | index: '3-2', | ||
85 | title: '三级菜单', | ||
86 | subs: [ | ||
87 | { | ||
88 | index: 'editor', | ||
89 | title: '富文本编辑器' | ||
90 | }, | ||
91 | { | ||
92 | index: 'markdown', | ||
93 | title: 'markdown编辑器' | ||
94 | } | ||
95 | ] | ||
96 | }, | ||
97 | { | ||
98 | index: 'upload', | ||
99 | title: '文件上传' | ||
100 | } | ||
101 | ] | ||
102 | }, | ||
103 | { | ||
104 | icon: 'el-icon-lx-emoji', | ||
105 | index: 'icon', | ||
106 | title: '自定义图标' | ||
107 | }, | ||
108 | { | ||
109 | icon: 'el-icon-pie-chart', | ||
110 | index: 'charts', | ||
111 | title: 'schart图表' | ||
112 | }, | ||
113 | { | ||
114 | icon: 'el-icon-rank', | ||
115 | index: '6', | ||
116 | title: '拖拽组件', | ||
117 | subs: [ | ||
118 | { | ||
119 | index: 'drag', | ||
120 | title: '拖拽列表' | ||
121 | }, | ||
122 | { | ||
123 | index: 'dialog', | ||
124 | title: '拖拽弹框' | ||
125 | } | ||
126 | ] | ||
127 | }, | ||
128 | { | ||
129 | icon: 'el-icon-lx-global', | ||
130 | index: 'i18n', | ||
131 | title: '国际化功能' | ||
132 | }, | ||
133 | { | ||
134 | icon: 'el-icon-lx-warn', | ||
135 | index: '7', | ||
136 | title: '错误处理', | ||
137 | subs: [ | ||
138 | { | ||
139 | index: 'permission', | ||
140 | title: '权限测试' | ||
141 | }, | ||
142 | { | ||
143 | index: '404', | ||
144 | title: '404页面' | ||
145 | } | ||
146 | ] | ||
147 | }, | ||
148 | { | ||
149 | icon: 'el-icon-lx-redpacket_fill', | ||
150 | index: '/donate', | ||
151 | title: '支持作者' | ||
152 | } | ||
153 | ] | ||
154 | }; | ||
155 | }, | ||
156 | computed: { | ||
157 | onRoutes() { | ||
158 | return this.$route.path.replace('/', ''); | ||
159 | } | ||
160 | }, | ||
161 | created() { | ||
162 | // 通过 Event Bus 进行组件间通信,来折叠侧边栏 | ||
163 | bus.$on('collapse', msg => { | ||
164 | this.collapse = msg; | ||
165 | bus.$emit('collapse-content', msg); | ||
166 | }); | ||
167 | } | ||
168 | }; | ||
169 | </script> | ||
170 | |||
171 | <style scoped> | ||
172 | .sidebar { | ||
173 | display: block; | ||
174 | position: absolute; | ||
175 | left: 0; | ||
176 | top: 70px; | ||
177 | bottom: 0; | ||
178 | overflow-y: scroll; | ||
179 | } | ||
180 | .sidebar::-webkit-scrollbar { | ||
181 | width: 0; | ||
182 | } | ||
183 | .sidebar-el-menu:not(.el-menu--collapse) { | ||
184 | width: 250px; | ||
185 | } | ||
186 | .sidebar > ul { | ||
187 | height: 100%; | ||
188 | } | ||
189 | </style> |
src/common/Tags.vue
File was created | 1 | <template> | |
2 | <div class="tags" v-if="showTags"> | ||
3 | <ul> | ||
4 | <li class="tags-li" v-for="(item,index) in tagsList" :class="{'active': isActive(item.path)}" :key="index"> | ||
5 | <router-link :to="item.path" class="tags-li-title"> | ||
6 | {{item.title}} | ||
7 | </router-link> | ||
8 | <span class="tags-li-icon" @click="closeTags(index)"><i class="el-icon-close"></i></span> | ||
9 | </li> | ||
10 | </ul> | ||
11 | <div class="tags-close-box"> | ||
12 | <el-dropdown @command="handleTags"> | ||
13 | <el-button size="mini" type="primary"> | ||
14 | 标签选项<i class="el-icon-arrow-down el-icon--right"></i> | ||
15 | </el-button> | ||
16 | <el-dropdown-menu size="small" slot="dropdown"> | ||
17 | <el-dropdown-item command="other">关闭其他</el-dropdown-item> | ||
18 | <el-dropdown-item command="all">关闭所有</el-dropdown-item> | ||
19 | </el-dropdown-menu> | ||
20 | </el-dropdown> | ||
21 | </div> | ||
22 | </div> | ||
23 | </template> | ||
24 | |||
25 | <script> | ||
26 | import bus from './bus'; | ||
27 | export default { | ||
28 | data() { | ||
29 | return { | ||
30 | tagsList: [] | ||
31 | } | ||
32 | }, | ||
33 | methods: { | ||
34 | isActive(path) { | ||
35 | return path === this.$route.fullPath; | ||
36 | }, | ||
37 | // 关闭单个标签 | ||
38 | closeTags(index) { | ||
39 | const delItem = this.tagsList.splice(index, 1)[0]; | ||
40 | const item = this.tagsList[index] ? this.tagsList[index] : this.tagsList[index - 1]; | ||
41 | if (item) { | ||
42 | delItem.path === this.$route.fullPath && this.$router.push(item.path); | ||
43 | }else{ | ||
44 | this.$router.push('/'); | ||
45 | } | ||
46 | }, | ||
47 | // 关闭全部标签 | ||
48 | closeAll(){ | ||
49 | this.tagsList = []; | ||
50 | this.$router.push('/'); | ||
51 | }, | ||
52 | // 关闭其他标签 | ||
53 | closeOther(){ | ||
54 | const curItem = this.tagsList.filter(item => { | ||
55 | return item.path === this.$route.fullPath; | ||
56 | }) | ||
57 | this.tagsList = curItem; | ||
58 | }, | ||
59 | // 设置标签 | ||
60 | setTags(route){ | ||
61 | const isExist = this.tagsList.some(item => { | ||
62 | return item.path === route.fullPath; | ||
63 | }) | ||
64 | if(!isExist){ | ||
65 | if(this.tagsList.length >= 8){ | ||
66 | this.tagsList.shift(); | ||
67 | } | ||
68 | this.tagsList.push({ | ||
69 | title: route.meta.title, | ||
70 | path: route.fullPath, | ||
71 | name: route.matched[1].components.default.name | ||
72 | }) | ||
73 | } | ||
74 | bus.$emit('tags', this.tagsList); | ||
75 | }, | ||
76 | handleTags(command){ | ||
77 | command === 'other' ? this.closeOther() : this.closeAll(); | ||
78 | } | ||
79 | }, | ||
80 | computed: { | ||
81 | showTags() { | ||
82 | return this.tagsList.length > 0; | ||
83 | } | ||
84 | }, | ||
85 | watch:{ | ||
86 | $route(newValue, oldValue){ | ||
87 | this.setTags(newValue); | ||
88 | } | ||
89 | }, | ||
90 | created(){ | ||
91 | this.setTags(this.$route); | ||
92 | // 监听关闭当前页面的标签页 | ||
93 | bus.$on('close_current_tags', () => { | ||
94 | for (let i = 0, len = this.tagsList.length; i < len; i++) { | ||
95 | const item = this.tagsList[i]; | ||
96 | if(item.path === this.$route.fullPath){ | ||
97 | if(i < len - 1){ | ||
98 | this.$router.push(this.tagsList[i+1].path); | ||
99 | }else if(i > 0){ | ||
100 | this.$router.push(this.tagsList[i-1].path); | ||
101 | }else{ | ||
102 | this.$router.push('/'); | ||
103 | } | ||
104 | this.tagsList.splice(i, 1); | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | }) | ||
109 | } | ||
110 | } | ||
111 | </script> | ||
112 | |||
113 | |||
114 | <style> | ||
115 | .tags { | ||
116 | position: relative; | ||
117 | height: 30px; | ||
118 | overflow: hidden; | ||
119 | background: #fff; | ||
120 | padding-right: 120px; | ||
121 | box-shadow: 0 5px 10px #ddd; | ||
122 | } | ||
123 | .tags ul { | ||
124 | box-sizing: border-box; | ||
125 | width: 100%; | ||
126 | height: 100%; | ||
127 | } | ||
128 | .tags-li { | ||
129 | float: left; | ||
130 | margin: 3px 5px 2px 3px; | ||
131 | border-radius: 3px; | ||
132 | font-size: 12px; | ||
133 | overflow: hidden; | ||
134 | cursor: pointer; | ||
135 | height: 23px; | ||
136 | line-height: 23px; | ||
137 | border: 1px solid #e9eaec; | ||
138 | background: #fff; | ||
139 | padding: 0 5px 0 12px; | ||
140 | vertical-align: middle; | ||
141 | color: #666; | ||
142 | -webkit-transition: all .3s ease-in; | ||
143 | -moz-transition: all .3s ease-in; | ||
144 | transition: all .3s ease-in; | ||
145 | } | ||
146 | .tags-li:not(.active):hover { | ||
147 | background: #f8f8f8; | ||
148 | } | ||
149 | .tags-li.active { | ||
150 | color: #fff; | ||
151 | } | ||
152 | .tags-li-title { | ||
153 | float: left; | ||
154 | max-width: 80px; | ||
155 | overflow: hidden; | ||
156 | white-space: nowrap; | ||
157 | text-overflow: ellipsis; | ||
158 | margin-right: 5px; | ||
159 | color: #666; | ||
160 | } | ||
161 | .tags-li.active .tags-li-title { | ||
162 | color: #fff; | ||
163 | } | ||
164 | .tags-close-box { | ||
165 | position: absolute; | ||
166 | right: 0; | ||
167 | top: 0; | ||
168 | box-sizing: border-box; | ||
169 | padding-top: 1px; | ||
170 | text-align: center; | ||
171 | width: 110px; | ||
172 | height: 30px; | ||
173 | background: #fff; | ||
174 | box-shadow: -3px 0 15px 3px rgba(0, 0, 0, .1); | ||
175 | z-index: 10; | ||
176 | } | ||
177 | </style> |
src/common/bus.js
File was created | 1 | import Vue from 'vue'; | |
2 | |||
3 | // 使用 Event Bus | ||
4 | const bus = new Vue(); | ||
5 | |||
6 | export default bus; | ||
7 |
src/common/directives.js
File was created | 1 | import Vue from 'vue'; | |
2 | |||
3 | // v-dialogDrag: 弹窗拖拽属性 | ||
4 | Vue.directive('dialogDrag', { | ||
5 | bind(el, binding, vnode, oldVnode) { | ||
6 | const dialogHeaderEl = el.querySelector('.el-dialog__header'); | ||
7 | const dragDom = el.querySelector('.el-dialog'); | ||
8 | |||
9 | dialogHeaderEl.style.cssText += ';cursor:move;' | ||
10 | dragDom.style.cssText += ';top:0px;' | ||
11 | |||
12 | // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); | ||
13 | const sty = (() => { | ||
14 | if (window.document.currentStyle) { | ||
15 | return (dom, attr) => dom.currentStyle[attr]; | ||
16 | } else { | ||
17 | return (dom, attr) => getComputedStyle(dom, false)[attr]; | ||
18 | } | ||
19 | })() | ||
20 | |||
21 | dialogHeaderEl.onmousedown = (e) => { | ||
22 | // 鼠标按下,计算当前元素距离可视区的距离 | ||
23 | const disX = e.clientX - dialogHeaderEl.offsetLeft; | ||
24 | const disY = e.clientY - dialogHeaderEl.offsetTop; | ||
25 | |||
26 | const screenWidth = document.body.clientWidth; // body当前宽度 | ||
27 | const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) | ||
28 | |||
29 | const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 | ||
30 | const dragDomheight = dragDom.offsetHeight; // 对话框高度 | ||
31 | |||
32 | const minDragDomLeft = dragDom.offsetLeft; | ||
33 | const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; | ||
34 | |||
35 | const minDragDomTop = dragDom.offsetTop; | ||
36 | const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; | ||
37 | |||
38 | |||
39 | // 获取到的值带px 正则匹配替换 | ||
40 | let styL = sty(dragDom, 'left'); | ||
41 | let styT = sty(dragDom, 'top'); | ||
42 | |||
43 | // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px | ||
44 | if (styL.includes('%')) { | ||
45 | styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100); | ||
46 | styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100); | ||
47 | } else { | ||
48 | styL = +styL.replace(/\px/g, ''); | ||
49 | styT = +styT.replace(/\px/g, ''); | ||
50 | }; | ||
51 | |||
52 | document.onmousemove = function (e) { | ||
53 | // 通过事件委托,计算移动的距离 | ||
54 | let left = e.clientX - disX; | ||
55 | let top = e.clientY - disY; | ||
56 | |||
57 | // 边界处理 | ||
58 | if (-(left) > minDragDomLeft) { | ||
59 | left = -(minDragDomLeft); | ||
60 | } else if (left > maxDragDomLeft) { | ||
61 | left = maxDragDomLeft; | ||
62 | } | ||
63 | |||
64 | if (-(top) > minDragDomTop) { | ||
65 | top = -(minDragDomTop); | ||
66 | } else if (top > maxDragDomTop) { | ||
67 | top = maxDragDomTop; | ||
68 | } | ||
69 | |||
70 | // 移动当前元素 | ||
71 | dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; | ||
72 | }; | ||
73 | |||
74 | document.onmouseup = function (e) { | ||
75 | document.onmousemove = null; | ||
76 | document.onmouseup = null; | ||
77 | }; | ||
78 | } | ||
79 | } | ||
80 | }) |
src/common/i18n.js
File was created | 1 | export const messages = { | |
2 | 'zh': { | ||
3 | i18n: { | ||
4 | breadcrumb: '国际化产品', | ||
5 | tips: '通过切换语言按钮,来改变当前内容的语言。', | ||
6 | btn: '切换英文', | ||
7 | title1: '常用用法', | ||
8 | p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。', | ||
9 | p2: '没有什么比信念更能支撑我们度过艰难的时光了。', | ||
10 | p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。', | ||
11 | title2: '组件插值', | ||
12 | info: 'Element组件需要国际化,请参考 {action}。', | ||
13 | value: '文档' | ||
14 | } | ||
15 | }, | ||
16 | 'en': { | ||
17 | i18n: { | ||
18 | breadcrumb: 'International Products', | ||
19 | tips: 'Click on the button to change the current language. ', | ||
20 | btn: 'Switch Chinese', | ||
21 | title1: 'Common usage', | ||
22 | p1: "If you reveal your secrets to the wind you should not blame the wind for revealing them to the trees.", | ||
23 | p2: "Nothing can help us endure dark times better than our faith. ", | ||
24 | p3: "If you can do what you do best and be happy, you're further along in life than most people.", | ||
25 | title2: 'Component interpolation', | ||
26 | info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.', | ||
27 | value: 'documentation' | ||
28 | } | ||
29 | } | ||
30 | } |
src/layout/components/Navbar.vue
1 | <template> | 1 | <template> |
2 | <div class="navbar"> | 2 | <div class="navbar"> |
3 | <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> | 3 | <hamburger |
4 | :is-active="sidebar.opened" | ||
5 | class="hamburger-container" | ||
6 | @toggleClick="toggleSideBar" | ||
7 | /> | ||
4 | 8 | ||
5 | <breadcrumb class="breadcrumb-container" /> | 9 | <breadcrumb class="breadcrumb-container" /> |
6 | 10 | ||
7 | <div class="right-menu"> | 11 | <div class="right-menu"> |
8 | 语言设置 | 12 | <el-menu |
9 | <el-dropdown class="avatar-container" trigger="click"> | 13 | :default-active="activeIndex" |
10 | <div class="avatar-wrapper"> | 14 | class="el-menu-demo" |
11 | <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> | 15 | mode="horizontal" |
12 | <i class="el-icon-caret-bottom" /> | 16 | @select="handleSelect" |
13 | </div> | 17 | > |
14 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> | 18 | <el-menu-item index="1"> |
15 | <router-link to="/"> | 19 | <i class="el-icon-bell"></i>通知中心 |
16 | <el-dropdown-item> | 20 | <el-badge class="mark" :value="12" /> |
17 | Home | 21 | </el-menu-item> |
18 | </el-dropdown-item> | 22 | <el-submenu index="2"> |
19 | </router-link> | 23 | <template slot="title"> |
20 | <router-link to="/seting"> | 24 | <i class="el-icon-custom"></i>个人设置 |
21 | <el-dropdown-item> | 25 | </template> |
22 | 个人设置 | 26 | <el-menu-item index="2-1">选项1</el-menu-item> |
23 | </el-dropdown-item> | 27 | <el-menu-item index="2-2">选项2</el-menu-item> |
24 | </router-link> | 28 | <el-menu-item index="2-3">选项3</el-menu-item> |
25 | <!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> | 29 | </el-submenu> |
30 | <el-dropdown class="avatar-container" trigger="click"> | ||
31 | <div class="avatar-wrapper"> | ||
32 | <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar" /> | ||
33 | <i class="el-icon-caret-bottom" /> | ||
34 | </div> | ||
35 | <el-dropdown-menu slot="dropdown" class="user-dropdown"> | ||
36 | <router-link to="/"> | ||
37 | <el-dropdown-item>Home</el-dropdown-item> | ||
38 | </router-link> | ||
39 | <router-link to="/seting"> | ||
40 | <el-dropdown-item>个人设置</el-dropdown-item> | ||
41 | </router-link> | ||
42 | <!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> | ||
26 | <el-dropdown-item>Github</el-dropdown-item> | 43 | <el-dropdown-item>Github</el-dropdown-item> |
27 | </a> --> | 44 | </a>--> |
28 | <!-- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> | 45 | <!-- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> |
29 | <el-dropdown-item>Docs</el-dropdown-item> | 46 | <el-dropdown-item>Docs</el-dropdown-item> |
30 | </a> --> | 47 | </a>--> |
31 | <el-dropdown-item divided @click.native="logout"> | 48 | <el-dropdown-item divided @click.native="logout"> |
32 | <span style="display:block;">退出系统</span> | 49 | <span style="display:block;">退出系统</span> |
33 | </el-dropdown-item> | 50 | </el-dropdown-item> |
34 | </el-dropdown-menu> | 51 | </el-dropdown-menu> |
35 | </el-dropdown> | 52 | </el-dropdown> |
53 | <el-menu-item index="3" disabled>ddd</el-menu-item> | ||
54 | <el-menu-item index="4"> | ||
55 | <a href="https://glass.xiuyetang.com" target="_blank">跳到外部链接</a> | ||
56 | </el-menu-item> | ||
57 | </el-menu> | ||
36 | </div> | 58 | </div> |
37 | </div> | 59 | </div> |
38 | </template> | 60 | </template> |
39 | 61 | ||
40 | <script> | 62 | <script> |
41 | import { mapGetters } from 'vuex' | 63 | import { mapGetters } from "vuex"; |
42 | import Breadcrumb from '@/components/Breadcrumb' | 64 | import Breadcrumb from "@/components/Breadcrumb"; |
43 | import Hamburger from '@/components/Hamburger' | 65 | import Hamburger from "@/components/Hamburger"; |
44 | 66 | ||
45 | export default { | 67 | export default { |
46 | components: { | 68 | components: { |
47 | Breadcrumb, | 69 | Breadcrumb, |
48 | Hamburger | 70 | Hamburger |
49 | }, | 71 | }, |
50 | computed: { | 72 | computed: { |
51 | ...mapGetters([ | 73 | ...mapGetters(["sidebar", "avatar"]) |
52 | 'sidebar', | ||
53 | 'avatar' | ||
54 | ]) | ||
55 | }, | 74 | }, |
56 | methods: { | 75 | methods: { |
57 | toggleSideBar() { | 76 | toggleSideBar() { |
58 | this.$store.dispatch('app/toggleSideBar') | 77 | this.$store.dispatch("app/toggleSideBar"); |
59 | }, | 78 | }, |
60 | async logout() { | 79 | async logout() { |
61 | await this.$store.dispatch('user/logout') | 80 | await this.$store.dispatch("user/logout"); |
62 | this.$router.push(`/login?redirect=${this.$route.fullPath}`) | 81 | this.$router.push(`/login?redirect=${this.$route.fullPath}`); |
63 | } | 82 | } |
64 | } | 83 | } |
65 | } | 84 | }; |
66 | </script> | 85 | </script> |
67 | 86 | ||
68 | <style lang="scss" scoped> | 87 | <style lang="scss" scoped> |
88 | .item { | ||
89 | margin-top: 10px; | ||
90 | margin-right: 20px; | ||
91 | } | ||
69 | .navbar { | 92 | .navbar { |
70 | height: 50px; | 93 | height: 50px; |
71 | overflow: hidden; | 94 | overflow: hidden; |
72 | position: relative; | 95 | position: relative; |
73 | background: #fff; | 96 | background: #fff; |
74 | box-shadow: 0 1px 4px rgba(0,21,41,.08); | 97 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); |
75 | 98 | ||
76 | .hamburger-container { | 99 | .hamburger-container { |
77 | line-height: 46px; | 100 | line-height: 46px; |
78 | height: 100%; | 101 | height: 100%; |
79 | float: left; | 102 | float: left; |
80 | cursor: pointer; | 103 | cursor: pointer; |
81 | transition: background .3s; | 104 | transition: background 0.3s; |
82 | -webkit-tap-highlight-color:transparent; | 105 | -webkit-tap-highlight-color: transparent; |
83 | 106 | ||
84 | &:hover { | 107 | &:hover { |
85 | background: rgba(0, 0, 0, .025) | 108 | background: rgba(0, 0, 0, 0.025); |
86 | } | 109 | } |
87 | } | 110 | } |
88 | 111 | ||
89 | .breadcrumb-container { | 112 | .breadcrumb-container { |
90 | float: left; | 113 | float: left; |
91 | } | 114 | } |
92 | 115 | ||
93 | .right-menu { | 116 | .right-menu { |
94 | float: right; | 117 | float: right; |
95 | height: 100%; | 118 | height: 100%; |
96 | line-height: 50px; | 119 | line-height: 50px; |
97 | 120 | ||
98 | &:focus { | 121 | &:focus { |
99 | outline: none; | 122 | outline: none; |
100 | } | 123 | } |
101 | 124 | ||
102 | .right-menu-item { | 125 | .right-menu-item { |
103 | display: inline-block; | 126 | display: inline-block; |
104 | padding: 0 8px; | 127 | padding: 0 8px; |
105 | height: 100%; | 128 | height: 100%; |
106 | font-size: 18px; | 129 | font-size: 18px; |
107 | color: #5a5e66; | 130 | color: #5a5e66; |
108 | vertical-align: text-bottom; | 131 | vertical-align: text-bottom; |
109 | 132 | ||
110 | &.hover-effect { | 133 | &.hover-effect { |
111 | cursor: pointer; | 134 | cursor: pointer; |
112 | transition: background .3s; | 135 | transition: background 0.3s; |
113 | 136 | ||
114 | &:hover { | 137 | &:hover { |
115 | background: rgba(0, 0, 0, .025) | 138 | background: rgba(0, 0, 0, 0.025); |
116 | } | 139 | } |
117 | } | 140 | } |
118 | } | 141 | } |
119 | 142 | ||
120 | .avatar-container { | 143 | .avatar-container { |
121 | margin-right: 30px; | 144 | margin-right: 30px; |
122 | 145 | ||
123 | .avatar-wrapper { | 146 | .avatar-wrapper { |
124 | margin-top: 5px; | 147 | margin-top: 5px; |
125 | position: relative; | 148 | position: relative; |
126 | 149 | ||
127 | .user-avatar { | 150 | .user-avatar { |
128 | cursor: pointer; | 151 | cursor: pointer; |
129 | width: 40px; | 152 | width: 40px; |
130 | height: 40px; | 153 | height: 40px; |
131 | border-radius: 10px; | 154 | border-radius: 10px; |
132 | } | 155 | } |
133 | 156 | ||
134 | .el-icon-caret-bottom { | 157 | .el-icon-caret-bottom { |
135 | cursor: pointer; | 158 | cursor: pointer; |
136 | position: absolute; | 159 | position: absolute; |
137 | right: -20px; | 160 | right: -20px; |
138 | top: 25px; | 161 | top: 25px; |
139 | font-size: 12px; | 162 | font-size: 12px; |
140 | } | 163 | } |
141 | } | 164 | } |
142 | } | 165 | } |
143 | } | 166 | } |
src/layout/components/index.js
1 | // export { default as Navbar } from '../../common/Header' | ||
1 | export { default as Navbar } from './Navbar' | 2 | export { default as Navbar } from './Navbar' |
2 | export { default as Sidebar } from './Sidebar' | 3 | export { default as Sidebar } from './Sidebar' |
3 | export { default as AppMain } from './AppMain' | 4 | export { default as AppMain } from './AppMain' |
4 | 5 |
src/main.js
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | 2 | ||
3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets | 3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets |
4 | 4 | ||
5 | import ElementUI from 'element-ui' | 5 | import ElementUI from 'element-ui' |
6 | import 'element-ui/lib/theme-chalk/index.css' | 6 | import 'element-ui/lib/theme-chalk/index.css' |
7 | import locale from 'element-ui/lib/locale/lang/en' // lang i18n | 7 | // import locale from 'element-ui/lib/locale/lang/en' // lang i18n |
8 | // import local_zh from 'element-ui/lib/locale/lang/zh-CN' // 在node_module里面 | 8 | // import local_zh from 'element-ui/lib/locale/lang/zh-CN' // 在node_module里面 |
9 | 9 | ||
10 | import '@/styles/index.scss' // global css | 10 | import '@/styles/index.scss' // global css |
11 | 11 | ||
12 | import App from './App' | 12 | import App from './App' |
13 | import store from './store' | 13 | import store from './store' |
14 | import router from './router' | 14 | import router from './router' |
15 | 15 | ||
16 | import '@/icons' // icon | 16 | import '@/icons' // icon |
17 | import '@/permission' // permission control | 17 | import '@/permission' // permission control |
18 | 18 | ||
19 | /** | 19 | /** |
20 | * If you don't want to use mock-server | 20 | * If you don't want to use mock-server |
21 | * you want to use MockJs for mock api | 21 | * you want to use MockJs for mock api |
22 | * you can execute: mockXHR() | 22 | * you can execute: mockXHR() |
23 | * | 23 | * |
24 | * Currently MockJs will be used in the production environment, | 24 | * Currently MockJs will be used in the production environment, |
25 | * please remove it before going online ! ! ! | 25 | * please remove it before going online ! ! ! |
26 | */ | 26 | */ |
27 | if (process.env.NODE_ENV === 'production') { | 27 | if (process.env.NODE_ENV === 'production') { |
28 | const { mockXHR } = require('../mock') | 28 | const { mockXHR } = require('../mock') |
29 | mockXHR() | 29 | mockXHR() |
30 | } | 30 | } |
31 | 31 | ||
32 | Vue.use(ElementUI, { size: 'small', zIndex: 3000 }) | ||
32 | // set ElementUI lang to EN | 33 | // set ElementUI lang to EN |
33 | Vue.use(ElementUI, { locale }) | 34 | // Vue.use(ElementUI, { locale }) |
34 | // 如果想要中文版 element-ui,按如下方式声明 | 35 | // 如果想要中文版 element-ui,按如下方式声明 |
35 | // Vue.use(ElementUI, {local_zh}) | 36 | // Vue.use(ElementUI, {local_zh}) |
36 | |||
37 | Vue.config.productionTip = false | 37 | Vue.config.productionTip = false |
38 | 38 | ||
39 | new Vue({ | 39 | new Vue({ |
40 | el: '#app', | 40 | el: '#app', |
41 | router, | 41 | router, |
42 | store, | 42 | store, |
43 | render: h => h(App) | 43 | render: h => h(App) |
44 | }) | 44 | }) |
src/router/index.js
1 | import Vue from 'vue' | 1 | import Vue from 'vue' |
2 | import Router from 'vue-router' | 2 | import Router from 'vue-router' |
3 | 3 | ||
4 | Vue.use(Router) | 4 | Vue.use(Router) |
5 | 5 | ||
6 | /* Layout */ | 6 | /* Layout */ |
7 | import Layout from '@/layout' | 7 | import Layout from '@/layout' |
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Note: sub-menu only appear when route children.length >= 1 | 10 | * Note: sub-menu only appear when route children.length >= 1 |
11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html | 11 | * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html |
12 | * | 12 | * |
13 | * hidden: true if set true, item will not show in the sidebar(default is false) | 13 | * hidden: true if set true, item will not show in the sidebar(default is false) |
14 | * alwaysShow: true if set true, will always show the root menu | 14 | * alwaysShow: true if set true, will always show the root menu |
15 | * if not set alwaysShow, when item has more than one children route, | 15 | * if not set alwaysShow, when item has more than one children route, |
16 | * it will becomes nested mode, otherwise not show the root menu | 16 | * it will becomes nested mode, otherwise not show the root menu |
17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb | 17 | * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb |
18 | * name:'router-name' the name is used by <keep-alive> (must set!!!) | 18 | * name:'router-name' the name is used by <keep-alive> (must set!!!) |
19 | * meta : { | 19 | * meta : { |
20 | roles: ['admin','editor'] control the page roles (you can set multiple roles) | 20 | roles: ['admin','editor'] control the page roles (you can set multiple roles) |
21 | title: 'title' the name show in sidebar and breadcrumb (recommend set) | 21 | title: 'title' the name show in sidebar and breadcrumb (recommend set) |
22 | icon: 'svg-name' the icon show in the sidebar | 22 | icon: 'svg-name' the icon show in the sidebar |
23 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) | 23 | breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) |
24 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set | 24 | activeMenu: '/example/list' if set path, the sidebar will highlight the path you set |
25 | } | 25 | } |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * constantRoutes | 29 | * constantRoutes |
30 | * a base page that does not have permission requirements | 30 | * a base page that does not have permission requirements |
31 | * all roles can be accessed | 31 | * all roles can be accessed |
32 | */ | 32 | */ |
33 | export const constantRoutes = [ | 33 | export const constantRoutes = [{ |
34 | { | ||
35 | path: '/login', | 34 | path: '/login', |
36 | component: () => import('@/views/login/index'), | 35 | component: () => import('@/views/login/index'), |
37 | hidden: true | 36 | hidden: true |
38 | }, | 37 | }, |
39 | 38 | ||
40 | { | 39 | { |
41 | path: '/404', | 40 | path: '/404', |
42 | component: () => import('@/views/404'), | 41 | component: () => import('@/views/404'), |
43 | hidden: true | 42 | hidden: true |
44 | }, | 43 | }, |
45 | 44 | ||
46 | { | 45 | { |
47 | path: '/', | 46 | path: '/', |
48 | component: Layout, | 47 | component: Layout, |
49 | redirect: '/dashboard', | 48 | redirect: '/dashboard', |
50 | children: [{ | 49 | children: [{ |
51 | path: 'dashboard', | 50 | path: 'dashboard', |
52 | name: 'Dashboard', | 51 | name: 'Dashboard', |
53 | component: () => import('@/views/dashboard/index'), | 52 | component: () => import('@/views/dashboard/index'), |
54 | meta: { title: '中控台', icon: 'dashboard' } | 53 | meta: { |
54 | title: '中控台', | ||
55 | icon: 'dashboard' | ||
56 | } | ||
55 | }] | 57 | }] |
56 | }, | 58 | }, |
57 | { | 59 | { |
58 | path: '/user', | 60 | path: '/user', |
59 | component: Layout, | 61 | component: Layout, |
60 | redirect: '/user/list', | 62 | redirect: '/user/list', |
61 | name: 'user', | 63 | name: 'user', |
62 | meta: { title: '用户管理', icon: 'example' }, | 64 | meta: { |
63 | children: [ | 65 | title: '用户管理', |
64 | { | 66 | icon: 'example' |
67 | }, | ||
68 | children: [{ | ||
65 | path: 'user', | 69 | path: 'user', |
66 | name: 'User', | 70 | name: 'User', |
67 | component: () => import('@/views/table/index'), | 71 | component: () => import('@/views/table/index'), |
68 | meta: { title: '用户列表', icon: 'table' } | 72 | meta: { |
73 | title: '用户列表', | ||
74 | icon: 'table' | ||
75 | } | ||
69 | }, | 76 | }, |
70 | { | 77 | { |
71 | path: 'tree', | 78 | path: 'tree', |
72 | name: 'Table', | 79 | name: 'Table', |
73 | component: () => import('@/views/tree/index'), | 80 | component: () => import('@/views/tree/index'), |
74 | meta: { title: 'Tree', icon: 'tree' } | 81 | meta: { |
82 | title: 'Tree', | ||
83 | icon: 'tree' | ||
84 | } | ||
75 | } | 85 | } |
76 | ] | 86 | ] |
77 | }, | 87 | }, |
78 | { | 88 | { |
79 | path: '/example', | 89 | path: '/example', |
80 | component: Layout, | 90 | component: Layout, |
81 | redirect: '/example/table', | 91 | redirect: '/example/table', |
82 | name: 'Example', | 92 | name: 'Example', |
83 | meta: { title: 'E1111xample', icon: 'example' }, | 93 | meta: { |
84 | children: [ | 94 | title: '商家管理', |
85 | { | 95 | icon: 'example' |
96 | }, | ||
97 | children: [{ | ||
86 | path: 'table', | 98 | path: 'table', |
87 | name: 'Table', | 99 | name: 'Table', |
88 | component: () => import('@/views/table/index'), | 100 | component: () => import('@/views/table/index'), |
89 | meta: { title: 'Table', icon: 'table' } | 101 | meta: { |
102 | title: 'Table', | ||
103 | icon: 'table' | ||
104 | } | ||
90 | }, | 105 | }, |
91 | { | 106 | { |
92 | path: 'tree', | 107 | path: 'tree', |
93 | name: 'Tree', | 108 | name: 'Tree', |
94 | component: () => import('@/views/tree/index'), | 109 | component: () => import('@/views/tree/index'), |
95 | meta: { title: 'Tree', icon: 'tree' } | 110 | meta: { |
111 | title: 'Tree', | ||
112 | icon: 'tree' | ||
113 | } | ||
96 | } | 114 | } |
97 | ] | 115 | ] |
98 | }, | 116 | }, |
99 | |||
100 | { | 117 | { |
101 | path: '/form', | 118 | path: '/example', |
102 | component: Layout, | 119 | component: Layout, |
103 | children: [ | 120 | redirect: '/example/table', |
121 | name: 'Example', | ||
122 | meta: { | ||
123 | title: '产品管理', | ||
124 | icon: 'example' | ||
125 | }, | ||
126 | children: [{ | ||
127 | path: 'table', | ||
128 | name: 'Table', | ||
129 | component: () => import('@/views/table/index'), | ||
130 | meta: { | ||
131 | title: 'Table', | ||
132 | icon: 'table' | ||
133 | } | ||
134 | }, | ||
104 | { | 135 | { |
105 | path: 'index', | 136 | path: 'tree', |
106 | name: 'Form', | 137 | name: 'Tree', |
107 | component: () => import('@/views/form/index'), | 138 | component: () => import('@/views/tree/index'), |
108 | meta: { title: 'Form', icon: 'form' } | 139 | meta: { |
140 | title: 'Tree', | ||
141 | icon: 'tree' | ||
142 | } | ||
109 | } | 143 | } |
110 | ] | 144 | ] |
111 | } | 145 | }, |
112 | ] | ||
113 | |||
114 | /** | ||
115 | * asyncRoutes | ||
116 | * the routes that need to be dynamically loaded based on user roles | ||
117 | */ | ||
118 | export const asyncRoutes = [ | ||
119 | { | 146 | { |
120 | path: '/nested', | 147 | path: '/example', |
121 | component: Layout, | 148 | component: Layout, |
122 | redirect: '/nested/menu1', | 149 | redirect: '/example/table', |
123 | name: 'Nested', | 150 | name: 'Example', |
124 | meta: { | 151 | meta: { |
125 | title: 'Nested', | 152 | title: '元管理', |
126 | icon: 'nested' | 153 | icon: 'example' |
127 | }, | 154 | }, |
128 | children: [ | 155 | children: [{ |
129 | { | 156 | path: 'table', |
130 | path: 'menu1', | 157 | name: 'Table', |
131 | component: () => import('@/views/nested/menu1/index'), // Parent router-view | 158 | component: () => import('@/views/table/index'), |
132 | name: 'Menu1', | 159 | meta: { |
133 | meta: { title: 'Menu1' }, | 160 | title: 'Table', |
134 | children: [ | 161 | icon: 'table' |
135 | { | 162 | } |
136 | path: 'menu1-1', | ||
137 | component: () => import('@/views/nested/menu1/menu1-1'), | ||
138 | name: 'Menu1-1', | ||
139 | meta: { title: 'Menu1-1' } | ||
140 | }, | ||
141 | { | ||
142 | path: 'menu1-2', | ||
143 | component: () => import('@/views/nested/menu1/menu1-2'), | ||
144 | name: 'Menu1-2', | ||
145 | meta: { title: 'Menu1-2' }, | ||
146 | children: [ | ||
147 | { | ||
148 | path: 'menu1-2-1', | ||
149 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), | ||
150 | name: 'Menu1-2-1', | ||
151 | meta: { title: 'Menu1-2-1' } | ||
152 | }, | ||
153 | { | ||
154 | path: 'menu1-2-2', | ||
155 | component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), | ||
156 | name: 'Menu1-2-2', | ||
157 | meta: { title: 'Menu1-2-2' } | ||
158 | } | ||
159 | ] | ||
160 | }, | ||
161 | { | ||
162 | path: 'menu1-3', | ||
163 | component: () => import('@/views/nested/menu1/menu1-3'), | ||
164 | name: 'Menu1-3', | ||
165 | meta: { title: 'Menu1-3' } | ||
166 | } | ||
167 | ] | ||
168 | }, | 163 | }, |
169 | { | 164 | { |
170 | path: 'menu2', | 165 | path: 'tree', |
171 | component: () => import('@/views/nested/menu2/index'), | 166 | name: 'Tree', |
172 | meta: { title: 'menu2' } | 167 | component: () => import('@/views/tree/index'), |
168 | meta: { | ||
169 | title: 'Tree', | ||
170 | icon: 'tree' | ||
171 | } | ||
173 | } | 172 | } |
174 | ] | 173 | ] |
175 | }, | 174 | }, |
176 | |||
177 | { | 175 | { |
178 | path: 'external-link', | 176 | path: '/example', |
177 | component: Layout, | ||
178 | redirect: '/example/table', | ||
179 | name: 'Example', | ||
180 | meta: { | ||
181 | title: '交易管理', | ||
182 | icon: 'example' | ||
183 | }, | ||
184 | children: [{ | ||
185 | path: 'table', | ||
186 | name: 'Table', | ||
187 | component: () => import('@/views/table/index'), | ||
188 | meta: { | ||
189 | title: 'Table', | ||
190 | icon: 'table' | ||
191 | } | ||
192 | }, | ||
193 | { | ||
194 | path: 'tree', | ||
195 | name: 'Tree', | ||
196 | component: () => import('@/views/tree/index'), | ||
197 | meta: { | ||
198 | title: 'Tree', | ||
199 | icon: 'tree' | ||
200 | } | ||
201 | } | ||
202 | ] | ||
203 | }, { | ||
204 | path: '/example', | ||
179 | component: Layout, | 205 | component: Layout, |
180 | children: [ | 206 | redirect: '/example/table', |
207 | name: 'Example', | ||
208 | meta: { | ||
209 | title: '推荐系统', | ||
210 | icon: 'example' | ||
211 | }, | ||
212 | children: [{ | ||
213 | path: 'table', | ||
214 | name: 'Table', | ||
215 | component: () => import('@/views/table/index'), | ||
216 | meta: { | ||
217 | title: 'Table', | ||
218 | icon: 'table' | ||
219 | } | ||
220 | }, | ||
221 | { | ||
222 | path: 'tree', | ||
223 | name: 'Tree', | ||
224 | component: () => import('@/views/tree/index'), | ||
225 | meta: { | ||
226 | title: 'Tree', | ||
227 | icon: 'tree' | ||
228 | } | ||
229 | } | ||
230 | ] | ||
231 | }, { | ||
232 | path: '/system', | ||
233 | component: Layout, | ||
234 | redirect: '/system/table', | ||
235 | name: 'System', | ||
236 | meta: { | ||
237 | title: '系统设置', | ||
238 | icon: 'example' | ||
239 | }, | ||
240 | children: [{ | ||
241 | path: 'table', | ||
242 | name: 'Table', | ||
243 | component: () => import('@/views/table/index'), | ||
244 | meta: { | ||
245 | title: '行业设置', | ||
246 | icon: 'table' | ||
247 | } | ||
248 | }, | ||
249 | { | ||
250 | path: 'tree', | ||
251 | name: 'Tree', | ||
252 | component: () => import('@/views/tree/index'), | ||
253 | meta: { | ||
254 | title: '语言设置', | ||
255 | icon: 'tree' | ||
256 | } | ||
257 | }, | ||
258 | { | ||
259 | path: 'tree', | ||
260 | name: 'Tree', | ||
261 | component: () => import('@/views/tree/index'), | ||
262 | meta: { | ||
263 | title: '货币设置', | ||
264 | icon: 'tree' | ||
265 | } | ||
266 | }, | ||
267 | { | ||
268 | path: 'tree', | ||
269 | name: 'Tree', | ||
270 | component: () => import('@/views/tree/index'), | ||
271 | meta: { | ||
272 | title: '站点类型设置', | ||
273 | icon: 'tree' | ||
274 | } | ||
275 | }, | ||
276 | { | ||
277 | path: 'tree', | ||
278 | name: 'Tree', | ||
279 | component: () => import('@/views/tree/index'), | ||
280 | meta: { | ||
281 | title: '模版设置', | ||
282 | icon: 'tree' | ||
283 | } | ||
284 | }, | ||
181 | { | 285 | { |
182 | path: 'https://panjiachen.github.io/vue-element-admin-site/#/', | 286 | path: 'tree', |
183 | meta: { title: 'External Link', icon: 'link' } | 287 | name: 'Tree', |
288 | component: () => import('@/views/tree/index'), | ||
289 | meta: { | ||
290 | title: '权限设置', | ||
291 | icon: 'tree' | ||
292 | } | ||
184 | } | 293 | } |
185 | ] | 294 | ] |
186 | }, | 295 | }, |
296 | { | ||
297 | path: '/form', | ||
298 | component: Layout, |
src/views/403.vue
File was created | 1 | <template> | |
2 | <div class="error-page"> | ||
3 | <div class="error-code"> | ||
4 | 4 | ||
5 | <span>0</span>3 | ||
6 | </div> | ||
7 | <div class="error-desc">啊哦~ 你没有权限访问该页面哦</div> | ||
8 | <div class="error-handle"> | ||
9 | <router-link to="/"> | ||
10 | <el-button type="primary" size="large">返回首页</el-button> | ||
11 | </router-link> | ||
12 | <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button> | ||
13 | </div> | ||
14 | </div> | ||
15 | </template> | ||
16 | |||
17 | <script> | ||
18 | export default { | ||
19 | methods: { | ||
20 | goBack() { | ||
21 | this.$router.go(-1); | ||
22 | } | ||
23 | } | ||
24 | }; | ||
25 | </script> | ||
26 | |||
27 | |||
28 | <style scoped> | ||
29 | .error-page { | ||
30 | display: flex; | ||
31 | justify-content: center; | ||
32 | align-items: center; | ||
33 | flex-direction: column; | ||
34 | width: 100%; | ||
35 | height: 100%; | ||
36 | background: #f3f3f3; | ||
37 | box-sizing: border-box; | ||
38 | } | ||
39 | .error-code { | ||
40 | line-height: 1; | ||
41 | font-size: 250px; | ||
42 | font-weight: bolder; | ||
43 | color: #f02d2d; | ||
44 | } | ||
45 | .error-code span { | ||
46 | color: #00a854; | ||
47 | } | ||
48 | .error-desc { | ||
49 | font-size: 30px; | ||
50 | color: #777; | ||
51 | } | ||
52 | .error-handle { | ||
53 | margin-top: 30px; | ||
54 | padding-bottom: 200px; | ||
55 | } | ||
56 | .error-btn { | ||
57 | margin-left: 100px; | ||
58 | } | ||
59 | </style> |
src/views/404.vue
1 | <template> | 1 | <template> |
2 | <div class="wscn-http404-container"> | 2 | <div class="wscn-http404-container"> |
3 | <div class="wscn-http404"> | 3 | <div class="wscn-http404"> |
4 | <div class="pic-404"> | 4 | <div class="pic-404"> |
5 | <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404"> | 5 | <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404" /> |
6 | <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404"> | 6 | <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404" /> |
7 | <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404"> | 7 | <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404" /> |
8 | <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> | 8 | <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404" /> |
9 | </div> | 9 | </div> |
10 | <div class="bullshit"> | 10 | <div class="bullshit"> |
11 | <div class="bullshit__oops">OOPS!</div> | 11 | <div class="bullshit__oops">OOPS!</div> |
12 | <div class="bullshit__info">All rights reserved | 12 | <div class="bullshit__info"> |
13 | <a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a> | 13 | All rights reserved |
14 | <a | ||
15 | style="color:#20a0ff" | ||
16 | href="https://wallstreetcn.com" | ||
17 | target="_blank" | ||
18 | >wallstreetcn</a> | ||
14 | </div> | 19 | </div> |
15 | <div class="bullshit__headline">{{ message }}</div> | 20 | <div class="bullshit__headline">{{ message }}</div> |
16 | <div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div> | 21 | <div |
17 | <a href="" class="bullshit__return-home">Back to home</a> | 22 | class="bullshit__info" |
23 | >Please check that the URL you entered is correct, or click the button below to return to the homepage.</div> | ||
24 | <a href class="bullshit__return-home">Back to home</a> | ||
18 | </div> | 25 | </div> |
19 | </div> | 26 | </div> |
20 | </div> | 27 | </div> |
21 | </template> | 28 | </template> |
22 | 29 | ||
23 | <script> | 30 | <script> |
24 | |||
25 | export default { | 31 | export default { |
26 | name: 'Page404', | 32 | name: "Page404", |
27 | computed: { | 33 | computed: { |
28 | message() { | 34 | message() { |
29 | return 'The webmaster said that you can not enter this page...' | 35 | return "The webmaster said that you can not enter this page..."; |
30 | } | 36 | } |
31 | } | 37 | } |
32 | } | 38 | }; |
33 | </script> | 39 | </script> |
34 | 40 | ||
35 | <style lang="scss" scoped> | 41 | <style lang="scss" scoped> |
36 | .wscn-http404-container{ | 42 | .wscn-http404-container { |
37 | transform: translate(-50%,-50%); | 43 | transform: translate(-50%, -50%); |
38 | position: absolute; | 44 | position: absolute; |
39 | top: 40%; | 45 | top: 40%; |
40 | left: 50%; | 46 | left: 50%; |
41 | } | 47 | } |
42 | .wscn-http404 { | 48 | .wscn-http404 { |
43 | position: relative; | 49 | position: relative; |
44 | width: 1200px; | 50 | width: 1200px; |
45 | padding: 0 50px; | 51 | padding: 0 50px; |
46 | overflow: hidden; | 52 | overflow: hidden; |
47 | .pic-404 { | 53 | .pic-404 { |
48 | position: relative; | 54 | position: relative; |
49 | float: left; | 55 | float: left; |
50 | width: 600px; | 56 | width: 600px; |
51 | overflow: hidden; | 57 | overflow: hidden; |
52 | &__parent { | 58 | &__parent { |
53 | width: 100%; | 59 | width: 100%; |
54 | } | 60 | } |
55 | &__child { | 61 | &__child { |
56 | position: absolute; | 62 | position: absolute; |
57 | &.left { | 63 | &.left { |
58 | width: 80px; | 64 | width: 80px; |
59 | top: 17px; | 65 | top: 17px; |
60 | left: 220px; | 66 | left: 220px; |
61 | opacity: 0; | 67 | opacity: 0; |
62 | animation-name: cloudLeft; | 68 | animation-name: cloudLeft; |
63 | animation-duration: 2s; | 69 | animation-duration: 2s; |
64 | animation-timing-function: linear; | 70 | animation-timing-function: linear; |
65 | animation-fill-mode: forwards; | 71 | animation-fill-mode: forwards; |
66 | animation-delay: 1s; | 72 | animation-delay: 1s; |
67 | } | 73 | } |
68 | &.mid { | 74 | &.mid { |
69 | width: 46px; | 75 | width: 46px; |
70 | top: 10px; | 76 | top: 10px; |
71 | left: 420px; | 77 | left: 420px; |
72 | opacity: 0; | 78 | opacity: 0; |
73 | animation-name: cloudMid; | 79 | animation-name: cloudMid; |
74 | animation-duration: 2s; | 80 | animation-duration: 2s; |
75 | animation-timing-function: linear; | 81 | animation-timing-function: linear; |
76 | animation-fill-mode: forwards; | 82 | animation-fill-mode: forwards; |
77 | animation-delay: 1.2s; | 83 | animation-delay: 1.2s; |
78 | } | 84 | } |
79 | &.right { | 85 | &.right { |
80 | width: 62px; | 86 | width: 62px; |
81 | top: 100px; | 87 | top: 100px; |
82 | left: 500px; | 88 | left: 500px; |
83 | opacity: 0; | 89 | opacity: 0; |
84 | animation-name: cloudRight; | 90 | animation-name: cloudRight; |
85 | animation-duration: 2s; | 91 | animation-duration: 2s; |
86 | animation-timing-function: linear; | 92 | animation-timing-function: linear; |
87 | animation-fill-mode: forwards; | 93 | animation-fill-mode: forwards; |
88 | animation-delay: 1s; | 94 | animation-delay: 1s; |
89 | } | 95 | } |
90 | @keyframes cloudLeft { | 96 | @keyframes cloudLeft { |
91 | 0% { | 97 | 0% { |
92 | top: 17px; | 98 | top: 17px; |
93 | left: 220px; | 99 | left: 220px; |
94 | opacity: 0; | 100 | opacity: 0; |
95 | } | 101 | } |
96 | 20% { | 102 | 20% { |
97 | top: 33px; | 103 | top: 33px; |
98 | left: 188px; | 104 | left: 188px; |
99 | opacity: 1; | 105 | opacity: 1; |
100 | } | 106 | } |
101 | 80% { | 107 | 80% { |
102 | top: 81px; | 108 | top: 81px; |
103 | left: 92px; | 109 | left: 92px; |
104 | opacity: 1; | 110 | opacity: 1; |
105 | } | 111 | } |
106 | 100% { | 112 | 100% { |
107 | top: 97px; | 113 | top: 97px; |
108 | left: 60px; | 114 | left: 60px; |
109 | opacity: 0; | 115 | opacity: 0; |
110 | } | 116 | } |
111 | } | 117 | } |
112 | @keyframes cloudMid { | 118 | @keyframes cloudMid { |
113 | 0% { | 119 | 0% { |
114 | top: 10px; | 120 | top: 10px; |
115 | left: 420px; | 121 | left: 420px; |
116 | opacity: 0; | 122 | opacity: 0; |
117 | } | 123 | } |
118 | 20% { | 124 | 20% { |
119 | top: 40px; | 125 | top: 40px; |
120 | left: 360px; | 126 | left: 360px; |
121 | opacity: 1; | 127 | opacity: 1; |
122 | } | 128 | } |
123 | 70% { | 129 | 70% { |
124 | top: 130px; | 130 | top: 130px; |
125 | left: 180px; | 131 | left: 180px; |
126 | opacity: 1; | 132 | opacity: 1; |
127 | } | 133 | } |
128 | 100% { | 134 | 100% { |
129 | top: 160px; | 135 | top: 160px; |
130 | left: 120px; | 136 | left: 120px; |
131 | opacity: 0; | 137 | opacity: 0; |
132 | } | 138 | } |
133 | } | 139 | } |
134 | @keyframes cloudRight { | 140 | @keyframes cloudRight { |
135 | 0% { | 141 | 0% { |
136 | top: 100px; | 142 | top: 100px; |
137 | left: 500px; | 143 | left: 500px; |
138 | opacity: 0; | 144 | opacity: 0; |
139 | } | 145 | } |
140 | 20% { | 146 | 20% { |
141 | top: 120px; | 147 | top: 120px; |
142 | left: 460px; | 148 | left: 460px; |
143 | opacity: 1; | 149 | opacity: 1; |
144 | } | 150 | } |
145 | 80% { | 151 | 80% { |
146 | top: 180px; | 152 | top: 180px; |
147 | left: 340px; | 153 | left: 340px; |
148 | opacity: 1; | 154 | opacity: 1; |
149 | } | 155 | } |
150 | 100% { | 156 | 100% { |
151 | top: 200px; | 157 | top: 200px; |
152 | left: 300px; | 158 | left: 300px; |
153 | opacity: 0; | 159 | opacity: 0; |
154 | } | 160 | } |
155 | } | 161 | } |
156 | } | 162 | } |
157 | } | 163 | } |
158 | .bullshit { | 164 | .bullshit { |
159 | position: relative; | 165 | position: relative; |
160 | float: left; | 166 | float: left; |
161 | width: 300px; | 167 | width: 300px; |
162 | padding: 30px 0; | 168 | padding: 30px 0; |
163 | overflow: hidden; | 169 | overflow: hidden; |
164 | &__oops { | 170 | &__oops { |
165 | font-size: 32px; | 171 | font-size: 32px; |
166 | font-weight: bold; | 172 | font-weight: bold; |
167 | line-height: 40px; | 173 | line-height: 40px; |
168 | color: #1482f0; | 174 | color: #1482f0; |
169 | opacity: 0; | 175 | opacity: 0; |
170 | margin-bottom: 20px; | 176 | margin-bottom: 20px; |
171 | animation-name: slideUp; | 177 | animation-name: slideUp; |
172 | animation-duration: 0.5s; | 178 | animation-duration: 0.5s; |
173 | animation-fill-mode: forwards; | 179 | animation-fill-mode: forwards; |
174 | } | 180 | } |
175 | &__headline { | 181 | &__headline { |
176 | font-size: 20px; | 182 | font-size: 20px; |
177 | line-height: 24px; | 183 | line-height: 24px; |
178 | color: #222; | 184 | color: #222; |
179 | font-weight: bold; | 185 | font-weight: bold; |
180 | opacity: 0; | 186 | opacity: 0; |
181 | margin-bottom: 10px; | 187 | margin-bottom: 10px; |
182 | animation-name: slideUp; | 188 | animation-name: slideUp; |
183 | animation-duration: 0.5s; | 189 | animation-duration: 0.5s; |
184 | animation-delay: 0.1s; | 190 | animation-delay: 0.1s; |
185 | animation-fill-mode: forwards; | 191 | animation-fill-mode: forwards; |
186 | } | 192 | } |
187 | &__info { | 193 | &__info { |
188 | font-size: 13px; | 194 | font-size: 13px; |
189 | line-height: 21px; | 195 | line-height: 21px; |
190 | color: grey; | 196 | color: grey; |
191 | opacity: 0; | 197 | opacity: 0; |
192 | margin-bottom: 30px; | 198 | margin-bottom: 30px; |
193 | animation-name: slideUp; | 199 | animation-name: slideUp; |
194 | animation-duration: 0.5s; | 200 | animation-duration: 0.5s; |
195 | animation-delay: 0.2s; | 201 | animation-delay: 0.2s; |
196 | animation-fill-mode: forwards; | 202 | animation-fill-mode: forwards; |
197 | } | 203 | } |
198 | &__return-home { | 204 | &__return-home { |
199 | display: block; | 205 | display: block; |
200 | float: left; | 206 | float: left; |
201 | width: 110px; | 207 | width: 110px; |
202 | height: 36px; | 208 | height: 36px; |
203 | background: #1482f0; | 209 | background: #1482f0; |
204 | border-radius: 100px; | 210 | border-radius: 100px; |
205 | text-align: center; | 211 | text-align: center; |
206 | color: #ffffff; | 212 | color: #ffffff; |
207 | opacity: 0; | 213 | opacity: 0; |
208 | font-size: 14px; | 214 | font-size: 14px; |
209 | line-height: 36px; | 215 | line-height: 36px; |
210 | cursor: pointer; | 216 | cursor: pointer; |
211 | animation-name: slideUp; | 217 | animation-name: slideUp; |
212 | animation-duration: 0.5s; | 218 | animation-duration: 0.5s; |
213 | animation-delay: 0.3s; | 219 | animation-delay: 0.3s; |
214 | animation-fill-mode: forwards; | 220 | animation-fill-mode: forwards; |
215 | } | 221 | } |
216 | @keyframes slideUp { | 222 | @keyframes slideUp { |
217 | 0% { | 223 | 0% { |
218 | transform: translateY(60px); | 224 | transform: translateY(60px); |
219 | opacity: 0; | 225 | opacity: 0; |
220 | } | 226 | } |
221 | 100% { | 227 | 100% { |
222 | transform: translateY(0); | 228 | transform: translateY(0); |
223 | opacity: 1; | 229 | opacity: 1; |
224 | } | 230 | } |
225 | } | 231 | } |
226 | } | 232 | } |
227 | } | 233 | } |
228 | </style> | 234 | </style> |
src/views/502.vue
File was created | 1 | <template> | |
2 | <div class="error-page"> | ||
3 | <div class="error-code"> | ||
4 | 5 | ||
5 | <span>0</span>2 | ||
6 | </div> | ||
7 | <div class="error-desc">啊哦~ 系统出了故障!</div> | ||
8 | <div class="error-handle"> | ||
9 | <router-link to="/"> | ||
10 | <el-button type="primary" size="large">返回首页</el-button> | ||
11 | </router-link> | ||
12 | <el-button class="error-btn" type="primary" size="large" @click="goBack">返回上一页</el-button> | ||
13 | </div> | ||
14 | </div> | ||
15 | </template> | ||
16 | |||
17 | <script> | ||
18 | export default { | ||
19 | methods: { | ||
20 | goBack() { | ||
21 | this.$router.go(-1); | ||
22 | } | ||
23 | } | ||
24 | }; | ||
25 | </script> | ||
26 | <style scoped> | ||
27 | .error-page { | ||
28 | display: flex; | ||
29 | justify-content: center; | ||
30 | align-items: center; | ||
31 | flex-direction: column; | ||
32 | width: 100%; | ||
33 | height: 100%; | ||
34 | background: #f3f3f3; | ||
35 | box-sizing: border-box; | ||
36 | } | ||
37 | .error-code { | ||
38 | line-height: 1; | ||
39 | font-size: 250px; | ||
40 | font-weight: bolder; | ||
41 | color: #f02d2d; | ||
42 | } | ||
43 | .error-code span { | ||
44 | color: #00a854; | ||
45 | } | ||
46 | .error-desc { | ||
47 | font-size: 30px; | ||
48 | color: #777; | ||
49 | } | ||
50 | .error-handle { | ||
51 | margin-top: 30px; | ||
52 | padding-bottom: 200px; | ||
53 | } | ||
54 | .error-btn { | ||
55 | margin-left: 100px; | ||
56 | } | ||
57 | </style> |
src/views/dashboard/index.vue
1 | <template> | 1 | <template> |
2 | <div class="dashboard-container"> | 2 | <div> |
3 | <div class="dashboard-text">用户名: {{ name }}</div> | 3 | <el-row :gutter="20"> |
4 | <div class="dashboard-text">角色: <span v-for="role in roles" :key="role">{{ role }}</span></div> | 4 | <el-col :span="8"> |
5 | <el-card shadow="hover" class="mgb20" style="height:252px;"> | ||
6 | <div class="user-info"> | ||
7 | <img src="../../assets/img/img.jpg" class="user-avator" alt /> | ||
8 | <div class="user-info-cont"> | ||
9 | <div class="user-info-name">{{name}}</div> | ||
10 | <div>{{role}}</div> | ||
11 | </div> | ||
12 | </div> | ||
13 | <div class="user-info-list"> | ||
14 | 上次登录时间: | ||
15 | <span>2019-11-01</span> | ||
16 | </div> | ||
17 | <div class="user-info-list"> | ||
18 | 上次登录地点: | ||
19 | <span>东莞</span> | ||
20 | </div> | ||
21 | </el-card> | ||
22 | <el-card shadow="hover" style="height:252px;"> | ||
23 | <div slot="header" class="clearfix"> | ||
24 | <span>语言详情</span> | ||
25 | </div>Vue | ||
26 | <el-progress :percentage="71.3" color="#42b983"></el-progress>JavaScript | ||
27 | <el-progress :percentage="24.1" color="#f1e05a"></el-progress>CSS | ||
28 | <el-progress :percentage="13.7"></el-progress>HTML | ||
29 | <el-progress :percentage="5.9" color="#f56c6c"></el-progress> | ||
30 | </el-card> | ||
31 | </el-col> | ||
32 | <el-col :span="16"> | ||
33 | <el-row :gutter="20" class="mgb20"> | ||
34 | <el-col :span="8"> | ||
35 | <el-card shadow="hover" :body-style="{padding: '0px'}"> | ||
36 | <div class="grid-content grid-con-1"> | ||
37 | <i class="el-icon-lx-people grid-con-icon"></i> | ||
38 | <div class="grid-cont-right"> | ||
39 | <div class="grid-num">1234</div> | ||
40 | <div>用户访问量</div> | ||
41 | </div> | ||
42 | </div> | ||
43 | </el-card> | ||
44 | </el-col> | ||
45 | <el-col :span="8"> | ||
46 | <el-card shadow="hover" :body-style="{padding: '0px'}"> | ||
47 | <div class="grid-content grid-con-2"> | ||
48 | <i class="el-icon-lx-notice grid-con-icon"></i> | ||
49 | <div class="grid-cont-right"> | ||
50 | <div class="grid-num">321</div> | ||
51 | <div>系统消息</div> | ||
52 | </div> | ||
53 | </div> | ||
54 | </el-card> | ||
55 | </el-col> | ||
56 | <el-col :span="8"> | ||
57 | <el-card shadow="hover" :body-style="{padding: '0px'}"> | ||
58 | <div class="grid-content grid-con-3"> | ||
59 | <i class="el-icon-lx-goods grid-con-icon"></i> | ||
60 | <div class="grid-cont-right"> | ||
61 | <div class="grid-num">5000</div> | ||
62 | <div>数量</div> | ||
63 | </div> | ||
64 | </div> | ||
65 | </el-card> | ||
66 | </el-col> | ||
67 | </el-row> | ||
68 | <el-card shadow="hover" style="height:403px;"> | ||
69 | <div slot="header" class="clearfix"> | ||
70 | <span>待办事项</span> | ||
71 | <el-button style="float: right; padding: 3px 0" type="text" @click="addAction">添加</el-button> | ||
72 | </div> | ||
73 | <el-table :show-header="false" :data="todoList" style="width:100%;"> | ||
74 | <el-table-column width="40"> | ||
75 | <template slot-scope="scope"> | ||
76 | <el-checkbox v-model="scope.row.status"></el-checkbox> | ||
77 | </template> | ||
78 | </el-table-column> | ||
79 | <el-table-column> | ||
80 | <template slot-scope="scope"> | ||
81 | <div | ||
82 | class="todo-item" | ||
83 | :class="{'todo-item-del': scope.row.status}" | ||
84 | >{{scope.row.title}}</div> | ||
85 | </template> | ||
86 | </el-table-column> | ||
87 | <el-table-column width="60"> | ||
88 | <template> | ||
89 | <i class="el-icon-edit" @click="modiAction"></i> | ||
90 | <i class="el-icon-delete" @click="delAction"></i> | ||
91 | </template> | ||
92 | </el-table-column> | ||
93 | </el-table> | ||
94 | </el-card> | ||
95 | </el-col> | ||
96 | </el-row> | ||
97 | <el-row :gutter="20"> | ||
98 | <el-col :span="12"> | ||
99 | <el-card shadow="hover"> | ||
100 | <schart ref="bar" class="schart" canvasId="bar" :options="options"></schart> | ||
101 | </el-card> | ||
102 | </el-col> | ||
103 | <el-col :span="12"> | ||
104 | <el-card shadow="hover"> | ||
105 | <schart ref="line" class="schart" canvasId="line" :options="options2"></schart> | ||
106 | </el-card> | ||
107 | </el-col> | ||
108 | </el-row> | ||
5 | </div> | 109 | </div> |
6 | </template> | 110 | </template> |
7 | 111 | ||
8 | <script> | 112 | <script> |
9 | import { mapGetters } from 'vuex' | 113 | import { mapGetters } from "vuex"; |
114 | import Vue from "vue"; | ||
115 | import { | ||
116 | Pagination, | ||
117 | Dialog, | ||
118 | Autocomplete, | ||
119 | Dropdown, | ||
120 | DropdownMenu, | ||
121 | DropdownItem, | ||
122 | Menu, | ||
123 | Submenu, | ||
124 | MenuItem, | ||
125 | MenuItemGroup, | ||
126 | Input, | ||
127 | InputNumber, | ||
128 | Radio, | ||
129 | RadioGroup, | ||
130 | RadioButton, | ||
131 | Checkbox, | ||
132 | CheckboxButton, | ||
133 | CheckboxGroup, | ||
134 | Switch, | ||
135 | Select, | ||
136 | Option, | ||
137 | OptionGroup, | ||
138 | Button, | ||
139 | ButtonGroup, | ||
140 | Table, | ||
141 | TableColumn, | ||
142 | DatePicker, | ||
143 | TimeSelect, | ||
144 | TimePicker, | ||
145 | Popover, | ||
146 | Tooltip, | ||
147 | Breadcrumb, | ||
148 | BreadcrumbItem, | ||
149 | Form, | ||
150 | FormItem, | ||
151 | Tabs, | ||
152 | TabPane, | ||
153 | Tag, | ||
154 | Tree, | ||
155 | Alert, | ||
156 | Slider, | ||
157 | Icon, | ||
158 | Row, | ||
159 | Col, | ||
160 | Upload, | ||
161 | Progress, | ||
162 | Spinner, | ||
163 | Badge, | ||
164 | Card, | ||
165 | Rate, | ||
166 | Steps, | ||
167 | Step, | ||
168 | Carousel, | ||
169 | CarouselItem, | ||
170 | Collapse, | ||
171 | CollapseItem, | ||
172 | Cascader, | ||
173 | ColorPicker, | ||
174 | Transfer, | ||
175 | Container, | ||
176 | Header, | ||
177 | Aside, | ||
178 | Main, | ||
179 | Footer, | ||
180 | Timeline, | ||
181 | TimelineItem, | ||
182 | Link, | ||
183 | Divider, | ||
184 | Image, | ||
185 | Calendar, | ||
186 | Backtop, | ||
187 | PageHeader, | ||
188 | CascaderPanel, | ||
189 | Loading, | ||
190 | MessageBox, | ||
191 | Message, | ||
192 | Notification | ||
193 | } from "element-ui"; | ||
10 | // import ElementUI from 'element-ui' | 194 | // import ElementUI from 'element-ui' |
195 | Vue.prototype.$ELEMENT = { size: "small", zIndex: 3000 }; | ||
196 | Vue.use(Pagination); | ||
197 | Vue.use(Dialog); | ||
198 | Vue.use(Autocomplete); | ||
199 | Vue.use(Dropdown); | ||
200 | Vue.use(DropdownMenu); | ||
201 | Vue.use(DropdownItem); | ||
202 | Vue.use(Menu); | ||
203 | Vue.use(Submenu); | ||
204 | Vue.use(MenuItem); | ||
205 | Vue.use(MenuItemGroup); | ||
206 | Vue.use(Input); | ||
207 | Vue.use(InputNumber); | ||
208 | Vue.use(Radio); | ||
209 | Vue.use(RadioGroup); | ||
210 | Vue.use(RadioButton); | ||
211 | Vue.use(Checkbox); | ||
212 | Vue.use(CheckboxButton); | ||
213 | Vue.use(CheckboxGroup); | ||
214 | Vue.use(Switch); | ||
215 | Vue.use(Select); | ||
216 | Vue.use(Option); | ||
217 | Vue.use(OptionGroup); | ||
218 | Vue.use(Button); | ||
219 | Vue.use(ButtonGroup); | ||
220 | Vue.use(Table); | ||
221 | Vue.use(TableColumn); | ||
222 | Vue.use(DatePicker); | ||
223 | Vue.use(TimeSelect); | ||
224 | Vue.use(TimePicker); | ||
225 | Vue.use(Popover); | ||
226 | Vue.use(Tooltip); | ||
227 | Vue.use(Breadcrumb); | ||
228 | Vue.use(BreadcrumbItem); | ||
229 | Vue.use(Form); | ||
230 | Vue.use(FormItem); | ||
231 | Vue.use(Tabs); | ||
232 | Vue.use(TabPane); | ||
233 | Vue.use(Tag); | ||
234 | Vue.use(Tree); | ||
235 | Vue.use(Alert); | ||
236 | Vue.use(Slider); | ||
237 | Vue.use(Icon); | ||
238 | Vue.use(Row); | ||
239 | Vue.use(Col); | ||
240 | Vue.use(Upload); | ||
241 | Vue.use(Progress); | ||
242 | Vue.use(Spinner); | ||
243 | Vue.use(Badge); | ||
244 | Vue.use(Card); | ||
245 | Vue.use(Rate); | ||
246 | Vue.use(Steps); | ||
247 | Vue.use(Step); | ||
248 | Vue.use(Carousel); | ||
249 | Vue.use(CarouselItem); | ||
250 | Vue.use(Collapse); | ||
251 | Vue.use(CollapseItem); | ||
252 | Vue.use(Cascader); | ||
253 | Vue.use(ColorPicker); | ||
254 | Vue.use(Transfer); | ||
255 | Vue.use(Container); | ||
256 | Vue.use(Header); | ||
257 | Vue.use(Aside); | ||
258 | Vue.use(Main); | ||
259 | Vue.use(Footer); | ||
260 | Vue.use(Timeline); | ||
261 | Vue.use(TimelineItem); | ||
262 | Vue.use(Link); | ||
263 | Vue.use(Divider); | ||
264 | Vue.use(Image); | ||
265 | Vue.use(Calendar); | ||
266 | Vue.use(Backtop); | ||
267 | Vue.use(PageHeader); | ||
268 | Vue.use(CascaderPanel); | ||
269 | Vue.use(Loading.directive); | ||
270 | |||
271 | import Schart from "vue-schart"; | ||
272 | import bus from "../../common/bus"; | ||
273 | |||
11 | // 按需引入 引入 ECharts 主模块 | 274 | // 按需引入 引入 ECharts 主模块 |
12 | // var echarts = require('echarts/lib/echarts') | 275 | // var echarts = require('echarts/lib/echarts') |
13 | // 引入柱状图 | 276 | // 引入柱状图 |
14 | // require('echarts/lib/chart/bar') | 277 | // require('echarts/lib/chart/bar') |
15 | // 引入提示框和标题组件 | 278 | // 引入提示框和标题组件 |
16 | // require('echarts/lib/component/tooltip') | 279 | // require('echarts/lib/component/tooltip') |
17 | // require('echarts/lib/component/title') | 280 | // require('echarts/lib/component/title') |
18 | // 全部引入 | 281 | // 全部引入 |
19 | // var echarts = require('echarts') | 282 | // var echarts = require('echarts') |
20 | 283 | ||
21 | export default { | 284 | export default { |
22 | name: 'Dashboard', | 285 | name: "Dashboard", |
286 | data() { | ||
287 | return { | ||
288 | name: localStorage.getItem("ms_username"), | ||
289 | todoList: [ | ||
290 | { | ||
291 | title: "今天要修复100个bug", | ||
292 | status: true | ||
293 | }, | ||
294 | { | ||
295 | title: "今天要写100行代码加几个bug吧", | ||
296 | status: true | ||
297 | } | ||
298 | ], | ||
299 | data: [ | ||
300 | { | ||
301 | name: "2018/09/04", | ||
302 | value: 1083 | ||
303 | }, | ||
304 | { | ||
305 | name: "2018/09/10", | ||
306 | value: 1065 | ||
307 | } | ||
308 | ], | ||
309 | options: { | ||
310 | type: "bar", | ||
311 | title: { | ||
312 | text: "最近一周各品类销售图" | ||
313 | }, | ||
314 | xRorate: 25, | ||
315 | labels: ["周一", "周二", "周三", "周四", "周五"], | ||
316 | datasets: [ | ||
317 | { | ||
318 | label: "百货", | ||
319 | data: [164, 178, 190, 135, 160] | ||
320 | }, | ||
321 | { | ||
322 | label: "食品", | ||
323 | data: [144, 198, 150, 235, 120] | ||
324 | } | ||
325 | ] | ||
326 | }, | ||
327 | options2: { | ||
328 | type: "line", | ||
329 | title: { | ||
330 | text: "最近几个月各品类销售趋势图" | ||
331 | }, | ||
332 | labels: ["6月", "7月", "8月", "9月", "10月"], | ||
333 | datasets: [ | ||
334 | { | ||
335 | label: "百货", | ||
336 | data: [164, 178, 150, 135, 160] | ||
337 | }, | ||
338 | { | ||
339 | label: "食品", | ||
340 | data: [74, 118, 200, 235, 90] | ||
341 | } | ||
342 | ] | ||
343 | } | ||
344 | }; | ||
345 | }, | ||
346 | components: { | ||
347 | Schart | ||
348 | }, | ||
23 | computed: { | 349 | computed: { |
24 | ...mapGetters([ | 350 | // ...mapGetters(["name", "roles"]) |
25 | 'name', | 351 | role() { |
26 | 'roles' | 352 | return this.name === "admin" ? "超级管理员" : "普通用户"; |
27 | ]) | 353 | } |
354 | }, | ||
355 | methods: { | ||
356 | addAction(){ | ||
357 | this.$prompt("请输入内容", "提示", { | ||
358 | confirmButtonText: "确定", | ||
359 | cancelButtonText: "取消", | ||
360 | inputErrorMessage: "内容不能为空" | ||
361 | }) | ||
362 | .then(({ value }) => { | ||
363 | this.$message({ | ||
364 | type: "success", | ||
365 | message: "你的邮箱是: " + value | ||
366 | }); | ||
367 | }) | ||
368 | .catch(() => { | ||
369 | this.$message({ | ||
370 | type: "info", | ||
371 | message: "取消输入" | ||
372 | }); | ||
373 | }); | ||
374 | }, | ||
375 | modiAction() { | ||
376 | // this.$prompt("请输入邮箱", "提示", { | ||
377 | // confirmButtonText: "确定", | ||
378 | // cancelButtonText: "取消", | ||
379 | // inputPattern: /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/, | ||
380 | // inputErrorMessage: "邮箱格式不正确" | ||
381 | // }) | ||
382 | this.$prompt("请输入内容", "提示", { | ||
383 | confirmButtonText: "确定", | ||
384 | cancelButtonText: "取消", | ||
385 | inputErrorMessage: "内容不能为空" | ||
386 | }) | ||
387 | .then(({ value }) => { | ||
388 | this.$message({ | ||
389 | type: "success", | ||
390 | message: "你的邮箱是: " + value | ||
391 | }); | ||
392 | }) | ||
393 | .catch(() => { | ||
394 | this.$message({ | ||
395 | type: "info", | ||
396 | message: "取消输入" | ||
397 | }); | ||
398 | }); | ||
399 | }, | ||
400 | delAction() { | ||
401 | this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", { | ||
402 | confirmButtonText: "确定", | ||
403 | cancelButtonText: "取消", | ||
404 | type: "warning" | ||
405 | }) | ||
406 | .then(() => { | ||
407 | this.$message({ | ||
408 | type: "success", | ||
409 | message: "删除成功!" | ||
410 | }); | ||
411 | }) | ||
412 | .catch(() => { | ||
413 | this.$message({ | ||
414 | type: "info", | ||
415 | message: "已取消删除" | ||
416 | }); | ||
417 | }); | ||
418 | }, | ||
419 | changeDate() { | ||
420 | const now = new Date().getTime(); | ||
421 | this.data.forEach((item, index) => { | ||
422 | const date = new Date(now - (6 - index) * 86400000); | ||
423 | item.name = `${date.getFullYear()}/${date.getMonth() + | ||
424 | 1}/${date.getDate()}`; | ||
425 | }); | ||
426 | } | ||
28 | } | 427 | } |
29 | } | 428 | }; |
30 | </script> | 429 | </script> |
31 | 430 | ||
32 | <style lang="scss" scoped> | 431 | <style scoped> |
33 | .dashboard { | 432 | .el-row { |
34 | &-container { | 433 | margin-bottom: 20px; |
35 | margin: 30px; | 434 | } |
36 | } | 435 | .grid-content { |
37 | &-text { | 436 | display: flex; |
38 | font-size: 30px; | 437 | align-items: center; |
39 | line-height: 46px; | 438 | height: 100px; |
40 | } | 439 | } |
440 | .grid-cont-right { | ||
441 | flex: 1; | ||
442 | text-align: center; | ||
443 | font-size: 14px; | ||
444 | color: #999; | ||
445 | } | ||
446 | .grid-num { | ||
447 | font-size: 30px; | ||
448 | font-weight: bold; | ||
449 | } | ||
450 | .grid-con-icon { | ||
451 | font-size: 50px; | ||
452 | width: 100px; | ||
453 | height: 100px; | ||
454 | text-align: center; | ||
455 | line-height: 100px; | ||
456 | color: #fff; | ||
457 | } | ||
458 | .grid-con-1 .grid-con-icon { | ||
459 | background: rgb(45, 140, 240); | ||
460 | } | ||
461 | .grid-con-1 .grid-num { | ||
462 | color: rgb(45, 140, 240); | ||
463 | } | ||
464 | .grid-con-2 .grid-con-icon { | ||
465 | background: rgb(100, 213, 114); | ||
466 | } | ||
467 | .grid-con-2 .grid-num { | ||
468 | color: rgb(45, 140, 240); | ||
469 | } | ||
470 | .grid-con-3 .grid-con-icon { | ||
471 | background: rgb(242, 94, 67); | ||
472 | } | ||
473 | .grid-con-3 .grid-num { | ||
474 | color: rgb(242, 94, 67); | ||
475 | } | ||
476 | .user-info { | ||
477 | display: flex; | ||
478 | align-items: center; | ||
479 | padding-bottom: 20px; | ||
480 | border-bottom: 2px solid #ccc; | ||
481 | margin-bottom: 20px; | ||
482 | } | ||
483 | .user-avator { | ||
484 | width: 120px; | ||
485 | height: 120px; | ||
486 | border-radius: 50%; | ||
487 | } | ||
488 | .user-info-cont { | ||
489 | padding-left: 50px; | ||
490 | flex: 1; | ||
491 | font-size: 14px; | ||
492 | color: #999; | ||
493 | } | ||
494 | .user-info-cont div:first-child { | ||
495 | font-size: 30px; | ||
496 | color: #222; | ||
497 | } | ||
498 | .user-info-list { | ||
499 | font-size: 14px; | ||
500 | color: #999; | ||
501 | line-height: 25px; | ||
502 | } | ||
503 | .user-info-list span { | ||
504 | margin-left: 70px; | ||
505 | } | ||
506 | .mgb20 { | ||
507 | margin-bottom: 20px; | ||
508 | } | ||
509 | .todo-item { | ||
510 | font-size: 14px; | ||
511 | } | ||
512 | .todo-item-del { | ||
513 | text-decoration: line-through; | ||
514 | color: #999; | ||
515 | } | ||
516 | .schart { | ||
517 | width: 100%; | ||
518 | height: 300px; | ||
41 | } | 519 | } |
42 | </style> | 520 | </style> |
43 | 521 |
src/views/form/index.vue
1 | <template> | 1 | <template> |
2 | <div class="app-container"> | 2 | <div class="app-container"> |
3 | <el-form ref="form" :model="form" label-width="120px"> | 3 | <el-form ref="form" :model="form" label-width="120px"> |
4 | <el-form-item label="Activity name"> | 4 | <el-form-item label="Activity name"> |
5 | <el-input v-model="form.name" /> | 5 | <el-input v-model="form.name" /> |
6 | </el-form-item> | 6 | </el-form-item> |
7 | <el-form-item label="Activity zone"> | 7 | <el-form-item label="Activity zone"> |
8 | <el-select v-model="form.region" placeholder="please select your zone"> | 8 | <el-select v-model="form.region" placeholder="please select your zone"> |
9 | <el-option label="Zone one" value="shanghai" /> | 9 | <el-option label="Zone one" value="shanghai" /> |
10 | <el-option label="Zone two" value="beijing" /> | 10 | <el-option label="Zone two" value="beijing" /> |
11 | </el-select> | 11 | </el-select> |
12 | </el-form-item> | 12 | </el-form-item> |
13 | <el-form-item label="Activity time"> | 13 | <el-form-item label="Activity time"> |
14 | <el-col :span="11"> | 14 | <el-col :span="11"> |
15 | <el-date-picker v-model="form.date1" type="date" placeholder="Pick a date" style="width: 100%;" /> | 15 | <el-date-picker |
16 | v-model="form.date1" | ||
17 | type="date" | ||
18 | placeholder="Pick a date" | ||
19 | style="width: 100%;" | ||
20 | /> | ||
16 | </el-col> | 21 | </el-col> |
17 | <el-col :span="2" class="line">-</el-col> | 22 | <el-col :span="2" class="line">-</el-col> |
18 | <el-col :span="11"> | 23 | <el-col :span="11"> |
19 | <el-time-picker v-model="form.date2" type="fixed-time" placeholder="Pick a time" style="width: 100%;" /> | 24 | <el-time-picker |
25 | v-model="form.date2" | ||
26 | type="fixed-time" | ||
27 | placeholder="Pick a time" | ||
28 | style="width: 100%;" | ||
29 | /> | ||
20 | </el-col> | 30 | </el-col> |
21 | </el-form-item> | 31 | </el-form-item> |
22 | <el-form-item label="Instant delivery"> | 32 | <el-form-item label="Instant delivery"> |
23 | <el-switch v-model="form.delivery" /> | 33 | <el-switch v-model="form.delivery" /> |
24 | </el-form-item> | 34 | </el-form-item> |
25 | <el-form-item label="Activity type"> | 35 | <el-form-item label="Activity type"> |
26 | <el-checkbox-group v-model="form.type"> | 36 | <el-checkbox-group v-model="form.type"> |
27 | <el-checkbox label="Online activities" name="type" /> | 37 | <el-checkbox label="Online activities" name="type" /> |
28 | <el-checkbox label="Promotion activities" name="type" /> | 38 | <el-checkbox label="Promotion activities" name="type" /> |
29 | <el-checkbox label="Offline activities" name="type" /> | 39 | <el-checkbox label="Offline activities" name="type" /> |
30 | <el-checkbox label="Simple brand exposure" name="type" /> | 40 | <el-checkbox label="Simple brand exposure" name="type" /> |
31 | </el-checkbox-group> | 41 | </el-checkbox-group> |
32 | </el-form-item> | 42 | </el-form-item> |
33 | <el-form-item label="Resources"> | 43 | <el-form-item label="Resources"> |
34 | <el-radio-group v-model="form.resource"> | 44 | <el-radio-group v-model="form.resource"> |
35 | <el-radio label="Sponsor" /> | 45 | <el-radio label="Sponsor" /> |
36 | <el-radio label="Venue" /> | 46 | <el-radio label="Venue" /> |
37 | </el-radio-group> | 47 | </el-radio-group> |
38 | </el-form-item> | 48 | </el-form-item> |
39 | <el-form-item label="Activity form"> | 49 | <el-form-item label="Activity form"> |
40 | <el-input v-model="form.desc" type="textarea" /> | 50 | <el-input v-model="form.desc" type="textarea" /> |
41 | </el-form-item> | 51 | </el-form-item> |
42 | <el-form-item> | 52 | <el-form-item> |
43 | <el-button type="primary" @click="onSubmit">Create</el-button> | 53 | <el-button type="primary" @click="onSubmit">Create</el-button> |
44 | <el-button @click="onCancel">Cancel</el-button> | 54 | <el-button @click="onCancel">Cancel</el-button> |
45 | </el-form-item> | 55 | </el-form-item> |
46 | </el-form> | 56 | </el-form> |
47 | </div> | 57 | </div> |
48 | </template> | 58 | </template> |
49 | 59 | ||
50 | <script> | 60 | <script> |
51 | export default { | 61 | export default { |
52 | data() { | 62 | data() { |
53 | return { | 63 | return { |
54 | form: { | 64 | form: { |
55 | name: '', | 65 | name: "", |
56 | region: '', | 66 | region: "", |
57 | date1: '', | 67 | date1: "", |
58 | date2: '', | 68 | date2: "", |
59 | delivery: false, | 69 | delivery: false, |
60 | type: [], | 70 | type: [], |
61 | resource: '', | 71 | resource: "", |
62 | desc: '' | 72 | desc: "" |
63 | } | 73 | } |
64 | } | 74 | }; |
65 | }, | 75 | }, |
66 | methods: { | 76 | methods: { |
67 | onSubmit() { | 77 | onSubmit() { |
68 | this.$message('submit!') | 78 | this.$message("submit!"); |
69 | }, | 79 | }, |
70 | onCancel() { | 80 | onCancel() { |
71 | this.$message({ | 81 | this.$message({ |
72 | message: 'cancel!', | 82 | message: "cancel!", |
73 | type: 'warning' | 83 | type: "warning" |
74 | }) | 84 | }); |
75 | } | 85 | } |
76 | } | 86 | } |
77 | } | 87 | }; |
78 | </script> | 88 | </script> |
79 | 89 | ||
80 | <style scoped> | 90 | <style scoped> |
81 | .line{ | 91 | .line { |
82 | text-align: center; | 92 | text-align: center; |
83 | } | 93 | } |
84 | </style> | 94 | </style> |
85 | 95 | ||
86 | 96 |
src/views/nested/menu1/menu1-1/index.vue
1 | <template> | 1 | <template> |
2 | <div style="padding:30px;"> | 2 | <div style="padding:30px;"> |
3 | <el-alert :closable="false" title="menu 1-1" type="success"> | 3 | <el-alert :closable="false" title="menu 1-1" type="success"> |
4 | <router-view /> | 4 | <router-view /> |
5 | </el-alert> | 5 | </el-alert> |
6 | </div> | 6 | </div> |
7 | </template> | 7 | </template> |
8 | <template functional> | ||
9 | <div style="padding:30px;"> | ||
10 | <el-alert :closable="false" title="menu 1-2-1" type="warning" /> | ||
11 | </div> | ||
12 | </template> |
src/views/table/index.vue
1 | <template> | 1 | <template> |
2 | <div class="app-container"> | 2 | <div class="app-container"> |
3 | <el-table | 3 | <el-table |
4 | v-loading="listLoading" | 4 | v-loading="listLoading" |
5 | :data="list" | 5 | :data="list" |
6 | element-loading-text="Loading" | 6 | element-loading-text="Loading" |
7 | border | 7 | border |
8 | fit | 8 | fit |
9 | highlight-current-row | 9 | highlight-current-row |
10 | > | 10 | > |
11 | <el-table-column align="center" label="ID" width="95"> | 11 | <el-table-column align="center" label="用户id"> |
12 | <template slot-scope="scope"> | 12 | <template slot-scope="scope">{{ scope.$index }}</template> |
13 | {{ scope.$index }} | 13 | </el-table-column> |
14 | </template> | 14 | |
15 | <el-table-column label="openid"> | ||
16 | <template slot-scope="scope">{{ scope.row.openid }}</template> | ||
15 | </el-table-column> | 17 | </el-table-column> |
16 | <el-table-column label="Title"> | 18 | |
19 | <el-table-column label="昵称" width="110" align="center"> | ||
17 | <template slot-scope="scope"> | 20 | <template slot-scope="scope"> |
18 | {{ scope.row.title }} | 21 | <span>{{ scope.row.username }}</span> |
19 | </template> | 22 | </template> |
20 | </el-table-column> | 23 | </el-table-column> |
21 | <el-table-column label="Author" width="110" align="center"> | 24 | |
25 | <el-table-column label="头像" width="110" align="center"> | ||
26 | <template slot-scope="scope">{{ scope.row.avatar }}</template> | ||
27 | </el-table-column> | ||
28 | |||
29 | <el-table-column class-name="status-col" label="状态" align="center"> | ||
22 | <template slot-scope="scope"> | 30 | <template slot-scope="scope"> |
23 | <span>{{ scope.row.author }}</span> | 31 | <el-tag :type="scope.row.status | statusFilter">{{ scope.row.status }}</el-tag> |
24 | </template> | 32 | </template> |
25 | </el-table-column> | 33 | </el-table-column> |
26 | <el-table-column label="Pageviews" width="110" align="center"> | 34 | |
35 | <el-table-column align="center" prop="created_at" label="注册时间"> | ||
27 | <template slot-scope="scope"> | 36 | <template slot-scope="scope"> |
28 | {{ scope.row.pageviews }} | 37 | <i class="el-icon-time" /> |
38 | <span>{{ scope.row.create_at }}</span> | ||
29 | </template> | 39 | </template> |
30 | </el-table-column> | 40 | </el-table-column> |
31 | <el-table-column class-name="status-col" label="Status" width="110" align="center"> | 41 | <el-table-column align="center" prop="created_at" label="成交记录"> |
32 | <template slot-scope="scope"> | 42 | <template slot-scope="scope"> |
33 | <el-tag :type="scope.row.status | statusFilter">{{ scope.row.status }}</el-tag> | 43 | <i class="el-icon-time" /> |
44 | <span>{{ scope.row.pageviews }}</span> | ||
34 | </template> | 45 | </template> |
35 | </el-table-column> | 46 | </el-table-column> |
36 | <el-table-column align="center" prop="created_at" label="Display_time" width="200"> | 47 | <el-table-column align="center" prop="created_at" label="引流图"> |
37 | <template slot-scope="scope"> | 48 | <template slot-scope="scope"> |
38 | <i class="el-icon-time" /> | 49 | <span> |
39 | <span>{{ scope.row.display_time }}</span> | 50 | <el-button type="primary">子用户{{scope.row.pageviews}}</el-button> |
51 | </span> | ||
40 | </template> | 52 | </template> |
41 | </el-table-column> | 53 | </el-table-column> |
42 | </el-table> | 54 | </el-table> |
55 | <el-pagination background layout="prev, pager, next" :total="100"></el-pagination> | ||
43 | </div> | 56 | </div> |
44 | </template> | 57 | </template> |
45 | 58 | ||
46 | <script> | 59 | <script> |
47 | import { getList } from '@/api/table' | 60 | import { getList } from "@/api/table"; |
48 | 61 | ||
49 | export default { | 62 | export default { |
50 | filters: { | 63 | filters: { |
51 | statusFilter(status) { | 64 | statusFilter(status) { |
52 | const statusMap = { | 65 | const statusMap = { |
53 | published: 'success', | 66 | published: "success", |
54 | draft: 'gray', | 67 | draft: "gray", |
55 | deleted: 'danger' | 68 | deleted: "danger" |
56 | } | 69 | }; |
57 | return statusMap[status] | 70 | return statusMap[status]; |
58 | } | 71 | } |
59 | }, | 72 | }, |
60 | data() { | 73 | data() { |
61 | return { | 74 | return { |
62 | list: null, | 75 | list: null, |
63 | listLoading: true | 76 | listLoading: true |
64 | } | 77 | }; |
65 | }, | 78 | }, |
66 | created() { | 79 | created() { |
67 | this.fetchData() | 80 | this.fetchData(); |
68 | }, | 81 | }, |
69 | methods: { | 82 | methods: { |
70 | fetchData() { | 83 | fetchData() { |
71 | this.listLoading = true | 84 | this.listLoading = true; |
72 | getList().then(response => { | 85 | getList().then(response => { |
73 | console.log('----getList---', response) | 86 | console.log("----getList---", response); |
74 | this.list = response.data.items | 87 | this.list = response.data.items; |
75 | this.listLoading = false | 88 | this.listLoading = false; |
76 | }) | 89 | }); |
77 | } | 90 | } |
78 | } | 91 | } |
79 | } | 92 | }; |
80 | </script> | 93 | </script> |
81 | 94 |