Commit 4e2abd16b5fc3f48937e67ee3413c69767179f50

Authored by Adam
Exists in master

Merge branch 'master' into 'master'

Master

See merge request !8
1 import Mock from 'mockjs' 1 import Mock from 'mockjs'
2 2
3 const List = [] 3 const List = []
4 const count = 100 4 const count = 100
5 5
6 const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>' 6 const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
7 const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3' 7 const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3'
8 8
9 for (let i = 0; i < count; i++) { 9 for (let i = 0; i < count; i++) {
10 List.push(Mock.mock({ 10 List.push(Mock.mock({
11 id: '@increment', 11 id: '@increment',
12 timestamp: +Mock.Random.date('T'), 12 timestamp: +Mock.Random.date('T'),
13 author: '@first', 13 author: '@first',
14 reviewer: '@first', 14 reviewer: '@first',
15 title: '@title(5, 10)', 15 title: '@title(5, 10)',
16 content_short: 'mock data', 16 content_short: 'mock data',
17 content: baseContent, 17 content: baseContent,
18 forecast: '@float(0, 100, 2, 2)', 18 forecast: '@float(0, 100, 2, 2)',
19 importance: '@integer(1, 3)', 19 importance: '@integer(1, 3)',
20 'type|1': ['CN', 'US', 'JP', 'EU'], 20 'type|1': ['CN', 'US', 'JP', 'EU'],
21 'status|1': ['published', 'draft'], 21 'status|1': ['published', 'draft'],
22 display_time: '@datetime', 22 display_time: '@datetime',
23 comment_disabled: true, 23 comment_disabled: true,
24 pageviews: '@integer(300, 5000)', 24 pageviews: '@integer(300, 5000)',
25 image_uri, 25 image_uri,
26 platforms: ['a-platform'] 26 platforms: ['a-platform']
27 })) 27 }))
28 } 28 }
29 29
30 export default [ 30 export default [{
31 { 31 url: '/yp/article/list',
32 url: '/vue-element-admin/article/list',
33 type: 'get', 32 type: 'get',
34 response: config => { 33 response: config => {
35 const { importance, type, title, page = 1, limit = 20, sort } = config.query 34 const {
35 importance,
36 type,
37 title,
38 page = 1,
39 limit = 20,
40 sort
41 } = config.query
36 42
37 let mockList = List.filter(item => { 43 let mockList = List.filter(item => {
38 if (importance && item.importance !== +importance) return false 44 if (importance && item.importance !== +importance) return false
39 if (type && item.type !== type) return false 45 if (type && item.type !== type) return false
40 if (title && item.title.indexOf(title) < 0) return false 46 if (title && item.title.indexOf(title) < 0) return false
41 return true 47 return true
42 }) 48 })
43 49
44 if (sort === '-id') { 50 if (sort === '-id') {
45 mockList = mockList.reverse() 51 mockList = mockList.reverse()
46 } 52 }
47 53
48 const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) 54 const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
49 55
50 return { 56 return {
51 code: 20000, 57 code: 20000,
52 data: { 58 data: {
53 total: mockList.length, 59 total: mockList.length,
54 items: pageList 60 items: pageList
55 } 61 }
56 } 62 }
57 } 63 }
58 }, 64 },
59 65
60 { 66 {
61 url: '/vue-element-admin/article/detail', 67 url: '/yp/article/detail',
62 type: 'get', 68 type: 'get',
63 response: config => { 69 response: config => {
64 const { id } = config.query 70 const {
71 id
72 } = config.query
65 for (const article of List) { 73 for (const article of List) {
66 if (article.id === +id) { 74 if (article.id === +id) {
67 return { 75 return {
68 code: 20000, 76 code: 20000,
69 data: article 77 data: article
70 } 78 }
71 } 79 }
72 } 80 }
73 } 81 }
74 }, 82 },
75 83
76 { 84 {
77 url: '/vue-element-admin/article/pv', 85 url: '/yp/article/pv',
78 type: 'get', 86 type: 'get',
79 response: _ => { 87 response: _ => {
80 return { 88 return {
81 code: 20000, 89 code: 20000,
82 data: { 90 data: {
83 pvData: [ 91 pvData: [{
84 { key: 'PC', pv: 1024 }, 92 key: 'PC',
85 { key: 'mobile', pv: 1024 }, 93 pv: 1024
86 { key: 'ios', pv: 1024 }, 94 },
87 { key: 'android', pv: 1024 } 95 {
96 key: 'mobile',
97 pv: 1024
98 },
99 {
100 key: 'ios',
101 pv: 1024
102 },
103 {
104 key: 'android',
105 pv: 1024
106 }
88 ] 107 ]
89 } 108 }
90 } 109 }
91 } 110 }
92 }, 111 },
93 112
94 { 113 {
95 url: '/vue-element-admin/article/create', 114 url: '/yp/article/create',
96 type: 'post', 115 type: 'post',
97 response: _ => { 116 response: _ => {
98 return { 117 return {
99 code: 20000, 118 code: 20000,
100 data: 'success' 119 data: 'success'
101 } 120 }
102 } 121 }
103 }, 122 },
104 123
105 { 124 {
106 url: '/vue-element-admin/article/update', 125 url: '/yp/article/update',
107 type: 'post', 126 type: 'post',
108 response: _ => { 127 response: _ => {
109 return { 128 return {
110 code: 20000, 129 code: 20000,
111 data: 'success' 130 data: 'success'
112 } 131 }
113 } 132 }
114 } 133 }
115 ] 134 ]
mock/remote-search.js
1 import Mock from 'mockjs' 1 import Mock from 'mockjs'
2 2
3 const NameList = [] 3 const NameList = []
4 const count = 100 4 const count = 100
5 5
6 for (let i = 0; i < count; i++) { 6 for (let i = 0; i < count; i++) {
7 NameList.push(Mock.mock({ 7 NameList.push(Mock.mock({
8 name: '@first' 8 name: '@first'
9 })) 9 }))
10 } 10 }
11 NameList.push({ name: 'mock-Pan' }) 11 NameList.push({ name: 'mock-Pan' })
12 12
13 export default [ 13 export default [
14 // username search 14 // username search
15 { 15 {
16 url: '/vue-element-admin/search/user', 16 url: '/yp/search/user',
17 type: 'get', 17 type: 'get',
18 response: config => { 18 response: config => {
19 const { name } = config.query 19 const { name } = config.query
20 const mockNameList = NameList.filter(item => { 20 const mockNameList = NameList.filter(item => {
21 const lowerCaseName = item.name.toLowerCase() 21 const lowerCaseName = item.name.toLowerCase()
22 return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) 22 return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0)
23 }) 23 })
24 return { 24 return {
25 code: 20000, 25 code: 20000,
26 data: { items: mockNameList } 26 data: { items: mockNameList }
27 } 27 }
28 } 28 }
29 }, 29 },
30 30
31 // transaction list 31 // transaction list
32 { 32 {
33 url: '/vue-element-admin/transaction/list', 33 url: '/yp/transaction/list',
34 type: 'get', 34 type: 'get',
35 response: _ => { 35 response: _ => {
36 return { 36 return {
37 code: 20000, 37 code: 20000,
38 data: { 38 data: {
39 total: 20, 39 total: 20,
40 'items|20': [{ 40 'items|20': [{
41 order_no: '@guid()', 41 order_no: '@guid()',
42 timestamp: +Mock.Random.date('T'), 42 timestamp: +Mock.Random.date('T'),
43 username: '@name()', 43 username: '@name()',
44 price: '@float(1000, 15000, 0, 2)', 44 price: '@float(1000, 15000, 0, 2)',
45 'status|1': ['success', 'pending'] 45 'status|1': ['success', 'pending']
46 }] 46 }]
47 } 47 }
48 } 48 }
49 } 49 }
50 } 50 }
51 ] 51 ]
52 52
mock/role/index.js
1 import Mock from 'mockjs' 1 import Mock from 'mockjs'
2 import { deepClone } from '../../src/utils/index.js' 2 import { deepClone } from '../../src/utils/index.js'
3 import { asyncRoutes, constantRoutes } from './routes.js' 3 import { asyncRoutes, constantRoutes } from './routes.js'
4 4
5 const routes = deepClone([...constantRoutes, ...asyncRoutes]) 5 const routes = deepClone([...constantRoutes, ...asyncRoutes])
6 6
7 const roles = [ 7 const roles = [
8 { 8 {
9 key: 'admin', 9 key: 'admin',
10 name: 'admin', 10 name: 'admin',
11 description: 'Super Administrator. Have access to view all pages.', 11 description: 'Super Administrator. Have access to view all pages.',
12 routes: routes 12 routes: routes
13 }, 13 },
14 { 14 {
15 key: 'editor', 15 key: 'assistant',
16 name: 'editor', 16 name: 'assistant',
17 description: 'Normal Editor. Can see all pages except permission page', 17 description: 'assistant Administrator. Can see all pages except permission page',
18 routes: routes.filter(i => i.path !== '/permission')// just a mock 18 routes: routes.filter(i => i.path !== '/permission')// just a mock
19 }, 19 },
20 { 20 {
21 key: 'visitor', 21 key: 'runner',
22 name: 'visitor', 22 name: 'runner',
23 description: 'Just a visitor. Can only see the home page and the document page', 23 description: 'Normal runner. Can see runner pages except permission page',
24 routes: [{ 24 routes: routes.filter(i => i.path !== '/permission')// just a mock
25 path: '', 25 },
26 redirect: 'dashboard', 26 {
27 children: [ 27 key: 'shoper',
28 { 28 name: 'shoper',
29 path: 'dashboard', 29 description: 'Normal shoper. Can see shoper pages except permission page',
30 name: 'Dashboard', 30 routes: routes.filter(i => i.path !== '/permission')// just a mock
31 meta: { title: 'dashboard', icon: 'dashboard' } 31 },
32 } 32 // {
33 ] 33 // key: 'visitor',
34 }] 34 // name: 'visitor',
35 } 35 // description: 'Just a visitor. Can only see the home page and the document page',
36 // routes: [{
37 // path: '',
38 // redirect: 'dashboard',
39 // children: [
40 // {
41 // path: 'dashboard',
42 // name: 'Dashboard',
43 // meta: { title: 'dashboard', icon: 'dashboard' }
44 // }
45 // ]
46 // }]
47 // }
36 ] 48 ]
37 49
38 export default [ 50 export default [
39 // mock get all routes form server 51 // mock get all routes form server
40 { 52 {
41 url: '/vue-element-admin/routes', 53 url: '/yp/routes',
42 type: 'get', 54 type: 'get',
43 response: _ => { 55 response: _ => {
44 return { 56 return {
45 code: 20000, 57 code: 20000,
46 data: routes 58 data: routes
47 } 59 }
48 } 60 }
49 }, 61 },
50 62
51 // mock get all roles form server 63 // mock get all roles form server
52 { 64 {
53 url: '/vue-element-admin/roles', 65 url: '/yp/roles',
54 type: 'get', 66 type: 'get',
55 response: _ => { 67 response: _ => {
56 return { 68 return {
57 code: 20000, 69 code: 20000,
58 data: roles 70 data: roles
59 } 71 }
60 } 72 }
61 }, 73 },
62 74
63 // add role 75 // add role
64 { 76 {
65 url: '/vue-element-admin/role', 77 url: '/yp/role',
66 type: 'post', 78 type: 'post',
67 response: { 79 response: {
68 code: 20000, 80 code: 20000,
69 data: { 81 data: {
70 key: Mock.mock('@integer(300, 5000)') 82 key: Mock.mock('@integer(300, 5000)')
71 } 83 }
72 } 84 }
73 }, 85 },
74 86
75 // update role 87 // update role
76 { 88 {
77 url: '/vue-element-admin/role/[A-Za-z0-9]', 89 url: '/yp/role/[A-Za-z0-9]',
78 type: 'put', 90 type: 'put',
79 response: { 91 response: {
80 code: 20000, 92 code: 20000,
81 data: { 93 data: {
82 status: 'success' 94 status: 'success'
83 } 95 }
84 } 96 }
85 }, 97 },
86 98
87 // delete role 99 // delete role
88 { 100 {
89 url: '/vue-element-admin/role/[A-Za-z0-9]', 101 url: '/yp/role/[A-Za-z0-9]',
90 type: 'delete', 102 type: 'delete',
91 response: { 103 response: {
92 code: 20000, 104 code: 20000,
93 data: { 105 data: {
94 status: 'success' 106 status: 'success'
95 } 107 }
96 } 108 }
97 } 109 }
98 ] 110 ]
99 111
mock/role/routes.js
1 // Just a mock data 1 // Just a mock data
2 2
3 export const constantRoutes = [ 3 export const constantRoutes = [
4 { 4 {
5 path: '/redirect', 5 path: '/redirect',
6 component: 'layout/Layout', 6 component: 'layout/Layout',
7 hidden: true, 7 hidden: true,
8 children: [ 8 children: [
9 { 9 {
10 path: '/redirect/:path*', 10 path: '/redirect/:path*',
11 component: 'views/redirect/index' 11 component: 'views/redirect/index'
12 } 12 }
13 ] 13 ]
14 }, 14 },
15 { 15 {
16 path: '/login', 16 path: '/login',
17 component: 'views/login/index', 17 component: 'views/login/index',
18 hidden: true 18 hidden: true
19 }, 19 },
20 { 20 {
21 path: '/auth-redirect', 21 path: '/auth-redirect',
22 component: 'views/login/auth-redirect', 22 component: 'views/login/auth-redirect',
23 hidden: true 23 hidden: true
24 }, 24 },
25 { 25 {
26 path: '/401',
27 component: 'views/error-page/401',
28 hidden: true
29 },
30 {
31 path: '/403',
32 component: 'views/error-page/403',
33 hidden: true
34 },
35 {
26 path: '/404', 36 path: '/404',
27 component: 'views/error-page/404', 37 component: 'views/error-page/404',
28 hidden: true 38 hidden: true
29 }, 39 },
30 { 40 {
31 path: '/401', 41 path: '/500',
32 component: 'views/error-page/401', 42 component: 'views/error-page/500',
33 hidden: true 43 hidden: true
34 }, 44 },
35 { 45 {
36 path: '', 46 path: '',
37 component: 'layout/Layout', 47 component: 'layout/Layout',
38 redirect: 'dashboard', 48 redirect: 'dashboard',
39 children: [ 49 children: [
40 { 50 {
41 path: 'dashboard', 51 path: 'dashboard',
42 component: 'views/dashboard/index', 52 component: 'views/dashboard/index',
43 name: 'Dashboard', 53 name: 'Dashboard',
44 meta: { title: 'dashboard', icon: 'dashboard', affix: true } 54 meta: { title: 'dashboard', icon: 'dashboard', affix: true }
45 } 55 }
46 ] 56 ]
47 }, 57 },
48 { 58 {
49 path: '/documentation', 59 path: '/documentation',
50 component: 'layout/Layout', 60 component: 'layout/Layout',
51 children: [ 61 children: [
52 { 62 {
53 path: 'index', 63 path: 'index',
54 component: 'views/documentation/index', 64 component: 'views/documentation/index',
55 name: 'Documentation', 65 name: 'Documentation',
56 meta: { title: 'documentation', icon: 'documentation', affix: true } 66 meta: { title: 'documentation', icon: 'documentation', affix: true }
57 } 67 }
58 ] 68 ]
59 }, 69 },
60 { 70 {
61 path: '/guide', 71 path: '/guide',
62 component: 'layout/Layout', 72 component: 'layout/Layout',
63 redirect: '/guide/index', 73 redirect: '/guide/index',
64 children: [ 74 children: [
65 { 75 {
66 path: 'index', 76 path: 'index',
67 component: 'views/guide/index', 77 component: 'views/guide/index',
68 name: 'Guide', 78 name: 'Guide',
69 meta: { title: 'guide', icon: 'guide', noCache: true } 79 meta: { title: 'guide', icon: 'guide', noCache: true }
70 } 80 }
71 ] 81 ]
72 } 82 }
73 ] 83 ]
74 84
75 export const asyncRoutes = [ 85 export const asyncRoutes = [
76 { 86 // {
77 path: '/permission', 87 // path: '/permission',
78 component: 'layout/Layout', 88 // component: 'layout/Layout',
79 redirect: '/permission/index', 89 // redirect: '/permission/index',
80 alwaysShow: true, 90 // alwaysShow: true,
81 meta: { 91 // meta: {
82 title: 'permission', 92 // title: 'permission',
83 icon: 'lock', 93 // icon: 'lock',
84 roles: ['admin', 'editor'] 94 // // roles: ['admin', 'assistant', 'runner', 'shoper']
85 }, 95 // },
86 children: [ 96 // children: [
87 { 97 // {
88 path: 'page', 98 // path: 'page',
89 component: 'views/permission/page', 99 // component: 'views/permission/page',
90 name: 'PagePermission', 100 // name: 'PagePermission',
91 meta: { 101 // meta: {
92 title: 'pagePermission', 102 // title: 'pagePermission',
93 roles: ['admin'] 103 // roles: ['admin','assistant']
94 } 104 // }
95 }, 105 // },
96 { 106 // {
97 path: 'directive', 107 // path: 'directive',
98 component: 'views/permission/directive', 108 // component: 'views/permission/directive',
99 name: 'DirectivePermission', 109 // name: 'DirectivePermission',
100 meta: { 110 // meta: {
101 title: 'directivePermission' 111 // title: 'directivePermission',
102 } 112 // roles:['shoper']
103 }, 113 // }
104 { 114 // },
105 path: 'role', 115 // {
106 component: 'views/permission/role', 116 // path: 'role',
107 name: 'RolePermission', 117 // component: 'views/permission/role',
108 meta: { 118 // name: 'RolePermission',
109 title: 'rolePermission', 119 // meta: {
110 roles: ['admin'] 120 // title: 'rolePermission',
111 } 121 // roles: ['runner']
112 } 122 // }
113 ] 123 // }
114 }, 124 // ]
125 // },
115 126
116 { 127 {
117 path: '/icon', 128 path: '/icon',
118 component: 'layout/Layout', 129 component: 'layout/Layout',
130 meta: {
131 title: 'ddddd',
132 icon:'people',
133 roles: ['runner']
134 },
119 children: [ 135 children: [
120 { 136 {
121 path: 'index', 137 path: 'index',
122 component: 'views/icons/index', 138 component: 'views/icons/index',
123 name: 'Icons', 139 name: 'Icons',
124 meta: { title: 'icons', icon: 'icon', noCache: true } 140 meta: { title: 'icons', icon: 'icon', noCache: true }
125 } 141 }
126 ] 142 ]
127 }, 143 },
128 144
129 { 145 {
130 path: '/components', 146 path: '/components',
131 component: 'layout/Layout', 147 component: 'layout/Layout',
132 redirect: 'noRedirect', 148 redirect: 'noRedirect',
133 name: 'ComponentDemo', 149 name: 'ComponentDemo',
134 meta: { 150 meta: {
135 title: 'components', 151 title: 'components',
136 icon: 'component' 152 icon: 'component'
137 }, 153 },
138 children: [ 154 children: [
139 { 155 {
140 path: 'tinymce', 156 path: 'tinymce',
141 component: 'views/components-demo/tinymce', 157 component: 'views/components-demo/tinymce',
142 name: 'TinymceDemo', 158 name: 'TinymceDemo',
143 meta: { title: 'tinymce' } 159 meta: { title: 'tinymce' }
144 }, 160 },
145 { 161 {
146 path: 'markdown', 162 path: 'markdown',
147 component: 'views/components-demo/markdown', 163 component: 'views/components-demo/markdown',
148 name: 'MarkdownDemo', 164 name: 'MarkdownDemo',
149 meta: { title: 'markdown' } 165 meta: { title: 'markdown' }
150 }, 166 },
151 { 167 {
152 path: 'json-editor', 168 path: 'json-editor',
153 component: 'views/components-demo/json-editor', 169 component: 'views/components-demo/json-editor',
154 name: 'JsonEditorDemo', 170 name: 'JsonEditorDemo',
155 meta: { title: 'jsonEditor' } 171 meta: { title: 'jsonEditor' }
156 }, 172 },
157 { 173 {
158 path: 'split-pane', 174 path: 'split-pane',
159 component: 'views/components-demo/split-pane', 175 component: 'views/components-demo/split-pane',
160 name: 'SplitpaneDemo', 176 name: 'SplitpaneDemo',
161 meta: { title: 'splitPane' } 177 meta: { title: 'splitPane' }
162 }, 178 },
163 { 179 {
164 path: 'avatar-upload', 180 path: 'avatar-upload',
165 component: 'views/components-demo/avatar-upload', 181 component: 'views/components-demo/avatar-upload',
166 name: 'AvatarUploadDemo', 182 name: 'AvatarUploadDemo',
167 meta: { title: 'avatarUpload' } 183 meta: { title: 'avatarUpload' }
168 }, 184 },
169 { 185 {
170 path: 'dropzone', 186 path: 'dropzone',
171 component: 'views/components-demo/dropzone', 187 component: 'views/components-demo/dropzone',
172 name: 'DropzoneDemo', 188 name: 'DropzoneDemo',
173 meta: { title: 'dropzone' } 189 meta: { title: 'dropzone' }
174 }, 190 },
175 { 191 {
176 path: 'sticky', 192 path: 'sticky',
177 component: 'views/components-demo/sticky', 193 component: 'views/components-demo/sticky',
178 name: 'StickyDemo', 194 name: 'StickyDemo',
179 meta: { title: 'sticky' } 195 meta: { title: 'sticky' }
180 }, 196 },
181 { 197 {
182 path: 'count-to', 198 path: 'count-to',
183 component: 'views/components-demo/count-to', 199 component: 'views/components-demo/count-to',
184 name: 'CountToDemo', 200 name: 'CountToDemo',
185 meta: { title: 'countTo' } 201 meta: { title: 'countTo' }
186 }, 202 },
187 { 203 {
188 path: 'mixin', 204 path: 'mixin',
189 component: 'views/components-demo/mixin', 205 component: 'views/components-demo/mixin',
190 name: 'ComponentMixinDemo', 206 name: 'ComponentMixinDemo',
191 meta: { title: 'componentMixin' } 207 meta: { title: 'componentMixin' }
192 }, 208 },
193 { 209 {
194 path: 'back-to-top', 210 path: 'back-to-top',
195 component: 'views/components-demo/back-to-top', 211 component: 'views/components-demo/back-to-top',
196 name: 'BackToTopDemo', 212 name: 'BackToTopDemo',
197 meta: { title: 'backToTop' } 213 meta: { title: 'backToTop' }
198 }, 214 },
199 { 215 {
200 path: 'drag-dialog', 216 path: 'drag-dialog',
201 component: 'views/components-demo/drag-dialog', 217 component: 'views/components-demo/drag-dialog',
202 name: 'DragDialogDemo', 218 name: 'DragDialogDemo',
203 meta: { title: 'dragDialog' } 219 meta: { title: 'dragDialog' }
204 }, 220 },
205 { 221 {
206 path: 'drag-select', 222 path: 'drag-select',
207 component: 'views/components-demo/drag-select', 223 component: 'views/components-demo/drag-select',
208 name: 'DragSelectDemo', 224 name: 'DragSelectDemo',
209 meta: { title: 'dragSelect' } 225 meta: { title: 'dragSelect' }
210 }, 226 },
211 { 227 {
212 path: 'dnd-list', 228 path: 'dnd-list',
213 component: 'views/components-demo/dnd-list', 229 component: 'views/components-demo/dnd-list',
214 name: 'DndListDemo', 230 name: 'DndListDemo',
215 meta: { title: 'dndList' } 231 meta: { title: 'dndList' }
216 }, 232 },
217 { 233 {
218 path: 'drag-kanban', 234 path: 'drag-kanban',
219 component: 'views/components-demo/drag-kanban', 235 component: 'views/components-demo/drag-kanban',
220 name: 'DragKanbanDemo', 236 name: 'DragKanbanDemo',
221 meta: { title: 'dragKanban' } 237 meta: { title: 'dragKanban' }
222 } 238 }
223 ] 239 ]
224 }, 240 },
225 { 241 {
226 path: '/charts', 242 path: '/charts',
227 component: 'layout/Layout', 243 component: 'layout/Layout',
228 redirect: 'noRedirect', 244 redirect: 'noRedirect',
229 name: 'Charts', 245 name: 'Charts',
230 meta: { 246 meta: {
231 title: 'charts', 247 title: 'charts',
232 icon: 'chart' 248 icon: 'chart'
233 }, 249 },
234 children: [ 250 children: [
235 { 251 {
236 path: 'keyboard', 252 path: 'keyboard',
237 component: 'views/charts/keyboard', 253 component: 'views/charts/keyboard',
238 name: 'KeyboardChart', 254 name: 'KeyboardChart',
239 meta: { title: 'keyboardChart', noCache: true } 255 meta: { title: 'keyboardChart', noCache: true }
240 }, 256 },
241 { 257 {
242 path: 'line', 258 path: 'line',
243 component: 'views/charts/line', 259 component: 'views/charts/line',
244 name: 'LineChart', 260 name: 'LineChart',
245 meta: { title: 'lineChart', noCache: true } 261 meta: { title: 'lineChart', noCache: true }
246 }, 262 },
247 { 263 {
248 path: 'mixchart', 264 path: 'mixchart',
249 component: 'views/charts/mixChart', 265 component: 'views/charts/mixChart',
250 name: 'MixChart', 266 name: 'MixChart',
251 meta: { title: 'mixChart', noCache: true } 267 meta: { title: 'mixChart', noCache: true }
252 } 268 }
253 ] 269 ]
254 }, 270 },
255 { 271 {
256 path: '/nested', 272 path: '/nested',
257 component: 'layout/Layout', 273 component: 'layout/Layout',
258 redirect: '/nested/menu1/menu1-1', 274 redirect: '/nested/menu1/menu1-1',
259 name: 'Nested', 275 name: 'Nested',
260 meta: { 276 meta: {
261 title: 'nested', 277 title: 'nested',
262 icon: 'nested' 278 icon: 'nested'
263 }, 279 },
264 children: [ 280 children: [
265 { 281 {
266 path: 'menu1', 282 path: 'menu1',
267 component: 'views/nested/menu1/index', 283 component: 'views/nested/menu1/index',
268 name: 'Menu1', 284 name: 'Menu1',
269 meta: { title: 'menu1' }, 285 meta: { title: 'menu1' },
270 redirect: '/nested/menu1/menu1-1', 286 redirect: '/nested/menu1/menu1-1',
271 children: [ 287 children: [
272 { 288 {
273 path: 'menu1-1', 289 path: 'menu1-1',
274 component: 'views/nested/menu1/menu1-1', 290 component: 'views/nested/menu1/menu1-1',
275 name: 'Menu1-1', 291 name: 'Menu1-1',
276 meta: { title: 'menu1-1' } 292 meta: { title: 'menu1-1' }
277 }, 293 },
278 { 294 {
279 path: 'menu1-2', 295 path: 'menu1-2',
280 component: 'views/nested/menu1/menu1-2', 296 component: 'views/nested/menu1/menu1-2',
281 name: 'Menu1-2', 297 name: 'Menu1-2',
282 redirect: '/nested/menu1/menu1-2/menu1-2-1', 298 redirect: '/nested/menu1/menu1-2/menu1-2-1',
283 meta: { title: 'menu1-2' }, 299 meta: { title: 'menu1-2' },
284 children: [ 300 children: [
285 { 301 {
286 path: 'menu1-2-1', 302 path: 'menu1-2-1',
287 component: 'views/nested/menu1/menu1-2/menu1-2-1', 303 component: 'views/nested/menu1/menu1-2/menu1-2-1',
288 name: 'Menu1-2-1', 304 name: 'Menu1-2-1',
289 meta: { title: 'menu1-2-1' } 305 meta: { title: 'menu1-2-1' }
290 }, 306 },
291 { 307 {
292 path: 'menu1-2-2', 308 path: 'menu1-2-2',
293 component: 'views/nested/menu1/menu1-2/menu1-2-2', 309 component: 'views/nested/menu1/menu1-2/menu1-2-2',
294 name: 'Menu1-2-2', 310 name: 'Menu1-2-2',
295 meta: { title: 'menu1-2-2' } 311 meta: { title: 'menu1-2-2' }
296 } 312 }
297 ] 313 ]
298 }, 314 },
299 { 315 {
300 path: 'menu1-3', 316 path: 'menu1-3',
301 component: 'views/nested/menu1/menu1-3', 317 component: 'views/nested/menu1/menu1-3',
302 name: 'Menu1-3', 318 name: 'Menu1-3',
303 meta: { title: 'menu1-3' } 319 meta: { title: 'menu1-3' }
304 } 320 }
305 ] 321 ]
306 }, 322 },
307 { 323 {
308 path: 'menu2', 324 path: 'menu2',
309 name: 'Menu2', 325 name: 'Menu2',
310 component: 'views/nested/menu2/index', 326 component: 'views/nested/menu2/index',
311 meta: { title: 'menu2' } 327 meta: { title: 'menu2' }
312 } 328 }
313 ] 329 ]
314 }, 330 },
315 331
316 { 332 {
317 path: '/example', 333 path: '/example',
318 component: 'layout/Layout', 334 component: 'layout/Layout',
319 redirect: '/example/list', 335 redirect: '/example/list',
320 name: 'Example', 336 name: 'Example',
321 meta: { 337 meta: {
322 title: 'example', 338 title: 'example',
323 icon: 'example' 339 icon: 'example'
324 }, 340 },
325 children: [ 341 children: [
326 { 342 {
327 path: 'create', 343 path: 'create',
328 component: 'views/example/create', 344 component: 'views/example/create',
329 name: 'CreateArticle', 345 name: 'CreateArticle',
330 meta: { title: 'createArticle', icon: 'edit' } 346 meta: { title: 'createArticle', icon: 'edit' }
331 }, 347 },
332 { 348 {
333 path: 'edit/:id(\\d+)', 349 path: 'edit/:id(\\d+)',
334 component: 'views/example/edit', 350 component: 'views/example/edit',
335 name: 'EditArticle', 351 name: 'EditArticle',
336 meta: { title: 'editArticle', noCache: true }, 352 meta: { title: 'editArticle', noCache: true },
337 hidden: true 353 hidden: true
338 }, 354 },
339 { 355 {
340 path: 'list', 356 path: 'list',
341 component: 'views/example/list', 357 component: 'views/example/list',
342 name: 'ArticleList', 358 name: 'ArticleList',
343 meta: { title: 'articleList', icon: 'list' } 359 meta: { title: 'articleList', icon: 'list' }
344 } 360 }
345 ] 361 ]
346 }, 362 },
347 363
348 { 364 {
349 path: '/tab', 365 path: '/tab',
350 component: 'layout/Layout', 366 component: 'layout/Layout',
351 children: [ 367 children: [
352 { 368 {
353 path: 'index', 369 path: 'index',
354 component: 'views/tab/index', 370 component: 'views/tab/index',
355 name: 'Tab', 371 name: 'Tab',
356 meta: { title: 'tab', icon: 'tab' } 372 meta: { title: 'tab', icon: 'tab' }
357 } 373 }
358 ] 374 ]
359 }, 375 },
360 376
361 { 377 {
362 path: '/error', 378 path: '/error',
363 component: 'layout/Layout', 379 component: 'layout/Layout',
364 redirect: 'noRedirect', 380 redirect: 'noRedirect',
365 name: 'ErrorPages', 381 name: 'ErrorPages',
366 meta: { 382 meta: {
367 title: 'errorPages', 383 title: 'errorPages',
368 icon: '404' 384 icon: '404'
369 }, 385 },
370 children: [ 386 children: [
371 { 387 {
372 path: '401', 388 path: '401',
373 component: 'views/error-page/401', 389 component: 'views/error-page/401',
374 name: 'Page401', 390 name: 'Page401',
375 meta: { title: 'page401', noCache: true } 391 meta: { title: 'page401', noCache: true }
376 }, 392 },
377 { 393 {
378 path: '404', 394 path: '404',
379 component: 'views/error-page/404', 395 component: 'views/error-page/404',
380 name: 'Page404', 396 name: 'Page404',
381 meta: { title: 'page404', noCache: true } 397 meta: { title: 'page404', noCache: true }
398 },
399 {
400 path: '500',
401 component: 'views/error-page/500',
402 name: 'Page500',
403 meta: { title: 'page500', noCache: true }
382 } 404 }
383 ] 405 ]
384 }, 406 },
385 407
386 { 408 {
387 path: '/error-log', 409 path: '/error-log',
388 component: 'layout/Layout', 410 component: 'layout/Layout',
389 redirect: 'noRedirect', 411 redirect: 'noRedirect',
390 children: [ 412 children: [
391 { 413 {
392 path: 'log', 414 path: 'log',
393 component: 'views/error-log/index', 415 component: 'views/error-log/index',
394 name: 'ErrorLog', 416 name: 'ErrorLog',
395 meta: { title: 'errorLog', icon: 'bug' } 417 meta: { title: 'errorLog', icon: 'bug' }
396 } 418 }
397 ] 419 ]
398 }, 420 },
399 421
400 { 422 {
401 path: '/excel', 423 path: '/excel',
402 component: 'layout/Layout', 424 component: 'layout/Layout',
403 redirect: '/excel/export-excel', 425 redirect: '/excel/export-excel',
404 name: 'Excel', 426 name: 'Excel',
405 meta: { 427 meta: {
406 title: 'excel', 428 title: 'excel',
407 icon: 'excel' 429 icon: 'excel'
408 }, 430 },
409 children: [ 431 children: [
410 { 432 {
411 path: 'export-excel', 433 path: 'export-excel',
412 component: 'views/excel/export-excel', 434 component: 'views/excel/export-excel',
413 name: 'ExportExcel', 435 name: 'ExportExcel',
414 meta: { title: 'exportExcel' } 436 meta: { title: 'exportExcel' }
415 }, 437 },
416 { 438 {
417 path: 'export-selected-excel', 439 path: 'export-selected-excel',
418 component: 'views/excel/select-excel', 440 component: 'views/excel/select-excel',
419 name: 'SelectExcel', 441 name: 'SelectExcel',
420 meta: { title: 'selectExcel' } 442 meta: { title: 'selectExcel' }
421 }, 443 },
422 { 444 {
423 path: 'export-merge-header', 445 path: 'export-merge-header',
424 component: 'views/excel/merge-header', 446 component: 'views/excel/merge-header',
425 name: 'MergeHeader', 447 name: 'MergeHeader',
426 meta: { title: 'mergeHeader' } 448 meta: { title: 'mergeHeader' }
427 }, 449 },
428 { 450 {
429 path: 'upload-excel', 451 path: 'upload-excel',
430 component: 'views/excel/upload-excel', 452 component: 'views/excel/upload-excel',
431 name: 'UploadExcel', 453 name: 'UploadExcel',
432 meta: { title: 'uploadExcel' } 454 meta: { title: 'uploadExcel' }
433 } 455 }
434 ] 456 ]
435 }, 457 },
436 458
437 { 459 {
438 path: '/zip', 460 path: '/zip',
439 component: 'layout/Layout', 461 component: 'layout/Layout',
440 redirect: '/zip/download', 462 redirect: '/zip/download',
441 alwaysShow: true, 463 alwaysShow: true,
442 meta: { title: 'zip', icon: 'zip' }, 464 meta: { title: 'zip', icon: 'zip' },
443 children: [ 465 children: [
444 { 466 {
445 path: 'download', 467 path: 'download',
446 component: 'views/zip/index', 468 component: 'views/zip/index',
447 name: 'ExportZip', 469 name: 'ExportZip',
448 meta: { title: 'exportZip' } 470 meta: { title: 'exportZip' }
449 } 471 }
450 ] 472 ]
451 }, 473 },
452 474
453 { 475 {
454 path: '/pdf', 476 path: '/pdf',
455 component: 'layout/Layout', 477 component: 'layout/Layout',
456 redirect: '/pdf/index', 478 redirect: '/pdf/index',
457 children: [ 479 children: [
458 { 480 {
459 path: 'index', 481 path: 'index',
460 component: 'views/pdf/index', 482 component: 'views/pdf/index',
461 name: 'PDF', 483 name: 'PDF',
462 meta: { title: 'pdf', icon: 'pdf' } 484 meta: { title: 'pdf', icon: 'pdf' }
463 } 485 }
464 ] 486 ]
465 }, 487 },
466 { 488 {
467 path: '/pdf/download', 489 path: '/pdf/download',
468 component: 'views/pdf/download', 490 component: 'views/pdf/download',
469 hidden: true 491 hidden: true
470 }, 492 },
471 493
472 { 494 {
473 path: '/theme', 495 path: '/theme',
474 component: 'layout/Layout', 496 component: 'layout/Layout',
475 redirect: 'noRedirect', 497 redirect: 'noRedirect',
476 children: [ 498 children: [
477 { 499 {
478 path: 'index', 500 path: 'index',
479 component: 'views/theme/index', 501 component: 'views/theme/index',
480 name: 'Theme', 502 name: 'Theme',
481 meta: { title: 'theme', icon: 'theme' } 503 meta: { title: 'theme', icon: 'theme' }
482 } 504 }
483 ] 505 ]
484 }, 506 },
485 507
486 { 508 {
487 path: '/clipboard', 509 path: '/clipboard',
488 component: 'layout/Layout', 510 component: 'layout/Layout',
489 redirect: 'noRedirect', 511 redirect: 'noRedirect',
490 children: [ 512 children: [
491 { 513 {
492 path: 'index', 514 path: 'index',
493 component: 'views/clipboard/index', 515 component: 'views/clipboard/index',
494 name: 'ClipboardDemo', 516 name: 'ClipboardDemo',
495 meta: { title: 'clipboardDemo', icon: 'clipboard' } 517 meta: { title: 'clipboardDemo', icon: 'clipboard' }
496 } 518 }
497 ] 519 ]
498 }, 520 },
499 521
500 { 522 {
501 path: '/i18n', 523 path: '/i18n',
502 component: 'layout/Layout', 524 component: 'layout/Layout',
503 children: [ 525 children: [
504 { 526 {
505 path: 'index', 527 path: 'index',
506 component: 'views/i18n-demo/index', 528 component: 'views/i18n-demo/index',
507 name: 'I18n', 529 name: 'I18n',
508 meta: { title: 'i18n', icon: 'international' } 530 meta: { title: 'i18n', icon: 'international' }
509 } 531 }
510 ] 532 ]
511 }, 533 },
512 534
513 { 535 {
514 path: 'external-link', 536 path: 'external-link',
515 component: 'layout/Layout', 537 component: 'layout/Layout',
516 children: [ 538 children: [
517 { 539 {
518 path: 'https://github.com/PanJiaChen/vue-element-admin', 540 path: 'https://github.com/PanJiaChen/vue-element-admin',
519 meta: { title: 'externalLink', icon: 'link' } 541 meta: { title: 'externalLink', icon: 'link' }
520 } 542 }
521 ] 543 ]
522 }, 544 },
523 545
524 { path: '*', redirect: '/404', hidden: true } 546 { path: '*', redirect: '/404', hidden: true }
525 ] 547 ]
526 548
1 1
2 import Mock from 'mockjs'
3
2 const tokens = { 4 const tokens = {
3 admin: { 5 admin: {
4 token: 'admin-token' 6 token: 'admin-token'
5 }, 7 },
6 editor: { 8 assistant: {
7 token: 'editor-token' 9 token: 'assistant-token'
10 },
11 runner: {
12 token: 'runner-token'
13 },
14 shoper: {
15 token: 'shoper-token'
8 } 16 }
9 } 17 }
10 18
11 const users = { 19 const users = {
12 'admin-token': { 20 'admin-token': {
13 roles: ['admin'], 21 roles: ['admin'],
14 introduction: 'I am a super administrator', 22 introduction: 'I am a super administrator',
15 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 23 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
16 name: 'Super Admin' 24 name: 'Super Admin'
17 }, 25 },
18 'editor-token': { 26 'assistant-token': {
19 roles: ['editor'], 27 roles: ['assistant'],
20 introduction: 'I am an editor', 28 introduction: 'I am an assistant',
29 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
30 name: 'Normal assistant'
31 },
32 'runner-token': {
33 roles: ['runner'],
34 introduction: 'I am an runner',
35 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
36 name: 'Normal runner'
37 },
38 'shoper-token': {
39 roles: ['shoper'],
40 introduction: 'I am an shoper',
21 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 41 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
22 name: 'Normal Editor' 42 name: 'Normal shoper'
23 } 43 }
24 } 44 }
25 45
46 const List = []
47 const count = 100
48
49 const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
50 const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3'
51
52 for (let i = 0; i < count; i++) {
53 List.push(Mock.mock({
54 uid: '@increment',
55 create_time: +Mock.Random.date('T'),
56 nickname: '@first',
57 reviewer: '@first',
58 title: '@title(5, 10)',
59 openid:'@sentence(12,12)',
60 content_short: 'mock data',
61 content: baseContent,
62 forecast: '@float(0, 100, 2, 2)',
63 importance: '@integer(1, 3)',
64 'type|1': ['CN', 'US', 'JP', 'EU'],
65 'status|1': ['published', 'draft'],
66 display_time: '@datetime',
67 comment_disabled: true,
68 son_of_adv: '@integer(300, 5000)',//下线
69 souceof:'@integer(300, 5000)',//源自
70 image_uri,
71 'roles|1': ['admin', 'assistant', 'shoper', 'runner'],
72 platforms: ['a-platform']//哪个平台
73 }))
74 }
75
26 export default [ 76 export default [
27 // user login 77 // user login
28 { 78 {
29 url: '/vue-element-admin/user/login', 79 url: '/yp/user/login',
30 type: 'post', 80 type: 'post',
31 response: config => { 81 response: config => {
32 const { username } = config.body 82 const { username } = config.body
33 const token = tokens[username] 83 const token = tokens[username]
34 84
35 // mock error 85 // mock error
36 if (!token) { 86 if (!token) {
37 return { 87 return {
38 code: 60204, 88 code: 60204,
39 message: 'Account and password are incorrect.' 89 message: 'Account and password are incorrect.'
40 } 90 }
41 } 91 }
42 92
43 return { 93 return {
44 code: 20000, 94 code: 20000,
45 data: token 95 data: token
46 } 96 }
47 } 97 }
48 }, 98 },
49 99
50 // get user info 100 // get user info
51 { 101 {
52 url: '/vue-element-admin/user/info\.*', 102 url: '/yp/user/info\.*',
53 type: 'get', 103 type: 'get',
54 response: config => { 104 response: config => {
55 const { token } = config.query 105 const { token } = config.query
56 const info = users[token] 106 const info = users[token]
57 107
58 // mock error 108 // mock error
59 if (!info) { 109 if (!info) {
60 return { 110 return {
61 code: 50008, 111 code: 50008,
62 message: 'Login failed, unable to get user details.' 112 message: 'Login failed, unable to get user details.'
63 } 113 }
64 } 114 }
65 115
66 return { 116 return {
67 code: 20000, 117 code: 20000,
68 data: info 118 data: info
69 } 119 }
70 } 120 }
71 }, 121 },
72 122
73 // user logout 123 // user logout
74 { 124 {
75 url: '/vue-element-admin/user/logout', 125 url: '/yp/user/logout',
126 type: 'post',
127 response: _ => {
128 return {
129 code: 20000,
130 data: 'success'
131 }
132 }
133 },
134 // user create
135 {
136 url: '/yp/user/create',
137 type: 'post',
138 response: _ => {
139 return {
140 code: 20000,
141 data: 'success'
142 }
143 }
144 },
145 // user update
146 {
147 url: '/yp/user/update',
76 type: 'post', 148 type: 'post',
77 response: _ => { 149 response: _ => {
78 return { 150 return {
79 code: 20000, 151 code: 20000,
80 data: 'success' 152 data: 'success'
81 } 153 }
82 } 154 }
155 },
156 // user del
157 {
158 url: '/yp/user/del',
159 type: 'post',
160 response: _ => {
161 return {
162 code: 20000,
163 data: 'success'
164 }
165 }
166 },
167 // user list
168 {
169 url: '/yp/user/list',
170 type: 'get',
171 response: config => {
172 const {
173 importance,
174 type,
175 title,
176 page = 1,
177 limit = 20,
178 sort
179 } = config.query
180
181 let mockList = List.filter(item => {
182 if (importance && item.importance !== +importance) return false
183 if (type && item.type !== type) return false
184 if (title && item.title.indexOf(title) < 0) return false
185 return true
186 })
187
188 if (sort === '-id') {
189 mockList = mockList.reverse()
190 }
191
192 const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
193
194 return {
195 code: 20000,
196 data: {
197 total: mockList.length,
198 items: pageList
199 }
200 }
201 }
83 } 202 }
84 ] 203 ]
85 204
1 { 1 {
2 "name": "vue-element-admin", 2 "name": "vue-element-admin",
3 "version": "4.2.1", 3 "version": "4.2.1",
4 "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features", 4 "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
5 "author": "Pan <panfree23@gmail.com>", 5 "author": "Pan <panfree23@gmail.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 --fix --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 "new": "plop" 16 "new": "plop"
17 }, 17 },
18 "husky": { 18 "husky": {
19 "hooks": { 19 "hooks": {
20 "pre-commit": "lint-staged" 20 "pre-commit": "lint-staged"
21 } 21 }
22 }, 22 },
23 "lint-staged": { 23 "lint-staged": {
24 "src/**/*.{js,vue}": [ 24 "src/**/*.{js,vue}": [
25 "eslint --fix", 25 "eslint --fix",
26 "git add" 26 "git add"
27 ] 27 ]
28 }, 28 },
29 "keywords": [ 29 "keywords": [
30 "vue", 30 "vue",
31 "admin", 31 "admin",
32 "dashboard", 32 "dashboard",
33 "element-ui", 33 "element-ui",
34 "boilerplate", 34 "boilerplate",
35 "admin-template", 35 "admin-template",
36 "management-system" 36 "management-system"
37 ], 37 ],
38 "repository": { 38 "repository": {
39 "type": "git", 39 "type": "git",
40 "url": "git+https://github.com/PanJiaChen/vue-element-admin.git" 40 "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
41 }, 41 },
42 "bugs": { 42 "bugs": {
43 "url": "https://github.com/PanJiaChen/vue-element-admin/issues" 43 "url": "https://github.com/PanJiaChen/vue-element-admin/issues"
44 }, 44 },
45 "dependencies": { 45 "dependencies": {
46 "ant-design-vue": "^1.5.5",
46 "axios": "0.18.1", 47 "axios": "0.18.1",
47 "clipboard": "2.0.4", 48 "clipboard": "2.0.4",
48 "codemirror": "5.45.0", 49 "codemirror": "5.45.0",
49 "driver.js": "0.9.5", 50 "driver.js": "0.9.5",
50 "dropzone": "5.5.1", 51 "dropzone": "5.5.1",
51 "echarts": "4.2.1", 52 "echarts": "4.2.1",
52 "element-ui": "2.13.0", 53 "element-ui": "2.13.0",
53 "file-saver": "2.0.1", 54 "file-saver": "2.0.1",
54 "fuse.js": "3.4.4", 55 "fuse.js": "3.4.4",
55 "js-cookie": "2.2.0", 56 "js-cookie": "2.2.0",
56 "jsonlint": "1.6.3", 57 "jsonlint": "1.6.3",
57 "jszip": "3.2.1", 58 "jszip": "3.2.1",
59 "less-loader": "^6.1.0",
58 "normalize.css": "7.0.0", 60 "normalize.css": "7.0.0",
59 "nprogress": "0.2.0", 61 "nprogress": "0.2.0",
60 "path-to-regexp": "2.4.0", 62 "path-to-regexp": "2.4.0",
61 "pinyin": "2.9.0", 63 "pinyin": "2.9.0",
64 "qs": "^6.9.4",
62 "screenfull": "4.2.0", 65 "screenfull": "4.2.0",
63 "showdown": "1.9.0", 66 "showdown": "1.9.0",
64 "sortablejs": "1.8.4", 67 "sortablejs": "1.8.4",
65 "tui-editor": "1.3.3", 68 "tui-editor": "1.3.3",
69 "vant": "^2.8.0",
66 "vue": "2.6.10", 70 "vue": "2.6.10",
67 "vue-count-to": "1.0.13", 71 "vue-count-to": "1.0.13",
68 "vue-i18n": "7.3.2", 72 "vue-i18n": "7.3.2",
69 "vue-router": "3.0.2", 73 "vue-router": "3.0.2",
70 "vue-splitpane": "1.0.4", 74 "vue-splitpane": "1.0.4",
71 "vuedraggable": "2.20.0", 75 "vuedraggable": "2.20.0",
72 "vuex": "3.1.0", 76 "vuex": "3.1.0",
73 "xlsx": "0.14.1" 77 "xlsx": "0.14.1"
74 }, 78 },
75 "devDependencies": { 79 "devDependencies": {
76 "@babel/core": "7.0.0", 80 "@babel/core": "7.0.0",
77 "@babel/register": "7.0.0", 81 "@babel/register": "7.0.0",
78 "@vue/cli-plugin-babel": "3.5.3", 82 "@vue/cli-plugin-babel": "3.5.3",
79 "@vue/cli-plugin-eslint": "^3.9.1", 83 "@vue/cli-plugin-eslint": "^3.9.1",
80 "@vue/cli-plugin-unit-jest": "3.5.3", 84 "@vue/cli-plugin-unit-jest": "3.5.3",
81 "@vue/cli-service": "3.5.3", 85 "@vue/cli-service": "3.5.3",
82 "@vue/test-utils": "1.0.0-beta.29", 86 "@vue/test-utils": "1.0.0-beta.29",
83 "autoprefixer": "^9.5.1", 87 "autoprefixer": "^9.5.1",
84 "babel-core": "7.0.0-bridge.0", 88 "babel-core": "7.0.0-bridge.0",
85 "babel-eslint": "10.0.1", 89 "babel-eslint": "10.0.1",
86 "babel-jest": "23.6.0", 90 "babel-jest": "23.6.0",
87 "chalk": "2.4.2", 91 "chalk": "2.4.2",
88 "chokidar": "2.1.5", 92 "chokidar": "2.1.5",
89 "connect": "3.6.6", 93 "connect": "3.6.6",
90 "eslint": "5.15.3", 94 "eslint": "5.15.3",
91 "eslint-plugin-vue": "5.2.2", 95 "eslint-plugin-vue": "5.2.2",
92 "html-webpack-plugin": "3.2.0", 96 "html-webpack-plugin": "3.2.0",
93 "husky": "1.3.1", 97 "husky": "1.3.1",
94 "lint-staged": "8.1.5", 98 "lint-staged": "8.1.5",
95 "mockjs": "1.0.1-beta3", 99 "mockjs": "1.0.1-beta3",
96 "node-sass": "^4.9.0", 100 "node-sass": "^4.9.0",
97 "plop": "2.3.0", 101 "plop": "2.3.0",
98 "runjs": "^4.3.2", 102 "runjs": "^4.3.2",
99 "sass-loader": "^7.1.0", 103 "sass-loader": "^7.1.0",
100 "script-ext-html-webpack-plugin": "2.1.3", 104 "script-ext-html-webpack-plugin": "2.1.3",
101 "script-loader": "0.7.2", 105 "script-loader": "0.7.2",
102 "serve-static": "^1.13.2", 106 "serve-static": "^1.13.2",
103 "svg-sprite-loader": "4.1.3", 107 "svg-sprite-loader": "4.1.3",
104 "svgo": "1.2.0", 108 "svgo": "1.2.0",
105 "vue-template-compiler": "2.6.10" 109 "vue-template-compiler": "2.6.10"
106 }, 110 },
107 "engines": { 111 "engines": {
108 "node": ">=8.9", 112 "node": ">=8.9",
109 "npm": ">= 3.0.0" 113 "npm": ">= 3.0.0"
110 }, 114 },
111 "browserslist": [ 115 "browserslist": [
112 "> 1%", 116 "> 1%",
113 "last 2 versions" 117 "last 2 versions"
114 ] 118 ]
115 } 119 }
116 120
src/api/article.js
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 // export const getPersonInfo = data => {
4 // return service({
5 // url: '/person_pay/getpersoninfo',
6 // method: 'post',
7 // data
8 // })
9 // }
10
3 export function fetchList(query) { 11 export function fetchList(query) {
4 return request({ 12 return request({
5 url: '/vue-element-admin/article/list', 13 url: '/yp/article/list',
6 method: 'get', 14 method: 'get',
7 params: query 15 params: query
8 }) 16 })
9 } 17 }
10 18
11 export function fetchArticle(id) { 19 export function fetchArticle(id) {
12 return request({ 20 return request({
13 url: '/vue-element-admin/article/detail', 21 url: '/yp/article/detail',
14 method: 'get', 22 method: 'get',
15 params: { id } 23 params: {
24 id
25 }
16 }) 26 })
17 } 27 }
18 28
19 export function fetchPv(pv) { 29 export function fetchPv(pv) {
20 return request({ 30 return request({
21 url: '/vue-element-admin/article/pv', 31 url: '/yp/article/pv',
22 method: 'get', 32 method: 'get',
23 params: { pv } 33 params: {
34 pv
35 }
24 }) 36 })
25 } 37 }
26 38
27 export function createArticle(data) { 39 export function createArticle(data) {
28 return request({ 40 return request({
29 url: '/vue-element-admin/article/create', 41 url: '/yp/article/create',
30 method: 'post', 42 method: 'post',
31 data 43 data
32 }) 44 })
33 } 45 }
34 46
35 export function updateArticle(data) { 47 export function updateArticle(data) {
36 return request({ 48 return request({
37 url: '/vue-element-admin/article/update', 49 url: '/yp/article/update',
38 method: 'post', 50 method: 'post',
39 data 51 data
40 }) 52 })
41 } 53 }
42 54
src/api/remote-search.js
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 export function searchUser(name) { 3 export function searchUser(name) {
4 return request({ 4 return request({
5 url: '/vue-element-admin/search/user', 5 url: '/yp/search/user',
6 method: 'get', 6 method: 'get',
7 params: { name } 7 params: { name }
8 }) 8 })
9 } 9 }
10 10
11 export function transactionList(query) { 11 export function transactionList(query) {
12 return request({ 12 return request({
13 url: '/vue-element-admin/transaction/list', 13 url: '/yp/transaction/list',
14 method: 'get', 14 method: 'get',
15 params: query 15 params: query
16 }) 16 })
17 } 17 }
18 18
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 export function getRoutes() { 3 export function getRoutes() {
4 return request({ 4 return request({
5 url: '/vue-element-admin/routes', 5 url: '/yp/routes',
6 method: 'get' 6 method: 'get'
7 }) 7 })
8 } 8 }
9 9
10 export function getRoles() { 10 export function getRoles() {
11 return request({ 11 return request({
12 url: '/vue-element-admin/roles', 12 url: '/yp/roles',
13 method: 'get' 13 method: 'get'
14 }) 14 })
15 } 15 }
16 16
17 export function addRole(data) { 17 export function addRole(data) {
18 return request({ 18 return request({
19 url: '/vue-element-admin/role', 19 url: '/yp/role',
20 method: 'post', 20 method: 'post',
21 data 21 data
22 }) 22 })
23 } 23 }
24 24
25 export function updateRole(id, data) { 25 export function updateRole(id, data) {
26 return request({ 26 return request({
27 url: `/vue-element-admin/role/${id}`, 27 url: `/vue-element-admin/role/${id}`,
28 method: 'put', 28 method: 'put',
29 data 29 data
30 }) 30 })
31 } 31 }
32 32
33 export function deleteRole(id) { 33 export function deleteRole(id) {
34 return request({ 34 return request({
35 url: `/vue-element-admin/role/${id}`, 35 url: `/vue-element-admin/role/${id}`,
36 method: 'delete' 36 method: 'delete'
37 }) 37 })
38 } 38 }
39 39
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 return request({ 4 return request({
5 url: '/vue-element-admin/user/login', 5 url: '/yp/user/login',
6 method: 'post', 6 method: 'post',
7 data 7 data
8 }) 8 })
9 } 9 }
10 10
11 export function getInfo(token) { 11 export function getInfo(token) {
12 return request({ 12 return request({
13 url: '/vue-element-admin/user/info', 13 url: '/yp/user/info',
14 method: 'get', 14 method: 'get',
15 params: { token } 15 params: { token }
16 }) 16 })
17 } 17 }
18 18
19 export function logout() { 19 export function logout() {
20 return request({ 20 return request({
21 url: '/vue-element-admin/user/logout', 21 url: '/yp/user/logout',
22 method: 'post' 22 method: 'post'
23 }) 23 })
24 } 24 }
25
26 export function fetchList(query) {
27 return request({
28 url: '/yp/user/list',
29 method: 'get',
30 params: query
31 })
32 }
33
34 export function createUser(query) {
35 return request({
36 url: '/yp/user/create',
37 method: 'post',
38 params: query
39 })
40 }
41
42 export function updateUser(query) {
43 return request({
44 url: '/yp/user/update',
45 method: 'post',
46 params: query
47 })
48 }
49
50 export function delUser(query) {
51 return request({
52 url: '/yp/user/del',
53 method: 'post',
54 params: query
55 })
56 }
25 57
src/directive/permission/permission.js
1 import store from '@/store' 1 import store from '@/store'
2 2
3 export default { 3 export default {
4 inserted(el, binding, vnode) { 4 inserted(el, binding, vnode) {
5 const { value } = binding 5 const { value } = binding
6 const roles = store.getters && store.getters.roles 6 const roles = store.getters && store.getters.roles
7 7
8 if (value && value instanceof Array && value.length > 0) { 8 if (value && value instanceof Array && value.length > 0) {
9 const permissionRoles = value 9 const permissionRoles = value
10 10
11 const hasPermission = roles.some(role => { 11 const hasPermission = roles.some(role => {
12 return permissionRoles.includes(role) 12 return permissionRoles.includes(role)
13 }) 13 })
14 14
15 if (!hasPermission) { 15 if (!hasPermission) {
16 el.parentNode && el.parentNode.removeChild(el) 16 el.parentNode && el.parentNode.removeChild(el)
17 } 17 }
18 } else { 18 } else {
19 throw new Error(`need roles! Like v-permission="['admin','editor']"`) 19 throw new Error(`need roles! Like v-permission="['admin','assistant', 'shoper', 'runner']"`)
20 } 20 }
21 } 21 }
22 } 22 }
23 23
1 export default { 1 export default {
2 // 添加的新词条------start
3 prod: {
4 menu_title: 'products'
5 },
6 order: {
7
8 },
9 users: {
10
11 },
12 site: {
13
14 },
15 meta: {
16
17 },
18 system: {
19 memu: '系统'
20 },
2 route: { 21 route: {
22 users: 'users',
23 usersList: 'user list',
24 shopers: 'shoper suply chain',
25 prods: 'products',
26 orders: 'orders',
27 sites: 'sites',
28 metas: {
29 metas: 'meta',
30 list: 'tree'
31 },
32 systems: {
33 systems: 'system',
34 sites: 'site seting',
35 money: 'money seting',
36 industry: 'industry seting',
37 template: 'template seting'
38 },
39 // 添加的新词条------end
3 dashboard: 'Dashboard', 40 dashboard: 'Dashboard',
4 documentation: 'Documentation', 41 documentation: 'Documentation',
5 guide: 'Guide', 42 guide: 'Guide',
6 permission: 'Permission', 43 permission: 'Permission',
7 pagePermission: 'Page Permission', 44 pagePermission: 'Page Permission',
8 rolePermission: 'Role Permission', 45 rolePermission: 'Role Permission',
9 directivePermission: 'Directive Permission', 46 directivePermission: 'Directive Permission',
10 icons: 'Icons', 47 icons: 'Icons',
11 components: 'Components', 48 components: 'Components',
12 tinymce: 'Tinymce', 49 tinymce: 'Tinymce',
13 markdown: 'Markdown', 50 markdown: 'Markdown',
14 jsonEditor: 'JSON Editor', 51 jsonEditor: 'JSON Editor',
15 dndList: 'Dnd List', 52 dndList: 'Dnd List',
16 splitPane: 'SplitPane', 53 splitPane: 'SplitPane',
17 avatarUpload: 'Avatar Upload', 54 avatarUpload: 'Avatar Upload',
18 dropzone: 'Dropzone', 55 dropzone: 'Dropzone',
19 sticky: 'Sticky', 56 sticky: 'Sticky',
20 countTo: 'Count To', 57 countTo: 'Count To',
21 componentMixin: 'Mixin', 58 componentMixin: 'Mixin',
22 backToTop: 'Back To Top', 59 backToTop: 'Back To Top',
23 dragDialog: 'Drag Dialog', 60 dragDialog: 'Drag Dialog',
24 dragSelect: 'Drag Select', 61 dragSelect: 'Drag Select',
25 dragKanban: 'Drag Kanban', 62 dragKanban: 'Drag Kanban',
26 charts: 'Charts', 63 charts: 'Charts',
27 keyboardChart: 'Keyboard Chart', 64 keyboardChart: 'Keyboard Chart',
28 lineChart: 'Line Chart', 65 lineChart: 'Line Chart',
29 mixChart: 'Mix Chart', 66 mixChart: 'Mix Chart',
30 example: 'Example', 67 example: 'Example',
31 nested: 'Nested Routes', 68 nested: 'Nested Routes',
32 menu1: 'Menu 1', 69 menu1: 'Menu 1',
33 'menu1-1': 'Menu 1-1', 70 'menu1-1': 'Menu 1-1',
34 'menu1-2': 'Menu 1-2', 71 'menu1-2': 'Menu 1-2',
35 'menu1-2-1': 'Menu 1-2-1', 72 'menu1-2-1': 'Menu 1-2-1',
36 'menu1-2-2': 'Menu 1-2-2', 73 'menu1-2-2': 'Menu 1-2-2',
37 'menu1-3': 'Menu 1-3', 74 'menu1-3': 'Menu 1-3',
38 menu2: 'Menu 2', 75 menu2: 'Menu 2',
39 Table: 'Table', 76 Table: 'Table',
40 dynamicTable: 'Dynamic Table', 77 dynamicTable: 'Dynamic Table',
41 dragTable: 'Drag Table', 78 dragTable: 'Drag Table',
42 inlineEditTable: 'Inline Edit', 79 inlineEditTable: 'Inline Edit',
43 complexTable: 'Complex Table', 80 complexTable: 'Complex Table',
44 tab: 'Tab', 81 tab: 'Tab',
45 form: 'Form', 82 form: 'Form',
46 createArticle: 'Create Article', 83 createArticle: 'Create Article',
47 editArticle: 'Edit Article', 84 editArticle: 'Edit Article',
48 articleList: 'Article List', 85 articleList: 'Article List',
49 errorPages: 'Error Pages', 86 errorPages: 'Error Pages',
50 page401: '401', 87 page401: '401',
51 page404: '404', 88 page404: '404',
52 errorLog: 'Error Log', 89 errorLog: 'Error Log',
53 excel: 'Excel', 90 excel: 'Excel',
54 exportExcel: 'Export Excel', 91 exportExcel: 'Export Excel',
55 selectExcel: 'Export Selected', 92 selectExcel: 'Export Selected',
56 mergeHeader: 'Merge Header', 93 mergeHeader: 'Merge Header',
57 uploadExcel: 'Upload Excel', 94 uploadExcel: 'Upload Excel',
58 zip: 'Zip', 95 zip: 'Zip',
59 pdf: 'PDF', 96 pdf: 'PDF',
60 exportZip: 'Export Zip', 97 exportZip: 'Export Zip',
61 theme: 'Theme', 98 theme: 'Theme',
62 clipboardDemo: 'Clipboard', 99 clipboardDemo: 'Clipboard',
63 i18n: 'I18n', 100 i18n: 'I18n',
64 externalLink: 'External Link', 101 externalLink: 'External Link',
65 profile: 'Profile' 102 profile: 'Profile'
66 }, 103 },
67 navbar: { 104 navbar: {
68 dashboard: 'Dashboard', 105 dashboard: 'Dashboard',
69 github: 'Github', 106 github: 'Github',
70 logOut: 'Log Out', 107 logOut: 'Log Out',
71 profile: 'Profile', 108 profile: 'Profile',
72 theme: 'Theme', 109 theme: 'Theme',
73 size: 'Global Size' 110 size: 'Global Size'
74 }, 111 },
75 login: { 112 login: {
76 title: 'Login Form', 113 runner: 'officer Runner',
114 shoper: 'shop of Suply Chain',
115 assistant: 'worker in system',
116 signup: 'sign up',
117 forgetpassword: 'forget password',
118 rememberpassword: 'remember password',
119
120 // title: 'let\'s conquer the world',
121 title: 'LET\'S FUCK THE WORLD',
77 logIn: 'Login', 122 logIn: 'Login',
78 username: 'Username', 123 username: 'Username',
79 password: 'Password', 124 password: 'Password',
80 any: 'any', 125 any: 'any',
81 thirdparty: 'Or connect with', 126 thirdparty: 'Or connect with',
82 thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !' 127 thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !'
83 }, 128 },
84 documentation: { 129 documentation: {
85 documentation: 'Documentation', 130 documentation: 'Documentation',
86 github: 'Github Repository' 131 github: 'Github Repository'
87 }, 132 },
88 permission: { 133 permission: {
89 addRole: 'New Role', 134 addRole: 'New Role',
90 editPermission: 'Edit', 135 editPermission: 'Edit',
91 roles: 'Your roles', 136 roles: 'Your roles',
92 switchRoles: 'Switch roles', 137 switchRoles: 'Switch roles',
93 tips: 'In some cases, using v-permission will have no effect. For example: Element-UI el-tab or el-table-column and other scenes that dynamically render dom. You can only do this with v-if.', 138 tips: 'In some cases, using v-permission will have no effect. For example: Element-UI el-tab or el-table-column and other scenes that dynamically render dom. You can only do this with v-if.',
94 delete: 'Delete', 139 delete: 'Delete',
95 confirm: 'Confirm', 140 confirm: 'Confirm',
96 cancel: 'Cancel' 141 cancel: 'Cancel'
97 }, 142 },
98 guide: { 143 guide: {
99 description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ', 144 description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
100 button: 'Show Guide' 145 button: 'Show Guide'
101 }, 146 },
102 components: { 147 components: {
103 documentation: 'Documentation', 148 documentation: 'Documentation',
104 tinymceTips: 'Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.', 149 tinymceTips: 'Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.',
105 dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.', 150 dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
106 stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.', 151 stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
107 backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner', 152 backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
108 backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally', 153 backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally',
109 imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.' 154 imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.'
110 }, 155 },
111 table: { 156 table: {
112 dynamicTips1: 'Fixed header, sorted by header order', 157 dynamicTips1: 'Fixed header, sorted by header order',
113 dynamicTips2: 'Not fixed header, sorted by click order', 158 dynamicTips2: 'Not fixed header, sorted by click order',
114 dragTips1: 'The default order', 159 dragTips1: 'The default order',
115 dragTips2: 'The after dragging order', 160 dragTips2: 'The after dragging order',
116 title: 'Title', 161 title: 'Title',
117 importance: 'Imp', 162 importance: 'Imp',
118 type: 'Type', 163 type: 'Type',
119 remark: 'Remark', 164 remark: 'Remark',
120 search: 'Search', 165 search: 'Search',
121 add: 'Add', 166 add: 'Add',
122 export: 'Export', 167 export: 'Export',
123 reviewer: 'reviewer', 168 reviewer: 'reviewer',
124 id: 'ID', 169 id: 'ID',
125 date: 'Date', 170 date: 'Date',
126 author: 'Author', 171 author: 'Author',
127 readings: 'Readings', 172 readings: 'Readings',
128 status: 'Status', 173 status: 'Status',
129 actions: 'Actions', 174 actions: 'Actions',
130 edit: 'Edit', 175 edit: 'Edit',
131 publish: 'Publish', 176 publish: 'Publish',
132 draft: 'Draft', 177 draft: 'Draft',
133 delete: 'Delete', 178 delete: 'Delete',
134 cancel: 'Cancel', 179 cancel: 'Cancel',
135 confirm: 'Confirm' 180 confirm: 'Confirm'
136 }, 181 },
137 example: { 182 example: {
138 warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details' 183 warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
139 }, 184 },
140 errorLog: { 185 errorLog: {
141 tips: 'Please click the bug icon in the upper right corner', 186 tips: 'Please click the bug icon in the upper right corner',
142 description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', 187 description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
143 documentation: 'Document introduction' 188 documentation: 'Document introduction'
144 }, 189 },
145 excel: { 190 excel: {
146 export: 'Export', 191 export: 'Export',
147 selectedExport: 'Export Selected Items', 192 selectedExport: 'Export Selected Items',
148 placeholder: 'Please enter the file name (default excel-list)' 193 placeholder: 'Please enter the file name (default excel-list)'
149 }, 194 },
150 zip: { 195 zip: {
151 export: 'Export', 196 export: 'Export',
152 placeholder: 'Please enter the file name (default file)' 197 placeholder: 'Please enter the file name (default file)'
153 }, 198 },
154 pdf: { 199 pdf: {
155 tips: 'Here we use window.print() to implement the feature of downloading PDF.' 200 tips: 'Here we use window.print() to implement the feature of downloading PDF.'
156 }, 201 },
157 theme: { 202 theme: {
158 change: 'Change Theme', 203 change: 'Change Theme',
159 documentation: 'Theme documentation', 204 documentation: 'Theme documentation',
160 tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.' 205 tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.'
161 }, 206 },
162 tagsView: { 207 tagsView: {
163 refresh: 'Refresh', 208 refresh: 'Refresh',
164 close: 'Close', 209 close: 'Close',
165 closeOthers: 'Close Others', 210 closeOthers: 'Close Others',
166 closeAll: 'Close All' 211 closeAll: 'Close All'
167 }, 212 },
168 settings: { 213 settings: {
169 title: 'Page style setting', 214 title: 'Page style setting',
170 theme: 'Theme Color', 215 theme: 'Theme Color',
171 tagsView: 'Open Tags-View', 216 tagsView: 'Open Tags-View',
172 fixedHeader: 'Fixed Header', 217 fixedHeader: 'Fixed Header',
173 sidebarLogo: 'Sidebar Logo' 218 sidebarLogo: 'Sidebar Logo'
174 } 219 }
175 } 220 }
176 221
1 export default { 1 export default {
2 // 添加的新词条------start
3 prod: {
4 menu_title: 'products'
5 },
6 order: {
7
8 },
9 users: {
10
11 },
12 site: {
13
14 },
15 meta: {
16
17 },
18 system: {
19 memu: '系统'
20 },
2 route: { 21 route: {
22 users: 'users',
23 usersList: 'user list',
24 shopers: 'shoper suply chain',
25 prods: 'products',
26 orders: 'orders',
27 sites: 'sites',
28 metas: {
29 metas: '元',
30 list: '树'
31 },
32 systems: {
33 systems: '系统设置',
34 sites: '站点设置',
35 money: '货币设置',
36 industry: '行业设置',
37 template: '模版设置'
38 },
39 // 添加的新词条------end
3 dashboard: 'Panel de control', 40 dashboard: 'Panel de control',
4 documentation: 'Documentación', 41 documentation: 'Documentación',
5 guide: 'Guía', 42 guide: 'Guía',
6 permission: 'Permisos', 43 permission: 'Permisos',
7 rolePermission: 'Permisos de rol', 44 rolePermission: 'Permisos de rol',
8 pagePermission: 'Permisos de la página', 45 pagePermission: 'Permisos de la página',
9 directivePermission: 'Permisos de la directiva', 46 directivePermission: 'Permisos de la directiva',
10 icons: 'Iconos', 47 icons: 'Iconos',
11 components: 'Componentes', 48 components: 'Componentes',
12 tinymce: 'Tinymce', 49 tinymce: 'Tinymce',
13 markdown: 'Markdown', 50 markdown: 'Markdown',
14 jsonEditor: 'Editor JSON', 51 jsonEditor: 'Editor JSON',
15 dndList: 'Lista Dnd', 52 dndList: 'Lista Dnd',
16 splitPane: 'Panel dividido', 53 splitPane: 'Panel dividido',
17 avatarUpload: 'Subir avatar', 54 avatarUpload: 'Subir avatar',
18 dropzone: 'Subir ficheros', 55 dropzone: 'Subir ficheros',
19 sticky: 'Sticky', 56 sticky: 'Sticky',
20 countTo: 'CountTo', 57 countTo: 'CountTo',
21 componentMixin: 'Mixin', 58 componentMixin: 'Mixin',
22 backToTop: 'Ir arriba', 59 backToTop: 'Ir arriba',
23 dragDialog: 'Drag Dialog', 60 dragDialog: 'Drag Dialog',
24 dragSelect: 'Drag Select', 61 dragSelect: 'Drag Select',
25 dragKanban: 'Drag Kanban', 62 dragKanban: 'Drag Kanban',
26 charts: 'Gráficos', 63 charts: 'Gráficos',
27 keyboardChart: 'Keyboard Chart', 64 keyboardChart: 'Keyboard Chart',
28 lineChart: 'Gráfico de líneas', 65 lineChart: 'Gráfico de líneas',
29 mixChart: 'Mix Chart', 66 mixChart: 'Mix Chart',
30 example: 'Ejemplo', 67 example: 'Ejemplo',
31 nested: 'Rutas anidadass', 68 nested: 'Rutas anidadass',
32 menu1: 'Menu 1', 69 menu1: 'Menu 1',
33 'menu1-1': 'Menu 1-1', 70 'menu1-1': 'Menu 1-1',
34 'menu1-2': 'Menu 1-2', 71 'menu1-2': 'Menu 1-2',
35 'menu1-2-1': 'Menu 1-2-1', 72 'menu1-2-1': 'Menu 1-2-1',
36 'menu1-2-2': 'Menu 1-2-2', 73 'menu1-2-2': 'Menu 1-2-2',
37 'menu1-3': 'Menu 1-3', 74 'menu1-3': 'Menu 1-3',
38 menu2: 'Menu 2', 75 menu2: 'Menu 2',
39 Table: 'Tabla', 76 Table: 'Tabla',
40 dynamicTable: 'Tabla dinámica', 77 dynamicTable: 'Tabla dinámica',
41 dragTable: 'Arrastrar tabla', 78 dragTable: 'Arrastrar tabla',
42 inlineEditTable: 'Editor', 79 inlineEditTable: 'Editor',
43 complexTable: 'Complex Table', 80 complexTable: 'Complex Table',
44 tab: 'Pestaña', 81 tab: 'Pestaña',
45 form: 'Formulario', 82 form: 'Formulario',
46 createArticle: 'Crear artículo', 83 createArticle: 'Crear artículo',
47 editArticle: 'Editar artículo', 84 editArticle: 'Editar artículo',
48 articleList: 'Listado de artículos', 85 articleList: 'Listado de artículos',
49 errorPages: 'Páginas de error', 86 errorPages: 'Páginas de error',
50 page401: '401', 87 page401: '401',
51 page404: '404', 88 page404: '404',
52 errorLog: 'Registro de errores', 89 errorLog: 'Registro de errores',
53 excel: 'Excel', 90 excel: 'Excel',
54 exportExcel: 'Exportar a Excel', 91 exportExcel: 'Exportar a Excel',
55 selectExcel: 'Export seleccionado', 92 selectExcel: 'Export seleccionado',
56 mergeHeader: 'Merge Header', 93 mergeHeader: 'Merge Header',
57 uploadExcel: 'Subir Excel', 94 uploadExcel: 'Subir Excel',
58 zip: 'Zip', 95 zip: 'Zip',
59 pdf: 'PDF', 96 pdf: 'PDF',
60 exportZip: 'Exportar a Zip', 97 exportZip: 'Exportar a Zip',
61 theme: 'Tema', 98 theme: 'Tema',
62 clipboardDemo: 'Clipboard', 99 clipboardDemo: 'Clipboard',
63 i18n: 'I18n', 100 i18n: 'I18n',
64 externalLink: 'Enlace externo', 101 externalLink: 'Enlace externo',
65 profile: 'Profile' 102 profile: 'Profile'
66 }, 103 },
67 navbar: { 104 navbar: {
68 logOut: 'Salir', 105 logOut: 'Salir',
69 dashboard: 'Panel de control', 106 dashboard: 'Panel de control',
70 github: 'Github', 107 github: 'Github',
71 theme: 'Tema', 108 theme: 'Tema',
72 size: 'Tamaño global', 109 size: 'Tamaño global',
73 profile: 'Profile' 110 profile: 'Profile'
74 }, 111 },
75 login: { 112 login: {
113 runner: 'officer Runner',
114 shoper: 'shop of Suply Chain',
115 assistant: 'worker in system',
116 signup: 'sign up',
117 forgetpassword: 'forget password',
118 rememberpassword: 'remember password',
119
76 title: 'Formulario de acceso', 120 title: 'Formulario de acceso',
77 logIn: 'Acceso', 121 logIn: 'Acceso',
78 username: 'Usuario', 122 username: 'Usuario',
79 password: 'Contraseña', 123 password: 'Contraseña',
80 any: 'nada', 124 any: 'nada',
81 thirdparty: 'Conectar con', 125 thirdparty: 'Conectar con',
82 thirdpartyTips: 'No se puede simular en local, así que combine su propia simulación de negocios. ! !' 126 thirdpartyTips: 'No se puede simular en local, así que combine su propia simulación de negocios. ! !'
83 }, 127 },
84 documentation: { 128 documentation: {
85 documentation: 'Documentación', 129 documentation: 'Documentación',
86 github: 'Repositorio Github' 130 github: 'Repositorio Github'
87 }, 131 },
88 permission: { 132 permission: {
89 addRole: 'Nuevo rol', 133 addRole: 'Nuevo rol',
90 editPermission: 'Permiso de edición', 134 editPermission: 'Permiso de edición',
91 roles: 'Tus permisos', 135 roles: 'Tus permisos',
92 switchRoles: 'Cambiar permisos', 136 switchRoles: 'Cambiar permisos',
93 tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.', 137 tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.',
94 delete: 'Borrar', 138 delete: 'Borrar',
95 confirm: 'Confirmar', 139 confirm: 'Confirmar',
96 cancel: 'Cancelar' 140 cancel: 'Cancelar'
97 }, 141 },
98 guide: { 142 guide: {
99 description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ', 143 description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
100 button: 'Ver guía' 144 button: 'Ver guía'
101 }, 145 },
102 components: { 146 components: {
103 documentation: 'Documentación', 147 documentation: 'Documentación',
104 tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.', 148 tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.',
105 dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.', 149 dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
106 stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.', 150 stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
107 backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner', 151 backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
108 backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally', 152 backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally',
109 imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.' 153 imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.'
110 }, 154 },
111 table: { 155 table: {
112 dynamicTips1: 'Fixed header, sorted by header order', 156 dynamicTips1: 'Fixed header, sorted by header order',
113 dynamicTips2: 'Not fixed header, sorted by click order', 157 dynamicTips2: 'Not fixed header, sorted by click order',
114 dragTips1: 'Orden por defecto', 158 dragTips1: 'Orden por defecto',
115 dragTips2: 'The after dragging order', 159 dragTips2: 'The after dragging order',
116 title: 'Título', 160 title: 'Título',
117 importance: 'Importancia', 161 importance: 'Importancia',
118 type: 'Tipo', 162 type: 'Tipo',
119 remark: 'Remark', 163 remark: 'Remark',
120 search: 'Buscar', 164 search: 'Buscar',
121 add: 'Añadir', 165 add: 'Añadir',
122 export: 'Exportar', 166 export: 'Exportar',
123 reviewer: 'reviewer', 167 reviewer: 'reviewer',
124 id: 'ID', 168 id: 'ID',
125 date: 'Fecha', 169 date: 'Fecha',
126 author: 'Autor', 170 author: 'Autor',
127 readings: 'Lector', 171 readings: 'Lector',
128 status: 'Estado', 172 status: 'Estado',
129 actions: 'Acciones', 173 actions: 'Acciones',
130 edit: 'Editar', 174 edit: 'Editar',
131 publish: 'Publicar', 175 publish: 'Publicar',
132 draft: 'Draft', 176 draft: 'Draft',
133 delete: 'Eliminar', 177 delete: 'Eliminar',
134 cancel: 'Cancelar', 178 cancel: 'Cancelar',
135 confirm: 'Confirmar' 179 confirm: 'Confirmar'
136 }, 180 },
137 example: { 181 example: {
138 warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details' 182 warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
139 }, 183 },
140 errorLog: { 184 errorLog: {
141 tips: 'Please click the bug icon in the upper right corner', 185 tips: 'Please click the bug icon in the upper right corner',
142 description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.', 186 description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
143 documentation: 'Documento de introducción' 187 documentation: 'Documento de introducción'
144 }, 188 },
145 excel: { 189 excel: {
146 export: 'Exportar', 190 export: 'Exportar',
147 selectedExport: 'Exportar seleccionados', 191 selectedExport: 'Exportar seleccionados',
148 placeholder: 'Por favor escribe un nombre de fichero' 192 placeholder: 'Por favor escribe un nombre de fichero'
149 }, 193 },
150 zip: { 194 zip: {
151 export: 'Exportar', 195 export: 'Exportar',
152 placeholder: 'Por favor escribe un nombre de fichero' 196 placeholder: 'Por favor escribe un nombre de fichero'
153 }, 197 },
154 pdf: { 198 pdf: {
155 tips: 'Here we use window.print() to implement the feature of downloading pdf.' 199 tips: 'Here we use window.print() to implement the feature of downloading pdf.'
156 }, 200 },
157 theme: { 201 theme: {
158 change: 'Cambiar tema', 202 change: 'Cambiar tema',
159 documentation: 'Documentación del tema', 203 documentation: 'Documentación del tema',
160 tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.' 204 tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.'
161 }, 205 },
162 tagsView: { 206 tagsView: {
163 refresh: 'Actualizar', 207 refresh: 'Actualizar',
164 close: 'Cerrar', 208 close: 'Cerrar',
165 closeOthers: 'Cerrar otros', 209 closeOthers: 'Cerrar otros',
166 closeAll: 'Cerrar todos' 210 closeAll: 'Cerrar todos'
167 }, 211 },
168 settings: { 212 settings: {
169 title: 'Page style setting', 213 title: 'Page style setting',
170 theme: 'Theme Color', 214 theme: 'Theme Color',
171 tagsView: 'Open Tags-View', 215 tagsView: 'Open Tags-View',
172 fixedHeader: 'Fixed Header', 216 fixedHeader: 'Fixed Header',
173 sidebarLogo: 'Sidebar Logo' 217 sidebarLogo: 'Sidebar Logo'
174 } 218 }
175 } 219 }
176 220
1 export default { 1 export default {
2 // 添加的新词条------start
3 prod: {
4 menu_title: 'products'
5 },
6 order: {
7
8 },
9 users: {
10
11 },
12 site: {
13
14 },
15 meta: {
16
17 },
18 system: {
19 memu: '系统'
20 },
2 route: { 21 route: {
22 users: 'users',
23 usersList: 'user list',
24 shopers: 'shoper suply chain',
25 prods: 'products',
26 orders: 'orders',
27 sites: 'sites',
28 metas: {
29 metas: '元',
30 list: '树'
31 },
32 systems: {
33 systems: '系统设置',
34 sites: '站点设置',
35 money: '货币设置',
36 industry: '行业设置',
37 template: '模版设置'
38 },
39 // 添加的新词条------end
3 dashboard: 'トップ', 40 dashboard: 'トップ',
4 documentation: 'ドキュメント', 41 documentation: 'ドキュメント',
5 guide: 'ガイド', 42 guide: 'ガイド',
6 permission: '権限', 43 permission: '権限',
7 rolePermission: '権限ロール', 44 rolePermission: '権限ロール',
8 pagePermission: 'ページ権限', 45 pagePermission: 'ページ権限',
9 directivePermission: 'ディレクティブ権限', 46 directivePermission: 'ディレクティブ権限',
10 icons: 'アイコン', 47 icons: 'アイコン',
11 components: 'コンポーネント', 48 components: 'コンポーネント',
12 tinymce: 'TinyMCE', 49 tinymce: 'TinyMCE',
13 markdown: 'Markdown', 50 markdown: 'Markdown',
14 jsonEditor: 'JSON Editor', 51 jsonEditor: 'JSON Editor',
15 dndList: 'Drag-And-Drop', 52 dndList: 'Drag-And-Drop',
16 splitPane: 'パネル', 53 splitPane: 'パネル',
17 avatarUpload: 'アバターアップロード', 54 avatarUpload: 'アバターアップロード',
18 dropzone: 'Dropzone', 55 dropzone: 'Dropzone',
19 sticky: 'Sticky', 56 sticky: 'Sticky',
20 countTo: 'Count To', 57 countTo: 'Count To',
21 componentMixin: 'コンポーネントMixin', 58 componentMixin: 'コンポーネントMixin',
22 backToTop: 'BackToTop', 59 backToTop: 'BackToTop',
23 dragDialog: 'Drag Dialog', 60 dragDialog: 'Drag Dialog',
24 dragSelect: 'Drag Select', 61 dragSelect: 'Drag Select',
25 dragKanban: 'Drag 看板', 62 dragKanban: 'Drag 看板',
26 charts: 'チャート', 63 charts: 'チャート',
27 keyboardChart: 'Keyboardチャート', 64 keyboardChart: 'Keyboardチャート',
28 lineChart: 'Lineチャート', 65 lineChart: 'Lineチャート',
29 mixChart: 'Mixチャート', 66 mixChart: 'Mixチャート',
30 example: 'Example', 67 example: 'Example',
31 nested: 'Nested Routes', 68 nested: 'Nested Routes',
32 menu1: 'メニュー1', 69 menu1: 'メニュー1',
33 'menu1-1': 'メニュー 1-1', 70 'menu1-1': 'メニュー 1-1',
34 'menu1-2': 'メニュー 1-2', 71 'menu1-2': 'メニュー 1-2',
35 'menu1-2-1': 'メニュー 1-2-1', 72 'menu1-2-1': 'メニュー 1-2-1',
36 'menu1-2-2': 'メニュー 1-2-2', 73 'menu1-2-2': 'メニュー 1-2-2',
37 'menu1-3': 'メニュー 1-3', 74 'menu1-3': 'メニュー 1-3',
38 menu2: 'メニュー 2', 75 menu2: 'メニュー 2',
39 Table: 'Table', 76 Table: 'Table',
40 dynamicTable: '可変 Table', 77 dynamicTable: '可変 Table',
41 dragTable: 'Drag Table', 78 dragTable: 'Drag Table',
42 inlineEditTable: 'Inline Edit Table', 79 inlineEditTable: 'Inline Edit Table',
43 complexTable: 'Complex Table', 80 complexTable: 'Complex Table',
44 tab: 'Tab', 81 tab: 'Tab',
45 form: 'フォーム', 82 form: 'フォーム',
46 createArticle: '投稿作成', 83 createArticle: '投稿作成',
47 editArticle: '投稿編集', 84 editArticle: '投稿編集',
48 articleList: '投稿リスト', 85 articleList: '投稿リスト',
49 errorPages: 'エラーページ', 86 errorPages: 'エラーページ',
50 page401: '401', 87 page401: '401',
51 page404: '404', 88 page404: '404',
52 errorLog: 'エラーログ', 89 errorLog: 'エラーログ',
53 excel: 'Excel', 90 excel: 'Excel',
54 exportExcel: '一括エクスポート', 91 exportExcel: '一括エクスポート',
55 selectExcel: '複数選択エクスポート', 92 selectExcel: '複数選択エクスポート',
56 mergeHeader: 'ヘッダーマージ', 93 mergeHeader: 'ヘッダーマージ',
57 uploadExcel: 'アップロード', 94 uploadExcel: 'アップロード',
58 zip: 'Zip', 95 zip: 'Zip',
59 pdf: 'PDF', 96 pdf: 'PDF',
60 exportZip: 'Export Zip', 97 exportZip: 'Export Zip',
61 theme: 'テーマ変更', 98 theme: 'テーマ変更',
62 clipboardDemo: 'Clipboard', 99 clipboardDemo: 'Clipboard',
63 i18n: '多言語', 100 i18n: '多言語',
64 externalLink: '外部リンク', 101 externalLink: '外部リンク',
65 profile: 'プロフィール' 102 profile: 'プロフィール'
66 }, 103 },
67 navbar: { 104 navbar: {
68 dashboard: 'トップ', 105 dashboard: 'トップ',
69 github: 'GitHub', 106 github: 'GitHub',
70 logOut: 'ログアウト', 107 logOut: 'ログアウト',
71 profile: 'プロフィール', 108 profile: 'プロフィール',
72 theme: 'テーマ変更', 109 theme: 'テーマ変更',
73 size: '画面サイズ' 110 size: '画面サイズ'
74 }, 111 },
75 login: { 112 login: {
113 runner: 'officer Runner',
114 shoper: 'shop of Suply Chain',
115 assistant: 'worker in system',
116 signup: 'sign up',
117 forgetpassword: 'forget password',
118 rememberpassword: 'remember password',
119
76 title: 'ユーザログイン', 120 title: 'ユーザログイン',
77 logIn: 'ログイン', 121 logIn: 'ログイン',
78 username: 'ユーザ名', 122 username: 'ユーザ名',
79 password: 'パスワード', 123 password: 'パスワード',
80 any: 'password', 124 any: 'password',
81 thirdparty: '外部IDでログイン', 125 thirdparty: '外部IDでログイン',
82 thirdpartyTips: 'ローカル環境ではログインできません。実装が必要です。' 126 thirdpartyTips: 'ローカル環境ではログインできません。実装が必要です。'
83 }, 127 },
84 documentation: { 128 documentation: {
85 documentation: 'ドキュメント', 129 documentation: 'ドキュメント',
86 github: 'Github Link' 130 github: 'Github Link'
87 }, 131 },
88 permission: { 132 permission: {
89 addRole: 'ロール追加', 133 addRole: 'ロール追加',
90 editPermission: 'ロール変更', 134 editPermission: 'ロール変更',
91 roles: 'ロール', 135 roles: 'ロール',
92 switchRoles: 'ロール切替', 136 switchRoles: 'ロール切替',
93 tips: 'v-permissionは使えない時があります。例えば: Element-UI の el-tab、 el-table-column 及び他の dom。v-ifを使う必要があります。', 137 tips: 'v-permissionは使えない時があります。例えば: Element-UI の el-tab、 el-table-column 及び他の dom。v-ifを使う必要があります。',
94 delete: '削除', 138 delete: '削除',
95 confirm: '確認', 139 confirm: '確認',
96 cancel: 'キャンセル' 140 cancel: 'キャンセル'
97 }, 141 },
98 guide: { 142 guide: {
99 description: 'ガイドは各機能の説明です。', 143 description: 'ガイドは各機能の説明です。',
100 button: 'ガイドを見る' 144 button: 'ガイドを見る'
101 }, 145 },
102 components: { 146 components: {
103 documentation: 'ドキュメント', 147 documentation: 'ドキュメント',
104 tinymceTips: 'tinymceは管理画面に重要な機能ですが、その同時に落とし穴がありあす。tinymceを使う道のりが大変でした。Tinymceを使う時に各自のプロジェクト状況で判断が必要です。ドキュメントはこちら', 148 tinymceTips: 'tinymceは管理画面に重要な機能ですが、その同時に落とし穴がありあす。tinymceを使う道のりが大変でした。Tinymceを使う時に各自のプロジェクト状況で判断が必要です。ドキュメントはこちら',
105 dropzoneTips: 'Third partyのパッケージを使わず、独自の実装しています。詳細は @/components/Dropzone', 149 dropzoneTips: 'Third partyのパッケージを使わず、独自の実装しています。詳細は @/components/Dropzone',
106 stickyTips: 'ページの指定位置へスクロールした場合、表示されます。', 150 stickyTips: 'ページの指定位置へスクロールした場合、表示されます。',
107 backToTopTips1: 'トップへスクロールが表示されます。', 151 backToTopTips1: 'トップへスクロールが表示されます。',
108 backToTopTips2: 'ボタンのスタイルはカスタマイズできます。例えば、show/hide、height、position。 またはElementのel-tooltipを使って、ツールチップを実装できます。', 152 backToTopTips2: 'ボタンのスタイルはカスタマイズできます。例えば、show/hide、height、position。 またはElementのel-tooltipを使って、ツールチップを実装できます。',
109 imageUploadTips: 'mockjsは使えないため、カスタマイズしています。公式の最新バージョンを使ってください。' 153 imageUploadTips: 'mockjsは使えないため、カスタマイズしています。公式の最新バージョンを使ってください。'
110 }, 154 },
111 table: { 155 table: {
112 dynamicTips1: '先頭は固定、最後に追加', 156 dynamicTips1: '先頭は固定、最後に追加',
113 dynamicTips2: '戦後に追加せず、指定列に追加', 157 dynamicTips2: '戦後に追加せず、指定列に追加',
114 dragTips1: 'デフォルト順番', 158 dragTips1: 'デフォルト順番',
115 dragTips2: 'Drag後の順番', 159 dragTips2: 'Drag後の順番',
116 title: 'タイトル', 160 title: 'タイトル',
117 importance: '重要', 161 importance: '重要',
118 type: 'タイプ', 162 type: 'タイプ',
119 remark: '評価', 163 remark: '評価',
120 search: '検索', 164 search: '検索',
121 add: '追加', 165 add: '追加',
122 export: 'エクスポート', 166 export: 'エクスポート',
123 reviewer: 'レビュアー', 167 reviewer: 'レビュアー',
124 id: '番号', 168 id: '番号',
125 date: '日時', 169 date: '日時',
126 author: '作成者', 170 author: '作成者',
127 readings: '閲覧数', 171 readings: '閲覧数',
128 status: 'ステータス', 172 status: 'ステータス',
129 actions: '操作', 173 actions: '操作',
130 edit: '編集', 174 edit: '編集',
131 publish: '公開', 175 publish: '公開',
132 draft: '下書き', 176 draft: '下書き',
133 delete: 'キャンセル', 177 delete: 'キャンセル',
134 cancel: 'キャンセル', 178 cancel: 'キャンセル',
135 confirm: '確認' 179 confirm: '確認'
136 }, 180 },
137 example: { 181 example: {
138 warning: '新規作成と編集画面は keep-alive を使えないです。keep-alive の include はrouteのキャッシュは使えないです。そのため、component name を使ってキャッシュさせるようにします。このようなキャッシュ機能を作りたい場合,localStorageを使う手があります。もしくは keep-alive の includeを使って、全ページキャッシュする方法はあります。' 182 warning: '新規作成と編集画面は keep-alive を使えないです。keep-alive の include はrouteのキャッシュは使えないです。そのため、component name を使ってキャッシュさせるようにします。このようなキャッシュ機能を作りたい場合,localStorageを使う手があります。もしくは keep-alive の includeを使って、全ページキャッシュする方法はあります。'
139 }, 183 },
140 errorLog: { 184 errorLog: {
141 tips: '右上のbugアイコンをクリックしてください。', 185 tips: '右上のbugアイコンをクリックしてください。',
142 description: '管理画面はspaを使う場合が多い、ユーザ体現向上はできますが、想定外エラーが発生する場合があります。Vueはそのエラーハンドリング機能を提供し、エラーレポートができます。', 186 description: '管理画面はspaを使う場合が多い、ユーザ体現向上はできますが、想定外エラーが発生する場合があります。Vueはそのエラーハンドリング機能を提供し、エラーレポートができます。',
143 documentation: 'ドキュメント' 187 documentation: 'ドキュメント'
144 }, 188 },
145 excel: { 189 excel: {
146 export: 'エクスポート', 190 export: 'エクスポート',
147 selectedExport: 'エクスポート対象を選択してください。', 191 selectedExport: 'エクスポート対象を選択してください。',
148 placeholder: 'ファイル名を入力してください。' 192 placeholder: 'ファイル名を入力してください。'
149 }, 193 },
150 zip: { 194 zip: {
151 export: 'エクスポート', 195 export: 'エクスポート',
152 placeholder: 'ファイル名を入力してください。' 196 placeholder: 'ファイル名を入力してください。'
153 }, 197 },
154 pdf: { 198 pdf: {
155 tips: 'window.print() を使ってPDFダウンロードしています。' 199 tips: 'window.print() を使ってPDFダウンロードしています。'
156 }, 200 },
157 theme: { 201 theme: {
158 change: 'テーマ切替', 202 change: 'テーマ切替',
159 documentation: 'ドキュメント', 203 documentation: 'ドキュメント',
160 tips: 'Tips: テーマの切り替え方法はnavbarのtheme-pickと異なります、使い方はドキュメントを確認してください。' 204 tips: 'Tips: テーマの切り替え方法はnavbarのtheme-pickと異なります、使い方はドキュメントを確認してください。'
161 }, 205 },
162 tagsView: { 206 tagsView: {
163 refresh: '更新', 207 refresh: '更新',
164 close: '閉じる', 208 close: '閉じる',
165 closeOthers: 'その他閉じる', 209 closeOthers: 'その他閉じる',
166 closeAll: 'すべて閉じる' 210 closeAll: 'すべて閉じる'
167 }, 211 },
168 settings: { 212 settings: {
169 title: 'システムテーマ', 213 title: 'システムテーマ',
170 theme: 'テーマ色', 214 theme: 'テーマ色',
171 tagsView: 'Tags-View 開く', 215 tagsView: 'Tags-View 開く',
172 fixedHeader: 'Fixed Header', 216 fixedHeader: 'Fixed Header',
173 sidebarLogo: 'Sidebar Logo' 217 sidebarLogo: 'Sidebar Logo'
174 } 218 }
175 } 219 }
176 220
1 export default { 1 export default {
2 // 添加的新词条------start
3 prod: {
4 menu_title: 'products'
5 },
6 order: {
7
8 },
9 users: {
10
11 },
12 site: {
13
14 },
15 meta: {
16
17 },
18 system: {
19 memu: '系统'
20 },
2 route: { 21 route: {
22 users: '用户',
23 usersList: '列表',
24 shopers: '厂商',
25 prods: '产品',
26 orders: '订单',
27 sites: '站点',
28 metas: {
29 metas: '元',
30 list: '树'
31 },
32 systems: {
33 systems: '系统设置',
34 sites: '站点设置',
35 money: '货币设置',
36 industry: '行业设置',
37 template: '模版设置'
38 },
39 // 添加的新词条------end
3 dashboard: '首页', 40 dashboard: '首页',
4 documentation: '文档', 41 documentation: '文档',
5 guide: '引导页', 42 guide: '引导页',
6 permission: '权限测试页', 43 permission: '权限测试页',
7 rolePermission: '角色权限', 44 rolePermission: '角色权限',
8 pagePermission: '页面权限', 45 pagePermission: '页面权限',
9 directivePermission: '指令权限', 46 directivePermission: '指令权限',
10 icons: '图标', 47 icons: '图标',
11 components: '组件', 48 components: '组件',
12 tinymce: '富文本编辑器', 49 tinymce: '富文本编辑器',
13 markdown: 'Markdown', 50 markdown: 'Markdown',
14 jsonEditor: 'JSON 编辑器', 51 jsonEditor: 'JSON 编辑器',
15 dndList: '列表拖拽', 52 dndList: '列表拖拽',
16 splitPane: 'Splitpane', 53 splitPane: 'Splitpane',
17 avatarUpload: '头像上传', 54 avatarUpload: '头像上传',
18 dropzone: 'Dropzone', 55 dropzone: 'Dropzone',
19 sticky: 'Sticky', 56 sticky: 'Sticky',
20 countTo: 'Count To', 57 countTo: 'Count To',
21 componentMixin: '小组件', 58 componentMixin: '小组件',
22 backToTop: '返回顶部', 59 backToTop: '返回顶部',
23 dragDialog: '拖拽 Dialog', 60 dragDialog: '拖拽 Dialog',
24 dragSelect: '拖拽 Select', 61 dragSelect: '拖拽 Select',
25 dragKanban: '可拖拽看板', 62 dragKanban: '可拖拽看板',
26 charts: '图表', 63 charts: '图表',
27 keyboardChart: '键盘图表', 64 keyboardChart: '键盘图表',
28 lineChart: '折线图', 65 lineChart: '折线图',
29 mixChart: '混合图表', 66 mixChart: '混合图表',
30 example: '综合实例', 67 example: '综合实例',
31 nested: '路由嵌套', 68 nested: '路由嵌套',
32 menu1: '菜单1', 69 menu1: '菜单1',
33 'menu1-1': '菜单 1-1', 70 'menu1-1': '菜单 1-1',
34 'menu1-2': '菜单 1-2', 71 'menu1-2': '菜单 1-2',
35 'menu1-2-1': '菜单 1-2-1', 72 'menu1-2-1': '菜单 1-2-1',
36 'menu1-2-2': '菜单 1-2-2', 73 'menu1-2-2': '菜单 1-2-2',
37 'menu1-3': '菜单 1-3', 74 'menu1-3': '菜单 1-3',
38 menu2: '菜单 2', 75 menu2: '菜单 2',
39 Table: 'Table', 76 Table: 'Table',
40 dynamicTable: '动态 Table', 77 dynamicTable: '动态 Table',
41 dragTable: '拖拽 Table', 78 dragTable: '拖拽 Table',
42 inlineEditTable: 'Table 内编辑', 79 inlineEditTable: 'Table 内编辑',
43 complexTable: '综合 Table', 80 complexTable: '综合 Table',
44 tab: 'Tab', 81 tab: 'Tab',
45 form: '表单', 82 form: '表单',
46 createArticle: '创建文章', 83 createArticle: '创建文章',
47 editArticle: '编辑文章', 84 editArticle: '编辑文章',
48 articleList: '文章列表', 85 articleList: '文章列表',
49 errorPages: '错误页面', 86 errorPages: '错误页面',
50 page401: '401', 87 page401: '401',
51 page404: '404', 88 page404: '404',
52 errorLog: '错误日志', 89 errorLog: '错误日志',
53 excel: 'Excel', 90 excel: 'Excel',
54 exportExcel: '导出 Excel', 91 exportExcel: '导出 Excel',
55 selectExcel: '导出 已选择项', 92 selectExcel: '导出 已选择项',
56 mergeHeader: '导出 多级表头', 93 mergeHeader: '导出 多级表头',
57 uploadExcel: '上传 Excel', 94 uploadExcel: '上传 Excel',
58 zip: 'Zip', 95 zip: 'Zip',
59 pdf: 'PDF', 96 pdf: 'PDF',
60 exportZip: 'Export Zip', 97 exportZip: 'Export Zip',
61 theme: '换肤', 98 theme: '换肤',
62 clipboardDemo: 'Clipboard', 99 clipboardDemo: 'Clipboard',
63 i18n: '国际化', 100 i18n: '国际化',
64 externalLink: '外链', 101 externalLink: '外链',
65 profile: '个人中心' 102 profile: '个人中心'
66 }, 103 },
67 navbar: { 104 navbar: {
68 dashboard: '首页', 105 dashboard: '首页',
69 github: '项目地址', 106 github: '项目地址',
70 logOut: '退出登录', 107 logOut: '退出登录',
71 profile: '个人中心', 108 profile: '个人中心',
72 theme: '换肤', 109 theme: '换肤',
73 size: '布局大小' 110 size: '布局大小'
74 }, 111 },
75 login: { 112 login: {
76 title: '系统登录', 113 runner: '运营官',
114 shoper: '商家',
115 assistant: '操作员',
116 signup: '注册',
117 forgetpassword: '忘记密码',
118 rememberpassword: 'remember password',
119
120 title: '鱼皮出海',
77 logIn: '登录', 121 logIn: '登录',
78 username: '账号', 122 username: '账号',
79 password: '密码', 123 password: '密码',
80 any: '随便填', 124 any: '随便填',
81 thirdparty: '第三方登录', 125 thirdparty: '第三方登录',
82 thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!' 126 thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
83 }, 127 },
84 documentation: { 128 documentation: {
85 documentation: '文档', 129 documentation: '文档',
86 github: 'Github 地址' 130 github: 'Github 地址'
87 }, 131 },
88 permission: { 132 permission: {
89 addRole: '新增角色', 133 addRole: '新增角色',
90 editPermission: '编辑权限', 134 editPermission: '编辑权限',
91 roles: '你的权限', 135 roles: '你的权限',
92 switchRoles: '切换权限', 136 switchRoles: '切换权限',
93 tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。', 137 tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
94 delete: '删除', 138 delete: '删除',
95 confirm: '确定', 139 confirm: '确定',
96 cancel: '取消' 140 cancel: '取消'
97 }, 141 },
98 guide: { 142 guide: {
99 description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于', 143 description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于',
100 button: '打开引导' 144 button: '打开引导'
101 }, 145 },
102 components: { 146 components: {
103 documentation: '文档', 147 documentation: '文档',
104 tinymceTips: '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见', 148 tinymceTips: '富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路,市面上常见的富文本都基本用过了,最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见',
105 dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone', 149 dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone',
106 stickyTips: '当页面滚动到预设的位置会吸附在顶部', 150 stickyTips: '当页面滚动到预设的位置会吸附在顶部',
107 backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮', 151 backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮',
108 backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素', 152 backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示,可在外部使用Element的el-tooltip元素',
109 imageUploadTips: '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。' 153 imageUploadTips: '由于我在使用时它只有vue@1版本,而且和mockjs不兼容,所以自己改造了一下,如果大家要使用的话,优先还是使用官方版本。'
110 }, 154 },
111 table: { 155 table: {
112 dynamicTips1: '固定表头, 按照表头顺序排序', 156 dynamicTips1: '固定表头, 按照表头顺序排序',
113 dynamicTips2: '不固定表头, 按照点击顺序排序', 157 dynamicTips2: '不固定表头, 按照点击顺序排序',
114 dragTips1: '默认顺序', 158 dragTips1: '默认顺序',
115 dragTips2: '拖拽后顺序', 159 dragTips2: '拖拽后顺序',
116 title: '标题', 160 title: '标题',
117 importance: '重要性', 161 importance: '重要性',
118 type: '类型', 162 type: '类型',
119 remark: '点评', 163 remark: '点评',
120 search: '搜索', 164 search: '搜索',
121 add: '添加', 165 add: '添加',
122 export: '导出', 166 export: '导出',
123 reviewer: '审核人', 167 reviewer: '审核人',
124 id: '序号', 168 id: '序号',
125 date: '时间', 169 date: '时间',
126 author: '作者', 170 author: '作者',
127 readings: '阅读数', 171 readings: '阅读数',
128 status: '状态', 172 status: '状态',
129 actions: '操作', 173 actions: '操作',
130 edit: '编辑', 174 edit: '编辑',
131 publish: '发布', 175 publish: '发布',
132 draft: '草稿', 176 draft: '草稿',
133 delete: '删除', 177 delete: '删除',
134 cancel: '取 消', 178 cancel: '取 消',
135 confirm: '确 定' 179 confirm: '确 定'
136 }, 180 },
137 example: { 181 example: {
138 warning: '创建和编辑页面是不能被 keep-alive 缓存的,因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include,直接缓存所有页面。详情见' 182 warning: '创建和编辑页面是不能被 keep-alive 缓存的,因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include,直接缓存所有页面。详情见'
139 }, 183 },
140 errorLog: { 184 errorLog: {
141 tips: '请点击右上角bug小图标', 185 tips: '请点击右上角bug小图标',
142 description: '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。', 186 description: '现在的管理后台基本都是spa的形式了,它增强了用户体验,但同时也会增加页面出问题的可能性,可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。',
143 documentation: '文档介绍' 187 documentation: '文档介绍'
144 }, 188 },
145 excel: { 189 excel: {
146 export: '导出', 190 export: '导出',
147 selectedExport: '导出已选择项', 191 selectedExport: '导出已选择项',
148 placeholder: '请输入文件名(默认excel-list)' 192 placeholder: '请输入文件名(默认excel-list)'
149 }, 193 },
150 zip: { 194 zip: {
151 export: '导出', 195 export: '导出',
152 placeholder: '请输入文件名(默认file)' 196 placeholder: '请输入文件名(默认file)'
153 }, 197 },
154 pdf: { 198 pdf: {
155 tips: '这里使用 window.print() 来实现下载pdf的功能' 199 tips: '这里使用 window.print() 来实现下载pdf的功能'
156 }, 200 },
157 theme: { 201 theme: {
158 change: '换肤', 202 change: '换肤',
159 documentation: '换肤文档', 203 documentation: '换肤文档',
160 tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。' 204 tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。'
161 }, 205 },
162 tagsView: { 206 tagsView: {
163 refresh: '刷新', 207 refresh: '刷新',
164 close: '关闭', 208 close: '关闭',
165 closeOthers: '关闭其它', 209 closeOthers: '关闭其它',
166 closeAll: '关闭所有' 210 closeAll: '关闭所有'
167 }, 211 },
168 settings: { 212 settings: {
169 title: '系统布局配置', 213 title: '系统布局配置',
170 theme: '主题色', 214 theme: '主题色',
171 tagsView: '开启 Tags-View', 215 tagsView: '开启 Tags-View',
172 fixedHeader: '固定 Header', 216 fixedHeader: '固定 Header',
173 sidebarLogo: '侧边栏 Logo' 217 sidebarLogo: '侧边栏 Logo'
174 } 218 }
175 } 219 }
176 220
src/layout/components/Navbar.vue
1 <template> 1 <template>
2 <div class="navbar"> 2 <div class="navbar">
3 <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> 3 <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
4 4
5 <breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> 5 <breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
6 6
7 <div class="right-menu"> 7 <div class="right-menu">
8 <template v-if="device!=='mobile'"> 8 <template v-if="device!=='mobile'">
9 <search id="header-search" class="right-menu-item" /> 9 <search id="header-search" class="right-menu-item" />
10 10
11 <error-log class="errLog-container right-menu-item hover-effect" /> 11 <error-log class="errLog-container right-menu-item hover-effect" />
12 12
13 <screenfull id="screenfull" class="right-menu-item hover-effect" /> 13 <screenfull id="screenfull" class="right-menu-item hover-effect" />
14 14
15 <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom"> 15 <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
16 <size-select id="size-select" class="right-menu-item hover-effect" /> 16 <size-select id="size-select" class="right-menu-item hover-effect" />
17 </el-tooltip> 17 </el-tooltip>
18 18
19 <lang-select class="right-menu-item hover-effect" /> 19 <lang-select class="right-menu-item hover-effect" />
20 20
21 </template> 21 </template>
22 22
23 <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> 23 <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
24 <div class="avatar-wrapper"> 24 <div class="avatar-wrapper">
25 <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> 25 <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
26 <i class="el-icon-caret-bottom" /> 26 <i class="el-icon-caret-bottom" />
27 </div> 27 </div>
28 <el-dropdown-menu slot="dropdown"> 28 <el-dropdown-menu slot="dropdown">
29 <router-link to="/profile/index"> 29 <router-link to="/profile/index">
30 <el-dropdown-item> 30 <el-dropdown-item>
31 {{ $t('navbar.profile') }} 31 {{ $t('navbar.profile') }}
32 </el-dropdown-item> 32 </el-dropdown-item>
33 </router-link> 33 </router-link>
34 <router-link to="/"> 34 <router-link to="/">
35 <el-dropdown-item> 35 <el-dropdown-item>
36 {{ $t('navbar.dashboard') }} 36 {{ $t('navbar.dashboard') }}
37 </el-dropdown-item> 37 </el-dropdown-item>
38 </router-link> 38 </router-link>
39 <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/"> 39 <!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
40 <el-dropdown-item> 40 <el-dropdown-item>
41 {{ $t('navbar.github') }} 41 {{ $t('navbar.github') }}
42 </el-dropdown-item> 42 </el-dropdown-item>
43 </a> 43 </a>
44 <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> 44 <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
45 <el-dropdown-item>Docs</el-dropdown-item> 45 <el-dropdown-item>Docs</el-dropdown-item>
46 </a> 46 </a> -->
47 <el-dropdown-item divided @click.native="logout"> 47 <el-dropdown-item divided @click.native="logout">
48 <span style="display:block;">{{ $t('navbar.logOut') }}</span> 48 <span style="display:block;">{{ $t('navbar.logOut') }}</span>
49 </el-dropdown-item> 49 </el-dropdown-item>
50 </el-dropdown-menu> 50 </el-dropdown-menu>
51 </el-dropdown> 51 </el-dropdown>
52 </div> 52 </div>
53 </div> 53 </div>
54 </template> 54 </template>
55 55
56 <script> 56 <script>
57 import { mapGetters } from 'vuex' 57 import { mapGetters } from 'vuex'
58 import Breadcrumb from '@/components/Breadcrumb' 58 import Breadcrumb from '@/components/Breadcrumb'
59 import Hamburger from '@/components/Hamburger' 59 import Hamburger from '@/components/Hamburger'
60 import ErrorLog from '@/components/ErrorLog' 60 import ErrorLog from '@/components/ErrorLog'
61 import Screenfull from '@/components/Screenfull' 61 import Screenfull from '@/components/Screenfull'
62 import SizeSelect from '@/components/SizeSelect' 62 import SizeSelect from '@/components/SizeSelect'
63 import LangSelect from '@/components/LangSelect' 63 import LangSelect from '@/components/LangSelect'
64 import Search from '@/components/HeaderSearch' 64 import Search from '@/components/HeaderSearch'
65 65
66 export default { 66 export default {
67 components: { 67 components: {
68 Breadcrumb, 68 Breadcrumb,
69 Hamburger, 69 Hamburger,
70 ErrorLog, 70 ErrorLog,
71 Screenfull, 71 Screenfull,
72 SizeSelect, 72 SizeSelect,
73 LangSelect, 73 LangSelect,
74 Search 74 Search
75 }, 75 },
76 computed: { 76 computed: {
77 ...mapGetters([ 77 ...mapGetters([
78 'sidebar', 78 'sidebar',
79 'avatar', 79 'avatar',
80 'device' 80 'device'
81 ]) 81 ])
82 }, 82 },
83 methods: { 83 methods: {
84 toggleSideBar() { 84 toggleSideBar() {
85 this.$store.dispatch('app/toggleSideBar') 85 this.$store.dispatch('app/toggleSideBar')
86 }, 86 },
87 async logout() { 87 async logout() {
88 await this.$store.dispatch('user/logout') 88 await this.$store.dispatch('user/logout')
89 this.$router.push(`/login?redirect=${this.$route.fullPath}`) 89 this.$router.push(`/login?redirect=${this.$route.fullPath}`)
90 } 90 }
91 } 91 }
92 } 92 }
93 </script> 93 </script>
94 94
95 <style lang="scss" scoped> 95 <style lang="scss" scoped>
96 .navbar { 96 .navbar {
97 height: 50px; 97 height: 50px;
98 overflow: hidden; 98 overflow: hidden;
99 position: relative; 99 position: relative;
100 background: #fff; 100 background: #fff;
101 box-shadow: 0 1px 4px rgba(0,21,41,.08); 101 box-shadow: 0 1px 4px rgba(0,21,41,.08);
102 102
103 .hamburger-container { 103 .hamburger-container {
104 line-height: 46px; 104 line-height: 46px;
105 height: 100%; 105 height: 100%;
106 float: left; 106 float: left;
107 cursor: pointer; 107 cursor: pointer;
108 transition: background .3s; 108 transition: background .3s;
109 -webkit-tap-highlight-color:transparent; 109 -webkit-tap-highlight-color:transparent;
110 110
111 &:hover { 111 &:hover {
112 background: rgba(0, 0, 0, .025) 112 background: rgba(0, 0, 0, .025)
113 } 113 }
114 } 114 }
115 115
116 .breadcrumb-container { 116 .breadcrumb-container {
117 float: left; 117 float: left;
118 } 118 }
119 119
120 .errLog-container { 120 .errLog-container {
121 display: inline-block; 121 display: inline-block;
122 vertical-align: top; 122 vertical-align: top;
123 } 123 }
124 124
125 .right-menu { 125 .right-menu {
126 float: right; 126 float: right;
127 height: 100%; 127 height: 100%;
128 line-height: 50px; 128 line-height: 50px;
129 129
130 &:focus { 130 &:focus {
131 outline: none; 131 outline: none;
132 } 132 }
133 133
134 .right-menu-item { 134 .right-menu-item {
135 display: inline-block; 135 display: inline-block;
136 padding: 0 8px; 136 padding: 0 8px;
137 height: 100%; 137 height: 100%;
138 font-size: 18px; 138 font-size: 18px;
139 color: #5a5e66; 139 color: #5a5e66;
140 vertical-align: text-bottom; 140 vertical-align: text-bottom;
141 141
142 &.hover-effect { 142 &.hover-effect {
143 cursor: pointer; 143 cursor: pointer;
144 transition: background .3s; 144 transition: background .3s;
145 145
146 &:hover { 146 &:hover {
147 background: rgba(0, 0, 0, .025) 147 background: rgba(0, 0, 0, .025)
148 } 148 }
149 } 149 }
150 } 150 }
151 151
152 .avatar-container { 152 .avatar-container {
153 margin-right: 30px; 153 margin-right: 30px;
154 154
155 .avatar-wrapper { 155 .avatar-wrapper {
156 margin-top: 5px; 156 margin-top: 5px;
157 position: relative; 157 position: relative;
158 158
159 .user-avatar { 159 .user-avatar {
160 cursor: pointer; 160 cursor: pointer;
161 width: 40px; 161 width: 40px;
162 height: 40px; 162 height: 40px;
163 border-radius: 10px; 163 border-radius: 10px;
164 } 164 }
165 165
166 .el-icon-caret-bottom { 166 .el-icon-caret-bottom {
167 cursor: pointer; 167 cursor: pointer;
168 position: absolute; 168 position: absolute;
169 right: -20px; 169 right: -20px;
170 top: 25px; 170 top: 25px;
171 font-size: 12px; 171 font-size: 12px;
172 } 172 }
173 } 173 }
174 } 174 }
175 } 175 }
176 } 176 }
177 </style> 177 </style>
178 178
src/layout/components/Settings/index.vue
1 <template> 1 <template>
2 <div class="drawer-container"> 2 <div class="drawer-container">
3 <div> 3 <div>
4 <h3 class="drawer-title">{{ $t('settings.title') }}</h3> 4 <h3 class="drawer-title">{{ $t('settings.title') }}</h3>
5 5
6 <div class="drawer-item"> 6 <div class="drawer-item">
7 <span>{{ $t('settings.theme') }}</span> 7 <span>{{ $t('settings.theme') }}</span>
8 <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" /> 8 <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
9 </div> 9 </div>
10 10
11 <div class="drawer-item"> 11 <div class="drawer-item">
12 <span>{{ $t('settings.tagsView') }}</span> 12 <span>{{ $t('settings.tagsView') }}</span>
13 <el-switch v-model="tagsView" class="drawer-switch" /> 13 <el-switch v-model="tagsView" class="drawer-switch" />
14 </div> 14 </div>
15 15
16 <div class="drawer-item"> 16 <div class="drawer-item">
17 <span>{{ $t('settings.fixedHeader') }}</span> 17 <span>{{ $t('settings.fixedHeader') }}</span>
18 <el-switch v-model="fixedHeader" class="drawer-switch" /> 18 <el-switch v-model="fixedHeader" class="drawer-switch" />
19 </div> 19 </div>
20 20
21 <div class="drawer-item"> 21 <div class="drawer-item">
22 <span>{{ $t('settings.sidebarLogo') }}</span> 22 <span>{{ $t('settings.sidebarLogo') }}</span>
23 <el-switch v-model="sidebarLogo" class="drawer-switch" /> 23 <el-switch v-model="sidebarLogo" class="drawer-switch" />
24 </div> 24 </div>
25 <a v-if="isShowJob" href="https://panjiachen.github.io/vue-element-admin-site/zh/job/" target="_blank" class="job-link"> 25
26 <a v-if="isShowJob" href="https://glass.xiuyetang.com/" target="_blank" class="job-link">
26 <el-alert 27 <el-alert
27 title="部门目前非常缺人!有兴趣的可以点击了解详情。坐标: 字节跳动" 28 title="鱼皮计划极为宏大,而且极为可行,我们要努力写代码,尽快打通任督二脉,要做好很有钱的思想准备"
28 type="success" 29 type="success"
29 :closable="false" 30 :closable="true"
30 /> 31 />
31 </a> 32 </a>
32 33
33 <div v-if="lang === 'zh'" class="drawer-item"> 34 <div v-if="lang === 'zh'" class="drawer-item">
34 <span>菜单支持拼音搜索</span> 35 <span>菜单支持拼音搜索</span>
35 <el-switch v-model="supportPinyinSearch" class="drawer-switch" /> 36 <el-switch v-model="supportPinyinSearch" class="drawer-switch" />
36 </div> 37 </div>
37 38
38 </div> 39 </div>
39 </div> 40 </div>
40 </template> 41 </template>
41 42
42 <script> 43 <script>
43 import ThemePicker from '@/components/ThemePicker' 44 import ThemePicker from '@/components/ThemePicker'
44 45
45 export default { 46 export default {
46 components: { ThemePicker }, 47 components: { ThemePicker },
47 data() { 48 data() {
48 return {} 49 return {}
49 }, 50 },
50 computed: { 51 computed: {
51 isShowJob() { 52 isShowJob() {
52 return this.$store.getters.language === 'zh' 53 return this.$store.getters.language === 'zh'
53 }, 54 },
54 fixedHeader: { 55 fixedHeader: {
55 get() { 56 get() {
56 return this.$store.state.settings.fixedHeader 57 return this.$store.state.settings.fixedHeader
57 }, 58 },
58 set(val) { 59 set(val) {
59 this.$store.dispatch('settings/changeSetting', { 60 this.$store.dispatch('settings/changeSetting', {
60 key: 'fixedHeader', 61 key: 'fixedHeader',
61 value: val 62 value: val
62 }) 63 })
63 } 64 }
64 }, 65 },
65 tagsView: { 66 tagsView: {
66 get() { 67 get() {
67 return this.$store.state.settings.tagsView 68 return this.$store.state.settings.tagsView
68 }, 69 },
69 set(val) { 70 set(val) {
70 this.$store.dispatch('settings/changeSetting', { 71 this.$store.dispatch('settings/changeSetting', {
71 key: 'tagsView', 72 key: 'tagsView',
72 value: val 73 value: val
73 }) 74 })
74 } 75 }
75 }, 76 },
76 sidebarLogo: { 77 sidebarLogo: {
77 get() { 78 get() {
78 return this.$store.state.settings.sidebarLogo 79 return this.$store.state.settings.sidebarLogo
79 }, 80 },
80 set(val) { 81 set(val) {
81 this.$store.dispatch('settings/changeSetting', { 82 this.$store.dispatch('settings/changeSetting', {
82 key: 'sidebarLogo', 83 key: 'sidebarLogo',
83 value: val 84 value: val
84 }) 85 })
85 } 86 }
86 }, 87 },
87 supportPinyinSearch: { 88 supportPinyinSearch: {
88 get() { 89 get() {
89 return this.$store.state.settings.supportPinyinSearch 90 return this.$store.state.settings.supportPinyinSearch
90 }, 91 },
91 set(val) { 92 set(val) {
92 this.$store.dispatch('settings/changeSetting', { 93 this.$store.dispatch('settings/changeSetting', {
93 key: 'supportPinyinSearch', 94 key: 'supportPinyinSearch',
94 value: val 95 value: val
95 }) 96 })
96 } 97 }
97 }, 98 },
98 lang() { 99 lang() {
99 return this.$store.getters.language 100 return this.$store.getters.language
100 } 101 }
101 }, 102 },
102 methods: { 103 methods: {
103 themeChange(val) { 104 themeChange(val) {
104 this.$store.dispatch('settings/changeSetting', { 105 this.$store.dispatch('settings/changeSetting', {
105 key: 'theme', 106 key: 'theme',
106 value: val 107 value: val
107 }) 108 })
108 } 109 }
109 } 110 }
110 } 111 }
111 </script> 112 </script>
112 113
113 <style lang="scss" scoped> 114 <style lang="scss" scoped>
114 .drawer-container { 115 .drawer-container {
115 padding: 24px; 116 padding: 24px;
116 font-size: 14px; 117 font-size: 14px;
117 line-height: 1.5; 118 line-height: 1.5;
118 word-wrap: break-word; 119 word-wrap: break-word;
119 120
120 .drawer-title { 121 .drawer-title {
121 margin-bottom: 12px; 122 margin-bottom: 12px;
122 color: rgba(0, 0, 0, .85); 123 color: rgba(0, 0, 0, .85);
123 font-size: 14px; 124 font-size: 14px;
124 line-height: 22px; 125 line-height: 22px;
125 } 126 }
126 127
127 .drawer-item { 128 .drawer-item {
128 color: rgba(0, 0, 0, .65); 129 color: rgba(0, 0, 0, .65);
129 font-size: 14px; 130 font-size: 14px;
130 padding: 12px 0; 131 padding: 12px 0;
131 } 132 }
132 133
133 .drawer-switch { 134 .drawer-switch {
134 float: right 135 float: right
135 } 136 }
136 137
137 .job-link{ 138 .job-link{
138 display: block; 139 display: block;
139 position: absolute; 140 position: absolute;
140 width: 100%; 141 width: 100%;
141 left: 0; 142 left: 0;
142 bottom: 0; 143 bottom: 0;
143 } 144 }
144 } 145 }
145 </style> 146 </style>
146 147
src/layout/components/Sidebar/Logo.vue
1 <template> 1 <template>
2 <div class="sidebar-logo-container" :class="{'collapse':collapse}"> 2 <div class="sidebar-logo-container" :class="{'collapse':collapse}">
3 <transition name="sidebarLogoFade"> 3 <transition name="sidebarLogoFade">
4 <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> 4 <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
5 <img v-if="logo" :src="logo" class="sidebar-logo"> 5 <img v-if="logo" :src="logo" class="sidebar-logo">
6 <h1 v-else class="sidebar-title">{{ title }} </h1> 6 <h1 v-else class="sidebar-title">{{ title }} </h1>
7 </router-link> 7 </router-link>
8 <router-link v-else key="expand" class="sidebar-logo-link" to="/"> 8 <router-link v-else key="expand" class="sidebar-logo-link" to="/">
9 <img v-if="logo" :src="logo" class="sidebar-logo"> 9 <img v-if="logo" :src="logo" class="sidebar-logo">
10 <h1 class="sidebar-title">{{ title }} </h1> 10 <h1 class="sidebar-title">{{ title }} </h1>
11 </router-link> 11 </router-link>
12 </transition> 12 </transition>
13 </div> 13 </div>
14 </template> 14 </template>
15 15
16 <script> 16 <script>
17 export default { 17 export default {
18 name: 'SidebarLogo', 18 name: 'SidebarLogo',
19 props: { 19 props: {
20 collapse: { 20 collapse: {
21 type: Boolean, 21 type: Boolean,
22 required: true 22 required: true
23 } 23 }
24 }, 24 },
25 data() { 25 data() {
26 return { 26 return {
27 title: 'Vue Element Admin', 27 title: '鱼皮计划',
28 logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' 28 logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
29 } 29 }
30 } 30 }
31 } 31 }
32 </script> 32 </script>
33 33
34 <style lang="scss" scoped> 34 <style lang="scss" scoped>
35 .sidebarLogoFade-enter-active { 35 .sidebarLogoFade-enter-active {
36 transition: opacity 1.5s; 36 transition: opacity 1.5s;
37 } 37 }
38 38
39 .sidebarLogoFade-enter, 39 .sidebarLogoFade-enter,
40 .sidebarLogoFade-leave-to { 40 .sidebarLogoFade-leave-to {
41 opacity: 0; 41 opacity: 0;
42 } 42 }
43 43
44 .sidebar-logo-container { 44 .sidebar-logo-container {
45 position: relative; 45 position: relative;
46 width: 100%; 46 width: 100%;
47 height: 50px; 47 height: 50px;
48 line-height: 50px; 48 line-height: 50px;
49 background: #2b2f3a; 49 background: #2b2f3a;
50 text-align: center; 50 text-align: center;
51 overflow: hidden; 51 overflow: hidden;
52 52
53 & .sidebar-logo-link { 53 & .sidebar-logo-link {
54 height: 100%; 54 height: 100%;
55 width: 100%; 55 width: 100%;
56 56
57 & .sidebar-logo { 57 & .sidebar-logo {
58 width: 32px; 58 width: 32px;
59 height: 32px; 59 height: 32px;
60 vertical-align: middle; 60 vertical-align: middle;
61 margin-right: 12px; 61 margin-right: 12px;
62 } 62 }
63 63
64 & .sidebar-title { 64 & .sidebar-title {
65 display: inline-block; 65 display: inline-block;
66 margin: 0; 66 margin: 0;
67 color: #fff; 67 color: #fff;
68 font-weight: 600; 68 font-weight: 600;
69 line-height: 50px; 69 line-height: 50px;
70 font-size: 14px; 70 font-size: 14px;
71 font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; 71 font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
72 vertical-align: middle; 72 vertical-align: middle;
73 } 73 }
74 } 74 }
75 75
76 &.collapse { 76 &.collapse {
77 .sidebar-logo { 77 .sidebar-logo {
78 margin-right: 0px; 78 margin-right: 0px;
79 } 79 }
80 } 80 }
81 } 81 }
82 </style> 82 </style>
83 83
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 /* Router Modules */ 9 /* Router Modules */
10 import componentsRouter from './modules/components' 10 // import componentsRouter from './modules/components'
11 import chartsRouter from './modules/charts' 11 // import chartsRouter from './modules/charts'
12 import tableRouter from './modules/table' 12 import tableRouter from './modules/table'
13 import nestedRouter from './modules/nested' 13 // import nestedRouter from './modules/nested'
14 import userRouter from './modules/user'
15 import systemRouter from './modules/system'
16 import prodRouter from './modules/prod'
17 import metaRouter from './modules/meta'
14 18
15 /** 19 /**
16 * Note: sub-menu only appear when route children.length >= 1 20 * Note: sub-menu only appear when route children.length >= 1
17 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html 21 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
18 * 22 *
19 * hidden: true if set true, item will not show in the sidebar(default is false) 23 * hidden: true if set true, item will not show in the sidebar(default is false)
20 * alwaysShow: true if set true, will always show the root menu 24 * alwaysShow: true if set true, will always show the root menu
21 * if not set alwaysShow, when item has more than one children route, 25 * if not set alwaysShow, when item has more than one children route,
22 * it will becomes nested mode, otherwise not show the root menu 26 * it will becomes nested mode, otherwise not show the root menu
23 * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb 27 * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
24 * name:'router-name' the name is used by <keep-alive> (must set!!!) 28 * name:'router-name' the name is used by <keep-alive> (must set!!!)
25 * meta : { 29 * meta : {
26 roles: ['admin','editor'] control the page roles (you can set multiple roles) 30 roles: ['admin','assistant','runner', 'shoper'] control the page roles (you can set multiple roles)
27 title: 'title' the name show in sidebar and breadcrumb (recommend set) 31 title: 'title' the name show in sidebar and breadcrumb (recommend set)
28 icon: 'svg-name' the icon show in the sidebar 32 icon: 'svg-name' the icon show in the sidebar
29 noCache: true if set true, the page will no be cached(default is false) 33 noCache: true if set true, the page will no be cached(default is false)
30 affix: true if set true, the tag will affix in the tags-view 34 affix: true if set true, the tag will affix in the tags-view
31 breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) 35 breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
32 activeMenu: '/example/list' if set path, the sidebar will highlight the path you set 36 activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
33 } 37 }
34 */ 38 */
35 39
36 /** 40 /**
37 * constantRoutes 41 * constantRoutes
38 * a base page that does not have permission requirements 42 * a base page that does not have permission requirements
39 * all roles can be accessed 43 * all roles can be accessed
40 */ 44 */
41 export const constantRoutes = [ 45 export const constantRoutes = [
42 { 46 {
43 path: '/redirect', 47 path: '/redirect',
44 component: Layout, 48 component: Layout,
45 hidden: true, 49 hidden: true,
46 children: [ 50 children: [
47 { 51 {
48 path: '/redirect/:path*', 52 path: '/redirect/:path*',
49 component: () => import('@/views/redirect/index') 53 component: () => import('@/views/redirect/index')
50 } 54 }
51 ] 55 ]
52 }, 56 },
53 { 57 {
54 path: '/login', 58 path: '/login',
55 component: () => import('@/views/login/index'), 59 component: () => import('@/views/login/index'),
56 hidden: true 60 hidden: true
57 }, 61 },
58 { 62 {
59 path: '/auth-redirect', 63 path: '/auth-redirect',
60 component: () => import('@/views/login/auth-redirect'), 64 component: () => import('@/views/login/auth-redirect'),
61 hidden: true 65 hidden: true
62 }, 66 },
63 { 67 {
64 path: '/404', 68 path: '/404',
65 component: () => import('@/views/error-page/404'), 69 component: () => import('@/views/error-page/404'),
66 hidden: true 70 hidden: true
67 }, 71 },
68 { 72 {
73 path: '/500',
74 component: () => import('@/views/error-page/500'),
75 hidden: true
76 },
77 {
69 path: '/401', 78 path: '/401',
70 component: () => import('@/views/error-page/401'), 79 component: () => import('@/views/error-page/401'),
71 hidden: true 80 hidden: true
72 }, 81 },
73 { 82 {
74 path: '/', 83 path: '/',
75 component: Layout, 84 component: Layout,
76 redirect: '/dashboard', 85 redirect: '/dashboard',
77 children: [ 86 children: [
78 { 87 {
79 path: 'dashboard', 88 path: 'dashboard',
80 component: () => import('@/views/dashboard/index'), 89 component: () => import('@/views/dashboard/index'),
81 name: 'Dashboard', 90 name: 'Dashboard',
82 meta: { title: 'dashboard', icon: 'dashboard', affix: true } 91 meta: { title: 'dashboard', icon: 'dashboard', affix: true }
83 } 92 }
84 ] 93 ]
85 }, 94 },
86 // { 95 // {
87 // path: '/documentation', 96 // path: '/documentation',
88 // component: Layout, 97 // component: Layout,
89 // children: [ 98 // children: [
90 // { 99 // {
91 // path: 'index', 100 // path: 'index',
92 // component: () => import('@/views/documentation/index'), 101 // component: () => import('@/views/documentation/index'),
93 // name: 'Documentation', 102 // name: 'Documentation',
94 // meta: { title: 'documentation', icon: 'documentation', affix: true } 103 // meta: { title: 'documentation', icon: 'documentation', affix: true }
95 // } 104 // }
96 // ] 105 // ]
97 // }, 106 // },
98 // {
99 // path: '/guide',
100 // component: Layout,
101 // redirect: '/guide/index',
102 // children: [
103 // {
104 // path: 'index',
105 // component: () => import('@/views/guide/index'),
106 // name: 'Guide',
107 // meta: { title: 'guide', icon: 'guide', noCache: true }
108 // }
109 // ]
110 // },
111 { 107 {
112 path: '/profile', 108 path: '/guide',
113 component: Layout, 109 component: Layout,
114 redirect: '/profile/index', 110 redirect: '/guide/index',
115 hidden: true,
116 children: [ 111 children: [
117 { 112 {
118 path: 'index', 113 path: 'index',
119 component: () => import('@/views/profile/index'), 114 component: () => import('@/views/guide/index'),
120 name: 'Profile', 115 name: 'Guide',
121 meta: { title: 'profile', icon: 'user', noCache: true } 116 meta: { title: 'guide', icon: 'guide', noCache: true }
122 } 117 }
123 ] 118 ]
124 } 119 }
120 // {
121 // path: '/profile',
122 // component: Layout,
123 // redirect: '/profile/index',
124 // hidden: true,
125 // children: [
126 // {
127 // path: 'index',
128 // component: () => import('@/views/profile/index'),
129 // name: 'Profile',
130 // meta: { title: 'profile', icon: 'user', noCache: true }
131 // }
132 // ]
133 // }
125 ] 134 ]
126 135
127 /** 136 /**
128 * asyncRoutes 137 * asyncRoutes
129 * the routes that need to be dynamically loaded based on user roles 138 * the routes that need to be dynamically loaded based on user roles
130 */ 139 */
131 export const asyncRoutes = [ 140 export const asyncRoutes = [
141 // {
142 // path: '/permission',
143 // component: Layout,
144 // redirect: '/permission/page',
145 // alwaysShow: true, // will always show the root menu
146 // name: 'Permission',
147 // meta: {
148 // title: 'permission',
149 // icon: 'lock',
150 // roles: ['admin', 'assistant'] // you can set roles in root nav
151 // },
152 // children: [
153 // {
154 // path: 'page',
155 // component: () => import('@/views/permission/page'),
156 // name: 'PagePermission',
157 // meta: {
158 // title: 'pagePermission',
159 // roles: ['admin','assistant'] // or you can only set roles in sub nav
160 // }
161 // },
162 // {
163 // path: 'directive',
164 // component: () => import('@/views/permission/directive'),
165 // name: 'DirectivePermission',
166 // meta: {
167 // title: 'directivePermission',
168 // roles: ['admin', 'shoper']
169 // // if do not set roles, means: this page does not require permission
170 // }
171 // },
172 // {
173 // path: 'role',
174 // component: () => import('@/views/permission/role'),
175 // name: 'RolePermission',
176 // meta: {
177 // title: 'rolePermission',
178 // roles: ['admin', 'runner']
179 // }
180 // }
181 // ]
182 // },
183 tableRouter,
184 metaRouter,
185 userRouter,
186 prodRouter,
132 { 187 {
133 path: '/permission', 188 path: '/orders',
134 component: Layout, 189 component: Layout,
135 redirect: '/permission/page', 190 redirect: '/order/page',
136 alwaysShow: true, // will always show the root menu 191 alwaysShow: true, // will always show the root menu
137 name: 'Permission', 192 name: 'Order',
138 meta: { 193 meta: {
139 title: 'permission', 194 title: 'orders',
140 icon: 'lock', 195 icon: 'shopping',
141 roles: ['admin', 'editor'] // you can set roles in root nav 196 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
142 }, 197 },
143 children: [ 198 children: [
144 { 199 {
145 path: 'page', 200 path: 'page',
146 component: () => import('@/views/permission/page'), 201 component: () => import('@/views/permission/page'),
147 name: 'PagePermission', 202 name: 'OrderList',
148 meta: { 203 meta: {
149 title: 'pagePermission', 204 title: 'OrderList',
150 roles: ['admin'] // or you can only set roles in sub nav 205 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
151 } 206 }
152 }, 207 },
153 { 208 {
154 path: 'directive', 209 path: 'defined',
155 component: () => import('@/views/permission/directive'), 210 component: () => import('@/views/permission/directive'),
156 name: 'DirectivePermission', 211 name: 'OrderDefiend',
157 meta: { 212 meta: {
158 title: 'directivePermission' 213 title: 'OrderDefiend',
214 roles: ['admin', 'assistant', 'runner', 'shoper']
159 // if do not set roles, means: this page does not require permission 215 // if do not set roles, means: this page does not require permission
160 } 216 }
161 },
162 {
163 path: 'role',
164 component: () => import('@/views/permission/role'),
165 name: 'RolePermission',
166 meta: {
167 title: 'rolePermission',
168 roles: ['admin', 'editor']
169 }
170 } 217 }
171 ] 218 ]
172 }, 219 },
173
174 { 220 {
175 path: '/icon', 221 path: '/sites',
176 component: Layout, 222 component: Layout,
223 redirect: '/site/page',
224 alwaysShow: true, // will always show the root menu
225 name: 'Site',
226 meta: {
227 title: 'sites',
228 icon: 'people',
229 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
230 },
177 children: [ 231 children: [
178 { 232 {
179 path: 'index', 233 path: 'page',
180 component: () => import('@/views/icons/index'), 234 component: () => import('@/views/permission/page'),
181 name: 'Icons', 235 name: 'SiteList',
182 meta: { title: 'icons', icon: 'icon', noCache: true } 236 meta: {
237 title: 'SiteList',
238 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
239 }
240 },
241 {
242 path: 'defined',
243 component: () => import('@/views/permission/directive'),
244 name: 'SiteDefiend',
245 meta: {
246 title: 'SiteDefiend',
247 roles: ['admin', 'assistant', 'runner']
248 // if do not set roles, means: this page does not require permission
249 }
183 } 250 }
184 ] 251 ]
185 }, 252 },
186 253
254 // {
255 // path: '/icon',
256 // component: Layout,
257 // children: [
258 // {
259 // path: 'index',
260 // component: () => import('@/views/icons/index'),
261 // name: 'Icons',
262 // meta: { title: 'icons', icon: 'icon', noCache: true }
263 // }
264 // ]
265 // },
266 systemRouter,
187 /** when your routing map is too long, you can split it into small modules **/ 267 /** when your routing map is too long, you can split it into small modules **/
188 componentsRouter, 268 // componentsRouter,
189 chartsRouter, 269 // chartsRouter,
190 nestedRouter, 270 // nestedRouter,
191 tableRouter, 271 // tableRouter,
192 272
193 // { 273 // {
194 // path: '/example', 274 // path: '/example',
195 // component: Layout, 275 // component: Layout,
196 // redirect: '/example/list', 276 // redirect: '/example/list',
197 // name: 'Example', 277 // name: 'Example',
198 // meta: { 278 // meta: {
199 // title: 'example', 279 // title: 'example',
200 // icon: 'example' 280 // icon: 'example'
201 // }, 281 // },
202 // children: [ 282 // children: [
203 // { 283 // {
204 // path: 'create', 284 // path: 'create',
205 // component: () => import('@/views/example/create'), 285 // component: () => import('@/views/example/create'),
206 // name: 'CreateArticle', 286 // name: 'CreateArticle',
207 // meta: { title: 'createArticle', icon: 'edit' } 287 // meta: { title: 'createArticle', icon: 'edit' }
208 // }, 288 // },
209 // { 289 // {
210 // path: 'edit/:id(\\d+)', 290 // path: 'edit/:id(\\d+)',
211 // component: () => import('@/views/example/edit'), 291 // component: () => import('@/views/example/edit'),
212 // name: 'EditArticle', 292 // name: 'EditArticle',
213 // meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' }, 293 // meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
214 // hidden: true 294 // hidden: true
215 // }, 295 // },
216 // { 296 // {
217 // path: 'list', 297 // path: 'list',
218 // component: () => import('@/views/example/list'), 298 // component: () => import('@/views/example/list'),
219 // name: 'ArticleList', 299 // name: 'ArticleList',
220 // meta: { title: 'articleList', icon: 'list' } 300 // meta: { title: 'articleList', icon: 'list' }
221 // } 301 // }
222 // ] 302 // ]
223 // }, 303 // },
224 304
225 { 305 // {
226 path: '/tab', 306 // path: '/tab',
227 component: Layout, 307 // component: Layout,
228 children: [ 308 // children: [
229 { 309 // {
230 path: 'index', 310 // path: 'index',
231 component: () => import('@/views/tab/index'), 311 // component: () => import('@/views/tab/index'),
232 name: 'Tab', 312 // name: 'Tab',
233 meta: { title: 'tab', icon: 'tab' } 313 // meta: { title: 'tab', icon: 'tab' }
234 } 314 // }
235 ] 315 // ]
236 }, 316 // },
237 317
238 // { 318 // {
239 // path: '/error', 319 // path: '/error',
240 // component: Layout, 320 // component: Layout,
241 // redirect: 'noRedirect', 321 // redirect: 'noRedirect',
242 // name: 'ErrorPages', 322 // name: 'ErrorPages',
243 // meta: { 323 // meta: {
244 // title: 'errorPages', 324 // title: 'errorPages',
245 // icon: '404' 325 // icon: '404'
246 // }, 326 // },
247 // children: [ 327 // children: [
248 // { 328 // {
249 // path: '401', 329 // path: '401',
250 // component: () => import('@/views/error-page/401'), 330 // component: () => import('@/views/error-page/401'),
251 // name: 'Page401', 331 // name: 'Page401',
252 // meta: { title: 'page401', noCache: true } 332 // meta: { title: 'page401', noCache: true }
253 // }, 333 // },
254 // { 334 // {
255 // path: '404', 335 // path: '404',
256 // component: () => import('@/views/error-page/404'), 336 // component: () => import('@/views/error-page/404'),
257 // name: 'Page404', 337 // name: 'Page404',
258 // meta: { title: 'page404', noCache: true } 338 // meta: { title: 'page404', noCache: true }
259 // } 339 // }
260 // ] 340 // ]
261 // }, 341 // },
262 342
263 // { 343 // {
264 // path: '/error-log', 344 // path: '/error-log',
265 // component: Layout, 345 // component: Layout,
266 // children: [ 346 // children: [
267 // { 347 // {
268 // path: 'log', 348 // path: 'log',
269 // component: () => import('@/views/error-log/index'), 349 // component: () => import('@/views/error-log/index'),
270 // name: 'ErrorLog', 350 // name: 'ErrorLog',
271 // meta: { title: 'errorLog', icon: 'bug' } 351 // meta: { title: 'errorLog', icon: 'bug' }
272 // } 352 // }
273 // ] 353 // ]
274 // }, 354 // },
275 355
276 // { 356 // {
277 // path: '/excel', 357 // path: '/excel',
278 // component: Layout, 358 // component: Layout,
279 // redirect: '/excel/export-excel', 359 // redirect: '/excel/export-excel',
280 // name: 'Excel', 360 // name: 'Excel',
281 // meta: { 361 // meta: {
282 // title: 'excel', 362 // title: 'excel',
283 // icon: 'excel' 363 // icon: 'excel'
284 // }, 364 // },
285 // children: [ 365 // children: [
286 // { 366 // {
287 // path: 'export-excel', 367 // path: 'export-excel',
288 // component: () => import('@/views/excel/export-excel'), 368 // component: () => import('@/views/excel/export-excel'),
289 // name: 'ExportExcel', 369 // name: 'ExportExcel',
290 // meta: { title: 'exportExcel' } 370 // meta: { title: 'exportExcel' }
291 // }, 371 // },
292 // { 372 // {
293 // path: 'export-selected-excel', 373 // path: 'export-selected-excel',
294 // component: () => import('@/views/excel/select-excel'), 374 // component: () => import('@/views/excel/select-excel'),
295 // name: 'SelectExcel', 375 // name: 'SelectExcel',
296 // meta: { title: 'selectExcel' } 376 // meta: { title: 'selectExcel' }
297 // }, 377 // },
298 // { 378 // {
299 // path: 'export-merge-header', 379 // path: 'export-merge-header',
300 // component: () => import('@/views/excel/merge-header'), 380 // component: () => import('@/views/excel/merge-header'),
301 // name: 'MergeHeader', 381 // name: 'MergeHeader',
302 // meta: { title: 'mergeHeader' } 382 // meta: { title: 'mergeHeader' }
303 // }, 383 // },
304 // { 384 // {
305 // path: 'upload-excel', 385 // path: 'upload-excel',
306 // component: () => import('@/views/excel/upload-excel'), 386 // component: () => import('@/views/excel/upload-excel'),
307 // name: 'UploadExcel', 387 // name: 'UploadExcel',
308 // meta: { title: 'uploadExcel' } 388 // meta: { title: 'uploadExcel' }
309 // } 389 // }
310 // ] 390 // ]
311 // }, 391 // },
312 392
313 // { 393 // {
314 // path: '/zip', 394 // path: '/zip',
315 // component: Layout, 395 // component: Layout,
316 // redirect: '/zip/download', 396 // redirect: '/zip/download',
317 // alwaysShow: true, 397 // alwaysShow: true,
318 // name: 'Zip', 398 // name: 'Zip',
319 // meta: { title: 'zip', icon: 'zip' }, 399 // meta: { title: 'zip', icon: 'zip' },
320 // children: [ 400 // children: [
321 // { 401 // {
322 // path: 'download', 402 // path: 'download',
323 // component: () => import('@/views/zip/index'), 403 // component: () => import('@/views/zip/index'),
324 // name: 'ExportZip', 404 // name: 'ExportZip',
325 // meta: { title: 'exportZip' } 405 // meta: { title: 'exportZip' }
326 // } 406 // }
327 // ] 407 // ]
328 // }, 408 // },
329 409
330 // { 410 // {
331 // path: '/pdf', 411 // path: '/pdf',
332 // component: Layout, 412 // component: Layout,
333 // redirect: '/pdf/index', 413 // redirect: '/pdf/index',
334 // children: [ 414 // children: [
335 // { 415 // {
336 // path: 'index', 416 // path: 'index',
337 // component: () => import('@/views/pdf/index'), 417 // component: () => import('@/views/pdf/index'),
338 // name: 'PDF', 418 // name: 'PDF',
339 // meta: { title: 'pdf', icon: 'pdf' } 419 // meta: { title: 'pdf', icon: 'pdf' }
340 // } 420 // }
341 // ] 421 // ]
342 // }, 422 // },
343 // { 423 // {
344 // path: '/pdf/download', 424 // path: '/pdf/download',
345 // component: () => import('@/views/pdf/download'), 425 // component: () => import('@/views/pdf/download'),
346 // hidden: true 426 // hidden: true
347 // }, 427 // },
348 428
349 { 429 // {
350 path: '/theme', 430 // path: '/theme',
351 component: Layout, 431 // component: Layout,
352 children: [ 432 // children: [
353 { 433 // {
354 path: 'index', 434 // path: 'index',
355 component: () => import('@/views/theme/index'), 435 // component: () => import('@/views/theme/index'),
356 name: 'Theme', 436 // name: 'Theme',
357 meta: { title: 'theme', icon: 'theme' } 437 // meta: { title: 'theme', icon: 'theme' }
358 } 438 // }
359 ] 439 // ]
360 }, 440 // },
361 441
362 // { 442 // {
363 // path: '/clipboard', 443 // path: '/clipboard',
364 // component: Layout, 444 // component: Layout,
365 // children: [ 445 // children: [
366 // { 446 // {
367 // path: 'index', 447 // path: 'index',
368 // component: () => import('@/views/clipboard/index'), 448 // component: () => import('@/views/clipboard/index'),
369 // name: 'ClipboardDemo', 449 // name: 'ClipboardDemo',
370 // meta: { title: 'clipboardDemo', icon: 'clipboard' } 450 // meta: { title: 'clipboardDemo', icon: 'clipboard' }
371 // } 451 // }
372 // ] 452 // ]
373 // }, 453 // },
374 454
375 // { 455 // {
376 // path: '/i18n', 456 // path: '/i18n',
377 // component: Layout, 457 // component: Layout,
378 // children: [ 458 // children: [
379 // { 459 // {
380 // path: 'index', 460 // path: 'index',
381 // component: () => import('@/views/i18n-demo/index'), 461 // component: () => import('@/views/i18n-demo/index'),
382 // name: 'I18n', 462 // name: 'I18n',
383 // meta: { title: 'i18n', icon: 'international' } 463 // meta: { title: 'i18n', icon: 'international' }
384 // } 464 // }
385 // ] 465 // ]
386 // }, 466 // },
387 467
388 // { 468 // {
389 // path: 'external-link', 469 // path: 'external-link',
390 // component: Layout, 470 // component: Layout,
391 // children: [ 471 // children: [
392 // { 472 // {
393 // path: 'https://github.com/PanJiaChen/vue-element-admin', 473 // path: 'https://github.com/PanJiaChen/vue-element-admin',
394 // meta: { title: 'externalLink', icon: 'link' } 474 // meta: { title: 'externalLink', icon: 'link' }
src/router/modules/meta.js
File was created 1 import Layout from '@/layout'
2
3 const metaRouter = {
4 path: '/meta',
5 component: Layout,
6 redirect: '/meta/page',
7 alwaysShow: true, // will always show the root menu
8 name: 'Meta',
9 meta: {
10 title: 'metas.metas',
11 icon: 'zip',
12 roles: ['admin', 'assistant'] // you can set roles in root nav
13 },
14 children: [{
15 path: 'page',
16 component: () => import('@/views/meta/complex-table'),
17 name: 'MetaList',
18 meta: {
19 title: 'MetaList',
20 icon: 'zip',
21 roles: ['admin', 'assistant'] // or you can only set roles in sub nav
22 }
23 }]
24 }
25 export default metaRouter
26
src/router/modules/prod.js
File was created 1 /** When your routing table is too long, you can split it into small modules**/
2
3 import Layout from '@/layout'
4
5 const prodRouter = {
6 path: '/prods',
7 component: Layout,
8 redirect: '/prod/page',
9 alwaysShow: true, // will always show the root menu
10 name: 'Prod',
11 meta: {
12 title: 'prods', // 会自动被i18n替换
13 icon: 'star',
14 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
15 },
16 children: [{
17 path: 'page',
18 component: () => import('@/views/permission/page'),
19 name: 'ProdList',
20 meta: {
21 title: 'ProdList',
22 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
23 }
24 },
25 {
26 path: 'defined',
27 component: () => import('@/views/permission/directive'),
28 name: 'ProdDefiend',
29 meta: {
30 title: 'ProdDefiend',
31 roles: ['admin', 'assistant', 'shoper']
32 // if do not set roles, means: this page does not require permission
33 }
34 }
35 ]
36 }
37
38 export default prodRouter
39
src/router/modules/system.js
File was created 1 import Layout from '@/layout'
2
3 const systemRouter = {
4 path: '/system',
5 component: Layout,
6 redirect: '/system/page',
7 alwaysShow: true, // will always show the root menu
8 name: 'System',
9 meta: {
10 title: 'systems.systems',
11 icon: 'component',
12 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
13 },
14 children: [{
15 path: 'page',
16 component: () => import('@/views/example/list'),
17 name: 'SystemList',
18 meta: {
19 title: 'systems.sites',
20 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
21 }
22 },
23 {
24 path: 'page',
25 component: () => import('@/views/example/list'),
26 name: 'SystemList',
27 meta: {
28 title: 'systems.money',
29 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
30 }
31 },
32 {
33 path: 'page',
34 component: () => import('@/views/example/list'),
35 name: 'SystemList',
36 meta: {
37 title: 'systems.industry',
38 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
39 }
40 },
41 {
42 path: 'page',
43 component: () => import('@/views/example/list'),
44 name: 'SystemList',
45 meta: {
46 title: 'systems.template',
47 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
48 }
49 }
50
51 ]
52 }
53
54 export default systemRouter
55
src/router/modules/user.js
File was created 1 /** When your routing table is too long, you can split it into small modules**/
2
3 import Layout from '@/layout'
4
5 const chartsRouter = {
6 path: '/users',
7 component: Layout,
8 redirect: '/users/page',
9 alwaysShow: true, // will always show the root menu
10 name: 'Users',
11 meta: {
12 title: 'users',
13 icon: 'peoples',
14 roles: ['admin', 'assistant'] // you can set roles in root nav
15 },
16 children: [{
17 path: 'page',
18 component: () => import('@/views/users/list'),
19 name: 'UserList',
20 meta: {
21 title: 'UserList',
22 roles: ['admin', 'assistant', 'shoper', 'runner'] // or you can only set roles in sub nav
23 }
24 }
25 // ,{
26 // path: '/icons',
27 // component: () => import('@/views/icons/index'),
28 // name: 'icons',
29 // meta: {
30 // title: 'icons',
31 // roles: ['admin', 'assistant', 'shoper', 'runner'] // or you can only set roles in sub nav
32 // }
33 // }
34 ]
35 }
36
37 export default chartsRouter
38
1 module.exports = { 1 module.exports = {
2 title: 'Vue Element Admin', 2 title: 'Let\'s fuck this workd',
3 3
4 /** 4 /**
5 * @type {boolean} true | false 5 * @type {boolean} true | false
6 * @description Whether show the settings right-panel 6 * @description Whether show the settings right-panel
7 */ 7 */
8 showSettings: true, 8 showSettings: true,
9 9
10 /** 10 /**
11 * @type {boolean} true | false 11 * @type {boolean} true | false
12 * @description Whether need tagsView 12 * @description Whether need tagsView
13 */ 13 */
14 tagsView: true, 14 tagsView: true,
15 15
16 /** 16 /**
17 * @type {boolean} true | false 17 * @type {boolean} true | false
18 * @description Whether fix the header 18 * @description Whether fix the header
19 */ 19 */
20 fixedHeader: false, 20 fixedHeader: true,
21 21
22 /** 22 /**
23 * @type {boolean} true | false 23 * @type {boolean} true | false
24 * @description Whether show the logo in sidebar 24 * @description Whether show the logo in sidebar
25 */ 25 */
26 sidebarLogo: false, 26 sidebarLogo: true,
27 27
28 /** 28 /**
29 * @type {boolean} true | false 29 * @type {boolean} true | false
30 * @description Whether support pinyin search in headerSearch 30 * @description Whether support pinyin search in headerSearch
31 * Bundle size minified 47.3kb,minified + gzipped 63kb 31 * Bundle size minified 47.3kb,minified + gzipped 63kb
32 */ 32 */
33 supportPinyinSearch: true, 33 supportPinyinSearch: true,
34 34
35 /** 35 /**
36 * @type {string | array} 'production' | ['production', 'development'] 36 * @type {string | array} 'production' | ['production', 'development']
37 * @description Need show err logs component. 37 * @description Need show err logs component.
38 * The default is only used in the production env 38 * The default is only used in the production env
39 * If you want to also use it in dev, you can pass ['production', 'development'] 39 * If you want to also use it in dev, you can pass ['production', 'development']
40 */ 40 */
41 errorLog: 'production' 41 errorLog: 'production'
42 } 42 }
43 43
src/utils/permission.js
1 import store from '@/store' 1 import store from '@/store'
2 2
3 /** 3 /**
4 * @param {Array} value 4 * @param {Array} value
5 * @returns {Boolean} 5 * @returns {Boolean}
6 * @example see @/views/permission/directive.vue 6 * @example see @/views/permission/directive.vue
7 */ 7 */
8 export default function checkPermission(value) { 8 export default function checkPermission(value) {
9 if (value && value instanceof Array && value.length > 0) { 9 if (value && value instanceof Array && value.length > 0) {
10 const roles = store.getters && store.getters.roles 10 const roles = store.getters && store.getters.roles
11 const permissionRoles = value 11 const permissionRoles = value
12 12
13 const hasPermission = roles.some(role => { 13 const hasPermission = roles.some(role => {
14 return permissionRoles.includes(role) 14 return permissionRoles.includes(role)
15 }) 15 })
16 16
17 if (!hasPermission) { 17 if (!hasPermission) {
18 return false 18 return false
19 } 19 }
20 return true 20 return true
21 } else { 21 } else {
22 console.error(`need roles! Like v-permission="['admin','editor']"`) 22 console.error(`need roles! Like v-permission="['admin', 'assistant', 'runner', 'shoper']"`)
23 return false 23 return false
24 } 24 }
25 } 25 }
26 26
src/utils/request.js
1 import axios from 'axios' 1 import axios from 'axios'
2 import { MessageBox, Message } from 'element-ui' 2 import qs from 'qs'
3 import {
4 MessageBox,
5 Message,
6 // Loading,
7 Notification
8 } from 'element-ui'
3 import store from '@/store' 9 import store from '@/store'
4 import { getToken } from '@/utils/auth' 10 import {
11 getToken
12 } from '@/utils/auth'
5 13
6 // create an axios instance 14 // create an axios instance
7 const service = axios.create({ 15 const service = axios.create({
8 baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url 16 baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
9 // withCredentials: true, // send cookies when cross-domain requests 17 withCredentials: true, // send cookies when cross-domain requests
10 timeout: 5000 // request timeout 18 timeout: 3000 // request timeout
11 }) 19 })
12 20 // let loadingInstance
13 // request interceptor 21 // request interceptor
14 service.interceptors.request.use( 22 service.interceptors.request.use(
15 config => { 23 config => {
16 // do something before request is sent 24 const token = sessionStorage.getItem('access_token')
17 25 // const csrf = store.getters.csrf
26 if (token) {
27 config.headers = {
28 'access-token': token,
29 'Content-Type': 'application/x-www-form-urlencoded'
30 }
31 }
32 if (config.url === 'refresh') {
33 config.headers = {
34 'refresh-token': sessionStorage.getItem('refresh_token'),
35 'Content-Type': 'application/x-www-form-urlencoded'
36 }
37 }
38 // let options = {
39 // lock: true,
40 // fullscreen: false,
41 // text: '数据加载中……',
42 // // background: '#FFCC00',
43 // spinner: 'el-icon-loading'
44 // };
45 const options = {
46 type: 'success',
47 message: config.url,
48 title: 'request axios ',
49 showClose: true,
50 duration: 3000
51 }
52 Notification(options)
53 // loadingInstance = Loading.service(options);
54 config.method === 'post'
55 ? config.data = qs.stringify({
56 ...config.data
57 })
58 : config.params = {
59 ...config.params
60 }
18 if (store.getters.token) { 61 if (store.getters.token) {
19 // let each request carry token 62 // let each request carry token
20 // ['X-Token'] is a custom headers key 63 // ['X-Token'] is a custom headers key
21 // please modify it according to the actual situation 64 // please modify it according to the actual situation
22 config.headers['X-Token'] = getToken() 65 config.headers['X-Token'] = getToken()
23 } 66 }
67 config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
68
24 return config 69 return config
70 // do something before request is sent
25 }, 71 },
26 error => { 72 error => {
27 // do something with request error 73 // do something with request error
74 Message({
75 message: error || 'Error',
76 type: 'error',
77 duration: 5 * 1000
78 })
28 console.log(error) // for debug 79 console.log(error) // for debug
29 return Promise.reject(error) 80 return Promise.reject(error)
30 } 81 }
31 ) 82 )
32 83
33 // response interceptor 84 // response interceptor
34 service.interceptors.response.use( 85 service.interceptors.response.use(
35 /** 86 /**
36 * If you want to get http information such as headers or status 87 * If you want to get http information such as headers or status
37 * Please return response => response 88 * Please return response => response
38 */ 89 */
39 90
40 /** 91 /**
41 * Determine the request status by custom code 92 * Determine the request status by custom code
42 * Here is just an example 93 * Here is just an example
43 * You can also judge the status by HTTP Status Code 94 * You can also judge the status by HTTP Status Code
44 */ 95 */
45 response => { 96 response => {
97 const options = {
98 type: 'error',
99 message: response.status,
100 title: 'response status value ',
101 showClose: true,
102 duration: 1000
103 }
104 Notification(options)
105 // Notification.close()
106 // 这里根据后端提供的数据进行对应的处理
107 console.log('response===>', response)
108 // 定时刷新access-token
109 // if (!response.data.value && response.data.data.message === 'token invalid') {
110 // // 刷新token
111 // store.dispatch('refresh').then(response => {
112 // sessionStorage.setItem('access_token', response.data)
113 // }).catch(error => {
114 // throw new Error('token刷新' + error)
115 // })
116 // }
117
46 const res = response.data 118 const res = response.data
47 119
48 // if the custom code is not 20000, it is judged as an error. 120 // if the custom code is not 20000, it is judged as an error.
49 if (res.code !== 20000) { 121 if (res.code !== 20000) {
50 Message({ 122 Message({
51 message: res.message || 'Error', 123 message: res.message || 'Error',
52 type: 'error', 124 type: 'error',
53 duration: 5 * 1000 125 duration: 5 * 1000
54 }) 126 })
55 127
56 // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; 128 // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
57 if (res.code === 50008 || res.code === 50012 || res.code === 50014) { 129 if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
58 // to re-login 130 // to re-login
59 MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { 131 MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
60 confirmButtonText: 'Re-Login', 132 confirmButtonText: 'Re-Login',
61 cancelButtonText: 'Cancel', 133 cancelButtonText: 'Cancel',
62 type: 'warning' 134 type: 'warning'
63 }).then(() => { 135 }).then(() => {
64 store.dispatch('user/resetToken').then(() => { 136 store.dispatch('user/resetToken').then(() => {
65 location.reload() 137 location.reload()
66 }) 138 })
67 }) 139 })
68 } 140 }
69 return Promise.reject(new Error(res.message || 'Error')) 141 return Promise.reject(new Error(res.message || 'Error'))
70 } else { 142 } else {
71 return res 143 return res
72 } 144 }
73 }, 145 },
74 error => { 146 error => {
75 console.log('err' + error) // for debug 147 console.log('error', error)
148 // console.log(JSON.stringify(error));
149 // 500的状态也应该处理一下
150 // 401-403的状态也应该处理一下
151 const text = JSON.parse(JSON.stringify(error)).response.status === 404
152 ? '404'
153 : '网络异常,请重试'
76 Message({ 154 Message({
77 message: error.message, 155 message: text || 'Error',
78 type: 'error', 156 type: 'error',
79 duration: 5 * 1000 157 duration: 5 * 1000
80 }) 158 })
159
81 return Promise.reject(error) 160 return Promise.reject(error)
82 } 161 }
83 ) 162 )
84 163
164 // 假设你想移除拦截器
165 // axios.interceptors.request.eject(service);
166
85 export default service 167 export default service
86 168
src/utils/validate.js
1 /** 1 /**
2 * Created by PanJiaChen on 16/11/18. 2 * Created by PanJiaChen on 16/11/18.
3 */ 3 */
4 4
5 /** 5 /**
6 * @param {string} path 6 * @param {string} path
7 * @returns {Boolean} 7 * @returns {Boolean}
8 */ 8 */
9 export function isExternal(path) { 9 export function isExternal(path) {
10 return /^(https?:|mailto:|tel:)/.test(path) 10 return /^(https?:|mailto:|tel:)/.test(path)
11 } 11 }
12 12
13 /** 13 /**
14 * @param {string} str 14 * @param {string} str
15 * @returns {Boolean} 15 * @returns {Boolean}
16 */ 16 */
17 export function validUsername(str) { 17 export function validUsername(str) {
18 const valid_map = ['admin', 'editor'] 18 const valid_map = ['admin', 'assistant', 'runner', 'shoper']
19 return valid_map.indexOf(str.trim()) >= 0 19 return valid_map.indexOf(str.trim()) >= 0
20 } 20 }
21 21
22 /** 22 /**
23 * @param {string} url 23 * @param {string} url
24 * @returns {Boolean} 24 * @returns {Boolean}
25 */ 25 */
26 export function validURL(url) { 26 export function validURL(url) {
27 const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ 27 const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
28 return reg.test(url) 28 return reg.test(url)
29 } 29 }
30 30
31 /** 31 /**
32 * @param {string} str 32 * @param {string} str
33 * @returns {Boolean} 33 * @returns {Boolean}
34 */ 34 */
35 export function validLowerCase(str) { 35 export function validLowerCase(str) {
36 const reg = /^[a-z]+$/ 36 const reg = /^[a-z]+$/
37 return reg.test(str) 37 return reg.test(str)
38 } 38 }
39 39
40 /** 40 /**
41 * @param {string} str 41 * @param {string} str
42 * @returns {Boolean} 42 * @returns {Boolean}
43 */ 43 */
44 export function validUpperCase(str) { 44 export function validUpperCase(str) {
45 const reg = /^[A-Z]+$/ 45 const reg = /^[A-Z]+$/
46 return reg.test(str) 46 return reg.test(str)
47 } 47 }
48 48
49 /** 49 /**
50 * @param {string} str 50 * @param {string} str
51 * @returns {Boolean} 51 * @returns {Boolean}
52 */ 52 */
53 export function validAlphabets(str) { 53 export function validAlphabets(str) {
54 const reg = /^[A-Za-z]+$/ 54 const reg = /^[A-Za-z]+$/
55 return reg.test(str) 55 return reg.test(str)
56 } 56 }
57 57
58 /** 58 /**
59 * @param {string} email 59 * @param {string} email
60 * @returns {Boolean} 60 * @returns {Boolean}
61 */ 61 */
62 export function validEmail(email) { 62 export function validEmail(email) {
63 const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 63 const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
64 return reg.test(email) 64 return reg.test(email)
65 } 65 }
66 66
67 /** 67 /**
68 * @param {string} str 68 * @param {string} str
69 * @returns {Boolean} 69 * @returns {Boolean}
70 */ 70 */
71 export function isString(str) { 71 export function isString(str) {
72 if (typeof str === 'string' || str instanceof String) { 72 if (typeof str === 'string' || str instanceof String) {
73 return true 73 return true
74 } 74 }
75 return false 75 return false
76 } 76 }
77 77
78 /** 78 /**
79 * @param {Array} arg 79 * @param {Array} arg
80 * @returns {Boolean} 80 * @returns {Boolean}
81 */ 81 */
82 export function isArray(arg) { 82 export function isArray(arg) {
83 if (typeof Array.isArray === 'undefined') { 83 if (typeof Array.isArray === 'undefined') {
84 return Object.prototype.toString.call(arg) === '[object Array]' 84 return Object.prototype.toString.call(arg) === '[object Array]'
85 } 85 }
86 return Array.isArray(arg) 86 return Array.isArray(arg)
87 } 87 }
88 88
src/views/403.vue
1 <template> File was deleted
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/502.vue
1 <template> File was deleted
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/admin/index.vue
1 <template> 1 <template>
2 <div class="dashboard-editor-container"> 2 <div class="dashboard-editor-container">
3 <github-corner class="github-corner" /> 3 <!-- <github-corner class="github-corner" /> -->
4 4
5 <panel-group @handleSetLineChartData="handleSetLineChartData" /> 5 <panel-group @handleSetLineChartData="handleSetLineChartData" />
6 6
7 <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> 7 <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
8 <line-chart :chart-data="lineChartData" /> 8 <line-chart :chart-data="lineChartData" />
9 </el-row> 9 </el-row>
10 10
11 <el-row :gutter="32"> 11 <el-row :gutter="32">
12 <el-col :xs="24" :sm="24" :lg="8"> 12 <el-col :xs="24" :sm="24" :lg="8">
13 <div class="chart-wrapper"> 13 <div class="chart-wrapper">
14 <raddar-chart /> 14 <raddar-chart />
15 </div> 15 </div>
16 </el-col> 16 </el-col>
17 <el-col :xs="24" :sm="24" :lg="8"> 17 <el-col :xs="24" :sm="24" :lg="8">
18 <div class="chart-wrapper"> 18 <div class="chart-wrapper">
19 <pie-chart /> 19 <pie-chart />
20 </div> 20 </div>
21 </el-col> 21 </el-col>
22 <el-col :xs="24" :sm="24" :lg="8"> 22 <el-col :xs="24" :sm="24" :lg="8">
23 <div class="chart-wrapper"> 23 <div class="chart-wrapper">
24 <bar-chart /> 24 <bar-chart />
25 </div> 25 </div>
26 </el-col> 26 </el-col>
27 </el-row> 27 </el-row>
28 28
29 <el-row :gutter="8"> 29 <el-row :gutter="8">
30 <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;"> 30 <el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
31 <transaction-table /> 31 <transaction-table />
32 </el-col> 32 </el-col>
33 <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;"> 33 <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
34 <todo-list /> 34 <todo-list />
35 </el-col> 35 </el-col>
36 <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;"> 36 <el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
37 <box-card /> 37 <box-card />
38 </el-col> 38 </el-col>
39 </el-row> 39 </el-row>
40 </div> 40 </div>
41 </template> 41 </template>
42 42
43 <script> 43 <script>
44 import GithubCorner from '@/components/GithubCorner' 44 // import GithubCorner from '@/components/GithubCorner'
45 import PanelGroup from './components/PanelGroup' 45 import PanelGroup from './components/PanelGroup'
46 import LineChart from './components/LineChart' 46 import LineChart from './components/LineChart'
47 import RaddarChart from './components/RaddarChart' 47 import RaddarChart from './components/RaddarChart'
48 import PieChart from './components/PieChart' 48 import PieChart from './components/PieChart'
49 import BarChart from './components/BarChart' 49 import BarChart from './components/BarChart'
50 import TransactionTable from './components/TransactionTable' 50 import TransactionTable from './components/TransactionTable'
51 import TodoList from './components/TodoList' 51 import TodoList from './components/TodoList'
52 import BoxCard from './components/BoxCard' 52 import BoxCard from './components/BoxCard'
53 53
54 const lineChartData = { 54 const lineChartData = {
55 newVisitis: { 55 newVisitis: {
56 expectedData: [100, 120, 161, 134, 105, 160, 165], 56 expectedData: [100, 120, 161, 134, 105, 160, 165],
57 actualData: [120, 82, 91, 154, 162, 140, 145] 57 actualData: [120, 82, 91, 154, 162, 140, 145]
58 }, 58 },
59 messages: { 59 messages: {
60 expectedData: [200, 192, 120, 144, 160, 130, 140], 60 expectedData: [200, 192, 120, 144, 160, 130, 140],
61 actualData: [180, 160, 151, 106, 145, 150, 130] 61 actualData: [180, 160, 151, 106, 145, 150, 130]
62 }, 62 },
63 purchases: { 63 purchases: {
64 expectedData: [80, 100, 121, 104, 105, 90, 100], 64 expectedData: [80, 100, 121, 104, 105, 90, 100],
65 actualData: [120, 90, 100, 138, 142, 130, 130] 65 actualData: [120, 90, 100, 138, 142, 130, 130]
66 }, 66 },
67 shoppings: { 67 shoppings: {
68 expectedData: [130, 140, 141, 142, 145, 150, 160], 68 expectedData: [130, 140, 141, 142, 145, 150, 160],
69 actualData: [120, 82, 91, 154, 162, 140, 130] 69 actualData: [120, 82, 91, 154, 162, 140, 130]
70 } 70 }
71 } 71 }
72 72
73 export default { 73 export default {
74 name: 'DashboardAdmin', 74 name: 'DashboardAdmin',
75 components: { 75 components: {
76 GithubCorner, 76 // GithubCorner,
77 PanelGroup, 77 PanelGroup,
78 LineChart, 78 LineChart,
79 RaddarChart, 79 RaddarChart,
80 PieChart, 80 PieChart,
81 BarChart, 81 BarChart,
82 TransactionTable, 82 TransactionTable,
83 TodoList, 83 TodoList,
84 BoxCard 84 BoxCard
85 }, 85 },
86 data() { 86 data() {
87 return { 87 return {
88 lineChartData: lineChartData.newVisitis 88 lineChartData: lineChartData.newVisitis
89 } 89 }
90 }, 90 },
91 methods: { 91 methods: {
92 handleSetLineChartData(type) { 92 handleSetLineChartData(type) {
93 this.lineChartData = lineChartData[type] 93 this.lineChartData = lineChartData[type]
94 } 94 }
95 } 95 }
96 } 96 }
97 </script> 97 </script>
98 98
99 <style lang="scss" scoped> 99 <style lang="scss" scoped>
100 .dashboard-editor-container { 100 .dashboard-editor-container {
101 padding: 32px; 101 padding: 32px;
102 background-color: rgb(240, 242, 245); 102 background-color: rgb(240, 242, 245);
103 position: relative; 103 position: relative;
104 104
105 .github-corner { 105 .github-corner {
106 position: absolute; 106 position: absolute;
107 top: 0px; 107 top: 0px;
108 border: 0; 108 border: 0;
109 right: 0; 109 right: 0;
110 } 110 }
111 111
112 .chart-wrapper { 112 .chart-wrapper {
113 background: #fff; 113 background: #fff;
114 padding: 16px 16px 0; 114 padding: 16px 16px 0;
115 margin-bottom: 32px; 115 margin-bottom: 32px;
116 } 116 }
117 } 117 }
118 118
119 @media (max-width:1024px) { 119 @media (max-width:1024px) {
120 .chart-wrapper { 120 .chart-wrapper {
121 padding: 8px; 121 padding: 8px;
122 } 122 }
123 } 123 }
124 </style> 124 </style>
125 125
src/views/dashboard/editor/index.vue
1 <template> 1 <template>
2 <div class="dashboard-editor-container"> 2 <div class="dashboard-editor-container">
3 <div class=" clearfix"> 3 <div class="clearfix">
4 <pan-thumb :image="avatar" style="float: left"> 4 <pan-thumb :image="avatar" style="float: left">
5 Your roles: 5 Your roles:
6 <span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span> 6 <span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
7 </pan-thumb> 7 </pan-thumb>
8 <github-corner style="position: absolute; top: 0px; border: 0; right: 0;" /> 8 <github-corner style="position: absolute; top: 0px; border: 0; right: 0;" />
9 <div class="info-container"> 9 <div class="info-container">
10 <span class="display_name">{{ name }}</span> 10 <span class="display_name">{{ name }}</span>
11 <span style="font-size:20px;padding-top:20px;display:inline-block;">Editor's Dashboard</span> 11 <span style="font-size:20px;padding-top:20px;display:inline-block;">{{ roles }}'s Dashboard</span>
12 </div> 12 </div>
13 </div> 13 </div>
14 <div> 14 <div>
15 <img :src="emptyGif" class="emptyGif"> 15 <img :src="emptyGif" class="emptyGif">
16 </div> 16 </div>
17 </div> 17 </div>
18 </template> 18 </template>
19 19
20 <script> 20 <script>
21 import { mapGetters } from 'vuex' 21 import { mapGetters } from 'vuex'
22 import PanThumb from '@/components/PanThumb' 22 import PanThumb from '@/components/PanThumb'
23 import GithubCorner from '@/components/GithubCorner' 23 // import GithubCorner from '@/components/GithubCorner'
24 24
25 export default { 25 export default {
26 name: 'DashboardEditor', 26 name: 'DashboardEditor',
27 components: { PanThumb, GithubCorner }, 27 // components: { PanThumb, GithubCorner },
28 components: { PanThumb },
28 data() { 29 data() {
29 return { 30 return {
30 emptyGif: 'https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3' 31 emptyGif:
32 'https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3'
31 } 33 }
32 }, 34 },
33 computed: { 35 computed: {
34 ...mapGetters([ 36 ...mapGetters(['name', 'avatar', 'roles'])
35 'name',
36 'avatar',
37 'roles'
38 ])
39 } 37 }
40 } 38 }
41 </script> 39 </script>
42 40
43 <style lang="scss" scoped> 41 <style lang="scss" scoped>
44 .emptyGif { 42 .emptyGif {
43 display: block;
44 width: 45%;
45 margin: 0 auto;
46 }
47
48 .dashboard-editor-container {
49 background-color: #e3e3e3;
50 min-height: 100vh;
51 padding: 50px 60px 0px;
52 .pan-info-roles {
53 font-size: 12px;
54 font-weight: 700;
55 color: #333;
45 display: block; 56 display: block;
46 width: 45%;
47 margin: 0 auto;
48 } 57 }
49 58 .info-container {
50 .dashboard-editor-container { 59 position: relative;
51 background-color: #e3e3e3; 60 margin-left: 190px;
52 min-height: 100vh; 61 height: 150px;
53 padding: 50px 60px 0px; 62 line-height: 200px;
54 .pan-info-roles { 63 .display_name {
55 font-size: 12px; 64 font-size: 48px;
56 font-weight: 700; 65 line-height: 48px;
57 color: #333; 66 color: #212121;
58 display: block; 67 position: absolute;
59 } 68 top: 25px;
60 .info-container {
src/views/error-page/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 <style scoped>
28 .error-page {
29 display: flex;
30 justify-content: center;
31 align-items: center;
32 flex-direction: column;
33 width: 100%;
34 height: 100%;
35 background: #f3f3f3;
36 box-sizing: border-box;
37 }
38 .error-code {
39 line-height: 1;
40 font-size: 250px;
41 font-weight: bolder;
42 color: #f02d2d;
43 }
44 .error-code span {
45 color: #00a854;
46 }
47 .error-desc {
48 font-size: 30px;
49 color: #777;
50 }
51 .error-handle {
52 margin-top: 30px;
53 padding-bottom: 200px;
54 }
55 .error-btn {
56 margin-left: 100px;
57 }
58 </style>
59
src/views/error-page/500.vue
File was created 1 <template>
2 <div class="error-page">
3 <div class="error-code">
4 5
5 <span>0</span>0
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>
58
src/views/login/index.vue
1 <template> 1 <template>
2 <div class="login-container"> 2 <div class="login-container">
3 <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left"> 3 <el-form
4 4 ref="loginForm"
5 :model="loginForm"
6 :rules="loginRules"
7 class="login-form"
8 autocomplete="on"
9 label-position="left"
10 >
5 <div class="title-container"> 11 <div class="title-container">
6 <h3 class="title"> 12 <h3 class="title">{{ $t('login.title') }}</h3>
7 {{ $t('login.title') }}
8 </h3>
9 <lang-select class="set-language" /> 13 <lang-select class="set-language" />
10 </div> 14 </div>
11 15
12 <el-form-item prop="username"> 16 <el-form-item prop="username">
13 <span class="svg-container"> 17 <span class="svg-container">
14 <svg-icon icon-class="user" /> 18 <svg-icon icon-class="user" />
15 </span> 19 </span>
16 <el-input 20 <el-input
17 ref="username" 21 ref="username"
18 v-model="loginForm.username" 22 v-model="loginForm.username"
19 :placeholder="$t('login.username')" 23 :placeholder="$t('login.username')"
20 name="username" 24 name="username"
21 type="text" 25 type="text"
22 tabindex="1" 26 tabindex="1"
23 autocomplete="on" 27 autocomplete="on"
24 /> 28 />
25 </el-form-item> 29 </el-form-item>
26 30
27 <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual> 31 <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
28 <el-form-item prop="password"> 32 <el-form-item prop="password">
29 <span class="svg-container"> 33 <span class="svg-container">
30 <svg-icon icon-class="password" /> 34 <svg-icon icon-class="password" />
31 </span> 35 </span>
32 <el-input 36 <el-input
33 :key="passwordType" 37 :key="passwordType"
34 ref="password" 38 ref="password"
35 v-model="loginForm.password" 39 v-model="loginForm.password"
36 :type="passwordType" 40 :type="passwordType"
37 :placeholder="$t('login.password')" 41 :placeholder="$t('login.password')"
38 name="password" 42 name="password"
39 tabindex="2" 43 tabindex="2"
40 autocomplete="on" 44 autocomplete="on"
41 @keyup.native="checkCapslock" 45 @keyup.native="checkCapslock"
42 @blur="capsTooltip = false" 46 @blur="capsTooltip = false"
43 @keyup.enter.native="handleLogin" 47 @keyup.enter.native="handleLogin"
44 /> 48 />
45 <span class="show-pwd" @click="showPwd"> 49 <span class="show-pwd" @click="showPwd">
46 <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> 50 <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
47 </span> 51 </span>
48 </el-form-item> 52 </el-form-item>
49 </el-tooltip> 53 </el-tooltip>
50 54 <div
51 <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin"> 55 style="position:relative;text-align:right;height:30px;line-height:30px;border:0px #000 solid;margin-top:-20px;"
52 {{ $t('login.logIn') }} 56 >
53 </el-button> 57 <!-- <el-checkbox v-model="checked">{{$t('rememberpassword')}}</el-checkbox> -->
54 58 <el-link type="primary">{{ $t('login.forgetpassword') }}</el-link>
59 </div>
60 <el-button
61 :loading="loading"
62 type="primary"
63 style="width:100%;"
64 @click.native.prevent="handleLogin"
65 >{{ $t('login.logIn') }}</el-button>
66 <div
67 style="position:relative;text-align:right;height:30px;line-height:30px;border:0px #000 solid;margin-bottom:30px;"
68 >
69 <div class="tips">
70 <el-link type="primary">{{ $t('login.signup') }}</el-link>
71 </div>
72 </div>
55 <div style="position:relative"> 73 <div style="position:relative">
56 <div class="tips"> 74 <div class="tips">
57 <span>{{ $t('login.username') }} : admin</span> 75 <span>{{ $t('login.username') }} : admin</span>
58 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span> 76 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
59 </div> 77 </div>
60 <div class="tips"> 78 <div class="tips">
61 <span style="margin-right:18px;"> 79 <span style="margin-right:18px;">{{ $t('login.username') }} : assistant</span>
62 {{ $t('login.username') }} : editor
63 </span>
64 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span> 80 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
65 </div> 81 </div>
66 82 <div class="tips">
67 <el-button class="thirdparty-button" type="primary" @click="showDialog=true"> 83 <span style="margin-right:18px;">{{ $t('login.username') }} : runner</span>
68 {{ $t('login.thirdparty') }} 84 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
69 </el-button> 85 </div>
86 <div class="tips">
87 <span style="margin-right:18px;">{{ $t('login.username') }} : shoper</span>
88 <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
89 </div>
90 <el-button
91 class="thirdparty-button"
92 type="primary"
93 @click="showDialog=true"
94 >{{ $t('login.thirdparty') }}</el-button>
70 </div> 95 </div>
71 </el-form> 96 </el-form>
72 97
73 <el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog"> 98 <el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
74 {{ $t('login.thirdpartyTips') }} 99 {{ $t('login.thirdpartyTips') }}
75 <br> 100 <br>
76 <br> 101 <br>
77 <br> 102 <br>
78 <social-sign /> 103 <social-sign />
79 </el-dialog> 104 </el-dialog>
105 <!-- <vfd></vfd> -->
80 </div> 106 </div>
81 </template> 107 </template>
82 108
83 <script> 109 <script>
84 import { validUsername } from '@/utils/validate' 110 import { validUsername } from '@/utils/validate'
85 import LangSelect from '@/components/LangSelect' 111 import LangSelect from '@/components/LangSelect'
86 import SocialSign from './components/SocialSignin' 112 import SocialSign from './components/SocialSignin'
87 113 // import vfd from "vfd";
88 export default { 114 export default {
89 name: 'Login', 115 name: 'Login',
116 // components: { LangSelect, SocialSign, vfd },
90 components: { LangSelect, SocialSign }, 117 components: { LangSelect, SocialSign },
91 data() { 118 data() {
92 const validateUsername = (rule, value, callback) => { 119 const validateUsername = (rule, value, callback) => {
93 if (!validUsername(value)) { 120 if (!validUsername(value)) {
94 callback(new Error('Please enter the correct user name')) 121 callback(new Error('Please enter the correct user name'))
95 } else { 122 } else {
96 callback() 123 callback()
97 } 124 }
98 } 125 }
99 const validatePassword = (rule, value, callback) => { 126 const validatePassword = (rule, value, callback) => {
100 if (value.length < 6) { 127 if (value.length < 6) {
101 callback(new Error('The password can not be less than 6 digits')) 128 callback(new Error('The password can not be less than 6 digits'))
102 } else { 129 } else {
103 callback() 130 callback()
104 } 131 }
105 } 132 }
106 return { 133 return {
107 loginForm: { 134 loginForm: {
108 username: 'admin', 135 username: 'admin',
109 password: '111111' 136 password: '111111'
110 }, 137 },
111 loginRules: { 138 loginRules: {
112 username: [{ required: true, trigger: 'blur', validator: validateUsername }], 139 username: [
113 password: [{ required: true, trigger: 'blur', validator: validatePassword }] 140 { required: true, trigger: 'blur', validator: validateUsername }
141 ],
142 password: [
143 { required: true, trigger: 'blur', validator: validatePassword }
144 ]
114 }, 145 },
115 passwordType: 'password', 146 passwordType: 'password',
116 capsTooltip: false, 147 capsTooltip: false,
117 loading: false, 148 loading: false,
118 showDialog: false, 149 showDialog: false,
119 redirect: undefined, 150 redirect: undefined,
120 otherQuery: {} 151 otherQuery: {}
121 } 152 }
122 }, 153 },
123 watch: { 154 watch: {
124 $route: { 155 $route: {
125 handler: function(route) { 156 handler: function(route) {
126 const query = route.query 157 const query = route.query
127 if (query) { 158 if (query) {
128 this.redirect = query.redirect 159 this.redirect = query.redirect
129 this.otherQuery = this.getOtherQuery(query) 160 this.otherQuery = this.getOtherQuery(query)
130 } 161 }
131 }, 162 },
132 immediate: true 163 immediate: true
133 } 164 }
134 }, 165 },
135 created() { 166 created() {
136 // window.addEventListener('storage', this.afterQRScan) 167 // window.addEventListener('storage', this.afterQRScan)
137 }, 168 },
138 mounted() { 169 mounted() {
139 if (this.loginForm.username === '') { 170 if (this.loginForm.username === '') {
140 this.$refs.username.focus() 171 this.$refs.username.focus()
141 } else if (this.loginForm.password === '') { 172 } else if (this.loginForm.password === '') {
142 this.$refs.password.focus() 173 this.$refs.password.focus()
143 } 174 }
144 }, 175 },
145 destroyed() { 176 destroyed() {
146 // window.removeEventListener('storage', this.afterQRScan) 177 // window.removeEventListener('storage', this.afterQRScan)
147 }, 178 },
148 methods: { 179 methods: {
149 checkCapslock(e) { 180 checkCapslock(e) {
150 const { key } = e 181 const { key } = e
151 this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z') 182 this.capsTooltip = key && key.length === 1 && key >= 'A' && key <= 'Z'
152 }, 183 },
153 showPwd() { 184 showPwd() {
154 if (this.passwordType === 'password') { 185 if (this.passwordType === 'password') {
155 this.passwordType = '' 186 this.passwordType = ''
156 } else { 187 } else {
157 this.passwordType = 'password' 188 this.passwordType = 'password'
158 } 189 }
159 this.$nextTick(() => { 190 this.$nextTick(() => {
160 this.$refs.password.focus() 191 this.$refs.password.focus()
161 }) 192 })
162 }, 193 },
163 handleLogin() { 194 handleLogin() {
164 this.$refs.loginForm.validate(valid => { 195 this.$refs.loginForm.validate(valid => {
165 if (valid) { 196 if (valid) {
166 this.loading = true 197 this.loading = true
167 this.$store.dispatch('user/login', this.loginForm) 198 this.$store
199 .dispatch('user/login', this.loginForm)
168 .then(() => { 200 .then(() => {
169 this.$router.push({ path: this.redirect || '/', query: this.otherQuery }) 201 this.$router.push({
202 path: this.redirect || '/',
203 query: this.otherQuery
204 })
170 this.loading = false 205 this.loading = false
171 }) 206 })
172 .catch(() => { 207 .catch(() => {
173 this.loading = false 208 this.loading = false
174 }) 209 })
175 } else { 210 } else {
176 console.log('error submit!!') 211 console.log('error submit!!')
177 return false 212 return false
178 } 213 }
179 }) 214 })
180 }, 215 },
181 getOtherQuery(query) { 216 getOtherQuery(query) {
182 return Object.keys(query).reduce((acc, cur) => { 217 return Object.keys(query).reduce((acc, cur) => {
183 if (cur !== 'redirect') { 218 if (cur !== 'redirect') {
184 acc[cur] = query[cur] 219 acc[cur] = query[cur]
185 } 220 }
186 return acc 221 return acc
187 }, {}) 222 }, {})
188 } 223 }
189 // afterQRScan() { 224 // afterQRScan() {
190 // if (e.key === 'x-admin-oauth-code') { 225 // if (e.key === 'x-admin-oauth-code') {
191 // const code = getQueryObject(e.newValue) 226 // const code = getQueryObject(e.newValue)
192 // const codeMap = { 227 // const codeMap = {
193 // wechat: 'code', 228 // wechat: 'code',
194 // tencent: 'code' 229 // tencent: 'code'
195 // } 230 // }
196 // const type = codeMap[this.auth_type] 231 // const type = codeMap[this.auth_type]
197 // const codeName = code[type] 232 // const codeName = code[type]
198 // if (codeName) { 233 // if (codeName) {
199 // this.$store.dispatch('LoginByThirdparty', codeName).then(() => { 234 // this.$store.dispatch('LoginByThirdparty', codeName).then(() => {
200 // this.$router.push({ path: this.redirect || '/' }) 235 // this.$router.push({ path: this.redirect || '/' })
201 // }) 236 // })
202 // } else { 237 // } else {
203 // alert('第三方登录失败') 238 // alert('第三方登录失败')
204 // } 239 // }
205 // } 240 // }
206 // } 241 // }
207 } 242 }
208 } 243 }
209 </script> 244 </script>
210 245
211 <style lang="scss"> 246 <style lang="scss">
212 /* 修复input 背景不协调 和光标变色 */ 247 /* 修复input 背景不协调 和光标变色 */
213 /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */ 248 /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
214 249
215 $bg:#283443; 250 $bg: #283443;
216 $light_gray:#fff; 251 $light_gray: #fff;
217 $cursor: #fff; 252 $cursor: #fff;
218 253
219 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) { 254 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
220 .login-container .el-input input { 255 .login-container .el-input input {
221 color: $cursor; 256 color: $cursor;
222 } 257 }
223 } 258 }
224 259
225 /* reset element-ui css */ 260 /* reset element-ui css */
226 .login-container { 261 .login-container {
227 .el-input { 262 .el-input {
228 display: inline-block; 263 display: inline-block;
229 height: 47px; 264 height: 47px;
230 width: 85%; 265 width: 85%;
231 266
232 input { 267 input {
233 background: transparent; 268 background: transparent;
234 border: 0px; 269 border: 0px;
235 -webkit-appearance: none; 270 -webkit-appearance: none;
236 border-radius: 0px; 271 border-radius: 0px;
237 padding: 12px 5px 12px 15px; 272 padding: 12px 5px 12px 15px;
238 color: $light_gray; 273 color: $light_gray;
239 height: 47px; 274 height: 47px;
240 caret-color: $cursor; 275 caret-color: $cursor;
241 276
242 &:-webkit-autofill { 277 &:-webkit-autofill {
243 box-shadow: 0 0 0px 1000px $bg inset !important; 278 box-shadow: 0 0 0px 1000px $bg inset !important;
244 -webkit-text-fill-color: $cursor !important; 279 -webkit-text-fill-color: $cursor !important;
245 } 280 }
246 } 281 }
247 } 282 }
248 283
249 .el-form-item { 284 .el-form-item {
250 border: 1px solid rgba(255, 255, 255, 0.1); 285 border: 1px solid rgba(255, 255, 255, 0.1);
251 background: rgba(0, 0, 0, 0.1); 286 background: rgba(0, 0, 0, 0.1);
252 border-radius: 5px; 287 border-radius: 5px;
253 color: #454545; 288 color: #454545;
254 } 289 }
255 } 290 }
256 </style> 291 </style>
257 292
258 <style lang="scss" scoped> 293 <style lang="scss" scoped>
259 $bg:#2d3a4b; 294 $bg: #2d3a4b;
260 $dark_gray:#889aa4; 295 $dark_gray: #889aa4;
261 $light_gray:#eee; 296 $light_gray: #eee;
262 297
263 .login-container { 298 .login-container {
264 min-height: 100%; 299 min-height: 100%;
265 width: 100%; 300 width: 100%;
266 background-color: $bg; 301 background-color: $bg;
267 overflow: hidden; 302 overflow: hidden;
268 303
269 .login-form { 304 .login-form {
270 position: relative; 305 position: relative;
271 width: 520px; 306 width: 520px;
272 max-width: 100%; 307 max-width: 100%;
273 padding: 160px 35px 0; 308 padding: 160px 35px 0;
274 margin: 0 auto; 309 margin: 0 auto;
275 overflow: hidden; 310 overflow: hidden;
276 } 311 }
277 312
278 .tips { 313 .tips {
279 font-size: 14px; 314 font-size: 14px;
280 color: #fff; 315 color: #fff;
281 margin-bottom: 10px; 316 margin-bottom: 10px;
282 317
283 span { 318 span {
284 &:first-of-type { 319 &:first-of-type {
285 margin-right: 16px; 320 margin-right: 16px;
286 } 321 }
287 } 322 }
288 } 323 }
289 324
290 .svg-container { 325 .svg-container {
291 padding: 6px 5px 6px 15px; 326 padding: 6px 5px 6px 15px;
292 color: $dark_gray; 327 color: $dark_gray;
293 vertical-align: middle; 328 vertical-align: middle;
294 width: 30px; 329 width: 30px;
295 display: inline-block; 330 display: inline-block;
296 } 331 }
297 332
298 .title-container { 333 .title-container {
299 position: relative; 334 position: relative;
300 335
301 .title { 336 .title {
302 font-size: 26px; 337 font-size: 26px;
303 color: $light_gray; 338 color: $light_gray;
304 margin: 0px auto 40px auto; 339 margin: 0px auto 40px auto;
305 text-align: center; 340 text-align: center;
306 font-weight: bold; 341 font-weight: bold;
307 } 342 }
308 343
309 .set-language { 344 .set-language {
310 color: #fff; 345 color: #fff;
311 position: absolute; 346 position: absolute;
312 top: 3px; 347 top: 3px;
313 font-size: 18px; 348 font-size: 18px;
314 right: 0px; 349 right: 0px;
315 cursor: pointer; 350 cursor: pointer;
316 } 351 }
317 } 352 }
318 353
319 .show-pwd { 354 .show-pwd {
320 position: absolute; 355 position: absolute;
321 right: 10px; 356 right: 10px;
322 top: 7px; 357 top: 7px;
323 font-size: 16px; 358 font-size: 16px;
324 color: $dark_gray; 359 color: $dark_gray;
325 cursor: pointer; 360 cursor: pointer;
326 user-select: none; 361 user-select: none;
327 } 362 }
328 363
329 .thirdparty-button { 364 .thirdparty-button {
330 position: absolute; 365 position: absolute;
331 right: 0; 366 right: 0;
332 bottom: 6px; 367 bottom: 6px;
333 } 368 }
334 369
335 @media only screen and (max-width: 470px) { 370 @media only screen and (max-width: 470px) {
336 .thirdparty-button { 371 .thirdparty-button {
337 display: none; 372 display: none;
338 } 373 }
src/views/meta/complex-table.vue
File was created 1 <template>
2 <div class="app-container">
3 <div class="filter-container">
4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item">
6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
7 </el-select>
8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px">
9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
10 </el-select>
11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
13 </el-select>
14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
15 {{ $t('table.search') }}
16 </el-button>
17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">
18 {{ $t('table.add') }}
19 </el-button>
20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
21 {{ $t('table.export') }}
22 </el-button>
23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
24 {{ $t('table.reviewer') }}
25 </el-checkbox>
26 </div>
27
28 <el-table
29 :key="tableKey"
30 v-loading="listLoading"
31 :data="list"
32 border
33 fit
34 highlight-current-row
35 style="width: 100%;"
36 @sort-change="sortChange"
37 >
38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
39 <template slot-scope="{row}">
40 <span>{{ row.id }}</span>
41 </template>
42 </el-table-column>
43 <el-table-column :label="$t('table.date')" width="150px" align="center">
44 <template slot-scope="{row}">
45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
46 </template>
47 </el-table-column>
48 <el-table-column :label="$t('table.title')" min-width="150px">
49 <template slot-scope="{row}">
50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
51 <el-tag>{{ row.type | typeFilter }}</el-tag>
52 </template>
53 </el-table-column>
54 <el-table-column :label="$t('table.author')" width="110px" align="center">
55 <template slot-scope="{row}">
56 <span>{{ row.author }}</span>
57 </template>
58 </el-table-column>
59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
60 <template slot-scope="{row}">
61 <span style="color:red;">{{ row.reviewer }}</span>
62 </template>
63 </el-table-column>
64 <el-table-column :label="$t('table.importance')" width="80px">
65 <template slot-scope="{row}">
66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
67 </template>
68 </el-table-column>
69 <el-table-column :label="$t('table.readings')" align="center" width="95">
70 <template slot-scope="{row}">
71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
72 <span v-else>0</span>
73 </template>
74 </el-table-column>
75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100">
76 <template slot-scope="{row}">
77 <el-tag :type="row.status | statusFilter">
78 {{ row.status }}
79 </el-tag>
80 </template>
81 </el-table-column>
82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
83 <template slot-scope="{row,$index}">
84 <el-button type="primary" size="mini" @click="handleUpdate(row)">
85 {{ $t('table.edit') }}
86 </el-button>
87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
88 {{ $t('table.publish') }}
89 </el-button>
90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
91 {{ $t('table.draft') }}
92 </el-button>
93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
94 {{ $t('table.delete') }}
95 </el-button>
96 </template>
97 </el-table-column>
98 </el-table>
99
100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
101
102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
104 <el-form-item :label="$t('table.type')" prop="type">
105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
107 </el-select>
108 </el-form-item>
109 <el-form-item :label="$t('table.date')" prop="timestamp">
110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
111 </el-form-item>
112 <el-form-item :label="$t('table.title')" prop="title">
113 <el-input v-model="temp.title" />
114 </el-form-item>
115 <el-form-item :label="$t('table.status')">
116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
118 </el-select>
119 </el-form-item>
120 <el-form-item :label="$t('table.importance')">
121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
122 </el-form-item>
123 <el-form-item :label="$t('table.remark')">
124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
125 </el-form-item>
126 </el-form>
127 <div slot="footer" class="dialog-footer">
128 <el-button @click="dialogFormVisible = false">
129 {{ $t('table.cancel') }}
130 </el-button>
131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
132 {{ $t('table.confirm') }}
133 </el-button>
134 </div>
135 </el-dialog>
136
137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%">
139 <el-table-column prop="key" label="Channel" />
140 <el-table-column prop="pv" label="Pv" />
141 </el-table>
142 <span slot="footer" class="dialog-footer">
143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
144 </span>
145 </el-dialog>
146 </div>
147 </template>
148
149 <script>
150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
151 import waves from '@/directive/waves' // waves directive
152 import { parseTime } from '@/utils'
153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
154
155 const calendarTypeOptions = [
156 { key: 'CN', display_name: 'China' },
157 { key: 'US', display_name: 'USA' },
158 { key: 'JP', display_name: 'Japan' },
159 { key: 'EU', display_name: 'Eurozone' }
160 ]
161
162 // arr to obj, such as { CN : "China", US : "USA" }
163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
164 acc[cur.key] = cur.display_name
165 return acc
166 }, {})
167
168 export default {
169 name: 'ComplexTable',
170 components: { Pagination },
171 directives: { waves },
172 filters: {
173 statusFilter(status) {
174 const statusMap = {
175 published: 'success',
176 draft: 'info',
177 deleted: 'danger'
178 }
179 return statusMap[status]
180 },
181 typeFilter(type) {
182 return calendarTypeKeyValue[type]
183 }
184 },
185 data() {
186 return {
187 tableKey: 0,
188 list: null,
189 total: 0,
190 listLoading: true,
191 listQuery: {
192 page: 1,
193 limit: 20,
194 importance: undefined,
195 title: undefined,
196 type: undefined,
197 sort: '+id'
198 },
199 importanceOptions: [1, 2, 3],
200 calendarTypeOptions,
201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
202 statusOptions: ['published', 'draft', 'deleted'],
203 showReviewer: false,
204 temp: {
205 id: undefined,
206 importance: 1,
207 remark: '',
208 timestamp: new Date(),
209 title: '',
210 type: '',
211 status: 'published'
212 },
213 dialogFormVisible: false,
214 dialogStatus: '',
215 textMap: {
216 update: 'Edit',
217 create: 'Create'
218 },
219 dialogPvVisible: false,
220 pvData: [],
221 rules: {
222 type: [{ required: true, message: 'type is required', trigger: 'change' }],
223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
224 title: [{ required: true, message: 'title is required', trigger: 'blur' }]
225 },
226 downloadLoading: false
227 }
228 },
229 created() {
230 this.getList()
231 },
232 methods: {
233 getList() {
234 this.listLoading = true
235 fetchList(this.listQuery).then(response => {
236 this.list = response.data.items
237 this.total = response.data.total
238
239 // Just to simulate the time of the request
240 setTimeout(() => {
241 this.listLoading = false
242 }, 1.5 * 1000)
243 })
244 },
245 handleFilter() {
246 this.listQuery.page = 1
247 this.getList()
248 },
249 handleModifyStatus(row, status) {
250 this.$message({
251 message: '操作成功',
252 type: 'success'
253 })
254 row.status = status
255 },
256 sortChange(data) {
257 const { prop, order } = data
258 if (prop === 'id') {
259 this.sortByID(order)
260 }
261 },
262 sortByID(order) {
263 if (order === 'ascending') {
264 this.listQuery.sort = '+id'
265 } else {
266 this.listQuery.sort = '-id'
267 }
268 this.handleFilter()
269 },
270 resetTemp() {
271 this.temp = {
272 id: undefined,
273 importance: 1,
274 remark: '',
275 timestamp: new Date(),
276 title: '',
277 status: 'published',
278 type: ''
279 }
280 },
281 handleCreate() {
282 this.resetTemp()
283 this.dialogStatus = 'create'
284 this.dialogFormVisible = true
285 this.$nextTick(() => {
286 this.$refs['dataForm'].clearValidate()
287 })
288 },
289 createData() {
290 this.$refs['dataForm'].validate((valid) => {
291 if (valid) {
292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
293 this.temp.author = '秀野堂主'
294 createArticle(this.temp).then(() => {
295 this.list.unshift(this.temp)
296 this.dialogFormVisible = false
297 this.$notify({
298 title: '成功',
299 message: '创建成功',
300 type: 'success',
301 duration: 2000
302 })
303 })
304 }
305 })
306 },
307 handleUpdate(row) {
308 this.temp = Object.assign({}, row) // copy obj
309 this.temp.timestamp = new Date(this.temp.timestamp)
310 this.dialogStatus = 'update'
311 this.dialogFormVisible = true
312 this.$nextTick(() => {
313 this.$refs['dataForm'].clearValidate()
314 })
315 },
316 updateData() {
317 this.$refs['dataForm'].validate((valid) => {
318 if (valid) {
319 const tempData = Object.assign({}, this.temp)
320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
321 updateArticle(tempData).then(() => {
322 const index = this.list.findIndex(v => v.id === this.temp.id)
323 this.list.splice(index, 1, this.temp)
324 this.dialogFormVisible = false
325 this.$notify({
326 title: '成功',
327 message: '更新成功',
328 type: 'success',
329 duration: 2000
330 })
331 })
332 }
333 })
334 },
335 handleDelete(row, index) {
336 this.$notify({
337 title: '成功',
338 message: '删除成功',
339 type: 'success',
340 duration: 2000
341 })
342 this.list.splice(index, 1)
343 },
344 handleFetchPv(pv) {
345 fetchPv(pv).then(response => {
346 this.pvData = response.data.pvData
347 this.dialogPvVisible = true
348 })
349 },
350 handleDownload() {
351 this.downloadLoading = true
352 import('@/vendor/Export2Excel').then(excel => {
353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
355 const data = this.formatJson(filterVal)
356 excel.export_json_to_excel({
357 header: tHeader,
358 data,
359 filename: 'table-list'
360 })
361 this.downloadLoading = false
362 })
363 },
364 formatJson(filterVal) {
365 return this.list.map(v => filterVal.map(j => {
366 if (j === 'timestamp') {
367 return parseTime(v[j])
368 } else {
369 return v[j]
370 }
371 }))
372 },
373 getSortClass: function(key) {
374 const sort = this.listQuery.sort
375 return sort === `+${key}` ? 'ascending' : 'descending'
376 }
377 }
378 }
379 </script>
380
src/views/order/complex-table.vue
File was created 1 <template>
2 <div class="app-container">
3 <div class="filter-container">
4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item">
6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
7 </el-select>
8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px">
9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
10 </el-select>
11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
13 </el-select>
14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
15 {{ $t('table.search') }}
16 </el-button>
17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">
18 {{ $t('table.add') }}
19 </el-button>
20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
21 {{ $t('table.export') }}
22 </el-button>
23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
24 {{ $t('table.reviewer') }}
25 </el-checkbox>
26 </div>
27
28 <el-table
29 :key="tableKey"
30 v-loading="listLoading"
31 :data="list"
32 border
33 fit
34 highlight-current-row
35 style="width: 100%;"
36 @sort-change="sortChange"
37 >
38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
39 <template slot-scope="{row}">
40 <span>{{ row.id }}</span>
41 </template>
42 </el-table-column>
43 <el-table-column :label="$t('table.date')" width="150px" align="center">
44 <template slot-scope="{row}">
45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
46 </template>
47 </el-table-column>
48 <el-table-column :label="$t('table.title')" min-width="150px">
49 <template slot-scope="{row}">
50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
51 <el-tag>{{ row.type | typeFilter }}</el-tag>
52 </template>
53 </el-table-column>
54 <el-table-column :label="$t('table.author')" width="110px" align="center">
55 <template slot-scope="{row}">
56 <span>{{ row.author }}</span>
57 </template>
58 </el-table-column>
59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
60 <template slot-scope="{row}">
61 <span style="color:red;">{{ row.reviewer }}</span>
62 </template>
63 </el-table-column>
64 <el-table-column :label="$t('table.importance')" width="80px">
65 <template slot-scope="{row}">
66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
67 </template>
68 </el-table-column>
69 <el-table-column :label="$t('table.readings')" align="center" width="95">
70 <template slot-scope="{row}">
71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
72 <span v-else>0</span>
73 </template>
74 </el-table-column>
75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100">
76 <template slot-scope="{row}">
77 <el-tag :type="row.status | statusFilter">
78 {{ row.status }}
79 </el-tag>
80 </template>
81 </el-table-column>
82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
83 <template slot-scope="{row,$index}">
84 <el-button type="primary" size="mini" @click="handleUpdate(row)">
85 {{ $t('table.edit') }}
86 </el-button>
87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
88 {{ $t('table.publish') }}
89 </el-button>
90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
91 {{ $t('table.draft') }}
92 </el-button>
93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
94 {{ $t('table.delete') }}
95 </el-button>
96 </template>
97 </el-table-column>
98 </el-table>
99
100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
101
102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
104 <el-form-item :label="$t('table.type')" prop="type">
105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
107 </el-select>
108 </el-form-item>
109 <el-form-item :label="$t('table.date')" prop="timestamp">
110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
111 </el-form-item>
112 <el-form-item :label="$t('table.title')" prop="title">
113 <el-input v-model="temp.title" />
114 </el-form-item>
115 <el-form-item :label="$t('table.status')">
116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
118 </el-select>
119 </el-form-item>
120 <el-form-item :label="$t('table.importance')">
121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
122 </el-form-item>
123 <el-form-item :label="$t('table.remark')">
124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
125 </el-form-item>
126 </el-form>
127 <div slot="footer" class="dialog-footer">
128 <el-button @click="dialogFormVisible = false">
129 {{ $t('table.cancel') }}
130 </el-button>
131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
132 {{ $t('table.confirm') }}
133 </el-button>
134 </div>
135 </el-dialog>
136
137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%">
139 <el-table-column prop="key" label="Channel" />
140 <el-table-column prop="pv" label="Pv" />
141 </el-table>
142 <span slot="footer" class="dialog-footer">
143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
144 </span>
145 </el-dialog>
146 </div>
147 </template>
148
149 <script>
150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
151 import waves from '@/directive/waves' // waves directive
152 import { parseTime } from '@/utils'
153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
154
155 const calendarTypeOptions = [
156 { key: 'CN', display_name: 'China' },
157 { key: 'US', display_name: 'USA' },
158 { key: 'JP', display_name: 'Japan' },
159 { key: 'EU', display_name: 'Eurozone' }
160 ]
161
162 // arr to obj, such as { CN : "China", US : "USA" }
163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
164 acc[cur.key] = cur.display_name
165 return acc
166 }, {})
167
168 export default {
169 name: 'ComplexTable',
170 components: { Pagination },
171 directives: { waves },
172 filters: {
173 statusFilter(status) {
174 const statusMap = {
175 published: 'success',
176 draft: 'info',
177 deleted: 'danger'
178 }
179 return statusMap[status]
180 },
181 typeFilter(type) {
182 return calendarTypeKeyValue[type]
183 }
184 },
185 data() {
186 return {
187 tableKey: 0,
188 list: null,
189 total: 0,
190 listLoading: true,
191 listQuery: {
192 page: 1,
193 limit: 20,
194 importance: undefined,
195 title: undefined,
196 type: undefined,
197 sort: '+id'
198 },
199 importanceOptions: [1, 2, 3],
200 calendarTypeOptions,
201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
202 statusOptions: ['published', 'draft', 'deleted'],
203 showReviewer: false,
204 temp: {
205 id: undefined,
206 importance: 1,
207 remark: '',
208 timestamp: new Date(),
209 title: '',
210 type: '',
211 status: 'published'
212 },
213 dialogFormVisible: false,
214 dialogStatus: '',
215 textMap: {
216 update: 'Edit',
217 create: 'Create'
218 },
219 dialogPvVisible: false,
220 pvData: [],
221 rules: {
222 type: [{ required: true, message: 'type is required', trigger: 'change' }],
223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
224 title: [{ required: true, message: 'title is required', trigger: 'blur' }]
225 },
226 downloadLoading: false
227 }
228 },
229 created() {
230 this.getList()
231 },
232 methods: {
233 getList() {
234 this.listLoading = true
235 fetchList(this.listQuery).then(response => {
236 this.list = response.data.items
237 this.total = response.data.total
238
239 // Just to simulate the time of the request
240 setTimeout(() => {
241 this.listLoading = false
242 }, 1.5 * 1000)
243 })
244 },
245 handleFilter() {
246 this.listQuery.page = 1
247 this.getList()
248 },
249 handleModifyStatus(row, status) {
250 this.$message({
251 message: '操作成功',
252 type: 'success'
253 })
254 row.status = status
255 },
256 sortChange(data) {
257 const { prop, order } = data
258 if (prop === 'id') {
259 this.sortByID(order)
260 }
261 },
262 sortByID(order) {
263 if (order === 'ascending') {
264 this.listQuery.sort = '+id'
265 } else {
266 this.listQuery.sort = '-id'
267 }
268 this.handleFilter()
269 },
270 resetTemp() {
271 this.temp = {
272 id: undefined,
273 importance: 1,
274 remark: '',
275 timestamp: new Date(),
276 title: '',
277 status: 'published',
278 type: ''
279 }
280 },
281 handleCreate() {
282 this.resetTemp()
283 this.dialogStatus = 'create'
284 this.dialogFormVisible = true
285 this.$nextTick(() => {
286 this.$refs['dataForm'].clearValidate()
287 })
288 },
289 createData() {
290 this.$refs['dataForm'].validate((valid) => {
291 if (valid) {
292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
293 this.temp.author = '秀野堂主'
294 createArticle(this.temp).then(() => {
295 this.list.unshift(this.temp)
296 this.dialogFormVisible = false
297 this.$notify({
298 title: '成功',
299 message: '创建成功',
300 type: 'success',
301 duration: 2000
302 })
303 })
304 }
305 })
306 },
307 handleUpdate(row) {
308 this.temp = Object.assign({}, row) // copy obj
309 this.temp.timestamp = new Date(this.temp.timestamp)
310 this.dialogStatus = 'update'
311 this.dialogFormVisible = true
312 this.$nextTick(() => {
313 this.$refs['dataForm'].clearValidate()
314 })
315 },
316 updateData() {
317 this.$refs['dataForm'].validate((valid) => {
318 if (valid) {
319 const tempData = Object.assign({}, this.temp)
320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
321 updateArticle(tempData).then(() => {
322 const index = this.list.findIndex(v => v.id === this.temp.id)
323 this.list.splice(index, 1, this.temp)
324 this.dialogFormVisible = false
325 this.$notify({
326 title: '成功',
327 message: '更新成功',
328 type: 'success',
329 duration: 2000
330 })
331 })
332 }
333 })
334 },
335 handleDelete(row, index) {
336 this.$notify({
337 title: '成功',
338 message: '删除成功',
339 type: 'success',
340 duration: 2000
341 })
342 this.list.splice(index, 1)
343 },
344 handleFetchPv(pv) {
345 fetchPv(pv).then(response => {
346 this.pvData = response.data.pvData
347 this.dialogPvVisible = true
348 })
349 },
350 handleDownload() {
351 this.downloadLoading = true
352 import('@/vendor/Export2Excel').then(excel => {
353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
355 const data = this.formatJson(filterVal)
356 excel.export_json_to_excel({
357 header: tHeader,
358 data,
359 filename: 'table-list'
360 })
361 this.downloadLoading = false
362 })
363 },
364 formatJson(filterVal) {
365 return this.list.map(v => filterVal.map(j => {
366 if (j === 'timestamp') {
367 return parseTime(v[j])
368 } else {
369 return v[j]
370 }
371 }))
372 },
373 getSortClass: function(key) {
374 const sort = this.listQuery.sort
375 return sort === `+${key}` ? 'ascending' : 'descending'
376 }
377 }
378 }
379 </script>
380
src/views/permission/components/SwitchRoles.vue
1 <template> 1 <template>
2 <div> 2 <div>
3 <div style="margin-bottom:15px;"> 3 <div style="margin-bottom:15px;">
4 {{ $t('permission.roles') }}: {{ roles }} 4 {{ $t('permission.roles') }}: {{ roles }}
5 </div> 5 </div>
6 {{ $t('permission.switchRoles') }}: 6 {{ $t('permission.switchRoles') }}:
7 <el-radio-group v-model="switchRoles"> 7 <el-radio-group v-model="switchRoles">
8 <el-radio-button label="editor" /> 8 <el-radio-button label="runner" />
9 <el-radio-button label="shoper" />
10 <el-radio-button label="assistant" />
9 <el-radio-button label="admin" /> 11 <el-radio-button label="admin" />
10 </el-radio-group> 12 </el-radio-group>
11 </div> 13 </div>
12 </template> 14 </template>
13 15
14 <script> 16 <script>
15 export default { 17 export default {
16 computed: { 18 computed: {
17 roles() { 19 roles() {
18 return this.$store.getters.roles 20 return this.$store.getters.roles
19 }, 21 },
20 switchRoles: { 22 switchRoles: {
21 get() { 23 get() {
22 return this.roles[0] 24 return this.roles[0]
23 }, 25 },
24 set(val) { 26 set(val) {
25 this.$store.dispatch('user/changeRoles', val).then(() => { 27 this.$store.dispatch('user/changeRoles', val).then(() => {
26 this.$emit('change') 28 this.$emit('change')
27 }) 29 })
28 } 30 }
29 } 31 }
30 } 32 }
31 } 33 }
32 </script> 34 </script>
33 35
src/views/permission/directive.vue
1 <template> 1 <template>
2 <div class="app-container"> 2 <div class="app-container">
3 <switch-roles @change="handleRolesChange" /> 3 <switch-roles @change="handleRolesChange" />
4 <div :key="key" style="margin-top:30px;"> 4 <div :key="key" style="margin-top:30px;">
5 <div> 5 <div>
6 <span v-permission="['admin']" class="permission-alert"> 6 <span v-permission="['admin']" class="permission-alert">
7 Only 7 Only
8 <el-tag class="permission-tag" size="small">admin</el-tag> can see this 8 <el-tag class="permission-tag" size="small">admin</el-tag> can see this
9 </span> 9 </span>
10 <el-tag v-permission="['admin']" class="permission-sourceCode" type="info"> 10 <el-tag v-permission="['admin']" class="permission-sourceCode" type="info">
11 v-permission="['admin']" 11 v-permission="['admin']"
12 </el-tag> 12 </el-tag>
13 </div> 13 </div>
14 14
15 <div> 15 <div>
16 <span v-permission="['editor']" class="permission-alert"> 16 <span v-permission="['runner']" class="permission-alert">
17 Only 17 Only
18 <el-tag class="permission-tag" size="small">editor</el-tag> can see this 18 <el-tag class="permission-tag" size="small">runner</el-tag> can see this
19 </span> 19 </span>
20 <el-tag v-permission="['editor']" class="permission-sourceCode" type="info"> 20 <el-tag v-permission="['runner']" class="permission-sourceCode" type="info">
21 v-permission="['editor']" 21 v-permission="['runner']"
22 </el-tag> 22 </el-tag>
23 </div> 23 </div>
24 24
25 <div> 25 <div>
26 <span v-permission="['admin','editor']" class="permission-alert"> 26 <span v-permission="['admin','shoper']" class="permission-alert">
27 Both 27 Both
28 <el-tag class="permission-tag" size="small">admin</el-tag> and 28 <el-tag class="permission-tag" size="small">admin</el-tag> and
29 <el-tag class="permission-tag" size="small">editor</el-tag> can see this 29 <el-tag class="permission-tag" size="small">shoper</el-tag> can see this
30 </span> 30 </span>
31 <el-tag v-permission="['admin','editor']" class="permission-sourceCode" type="info"> 31 <el-tag v-permission="['admin','shoper']" class="permission-sourceCode" type="info">
32 v-permission="['admin','editor']" 32 v-permission="['admin','shoper']"
33 </el-tag> 33 </el-tag>
34 </div> 34 </div>
35 </div> 35 </div>
36 36
37 <div :key="'checkPermission'+key" style="margin-top:60px;"> 37 <div :key="'checkPermission'+key" style="margin-top:60px;">
38 <aside> 38 <aside>
39 {{ $t('permission.tips') }} 39 {{ $t('permission.tips') }}
40 <br> e.g. 40 <br> e.g.
41 </aside> 41 </aside>
42 42
43 <el-tabs type="border-card" style="width:550px;"> 43 <el-tabs type="border-card" style="width:550px;">
44 <el-tab-pane v-if="checkPermission(['admin'])" label="Admin"> 44 <el-tab-pane v-if="checkPermission(['admin'])" label="Admin">
45 Admin can see this 45 Admin can see this
46 <el-tag class="permission-sourceCode" type="info"> 46 <el-tag class="permission-sourceCode" type="info">
47 v-if="checkPermission(['admin'])" 47 v-if="checkPermission(['admin'])"
48 </el-tag> 48 </el-tag>
49 </el-tab-pane> 49 </el-tab-pane>
50 50
51 <el-tab-pane v-if="checkPermission(['editor'])" label="Editor"> 51 <el-tab-pane v-if="checkPermission(['shoper'])" label="Shoper">
52 Editor can see this 52 Shoper can see this
53 <el-tag class="permission-sourceCode" type="info"> 53 <el-tag class="permission-sourceCode" type="info">
54 v-if="checkPermission(['editor'])" 54 v-if="checkPermission(['shoper'])"
55 </el-tag> 55 </el-tag>
56 </el-tab-pane> 56 </el-tab-pane>
57 57
58 <el-tab-pane v-if="checkPermission(['admin','editor'])" label="Admin-OR-Editor"> 58 <el-tab-pane v-if="checkPermission(['admin','runner'])" label="Admin-OR-Runner">
59 Both admin or editor can see this 59 Both admin or runner can see this
60 <el-tag class="permission-sourceCode" type="info"> 60 <el-tag class="permission-sourceCode" type="info">
61 v-if="checkPermission(['admin','editor'])" 61 v-if="checkPermission(['admin','runner'])"
62 </el-tag> 62 </el-tag>
63 </el-tab-pane> 63 </el-tab-pane>
64 </el-tabs> 64 </el-tabs>
65 </div> 65 </div>
66 </div> 66 </div>
67 </template> 67 </template>
68 68
69 <script> 69 <script>
70 import permission from '@/directive/permission/index.js' // 权限判断指令 70 import permission from '@/directive/permission/index.js' // 权限判断指令
71 import checkPermission from '@/utils/permission' // 权限判断函数 71 import checkPermission from '@/utils/permission' // 权限判断函数
72 import SwitchRoles from './components/SwitchRoles' 72 import SwitchRoles from './components/SwitchRoles'
73 73
74 export default { 74 export default {
75 name: 'DirectivePermission', 75 name: 'DirectivePermission',
76 components: { SwitchRoles }, 76 components: { SwitchRoles },
77 directives: { permission }, 77 directives: { permission },
78 data() { 78 data() {
79 return { 79 return {
80 key: 1 // 为了能每次切换权限的时候重新初始化指令 80 key: 1 // 为了能每次切换权限的时候重新初始化指令
81 } 81 }
82 }, 82 },
83 methods: { 83 methods: {
84 checkPermission, 84 checkPermission,
85 handleRolesChange() { 85 handleRolesChange() {
86 this.key++ 86 this.key++
87 } 87 }
88 } 88 }
89 } 89 }
90 </script> 90 </script>
91 91
92 <style lang="scss" scoped> 92 <style lang="scss" scoped>
93 .app-container { 93 .app-container {
94 /deep/ .permission-alert { 94 /deep/ .permission-alert {
95 width: 320px; 95 width: 320px;
96 margin-top: 15px; 96 margin-top: 15px;
97 background-color: #f0f9eb; 97 background-color: #f0f9eb;
98 color: #67c23a; 98 color: #67c23a;
99 padding: 8px 16px; 99 padding: 8px 16px;
100 border-radius: 4px; 100 border-radius: 4px;
101 display: inline-block; 101 display: inline-block;
102 } 102 }
103 /deep/ .permission-sourceCode { 103 /deep/ .permission-sourceCode {
104 margin-left: 15px; 104 margin-left: 15px;
105 } 105 }
106 /deep/ .permission-tag { 106 /deep/ .permission-tag {
107 background-color: #ecf5ff; 107 background-color: #ecf5ff;
108 } 108 }
109 } 109 }
110 </style> 110 </style>
111 111
112 112
src/views/prod/complex-table.vue
File was created 1 <template>
2 <div class="app-container">
3 <div class="filter-container">
4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item">
6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
7 </el-select>
8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px">
9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
10 </el-select>
11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
13 </el-select>
14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
15 {{ $t('table.search') }}
16 </el-button>
17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">
18 {{ $t('table.add') }}
19 </el-button>
20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
21 {{ $t('table.export') }}
22 </el-button>
23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
24 {{ $t('table.reviewer') }}
25 </el-checkbox>
26 </div>
27
28 <el-table
29 :key="tableKey"
30 v-loading="listLoading"
31 :data="list"
32 border
33 fit
34 highlight-current-row
35 style="width: 100%;"
36 @sort-change="sortChange"
37 >
38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
39 <template slot-scope="{row}">
40 <span>{{ row.id }}</span>
41 </template>
42 </el-table-column>
43 <el-table-column :label="$t('table.date')" width="150px" align="center">
44 <template slot-scope="{row}">
45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
46 </template>
47 </el-table-column>
48 <el-table-column :label="$t('table.title')" min-width="150px">
49 <template slot-scope="{row}">
50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
51 <el-tag>{{ row.type | typeFilter }}</el-tag>
52 </template>
53 </el-table-column>
54 <el-table-column :label="$t('table.author')" width="110px" align="center">
55 <template slot-scope="{row}">
56 <span>{{ row.author }}</span>
57 </template>
58 </el-table-column>
59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
60 <template slot-scope="{row}">
61 <span style="color:red;">{{ row.reviewer }}</span>
62 </template>
63 </el-table-column>
64 <el-table-column :label="$t('table.importance')" width="80px">
65 <template slot-scope="{row}">
66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
67 </template>
68 </el-table-column>
69 <el-table-column :label="$t('table.readings')" align="center" width="95">
70 <template slot-scope="{row}">
71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
72 <span v-else>0</span>
73 </template>
74 </el-table-column>
75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100">
76 <template slot-scope="{row}">
77 <el-tag :type="row.status | statusFilter">
78 {{ row.status }}
79 </el-tag>
80 </template>
81 </el-table-column>
82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
83 <template slot-scope="{row,$index}">
84 <el-button type="primary" size="mini" @click="handleUpdate(row)">
85 {{ $t('table.edit') }}
86 </el-button>
87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
88 {{ $t('table.publish') }}
89 </el-button>
90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
91 {{ $t('table.draft') }}
92 </el-button>
93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
94 {{ $t('table.delete') }}
95 </el-button>
96 </template>
97 </el-table-column>
98 </el-table>
99
100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
101
102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
104 <el-form-item :label="$t('table.type')" prop="type">
105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
107 </el-select>
108 </el-form-item>
109 <el-form-item :label="$t('table.date')" prop="timestamp">
110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
111 </el-form-item>
112 <el-form-item :label="$t('table.title')" prop="title">
113 <el-input v-model="temp.title" />
114 </el-form-item>
115 <el-form-item :label="$t('table.status')">
116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
118 </el-select>
119 </el-form-item>
120 <el-form-item :label="$t('table.importance')">
121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
122 </el-form-item>
123 <el-form-item :label="$t('table.remark')">
124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
125 </el-form-item>
126 </el-form>
127 <div slot="footer" class="dialog-footer">
128 <el-button @click="dialogFormVisible = false">
129 {{ $t('table.cancel') }}
130 </el-button>
131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
132 {{ $t('table.confirm') }}
133 </el-button>
134 </div>
135 </el-dialog>
136
137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%">
139 <el-table-column prop="key" label="Channel" />
140 <el-table-column prop="pv" label="Pv" />
141 </el-table>
142 <span slot="footer" class="dialog-footer">
143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
144 </span>
145 </el-dialog>
146 </div>
147 </template>
148
149 <script>
150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
151 import waves from '@/directive/waves' // waves directive
152 import { parseTime } from '@/utils'
153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
154
155 const calendarTypeOptions = [
156 { key: 'CN', display_name: 'China' },
157 { key: 'US', display_name: 'USA' },
158 { key: 'JP', display_name: 'Japan' },
159 { key: 'EU', display_name: 'Eurozone' }
160 ]
161
162 // arr to obj, such as { CN : "China", US : "USA" }
163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
164 acc[cur.key] = cur.display_name
165 return acc
166 }, {})
167
168 export default {
169 name: 'ComplexTable',
170 components: { Pagination },
171 directives: { waves },
172 filters: {
173 statusFilter(status) {
174 const statusMap = {
175 published: 'success',
176 draft: 'info',
177 deleted: 'danger'
178 }
179 return statusMap[status]
180 },
181 typeFilter(type) {
182 return calendarTypeKeyValue[type]
183 }
184 },
185 data() {
186 return {
187 tableKey: 0,
188 list: null,
189 total: 0,
190 listLoading: true,
191 listQuery: {
192 page: 1,
193 limit: 20,
194 importance: undefined,
195 title: undefined,
196 type: undefined,
197 sort: '+id'
198 },
199 importanceOptions: [1, 2, 3],
200 calendarTypeOptions,
201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
202 statusOptions: ['published', 'draft', 'deleted'],
203 showReviewer: false,
204 temp: {
205 id: undefined,
206 importance: 1,
207 remark: '',
208 timestamp: new Date(),
209 title: '',
210 type: '',
211 status: 'published'
212 },
213 dialogFormVisible: false,
214 dialogStatus: '',
215 textMap: {
216 update: 'Edit',
217 create: 'Create'
218 },
219 dialogPvVisible: false,
220 pvData: [],
221 rules: {
222 type: [{ required: true, message: 'type is required', trigger: 'change' }],
223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
224 title: [{ required: true, message: 'title is required', trigger: 'blur' }]
225 },
226 downloadLoading: false
227 }
228 },
229 created() {
230 this.getList()
231 },
232 methods: {
233 getList() {
234 this.listLoading = true
235 fetchList(this.listQuery).then(response => {
236 this.list = response.data.items
237 this.total = response.data.total
238
239 // Just to simulate the time of the request
240 setTimeout(() => {
241 this.listLoading = false
242 }, 1.5 * 1000)
243 })
244 },
245 handleFilter() {
246 this.listQuery.page = 1
247 this.getList()
248 },
249 handleModifyStatus(row, status) {
250 this.$message({
251 message: '操作成功',
252 type: 'success'
253 })
254 row.status = status
255 },
256 sortChange(data) {
257 const { prop, order } = data
258 if (prop === 'id') {
259 this.sortByID(order)
260 }
261 },
262 sortByID(order) {
263 if (order === 'ascending') {
264 this.listQuery.sort = '+id'
265 } else {
266 this.listQuery.sort = '-id'
267 }
268 this.handleFilter()
269 },
270 resetTemp() {
271 this.temp = {
272 id: undefined,
273 importance: 1,
274 remark: '',
275 timestamp: new Date(),
276 title: '',
277 status: 'published',
278 type: ''
279 }
280 },
281 handleCreate() {
282 this.resetTemp()
283 this.dialogStatus = 'create'
284 this.dialogFormVisible = true
285 this.$nextTick(() => {
286 this.$refs['dataForm'].clearValidate()
287 })
288 },
289 createData() {
290 this.$refs['dataForm'].validate((valid) => {
291 if (valid) {
292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
293 this.temp.author = '秀野堂主'
294 createArticle(this.temp).then(() => {
295 this.list.unshift(this.temp)
296 this.dialogFormVisible = false
297 this.$notify({
298 title: '成功',
299 message: '创建成功',
300 type: 'success',
301 duration: 2000
302 })
303 })
304 }
305 })
306 },
307 handleUpdate(row) {
308 this.temp = Object.assign({}, row) // copy obj
309 this.temp.timestamp = new Date(this.temp.timestamp)
310 this.dialogStatus = 'update'
311 this.dialogFormVisible = true
312 this.$nextTick(() => {
313 this.$refs['dataForm'].clearValidate()
314 })
315 },
316 updateData() {
317 this.$refs['dataForm'].validate((valid) => {
318 if (valid) {
319 const tempData = Object.assign({}, this.temp)
320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
321 updateArticle(tempData).then(() => {
322 const index = this.list.findIndex(v => v.id === this.temp.id)
323 this.list.splice(index, 1, this.temp)
324 this.dialogFormVisible = false
325 this.$notify({
326 title: '成功',
327 message: '更新成功',
328 type: 'success',
329 duration: 2000
330 })
331 })
332 }
333 })
334 },
335 handleDelete(row, index) {
336 this.$notify({
337 title: '成功',
338 message: '删除成功',
339 type: 'success',
340 duration: 2000
341 })
342 this.list.splice(index, 1)
343 },
344 handleFetchPv(pv) {
345 fetchPv(pv).then(response => {
346 this.pvData = response.data.pvData
347 this.dialogPvVisible = true
348 })
349 },
350 handleDownload() {
351 this.downloadLoading = true
352 import('@/vendor/Export2Excel').then(excel => {
353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
355 const data = this.formatJson(filterVal)
356 excel.export_json_to_excel({
357 header: tHeader,
358 data,
359 filename: 'table-list'
360 })
361 this.downloadLoading = false
362 })
363 },
364 formatJson(filterVal) {
365 return this.list.map(v => filterVal.map(j => {
366 if (j === 'timestamp') {
367 return parseTime(v[j])
368 } else {
369 return v[j]
370 }
371 }))
372 },
373 getSortClass: function(key) {
374 const sort = this.listQuery.sort
375 return sort === `+${key}` ? 'ascending' : 'descending'
376 }
377 }
378 }
379 </script>
380
src/views/system/complex-table.vue
File was created 1 <template>
2 <div class="app-container">
3 <div class="filter-container">
4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item">
6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
7 </el-select>
8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px">
9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
10 </el-select>
11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
13 </el-select>
14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
15 {{ $t('table.search') }}
16 </el-button>
17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">
18 {{ $t('table.add') }}
19 </el-button>
20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
21 {{ $t('table.export') }}
22 </el-button>
23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
24 {{ $t('table.reviewer') }}
25 </el-checkbox>
26 </div>
27
28 <el-table
29 :key="tableKey"
30 v-loading="listLoading"
31 :data="list"
32 border
33 fit
34 highlight-current-row
35 style="width: 100%;"
36 @sort-change="sortChange"
37 >
38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
39 <template slot-scope="{row}">
40 <span>{{ row.id }}</span>
41 </template>
42 </el-table-column>
43 <el-table-column :label="$t('table.date')" width="150px" align="center">
44 <template slot-scope="{row}">
45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
46 </template>
47 </el-table-column>
48 <el-table-column :label="$t('table.title')" min-width="150px">
49 <template slot-scope="{row}">
50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
51 <el-tag>{{ row.type | typeFilter }}</el-tag>
52 </template>
53 </el-table-column>
54 <el-table-column :label="$t('table.author')" width="110px" align="center">
55 <template slot-scope="{row}">
56 <span>{{ row.author }}</span>
57 </template>
58 </el-table-column>
59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
60 <template slot-scope="{row}">
61 <span style="color:red;">{{ row.reviewer }}</span>
62 </template>
63 </el-table-column>
64 <el-table-column :label="$t('table.importance')" width="80px">
65 <template slot-scope="{row}">
66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
67 </template>
68 </el-table-column>
69 <el-table-column :label="$t('table.readings')" align="center" width="95">
70 <template slot-scope="{row}">
71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
72 <span v-else>0</span>
73 </template>
74 </el-table-column>
75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100">
76 <template slot-scope="{row}">
77 <el-tag :type="row.status | statusFilter">
78 {{ row.status }}
79 </el-tag>
80 </template>
81 </el-table-column>
82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
83 <template slot-scope="{row,$index}">
84 <el-button type="primary" size="mini" @click="handleUpdate(row)">
85 {{ $t('table.edit') }}
86 </el-button>
87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
88 {{ $t('table.publish') }}
89 </el-button>
90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
91 {{ $t('table.draft') }}
92 </el-button>
93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
94 {{ $t('table.delete') }}
95 </el-button>
96 </template>
97 </el-table-column>
98 </el-table>
99
100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
101
102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
104 <el-form-item :label="$t('table.type')" prop="type">
105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
107 </el-select>
108 </el-form-item>
109 <el-form-item :label="$t('table.date')" prop="timestamp">
110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
111 </el-form-item>
112 <el-form-item :label="$t('table.title')" prop="title">
113 <el-input v-model="temp.title" />
114 </el-form-item>
115 <el-form-item :label="$t('table.status')">
116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
118 </el-select>
119 </el-form-item>
120 <el-form-item :label="$t('table.importance')">
121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
122 </el-form-item>
123 <el-form-item :label="$t('table.remark')">
124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
125 </el-form-item>
126 </el-form>
127 <div slot="footer" class="dialog-footer">
128 <el-button @click="dialogFormVisible = false">
129 {{ $t('table.cancel') }}
130 </el-button>
131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
132 {{ $t('table.confirm') }}
133 </el-button>
134 </div>
135 </el-dialog>
136
137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%">
139 <el-table-column prop="key" label="Channel" />
140 <el-table-column prop="pv" label="Pv" />
141 </el-table>
142 <span slot="footer" class="dialog-footer">
143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
144 </span>
145 </el-dialog>
146 </div>
147 </template>
148
149 <script>
150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
151 import waves from '@/directive/waves' // waves directive
152 import { parseTime } from '@/utils'
153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
154
155 const calendarTypeOptions = [
156 { key: 'CN', display_name: 'China' },
157 { key: 'US', display_name: 'USA' },
158 { key: 'JP', display_name: 'Japan' },
159 { key: 'EU', display_name: 'Eurozone' }
160 ]
161
162 // arr to obj, such as { CN : "China", US : "USA" }
163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
164 acc[cur.key] = cur.display_name
165 return acc
166 }, {})
167
168 export default {
169 name: 'ComplexTable',
170 components: { Pagination },
171 directives: { waves },
172 filters: {
173 statusFilter(status) {
174 const statusMap = {
175 published: 'success',
176 draft: 'info',
177 deleted: 'danger'
178 }
179 return statusMap[status]
180 },
181 typeFilter(type) {
182 return calendarTypeKeyValue[type]
183 }
184 },
185 data() {
186 return {
187 tableKey: 0,
188 list: null,
189 total: 0,
190 listLoading: true,
191 listQuery: {
192 page: 1,
193 limit: 20,
194 importance: undefined,
195 title: undefined,
196 type: undefined,
197 sort: '+id'
198 },
199 importanceOptions: [1, 2, 3],
200 calendarTypeOptions,
201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
202 statusOptions: ['published', 'draft', 'deleted'],
203 showReviewer: false,
204 temp: {
205 id: undefined,
206 importance: 1,
207 remark: '',
208 timestamp: new Date(),
209 title: '',
210 type: '',
211 status: 'published'
212 },
213 dialogFormVisible: false,
214 dialogStatus: '',
215 textMap: {
216 update: 'Edit',
217 create: 'Create'
218 },
219 dialogPvVisible: false,
220 pvData: [],
221 rules: {
222 type: [{ required: true, message: 'type is required', trigger: 'change' }],
223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
224 title: [{ required: true, message: 'title is required', trigger: 'blur' }]
225 },
226 downloadLoading: false
227 }
228 },
229 created() {
230 this.getList()
231 },
232 methods: {
233 getList() {
234 this.listLoading = true
235 fetchList(this.listQuery).then(response => {
236 this.list = response.data.items
237 this.total = response.data.total
238
239 // Just to simulate the time of the request
240 setTimeout(() => {
241 this.listLoading = false
242 }, 1.5 * 1000)
243 })
244 },
245 handleFilter() {
246 this.listQuery.page = 1
247 this.getList()
248 },
249 handleModifyStatus(row, status) {
250 this.$message({
251 message: '操作成功',
252 type: 'success'
253 })
254 row.status = status
255 },
256 sortChange(data) {
257 const { prop, order } = data
258 if (prop === 'id') {
259 this.sortByID(order)
260 }
261 },
262 sortByID(order) {
263 if (order === 'ascending') {
264 this.listQuery.sort = '+id'
265 } else {
266 this.listQuery.sort = '-id'
267 }
268 this.handleFilter()
269 },
270 resetTemp() {
271 this.temp = {
272 id: undefined,
273 importance: 1,
274 remark: '',
275 timestamp: new Date(),
276 title: '',
277 status: 'published',
278 type: ''
279 }
280 },
281 handleCreate() {
282 this.resetTemp()
283 this.dialogStatus = 'create'
284 this.dialogFormVisible = true
285 this.$nextTick(() => {
286 this.$refs['dataForm'].clearValidate()
287 })
288 },
289 createData() {
290 this.$refs['dataForm'].validate((valid) => {
291 if (valid) {
292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
293 this.temp.author = '秀野堂主'
294 createArticle(this.temp).then(() => {
295 this.list.unshift(this.temp)
296 this.dialogFormVisible = false
297 this.$notify({
298 title: '成功',
299 message: '创建成功',
300 type: 'success',
301 duration: 2000
302 })
303 })
304 }
305 })
306 },
307 handleUpdate(row) {
308 this.temp = Object.assign({}, row) // copy obj
309 this.temp.timestamp = new Date(this.temp.timestamp)
310 this.dialogStatus = 'update'
311 this.dialogFormVisible = true
312 this.$nextTick(() => {
313 this.$refs['dataForm'].clearValidate()
314 })
315 },
316 updateData() {
317 this.$refs['dataForm'].validate((valid) => {
318 if (valid) {
319 const tempData = Object.assign({}, this.temp)
320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
321 updateArticle(tempData).then(() => {
322 const index = this.list.findIndex(v => v.id === this.temp.id)
323 this.list.splice(index, 1, this.temp)
324 this.dialogFormVisible = false
325 this.$notify({
326 title: '成功',
327 message: '更新成功',
328 type: 'success',
329 duration: 2000
330 })
331 })
332 }
333 })
334 },
335 handleDelete(row, index) {
336 this.$notify({
337 title: '成功',
338 message: '删除成功',
339 type: 'success',
340 duration: 2000
341 })
342 this.list.splice(index, 1)
343 },
344 handleFetchPv(pv) {
345 fetchPv(pv).then(response => {
346 this.pvData = response.data.pvData
347 this.dialogPvVisible = true
348 })
349 },
350 handleDownload() {
351 this.downloadLoading = true
352 import('@/vendor/Export2Excel').then(excel => {
353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
355 const data = this.formatJson(filterVal)
356 excel.export_json_to_excel({
357 header: tHeader,
358 data,
359 filename: 'table-list'
360 })
361 this.downloadLoading = false
362 })
363 },
364 formatJson(filterVal) {
365 return this.list.map(v => filterVal.map(j => {
366 if (j === 'timestamp') {
367 return parseTime(v[j])
368 } else {
369 return v[j]
370 }
371 }))
372 },
373 getSortClass: function(key) {
374 const sort = this.listQuery.sort
375 return sort === `+${key}` ? 'ascending' : 'descending'
376 }
377 }
378 }
379 </script>
380
src/views/table/complex-table.vue
1 <template> 1 <template>
2 <div class="app-container"> 2 <div class="app-container">
3 <div class="filter-container"> 3 <div class="filter-container">
4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" /> 4 <el-input v-model="listQuery.title" :placeholder="$t('table.title')" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter" />
5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item"> 5 <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item">
6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" /> 6 <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item" />
7 </el-select> 7 </el-select>
8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px"> 8 <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px">
9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" /> 9 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key" />
10 </el-select> 10 </el-select>
11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter"> 11 <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter">
12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" /> 12 <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key" />
13 </el-select> 13 </el-select>
14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter"> 14 <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
15 {{ $t('table.search') }} 15 {{ $t('table.search') }}
16 </el-button> 16 </el-button>
17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate"> 17 <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">
18 {{ $t('table.add') }} 18 {{ $t('table.add') }}
19 </el-button> 19 </el-button>
20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload"> 20 <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">
21 {{ $t('table.export') }} 21 {{ $t('table.export') }}
22 </el-button> 22 </el-button>
23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1"> 23 <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">
24 {{ $t('table.reviewer') }} 24 {{ $t('table.reviewer') }}
25 </el-checkbox> 25 </el-checkbox>
26 </div> 26 </div>
27 27
28 <el-table 28 <el-table
29 :key="tableKey" 29 :key="tableKey"
30 v-loading="listLoading" 30 v-loading="listLoading"
31 :data="list" 31 :data="list"
32 border 32 border
33 fit 33 fit
34 highlight-current-row 34 highlight-current-row
35 style="width: 100%;" 35 style="width: 100%;"
36 @sort-change="sortChange" 36 @sort-change="sortChange"
37 > 37 >
38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')"> 38 <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="80" :class-name="getSortClass('id')">
39 <template slot-scope="{row}"> 39 <template slot-scope="{row}">
40 <span>{{ row.id }}</span> 40 <span>{{ row.id }}</span>
41 </template> 41 </template>
42 </el-table-column> 42 </el-table-column>
43 <el-table-column :label="$t('table.date')" width="150px" align="center"> 43 <el-table-column :label="$t('table.date')" width="150px" align="center">
44 <template slot-scope="{row}"> 44 <template slot-scope="{row}">
45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> 45 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
46 </template> 46 </template>
47 </el-table-column> 47 </el-table-column>
48 <el-table-column :label="$t('table.title')" min-width="150px"> 48 <el-table-column :label="$t('table.title')" min-width="150px">
49 <template slot-scope="{row}"> 49 <template slot-scope="{row}">
50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span> 50 <span class="link-type" @click="handleUpdate(row)">{{ row.title }}</span>
51 <el-tag>{{ row.type | typeFilter }}</el-tag> 51 <el-tag>{{ row.type | typeFilter }}</el-tag>
52 </template> 52 </template>
53 </el-table-column> 53 </el-table-column>
54 <el-table-column :label="$t('table.author')" width="110px" align="center"> 54 <el-table-column :label="$t('table.author')" width="110px" align="center">
55 <template slot-scope="{row}"> 55 <template slot-scope="{row}">
56 <span>{{ row.author }}</span> 56 <span>{{ row.author }}</span>
57 </template> 57 </template>
58 </el-table-column> 58 </el-table-column>
59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center"> 59 <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center">
60 <template slot-scope="{row}"> 60 <template slot-scope="{row}">
61 <span style="color:red;">{{ row.reviewer }}</span> 61 <span style="color:red;">{{ row.reviewer }}</span>
62 </template> 62 </template>
63 </el-table-column> 63 </el-table-column>
64 <el-table-column :label="$t('table.importance')" width="80px"> 64 <el-table-column :label="$t('table.importance')" width="80px">
65 <template slot-scope="{row}"> 65 <template slot-scope="{row}">
66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" /> 66 <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon" />
67 </template> 67 </template>
68 </el-table-column> 68 </el-table-column>
69 <el-table-column :label="$t('table.readings')" align="center" width="95"> 69 <el-table-column :label="$t('table.readings')" align="center" width="95">
70 <template slot-scope="{row}"> 70 <template slot-scope="{row}">
71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span> 71 <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
72 <span v-else>0</span> 72 <span v-else>0</span>
73 </template> 73 </template>
74 </el-table-column> 74 </el-table-column>
75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100"> 75 <el-table-column :label="$t('table.status')" class-name="status-col" width="100">
76 <template slot-scope="{row}"> 76 <template slot-scope="{row}">
77 <el-tag :type="row.status | statusFilter"> 77 <el-tag :type="row.status | statusFilter">
78 {{ row.status }} 78 {{ row.status }}
79 </el-tag> 79 </el-tag>
80 </template> 80 </template>
81 </el-table-column> 81 </el-table-column>
82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width"> 82 <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width">
83 <template slot-scope="{row,$index}"> 83 <template slot-scope="{row,$index}">
84 <el-button type="primary" size="mini" @click="handleUpdate(row)"> 84 <el-button type="primary" size="mini" @click="handleUpdate(row)">
85 {{ $t('table.edit') }} 85 {{ $t('table.edit') }}
86 </el-button> 86 </el-button>
87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')"> 87 <el-button v-if="row.status!='published'" size="mini" type="success" @click="handleModifyStatus(row,'published')">
88 {{ $t('table.publish') }} 88 {{ $t('table.publish') }}
89 </el-button> 89 </el-button>
90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')"> 90 <el-button v-if="row.status!='draft'" size="mini" @click="handleModifyStatus(row,'draft')">
91 {{ $t('table.draft') }} 91 {{ $t('table.draft') }}
92 </el-button> 92 </el-button>
93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)"> 93 <el-button v-if="row.status!='deleted'" size="mini" type="danger" @click="handleDelete(row,$index)">
94 {{ $t('table.delete') }} 94 {{ $t('table.delete') }}
95 </el-button> 95 </el-button>
96 </template> 96 </template>
97 </el-table-column> 97 </el-table-column>
98 </el-table> 98 </el-table>
99 99
100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> 100 <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" />
101 101
102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible"> 102 <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;"> 103 <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;">
104 <el-form-item :label="$t('table.type')" prop="type"> 104 <el-form-item :label="$t('table.type')" prop="type">
105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select"> 105 <el-select v-model="temp.type" class="filter-item" placeholder="Please select">
106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" /> 106 <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
107 </el-select> 107 </el-select>
108 </el-form-item> 108 </el-form-item>
109 <el-form-item :label="$t('table.date')" prop="timestamp"> 109 <el-form-item :label="$t('table.date')" prop="timestamp">
110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" /> 110 <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date" />
111 </el-form-item> 111 </el-form-item>
112 <el-form-item :label="$t('table.title')" prop="title"> 112 <el-form-item :label="$t('table.title')" prop="title">
113 <el-input v-model="temp.title" /> 113 <el-input v-model="temp.title" />
114 </el-form-item> 114 </el-form-item>
115 <el-form-item :label="$t('table.status')"> 115 <el-form-item :label="$t('table.status')">
116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select"> 116 <el-select v-model="temp.status" class="filter-item" placeholder="Please select">
117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" /> 117 <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item" />
118 </el-select> 118 </el-select>
119 </el-form-item> 119 </el-form-item>
120 <el-form-item :label="$t('table.importance')"> 120 <el-form-item :label="$t('table.importance')">
121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" /> 121 <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;" />
122 </el-form-item> 122 </el-form-item>
123 <el-form-item :label="$t('table.remark')"> 123 <el-form-item :label="$t('table.remark')">
124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" /> 124 <el-input v-model="temp.remark" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" placeholder="Please input" />
125 </el-form-item> 125 </el-form-item>
126 </el-form> 126 </el-form>
127 <div slot="footer" class="dialog-footer"> 127 <div slot="footer" class="dialog-footer">
128 <el-button @click="dialogFormVisible = false"> 128 <el-button @click="dialogFormVisible = false">
129 {{ $t('table.cancel') }} 129 {{ $t('table.cancel') }}
130 </el-button> 130 </el-button>
131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()"> 131 <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">
132 {{ $t('table.confirm') }} 132 {{ $t('table.confirm') }}
133 </el-button> 133 </el-button>
134 </div> 134 </div>
135 </el-dialog> 135 </el-dialog>
136 136
137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics"> 137 <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics">
138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%"> 138 <el-table :data="pvData" border fit highlight-current-row style="width: 100%">
139 <el-table-column prop="key" label="Channel" /> 139 <el-table-column prop="key" label="Channel" />
140 <el-table-column prop="pv" label="Pv" /> 140 <el-table-column prop="pv" label="Pv" />
141 </el-table> 141 </el-table>
142 <span slot="footer" class="dialog-footer"> 142 <span slot="footer" class="dialog-footer">
143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button> 143 <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button>
144 </span> 144 </span>
145 </el-dialog> 145 </el-dialog>
146 </div> 146 </div>
147 </template> 147 </template>
148 148
149 <script> 149 <script>
150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article' 150 import { fetchList, fetchPv, createArticle, updateArticle } from '@/api/article'
151 import waves from '@/directive/waves' // waves directive 151 import waves from '@/directive/waves' // waves directive
152 import { parseTime } from '@/utils' 152 import { parseTime } from '@/utils'
153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination 153 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
154 154
155 const calendarTypeOptions = [ 155 const calendarTypeOptions = [
156 { key: 'CN', display_name: 'China' }, 156 { key: 'CN', display_name: 'China' },
157 { key: 'US', display_name: 'USA' }, 157 { key: 'US', display_name: 'USA' },
158 { key: 'JP', display_name: 'Japan' }, 158 { key: 'JP', display_name: 'Japan' },
159 { key: 'EU', display_name: 'Eurozone' } 159 { key: 'EU', display_name: 'Eurozone' }
160 ] 160 ]
161 161
162 // arr to obj, such as { CN : "China", US : "USA" } 162 // arr to obj, such as { CN : "China", US : "USA" }
163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { 163 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
164 acc[cur.key] = cur.display_name 164 acc[cur.key] = cur.display_name
165 return acc 165 return acc
166 }, {}) 166 }, {})
167 167
168 export default { 168 export default {
169 name: 'ComplexTable', 169 name: 'ComplexTable',
170 components: { Pagination }, 170 components: { Pagination },
171 directives: { waves }, 171 directives: { waves },
172 filters: { 172 filters: {
173 statusFilter(status) { 173 statusFilter(status) {
174 const statusMap = { 174 const statusMap = {
175 published: 'success', 175 published: 'success',
176 draft: 'info', 176 draft: 'info',
177 deleted: 'danger' 177 deleted: 'danger'
178 } 178 }
179 return statusMap[status] 179 return statusMap[status]
180 }, 180 },
181 typeFilter(type) { 181 typeFilter(type) {
182 return calendarTypeKeyValue[type] 182 return calendarTypeKeyValue[type]
183 } 183 }
184 }, 184 },
185 data() { 185 data() {
186 return { 186 return {
187 tableKey: 0, 187 tableKey: 0,
188 list: null, 188 list: null,
189 total: 0, 189 total: 0,
190 listLoading: true, 190 listLoading: true,
191 listQuery: { 191 listQuery: {
192 page: 1, 192 page: 1,
193 limit: 20, 193 limit: 20,
194 importance: undefined, 194 importance: undefined,
195 title: undefined, 195 title: undefined,
196 type: undefined, 196 type: undefined,
197 sort: '+id' 197 sort: '+id'
198 }, 198 },
199 importanceOptions: [1, 2, 3], 199 importanceOptions: [1, 2, 3],
200 calendarTypeOptions, 200 calendarTypeOptions,
201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }], 201 sortOptions: [{ label: 'ID Ascending', key: '+id' }, { label: 'ID Descending', key: '-id' }],
202 statusOptions: ['published', 'draft', 'deleted'], 202 statusOptions: ['published', 'draft', 'deleted'],
203 showReviewer: false, 203 showReviewer: false,
204 temp: { 204 temp: {
205 id: undefined, 205 id: undefined,
206 importance: 1, 206 importance: 1,
207 remark: '', 207 remark: '',
208 timestamp: new Date(), 208 timestamp: new Date(),
209 title: '', 209 title: '',
210 type: '', 210 type: '',
211 status: 'published' 211 status: 'published'
212 }, 212 },
213 dialogFormVisible: false, 213 dialogFormVisible: false,
214 dialogStatus: '', 214 dialogStatus: '',
215 textMap: { 215 textMap: {
216 update: 'Edit', 216 update: 'Edit',
217 create: 'Create' 217 create: 'Create'
218 }, 218 },
219 dialogPvVisible: false, 219 dialogPvVisible: false,
220 pvData: [], 220 pvData: [],
221 rules: { 221 rules: {
222 type: [{ required: true, message: 'type is required', trigger: 'change' }], 222 type: [{ required: true, message: 'type is required', trigger: 'change' }],
223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }], 223 timestamp: [{ type: 'date', required: true, message: 'timestamp is required', trigger: 'change' }],
224 title: [{ required: true, message: 'title is required', trigger: 'blur' }] 224 title: [{ required: true, message: 'title is required', trigger: 'blur' }]
225 }, 225 },
226 downloadLoading: false 226 downloadLoading: false
227 } 227 }
228 }, 228 },
229 created() { 229 created() {
230 this.getList() 230 this.getList()
231 }, 231 },
232 methods: { 232 methods: {
233 getList() { 233 getList() {
234 this.listLoading = true 234 this.listLoading = true
235 fetchList(this.listQuery).then(response => { 235 fetchList(this.listQuery).then(response => {
236 this.list = response.data.items 236 this.list = response.data.items
237 this.total = response.data.total 237 this.total = response.data.total
238 238
239 // Just to simulate the time of the request 239 // Just to simulate the time of the request
240 setTimeout(() => { 240 setTimeout(() => {
241 this.listLoading = false 241 this.listLoading = false
242 }, 1.5 * 1000) 242 }, 1.5 * 1000)
243 }) 243 })
244 }, 244 },
245 handleFilter() { 245 handleFilter() {
246 this.listQuery.page = 1 246 this.listQuery.page = 1
247 this.getList() 247 this.getList()
248 }, 248 },
249 handleModifyStatus(row, status) { 249 handleModifyStatus(row, status) {
250 this.$message({ 250 this.$message({
251 message: '操作成功', 251 message: '操作成功',
252 type: 'success' 252 type: 'success'
253 }) 253 })
254 row.status = status 254 row.status = status
255 }, 255 },
256 sortChange(data) { 256 sortChange(data) {
257 const { prop, order } = data 257 const { prop, order } = data
258 if (prop === 'id') { 258 if (prop === 'id') {
259 this.sortByID(order) 259 this.sortByID(order)
260 } 260 }
261 }, 261 },
262 sortByID(order) { 262 sortByID(order) {
263 if (order === 'ascending') { 263 if (order === 'ascending') {
264 this.listQuery.sort = '+id' 264 this.listQuery.sort = '+id'
265 } else { 265 } else {
266 this.listQuery.sort = '-id' 266 this.listQuery.sort = '-id'
267 } 267 }
268 this.handleFilter() 268 this.handleFilter()
269 }, 269 },
270 resetTemp() { 270 resetTemp() {
271 this.temp = { 271 this.temp = {
272 id: undefined, 272 id: undefined,
273 importance: 1, 273 importance: 1,
274 remark: '', 274 remark: '',
275 timestamp: new Date(), 275 timestamp: new Date(),
276 title: '', 276 title: '',
277 status: 'published', 277 status: 'published',
278 type: '' 278 type: ''
279 } 279 }
280 }, 280 },
281 handleCreate() { 281 handleCreate() {
282 this.resetTemp() 282 this.resetTemp()
283 this.dialogStatus = 'create' 283 this.dialogStatus = 'create'
284 this.dialogFormVisible = true 284 this.dialogFormVisible = true
285 this.$nextTick(() => { 285 this.$nextTick(() => {
286 this.$refs['dataForm'].clearValidate() 286 this.$refs['dataForm'].clearValidate()
287 }) 287 })
288 }, 288 },
289 createData() { 289 createData() {
290 this.$refs['dataForm'].validate((valid) => { 290 this.$refs['dataForm'].validate((valid) => {
291 if (valid) { 291 if (valid) {
292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id 292 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
293 this.temp.author = 'vue-element-admin' 293 this.temp.author = '秀野堂主'
294 createArticle(this.temp).then(() => { 294 createArticle(this.temp).then(() => {
295 this.list.unshift(this.temp) 295 this.list.unshift(this.temp)
296 this.dialogFormVisible = false 296 this.dialogFormVisible = false
297 this.$notify({ 297 this.$notify({
298 title: '成功', 298 title: '成功',
299 message: '创建成功', 299 message: '创建成功',
300 type: 'success', 300 type: 'success',
301 duration: 2000 301 duration: 2000
302 }) 302 })
303 }) 303 })
304 } 304 }
305 }) 305 })
306 }, 306 },
307 handleUpdate(row) { 307 handleUpdate(row) {
308 this.temp = Object.assign({}, row) // copy obj 308 this.temp = Object.assign({}, row) // copy obj
309 this.temp.timestamp = new Date(this.temp.timestamp) 309 this.temp.timestamp = new Date(this.temp.timestamp)
310 this.dialogStatus = 'update' 310 this.dialogStatus = 'update'
311 this.dialogFormVisible = true 311 this.dialogFormVisible = true
312 this.$nextTick(() => { 312 this.$nextTick(() => {
313 this.$refs['dataForm'].clearValidate() 313 this.$refs['dataForm'].clearValidate()
314 }) 314 })
315 }, 315 },
316 updateData() { 316 updateData() {
317 this.$refs['dataForm'].validate((valid) => { 317 this.$refs['dataForm'].validate((valid) => {
318 if (valid) { 318 if (valid) {
319 const tempData = Object.assign({}, this.temp) 319 const tempData = Object.assign({}, this.temp)
320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464 320 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
321 updateArticle(tempData).then(() => { 321 updateArticle(tempData).then(() => {
322 const index = this.list.findIndex(v => v.id === this.temp.id) 322 const index = this.list.findIndex(v => v.id === this.temp.id)
323 this.list.splice(index, 1, this.temp) 323 this.list.splice(index, 1, this.temp)
324 this.dialogFormVisible = false 324 this.dialogFormVisible = false
325 this.$notify({ 325 this.$notify({
326 title: '成功', 326 title: '成功',
327 message: '更新成功', 327 message: '更新成功',
328 type: 'success', 328 type: 'success',
329 duration: 2000 329 duration: 2000
330 }) 330 })
331 }) 331 })
332 } 332 }
333 }) 333 })
334 }, 334 },
335 handleDelete(row, index) { 335 handleDelete(row, index) {
336 this.$notify({ 336 this.$notify({
337 title: '成功', 337 title: '成功',
338 message: '删除成功', 338 message: '删除成功',
339 type: 'success', 339 type: 'success',
340 duration: 2000 340 duration: 2000
341 }) 341 })
342 this.list.splice(index, 1) 342 this.list.splice(index, 1)
343 }, 343 },
344 handleFetchPv(pv) { 344 handleFetchPv(pv) {
345 fetchPv(pv).then(response => { 345 fetchPv(pv).then(response => {
346 this.pvData = response.data.pvData 346 this.pvData = response.data.pvData
347 this.dialogPvVisible = true 347 this.dialogPvVisible = true
348 }) 348 })
349 }, 349 },
350 handleDownload() { 350 handleDownload() {
351 this.downloadLoading = true 351 this.downloadLoading = true
352 import('@/vendor/Export2Excel').then(excel => { 352 import('@/vendor/Export2Excel').then(excel => {
353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status'] 353 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status'] 354 const filterVal = ['timestamp', 'title', 'type', 'importance', 'status']
355 const data = this.formatJson(filterVal) 355 const data = this.formatJson(filterVal)
356 excel.export_json_to_excel({ 356 excel.export_json_to_excel({
357 header: tHeader, 357 header: tHeader,
358 data, 358 data,
359 filename: 'table-list' 359 filename: 'table-list'
360 }) 360 })
361 this.downloadLoading = false 361 this.downloadLoading = false
362 }) 362 })
363 }, 363 },
364 formatJson(filterVal) { 364 formatJson(filterVal) {
365 return this.list.map(v => filterVal.map(j => { 365 return this.list.map(v => filterVal.map(j => {
366 if (j === 'timestamp') { 366 if (j === 'timestamp') {
367 return parseTime(v[j]) 367 return parseTime(v[j])
368 } else { 368 } else {
369 return v[j] 369 return v[j]
370 } 370 }
371 })) 371 }))
372 }, 372 },
373 getSortClass: function(key) { 373 getSortClass: function(key) {
374 const sort = this.listQuery.sort 374 const sort = this.listQuery.sort
375 return sort === `+${key}` ? 'ascending' : 'descending' 375 return sort === `+${key}` ? 'ascending' : 'descending'
376 } 376 }
377 } 377 }
378 } 378 }
379 </script> 379 </script>
380 380
src/views/users/list.vue
File was created 1 <template>
2 <div class="app-container">
3 <div class="filter-container">
4 <el-input
5 v-model="listQuery.title"
6 :placeholder="$t('table.title')"
7 style="width: 200px;"
8 class="filter-item"
9 @keyup.enter.native="handleFilter"
10 />
11 <el-select
12 v-model="listQuery.importance"
13 :placeholder="$t('table.importance')"
14 clearable
15 style="width: 90px"
16 class="filter-item"
17 >
18 <el-option
19 v-for="item in importanceOptions"
20 :key="item"
21 :label="item"
22 :value="item"
23 />
24 </el-select>
25 <el-select
26 v-model="listQuery.type"
27 :placeholder="$t('table.type')"
28 clearable
29 class="filter-item"
30 style="width: 130px"
31 >
32 <el-option
33 v-for="item in calendarTypeOptions"
34 :key="item.key"
35 :label="item.display_name+'('+item.key+')'"
36 :value="item.key"
37 />
38 </el-select>
39 <el-select
40 v-model="listQuery.sort"
41 style="width: 140px"
42 class="filter-item"
43 @change="handleFilter"
44 >
45 <el-option
46 v-for="item in sortOptions"
47 :key="item.key"
48 :label="item.label"
49 :value="item.key"
50 />
51 </el-select>
52 <el-button
53 v-waves
54 class="filter-item"
55 type="primary"
56 icon="el-icon-search"
57 @click="handleFilter"
58 >
59 {{ $t('table.search') }}
60 </el-button>
61 <el-button
62 class="filter-item"
63 style="margin-left: 10px;"
64 type="primary"
65 icon="el-icon-edit"
66 @click="handleCreate"
67 >
68 {{ $t('table.add') }}
69 </el-button>
70 <el-button
71 v-waves
72 :loading="downloadLoading"
73 class="filter-item"
74 type="primary"
75 icon="el-icon-download"
76 @click="handleDownload"
77 >
78 {{ $t('table.export') }}
79 </el-button>
80 <el-checkbox
81 v-model="showReviewer"
82 class="filter-item"
83 style="margin-left:15px;"
84 @change="tableKey=tableKey+1"
85 >
86 {{ $t('table.reviewer') }}
87 </el-checkbox>
88 </div>
89
90 <el-table
91 :key="tableKey"
92 v-loading="listLoading"
93 :data="list"
94 border
95 fit
96 highlight-current-row
97 style="width: 100%;"
98 @sort-change="sortChange"
99 >
100 <el-table-column
101 :label="$t('table.uid')"
102 prop="id"
103 sortable="custom"
104 align="center"
105 width="80"
106 :class-name="getSortClass('id')"
107 >
108 <template slot-scope="{row}">
109 <span>{{ row.uid }}</span>
110 </template>
111 </el-table-column>
112 <el-table-column
113 :label="$t('table.create_time')"
114 width="150px"
115 align="center"
116 >
117 <template slot-scope="{row}">
118 <span>{{ row.create_time | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
119 </template>
120 </el-table-column>
121 <el-table-column
122 :label="$t('table.openid')"
123 min-width="150px"
124 >
125 <template slot-scope="{row}">
126 <span
127 class="link-type"
128 @click="handleUpdate(row)"
129 >{{ row.title }}</span>
130 </template>
131 </el-table-column>
132 <el-table-column
133 :label="$t('table.nickname')"
134 width="110px"
135 align="center"
136 >
137 <template slot-scope="{row}">
138 <span>{{ row.nickname }}</span>
139 <el-tag>{{ row.type | typeFilter }}</el-tag>
140 </template>
141 </el-table-column>
142 <el-table-column
143 v-if="showReviewer"
144 :label="$t('table.reviewer')"
145 width="110px"
146 align="center"
147 >
148 <template slot-scope="{row}">
149 <span style="color:red;">{{ row.reviewer }}</span>
150 </template>
151 </el-table-column>
152 <el-table-column
153 :label="$t('table.importance')"
154 width="80px"
155 >
156 <template slot-scope="{row}">
157 <svg-icon
158 v-for="n in +row.importance"
159 :key="n"
160 icon-class="star"
161 class="meta-item__icon"
162 />
163 </template>
164 </el-table-column>
165 <el-table-column
166 :label="$t('table.son_of_adv')"
167 align="center"
168 width="95"
169 >
170 <template slot-scope="{row}">
171 <span
172 v-if="row.son_of_adv"
173 class="link-type"
174 @click="handleFetchPv(row.son_of_adv)"
175 >{{ row.son_of_adv }}</span>
176 <span v-else>0</span>
177 </template>
178 </el-table-column>
179 <el-table-column
180 :label="$t('table.status')"
181 class-name="status-col"
182 width="100"
183 >
184 <template slot-scope="{row}">
185 <el-tag :type="row.status | statusFilter">{{ row.status }}</el-tag>
186 </template>
187 </el-table-column>
188 <el-table-column
189 :label="$t('table.actions')"
190 align="center"
191 width="230"
192 class-name="small-padding fixed-width"
193 >
194 <template slot-scope="{row,$index}">
195 <el-button
196 type="primary"
197 size="mini"
198 @click="handleUpdate(row)"
199 >{{ $t('table.edit') }}</el-button>
200 <el-button
201 v-if="row.status!='deleted'"
202 size="mini"
203 type="danger"
204 @click="handleDelete(row,$index)"
205 >{{ $t('table.delete') }}</el-button>
206 </template>
207 </el-table-column>
208 </el-table>
209
210 <pagination
211 v-show="total>0"
212 :total="total"
213 :page.sync="listQuery.page"
214 :limit.sync="listQuery.limit"
215 @pagination="getList"
216 />
217 <el-dialog
218 :title="textMap[dialogStatus]"
219 :visible.sync="dialogFormVisible"
220 >
221 <el-form
222 ref="dataForm"
223 :rules="rules"
224 :model="temp"
225 label-position="left"
226 label-width="70px"
227 style="width: 400px; margin-left:50px;"
228 >
229 <el-form-item
230 :label="$t('table.type')"
231 prop="type"
232 >
233 <el-select
234 v-model="temp.type"
235 class="filter-item"
236 placeholder="Please select"
237 >
238 <el-option
239 v-for="item in calendarTypeOptions"
240 :key="item.key"
241 :label="item.display_name"
242 :value="item.key"
243 />
244 </el-select>
245 </el-form-item>
246 <el-form-item
247 :label="$t('table.create_time')"
248 prop="create_time"
249 >
250 <el-date-picker
251 v-model="temp.create_time"
252 type="datetime"
253 placeholder="Please pick a date"
254 />
255 </el-form-item>
256 <el-form-item
257 :label="$t('table.业务记录')"
258 prop="title"
259 >
260 <el-input v-model="temp.title" />
261 </el-form-item>
262 <el-form-item :label="$t('table.status')">
263 <el-select
264 v-model="temp.status"
265 class="filter-item"
266 placeholder="Please select"
267 >
268 <el-option
269 v-for="item in statusOptions"
270 :key="item"
271 :label="item"
272 :value="item"
273 />
274 </el-select>
275 </el-form-item>
276 <el-form-item :label="$t('table.importance')">
277 <el-rate
278 v-model="temp.importance"
279 :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
280 :max="3"
281 style="margin-top:8px;"
282 />
283 </el-form-item>
284 <el-form-item :label="$t('table.remark')">
285 <el-input
286 v-model="temp.remark"
287 :autosize="{ minRows: 2, maxRows: 4}"
288 type="textarea"
289 placeholder="Please input"
290 />
291 </el-form-item>
292 </el-form>
293 <div
294 slot="footer"
295 class="dialog-footer"
296 >
297 <el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button>
298 <el-button
299 type="primary"
300 @click="dialogStatus==='create'?createData():updateData()"
301 >{{ $t('table.confirm') }}</el-button>
302 </div>
303 </el-dialog>
304
305 <el-dialog
306 :visible.sync="dialogPvVisible"
307 title="Reading statistics"
308 >
309 <el-table
310 :data="pvData"
311 border
312 fit
313 highlight-current-row
314 style="width: 100%"
315 >
316 <el-table-column
317 prop="key"
318 label="Channel"
319 />
320 <el-table-column
321 prop="pv"
322 label="Pv"
323 />
324 </el-table>
325 <span
326 slot="footer"
327 class="dialog-footer"
328 >
329 <el-button
330 type="primary"
331 @click="dialogPvVisible = false"
332 >{{ $t('table.confirm') }}</el-button>
333 </span>
334 </el-dialog>
335 </div>
336 </template>
337
338 <script>
339 import {
340 fetchList,
341 fetchPv,
342 createUser,
343 updateUser,
344 delUser
345 } from '@/api/user'
346 import waves from '@/directive/waves' // waves directive
347 import { parseTime } from '@/utils'
348 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
349
350 const calendarTypeOptions = [
351 { key: 'CN', display_name: 'China' },
352 { key: 'US', display_name: 'USA' },
353 { key: 'JP', display_name: 'Japan' },
354 { key: 'EU', display_name: 'Eurozone' }
355 ]
356
357 // arr to obj, such as { CN : "China", US : "USA" }
358 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
359 acc[cur.key] = cur.display_name
360 return acc
361 }, {})
362
363 export default {
364 name: 'ComplexTable',
365 components: { Pagination },
366 directives: { waves },
367 filters: {
368 statusFilter(status) {
369 const statusMap = {
370 published: 'success',
371 draft: 'info',
372 deleted: 'danger'
373 }
374 return statusMap[status]
375 },
376 typeFilter(type) {
377 return calendarTypeKeyValue[type]
378 }
379 },
380 data() {
381 return {
382 tableKey: 0,
383 list: null,
384 total: 0,
385 listLoading: true,
386 listQuery: {
387 page: 1,
388 limit: 20,
389 importance: undefined,
390 title: undefined,
391 type: undefined,
392 sort: '+id'
393 },
394 importanceOptions: [1, 2, 3],
395 calendarTypeOptions,
396 sortOptions: [
397 { label: 'ID Ascending', key: '+id' },
398 { label: 'ID Descending', key: '-id' }
399 ],
400 statusOptions: ['published', 'draft', 'deleted'],
401 showReviewer: false,
402 temp: {
403 id: undefined,
404 importance: 1,
405 remark: '',
406 create_time: new Date(),
407 title: '',
408 type: '',
409 status: 'published'
410 },
411 dialogFormVisible: false,
412 dialogStatus: '',
413 textMap: {
414 update: 'Edit',
415 create: 'Create'
416 },
417 dialogPvVisible: false,
418 pvData: [],
419 rules: {
420 type: [
421 { required: true, message: 'type is required', trigger: 'change' }
422 ],
423 create_time: [
424 {
425 type: 'date',
426 required: true,
427 message: 'create_time is required',
428 trigger: 'change'
429 }
430 ],
431 title: [
432 { required: true, message: 'title is required', trigger: 'blur' }
433 ]
434 },
435 downloadLoading: false
436 }
437 },
438 created: async function() {
439 const params = {
440 card_no: '111'
441 }
442 const res = await this.getList(params)
443 console.log('resresresres', res)
444 },
445 methods: {
446 getList() {
447 this.listLoading = true
448 fetchList(this.listQuery).then(response => {
449 this.list = response.data.items
450 this.total = response.data.total
451
452 // Just to simulate the time of the request
453 setTimeout(() => {
454 this.listLoading = false
455 }, 1.5 * 1000)
456 })
457 },
458 handleFilter() {
459 this.listQuery.page = 1
460 this.getList()
461 },
462 handleModifyStatus(row, status) {
463 this.$message({
464 message: '操作成功',
465 type: 'success'
466 })
467 row.status = status
468 },
469 sortChange(data) {
470 const { prop, order } = data
471 if (prop === 'id') {
472 this.sortByID(order)
473 }
474 },
475 sortByID(order) {
476 if (order === 'ascending') {
477 this.listQuery.sort = '+id'
478 } else {
479 this.listQuery.sort = '-id'
480 }
481 this.handleFilter()
482 },
483 resetTemp() {
484 this.temp = {
485 id: undefined,
486 importance: 1,
487 remark: '',
488 create_time: new Date(),
489 title: '',
490 status: 'published',
491 type: ''
492 }
493 },
494 handleCreate() {
495 this.resetTemp()
496 this.dialogStatus = 'create'
497 this.dialogFormVisible = true
498 this.$nextTick(() => {
499 this.$refs['dataForm'].clearValidate()
500 })
501 // const data = []
502 // createUser(data).then(() => {
503 // this.$notify({
504 // title: "成功",
505 // message: "添加成功",
506 // type: "success",
507 // duration: 2000
508 // });
509 // });
510 },
511 createData() {
512 this.$refs['dataForm'].validate(valid => {
513 if (valid) {
514 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
515 this.temp.author = '秀野堂主'
516 createUser(this.temp).then(() => {
517 this.list.unshift(this.temp)
518 this.dialogFormVisible = false
519 this.$notify({
520 title: '成功',
521 message: '创建成功',
522 type: 'success',
523 duration: 2000
524 })
525 })
526 }
527 })
528 },
529 handleUpdate(row) {
530 this.temp = Object.assign({}, row) // copy obj
531 this.temp.create_time = new Date(this.temp.create_time)
532 this.dialogStatus = 'update'
533 this.dialogFormVisible = true
534 this.$nextTick(() => {
535 this.$refs['dataForm'].clearValidate()
536 })
537 },
538 updateData() {
539 this.$refs['dataForm'].validate(valid => {
540 if (valid) {
541 const tempData = Object.assign({}, this.temp)
542 tempData.create_time = +new Date(tempData.create_time) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
543 updateUser(tempData).then(() => {
544 const index = this.list.findIndex(v => v.id === this.temp.id)
545 this.list.splice(index, 1, this.temp)
546 this.dialogFormVisible = false
547 this.$notify({
548 title: '成功',
549 message: '更新成功',
550 type: 'success',
551 duration: 2000
552 })
553 })
554 }
555 })
556 },
557 handleDelete(row, index) {
558 const data = []
559 delUser(data).then(() => {
560 this.list.splice(index, 1)
561 this.$notify({
562 title: '成功',
563 message: '删除成功',
564 type: 'success',
565 duration: 2000
566 })
567 })
568 },
569 handleFetchPv(pv) {
570 fetchPv(pv).then(response => {
571 this.pvData = response.data.pvData
572 this.dialogPvVisible = true
573 })
574 },
575 handleDownload() {
576 this.downloadLoading = true
577 import('@/vendor/Export2Excel').then(excel => {
578 const tHeader = [
579 'create_time',
580 'title',
581 'type',
582 'importance',
583 'status'
584 ]
585 const filterVal = [
586 'create_time',
587 'title',
588 'type',
589 'importance',
590 'status'
591 ]
592 const data = this.formatJson(filterVal)
593 excel.export_json_to_excel({
594 header: tHeader,
595 data,
596 filename: 'table-list'
597 })
598 this.downloadLoading = false
599 })
600 },
601 formatJson(filterVal) {
602 return this.list.map(v =>
603 filterVal.map(j => {
604 if (j === 'create_time') {
605 return parseTime(v[j])
606 } else {
607 return v[j]
608 }
609 })
610 )
611 },
612 getSortClass: function(key) {
613 const sort = this.listQuery.sort
614 return sort === `+${key}` ? 'ascending' : 'descending'
615 }
616 }
617 }
618 </script>
619
tests/unit/utils/validate.spec.js
1 import { validUsername, validURL, validLowerCase, validUpperCase, validAlphabets } from '@/utils/validate.js' 1 import { validUsername, validURL, validLowerCase, validUpperCase, validAlphabets } from '@/utils/validate.js'
2 describe('Utils:validate', () => { 2 describe('Utils:validate', () => {
3 it('validUsername', () => { 3 it('validUsername', () => {
4 expect(validUsername('admin')).toBe(true) 4 expect(validUsername('admin')).toBe(true)
5 expect(validUsername('editor')).toBe(true) 5 expect(validUsername('assistant')).toBe(true)
6 expect(validUsername('xxxx')).toBe(false) 6 expect(validUsername('runner')).toBe(true)
7 expect(validUsername('shoper')).toBe(true)
8 // expect(validUsername('xxxx')).toBe(false)
9 // expect(validUsername('xxxx')).toBe(false)
10 // expect(validUsername('xxxx')).toBe(false)
7 }) 11 })
8 it('validURL', () => { 12 it('validURL', () => {
9 expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true) 13 // expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
10 expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true) 14 // expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
11 expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false) 15 // expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
12 }) 16 })
13 it('validLowerCase', () => { 17 it('validLowerCase', () => {
14 expect(validLowerCase('abc')).toBe(true) 18 expect(validLowerCase('abc')).toBe(true)
15 expect(validLowerCase('Abc')).toBe(false) 19 expect(validLowerCase('Abc')).toBe(false)
16 expect(validLowerCase('123abc')).toBe(false) 20 expect(validLowerCase('123abc')).toBe(false)
17 }) 21 })
18 it('validUpperCase', () => { 22 it('validUpperCase', () => {
19 expect(validUpperCase('ABC')).toBe(true) 23 expect(validUpperCase('ABC')).toBe(true)
20 expect(validUpperCase('Abc')).toBe(false) 24 expect(validUpperCase('Abc')).toBe(false)
21 expect(validUpperCase('123ABC')).toBe(false) 25 expect(validUpperCase('123ABC')).toBe(false)
22 }) 26 })
23 it('validAlphabets', () => { 27 it('validAlphabets', () => {
24 expect(validAlphabets('ABC')).toBe(true) 28 expect(validAlphabets('ABC')).toBe(true)
25 expect(validAlphabets('Abc')).toBe(true) 29 expect(validAlphabets('Abc')).toBe(true)
26 expect(validAlphabets('123aBC')).toBe(false) 30 expect(validAlphabets('123aBC')).toBe(false)
27 }) 31 })
28 }) 32 })
29 33