Commit 50760eab92891e7022d2759fd55c1f173659e9d8

Authored by Adam
1 parent 3d3cdb68fc
Exists in master

auto commit the code by alias command

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: 'assistant', 15 key: 'assistant',
16 name: 'assistant', 16 name: 'assistant',
17 description: 'assistant Administrator. 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: 'runner', 21 key: 'runner',
22 name: 'runner', 22 name: 'runner',
23 description: 'Normal runner. Can see runner pages except permission page', 23 description: 'Normal runner. Can see runner pages except permission page',
24 routes: routes.filter(i => i.path !== '/permission')// just a mock 24 routes: routes.filter(i => i.path !== '/permission')// just a mock
25 }, 25 },
26 { 26 {
27 key: 'shoper', 27 key: 'shoper',
28 name: 'shoper', 28 name: 'shoper',
29 description: 'Normal shoper. Can see shoper pages except permission page', 29 description: 'Normal shoper. Can see shoper pages except permission page',
30 routes: routes.filter(i => i.path !== '/permission')// just a mock 30 routes: routes.filter(i => i.path !== '/permission')// just a mock
31 }, 31 },
32 // { 32 // {
33 // key: 'visitor', 33 // key: 'visitor',
34 // name: 'visitor', 34 // name: 'visitor',
35 // description: 'Just a visitor. Can only see the home page and the document page', 35 // description: 'Just a visitor. Can only see the home page and the document page',
36 // routes: [{ 36 // routes: [{
37 // path: '', 37 // path: '',
38 // redirect: 'dashboard', 38 // redirect: 'dashboard',
39 // children: [ 39 // children: [
40 // { 40 // {
41 // path: 'dashboard', 41 // path: 'dashboard',
42 // name: 'Dashboard', 42 // name: 'Dashboard',
43 // meta: { title: 'dashboard', icon: 'dashboard' } 43 // meta: { title: 'dashboard', icon: 'dashboard' }
44 // } 44 // }
45 // ] 45 // ]
46 // }] 46 // }]
47 // } 47 // }
48 ] 48 ]
49 49
50 export default [ 50 export default [
51 // mock get all routes form server 51 // mock get all routes form server
52 { 52 {
53 url: '/vue-element-admin/routes', 53 url: '/yp/routes',
54 type: 'get', 54 type: 'get',
55 response: _ => { 55 response: _ => {
56 return { 56 return {
57 code: 20000, 57 code: 20000,
58 data: routes 58 data: routes
59 } 59 }
60 } 60 }
61 }, 61 },
62 62
63 // mock get all roles form server 63 // mock get all roles form server
64 { 64 {
65 url: '/vue-element-admin/roles', 65 url: '/yp/roles',
66 type: 'get', 66 type: 'get',
67 response: _ => { 67 response: _ => {
68 return { 68 return {
69 code: 20000, 69 code: 20000,
70 data: roles 70 data: roles
71 } 71 }
72 } 72 }
73 }, 73 },
74 74
75 // add role 75 // add role
76 { 76 {
77 url: '/vue-element-admin/role', 77 url: '/yp/role',
78 type: 'post', 78 type: 'post',
79 response: { 79 response: {
80 code: 20000, 80 code: 20000,
81 data: { 81 data: {
82 key: Mock.mock('@integer(300, 5000)') 82 key: Mock.mock('@integer(300, 5000)')
83 } 83 }
84 } 84 }
85 }, 85 },
86 86
87 // update role 87 // update role
88 { 88 {
89 url: '/vue-element-admin/role/[A-Za-z0-9]', 89 url: '/yp/role/[A-Za-z0-9]',
90 type: 'put', 90 type: 'put',
91 response: { 91 response: {
92 code: 20000, 92 code: 20000,
93 data: { 93 data: {
94 status: 'success' 94 status: 'success'
95 } 95 }
96 } 96 }
97 }, 97 },
98 98
99 // delete role 99 // delete role
100 { 100 {
101 url: '/vue-element-admin/role/[A-Za-z0-9]', 101 url: '/yp/role/[A-Za-z0-9]',
102 type: 'delete', 102 type: 'delete',
103 response: { 103 response: {
104 code: 20000, 104 code: 20000,
105 data: { 105 data: {
106 status: 'success' 106 status: 'success'
107 } 107 }
108 } 108 }
109 } 109 }
110 ] 110 ]
111 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', 'assistant', 'runner', 'shoper'] 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','assistant'] 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 roles:['shoper'] 112 // roles:['shoper']
103 } 113 // }
104 }, 114 // },
105 { 115 // {
106 path: 'role', 116 // path: 'role',
107 component: 'views/permission/role', 117 // component: 'views/permission/role',
108 name: 'RolePermission', 118 // name: 'RolePermission',
109 meta: { 119 // meta: {
110 title: 'rolePermission', 120 // title: 'rolePermission',
111 roles: ['runner'] 121 // roles: ['runner']
112 } 122 // }
113 } 123 // }
114 ] 124 // ]
115 }, 125 // },
116 126
117 { 127 {
118 path: '/icon', 128 path: '/icon',
119 component: 'layout/Layout', 129 component: 'layout/Layout',
120 meta: { 130 meta: {
121 title: 'ddddd', 131 title: 'ddddd',
122 icon:'people', 132 icon:'people',
123 roles: ['runner'] 133 roles: ['runner']
124 }, 134 },
125 children: [ 135 children: [
126 { 136 {
127 path: 'index', 137 path: 'index',
128 component: 'views/icons/index', 138 component: 'views/icons/index',
129 name: 'Icons', 139 name: 'Icons',
130 meta: { title: 'icons', icon: 'icon', noCache: true } 140 meta: { title: 'icons', icon: 'icon', noCache: true }
131 } 141 }
132 ] 142 ]
133 }, 143 },
134 144
135 { 145 {
136 path: '/components', 146 path: '/components',
137 component: 'layout/Layout', 147 component: 'layout/Layout',
138 redirect: 'noRedirect', 148 redirect: 'noRedirect',
139 name: 'ComponentDemo', 149 name: 'ComponentDemo',
140 meta: { 150 meta: {
141 title: 'components', 151 title: 'components',
142 icon: 'component' 152 icon: 'component'
143 }, 153 },
144 children: [ 154 children: [
145 { 155 {
146 path: 'tinymce', 156 path: 'tinymce',
147 component: 'views/components-demo/tinymce', 157 component: 'views/components-demo/tinymce',
148 name: 'TinymceDemo', 158 name: 'TinymceDemo',
149 meta: { title: 'tinymce' } 159 meta: { title: 'tinymce' }
150 }, 160 },
151 { 161 {
152 path: 'markdown', 162 path: 'markdown',
153 component: 'views/components-demo/markdown', 163 component: 'views/components-demo/markdown',
154 name: 'MarkdownDemo', 164 name: 'MarkdownDemo',
155 meta: { title: 'markdown' } 165 meta: { title: 'markdown' }
156 }, 166 },
157 { 167 {
158 path: 'json-editor', 168 path: 'json-editor',
159 component: 'views/components-demo/json-editor', 169 component: 'views/components-demo/json-editor',
160 name: 'JsonEditorDemo', 170 name: 'JsonEditorDemo',
161 meta: { title: 'jsonEditor' } 171 meta: { title: 'jsonEditor' }
162 }, 172 },
163 { 173 {
164 path: 'split-pane', 174 path: 'split-pane',
165 component: 'views/components-demo/split-pane', 175 component: 'views/components-demo/split-pane',
166 name: 'SplitpaneDemo', 176 name: 'SplitpaneDemo',
167 meta: { title: 'splitPane' } 177 meta: { title: 'splitPane' }
168 }, 178 },
169 { 179 {
170 path: 'avatar-upload', 180 path: 'avatar-upload',
171 component: 'views/components-demo/avatar-upload', 181 component: 'views/components-demo/avatar-upload',
172 name: 'AvatarUploadDemo', 182 name: 'AvatarUploadDemo',
173 meta: { title: 'avatarUpload' } 183 meta: { title: 'avatarUpload' }
174 }, 184 },
175 { 185 {
176 path: 'dropzone', 186 path: 'dropzone',
177 component: 'views/components-demo/dropzone', 187 component: 'views/components-demo/dropzone',
178 name: 'DropzoneDemo', 188 name: 'DropzoneDemo',
179 meta: { title: 'dropzone' } 189 meta: { title: 'dropzone' }
180 }, 190 },
181 { 191 {
182 path: 'sticky', 192 path: 'sticky',
183 component: 'views/components-demo/sticky', 193 component: 'views/components-demo/sticky',
184 name: 'StickyDemo', 194 name: 'StickyDemo',
185 meta: { title: 'sticky' } 195 meta: { title: 'sticky' }
186 }, 196 },
187 { 197 {
188 path: 'count-to', 198 path: 'count-to',
189 component: 'views/components-demo/count-to', 199 component: 'views/components-demo/count-to',
190 name: 'CountToDemo', 200 name: 'CountToDemo',
191 meta: { title: 'countTo' } 201 meta: { title: 'countTo' }
192 }, 202 },
193 { 203 {
194 path: 'mixin', 204 path: 'mixin',
195 component: 'views/components-demo/mixin', 205 component: 'views/components-demo/mixin',
196 name: 'ComponentMixinDemo', 206 name: 'ComponentMixinDemo',
197 meta: { title: 'componentMixin' } 207 meta: { title: 'componentMixin' }
198 }, 208 },
199 { 209 {
200 path: 'back-to-top', 210 path: 'back-to-top',
201 component: 'views/components-demo/back-to-top', 211 component: 'views/components-demo/back-to-top',
202 name: 'BackToTopDemo', 212 name: 'BackToTopDemo',
203 meta: { title: 'backToTop' } 213 meta: { title: 'backToTop' }
204 }, 214 },
205 { 215 {
206 path: 'drag-dialog', 216 path: 'drag-dialog',
207 component: 'views/components-demo/drag-dialog', 217 component: 'views/components-demo/drag-dialog',
208 name: 'DragDialogDemo', 218 name: 'DragDialogDemo',
209 meta: { title: 'dragDialog' } 219 meta: { title: 'dragDialog' }
210 }, 220 },
211 { 221 {
212 path: 'drag-select', 222 path: 'drag-select',
213 component: 'views/components-demo/drag-select', 223 component: 'views/components-demo/drag-select',
214 name: 'DragSelectDemo', 224 name: 'DragSelectDemo',
215 meta: { title: 'dragSelect' } 225 meta: { title: 'dragSelect' }
216 }, 226 },
217 { 227 {
218 path: 'dnd-list', 228 path: 'dnd-list',
219 component: 'views/components-demo/dnd-list', 229 component: 'views/components-demo/dnd-list',
220 name: 'DndListDemo', 230 name: 'DndListDemo',
221 meta: { title: 'dndList' } 231 meta: { title: 'dndList' }
222 }, 232 },
223 { 233 {
224 path: 'drag-kanban', 234 path: 'drag-kanban',
225 component: 'views/components-demo/drag-kanban', 235 component: 'views/components-demo/drag-kanban',
226 name: 'DragKanbanDemo', 236 name: 'DragKanbanDemo',
227 meta: { title: 'dragKanban' } 237 meta: { title: 'dragKanban' }
228 } 238 }
229 ] 239 ]
230 }, 240 },
231 { 241 {
232 path: '/charts', 242 path: '/charts',
233 component: 'layout/Layout', 243 component: 'layout/Layout',
234 redirect: 'noRedirect', 244 redirect: 'noRedirect',
235 name: 'Charts', 245 name: 'Charts',
236 meta: { 246 meta: {
237 title: 'charts', 247 title: 'charts',
238 icon: 'chart' 248 icon: 'chart'
239 }, 249 },
240 children: [ 250 children: [
241 { 251 {
242 path: 'keyboard', 252 path: 'keyboard',
243 component: 'views/charts/keyboard', 253 component: 'views/charts/keyboard',
244 name: 'KeyboardChart', 254 name: 'KeyboardChart',
245 meta: { title: 'keyboardChart', noCache: true } 255 meta: { title: 'keyboardChart', noCache: true }
246 }, 256 },
247 { 257 {
248 path: 'line', 258 path: 'line',
249 component: 'views/charts/line', 259 component: 'views/charts/line',
250 name: 'LineChart', 260 name: 'LineChart',
251 meta: { title: 'lineChart', noCache: true } 261 meta: { title: 'lineChart', noCache: true }
252 }, 262 },
253 { 263 {
254 path: 'mixchart', 264 path: 'mixchart',
255 component: 'views/charts/mixChart', 265 component: 'views/charts/mixChart',
256 name: 'MixChart', 266 name: 'MixChart',
257 meta: { title: 'mixChart', noCache: true } 267 meta: { title: 'mixChart', noCache: true }
258 } 268 }
259 ] 269 ]
260 }, 270 },
261 { 271 {
262 path: '/nested', 272 path: '/nested',
263 component: 'layout/Layout', 273 component: 'layout/Layout',
264 redirect: '/nested/menu1/menu1-1', 274 redirect: '/nested/menu1/menu1-1',
265 name: 'Nested', 275 name: 'Nested',
266 meta: { 276 meta: {
267 title: 'nested', 277 title: 'nested',
268 icon: 'nested' 278 icon: 'nested'
269 }, 279 },
270 children: [ 280 children: [
271 { 281 {
272 path: 'menu1', 282 path: 'menu1',
273 component: 'views/nested/menu1/index', 283 component: 'views/nested/menu1/index',
274 name: 'Menu1', 284 name: 'Menu1',
275 meta: { title: 'menu1' }, 285 meta: { title: 'menu1' },
276 redirect: '/nested/menu1/menu1-1', 286 redirect: '/nested/menu1/menu1-1',
277 children: [ 287 children: [
278 { 288 {
279 path: 'menu1-1', 289 path: 'menu1-1',
280 component: 'views/nested/menu1/menu1-1', 290 component: 'views/nested/menu1/menu1-1',
281 name: 'Menu1-1', 291 name: 'Menu1-1',
282 meta: { title: 'menu1-1' } 292 meta: { title: 'menu1-1' }
283 }, 293 },
284 { 294 {
285 path: 'menu1-2', 295 path: 'menu1-2',
286 component: 'views/nested/menu1/menu1-2', 296 component: 'views/nested/menu1/menu1-2',
287 name: 'Menu1-2', 297 name: 'Menu1-2',
288 redirect: '/nested/menu1/menu1-2/menu1-2-1', 298 redirect: '/nested/menu1/menu1-2/menu1-2-1',
289 meta: { title: 'menu1-2' }, 299 meta: { title: 'menu1-2' },
290 children: [ 300 children: [
291 { 301 {
292 path: 'menu1-2-1', 302 path: 'menu1-2-1',
293 component: 'views/nested/menu1/menu1-2/menu1-2-1', 303 component: 'views/nested/menu1/menu1-2/menu1-2-1',
294 name: 'Menu1-2-1', 304 name: 'Menu1-2-1',
295 meta: { title: 'menu1-2-1' } 305 meta: { title: 'menu1-2-1' }
296 }, 306 },
297 { 307 {
298 path: 'menu1-2-2', 308 path: 'menu1-2-2',
299 component: 'views/nested/menu1/menu1-2/menu1-2-2', 309 component: 'views/nested/menu1/menu1-2/menu1-2-2',
300 name: 'Menu1-2-2', 310 name: 'Menu1-2-2',
301 meta: { title: 'menu1-2-2' } 311 meta: { title: 'menu1-2-2' }
302 } 312 }
303 ] 313 ]
304 }, 314 },
305 { 315 {
306 path: 'menu1-3', 316 path: 'menu1-3',
307 component: 'views/nested/menu1/menu1-3', 317 component: 'views/nested/menu1/menu1-3',
308 name: 'Menu1-3', 318 name: 'Menu1-3',
309 meta: { title: 'menu1-3' } 319 meta: { title: 'menu1-3' }
310 } 320 }
311 ] 321 ]
312 }, 322 },
313 { 323 {
314 path: 'menu2', 324 path: 'menu2',
315 name: 'Menu2', 325 name: 'Menu2',
316 component: 'views/nested/menu2/index', 326 component: 'views/nested/menu2/index',
317 meta: { title: 'menu2' } 327 meta: { title: 'menu2' }
318 } 328 }
319 ] 329 ]
320 }, 330 },
321 331
322 { 332 {
323 path: '/example', 333 path: '/example',
324 component: 'layout/Layout', 334 component: 'layout/Layout',
325 redirect: '/example/list', 335 redirect: '/example/list',
326 name: 'Example', 336 name: 'Example',
327 meta: { 337 meta: {
328 title: 'example', 338 title: 'example',
329 icon: 'example' 339 icon: 'example'
330 }, 340 },
331 children: [ 341 children: [
332 { 342 {
333 path: 'create', 343 path: 'create',
334 component: 'views/example/create', 344 component: 'views/example/create',
335 name: 'CreateArticle', 345 name: 'CreateArticle',
336 meta: { title: 'createArticle', icon: 'edit' } 346 meta: { title: 'createArticle', icon: 'edit' }
337 }, 347 },
338 { 348 {
339 path: 'edit/:id(\\d+)', 349 path: 'edit/:id(\\d+)',
340 component: 'views/example/edit', 350 component: 'views/example/edit',
341 name: 'EditArticle', 351 name: 'EditArticle',
342 meta: { title: 'editArticle', noCache: true }, 352 meta: { title: 'editArticle', noCache: true },
343 hidden: true 353 hidden: true
344 }, 354 },
345 { 355 {
346 path: 'list', 356 path: 'list',
347 component: 'views/example/list', 357 component: 'views/example/list',
348 name: 'ArticleList', 358 name: 'ArticleList',
349 meta: { title: 'articleList', icon: 'list' } 359 meta: { title: 'articleList', icon: 'list' }
350 } 360 }
351 ] 361 ]
352 }, 362 },
353 363
354 { 364 {
355 path: '/tab', 365 path: '/tab',
356 component: 'layout/Layout', 366 component: 'layout/Layout',
357 children: [ 367 children: [
358 { 368 {
359 path: 'index', 369 path: 'index',
360 component: 'views/tab/index', 370 component: 'views/tab/index',
361 name: 'Tab', 371 name: 'Tab',
362 meta: { title: 'tab', icon: 'tab' } 372 meta: { title: 'tab', icon: 'tab' }
363 } 373 }
364 ] 374 ]
365 }, 375 },
366 376
367 { 377 {
368 path: '/error', 378 path: '/error',
369 component: 'layout/Layout', 379 component: 'layout/Layout',
370 redirect: 'noRedirect', 380 redirect: 'noRedirect',
371 name: 'ErrorPages', 381 name: 'ErrorPages',
372 meta: { 382 meta: {
373 title: 'errorPages', 383 title: 'errorPages',
374 icon: '404' 384 icon: '404'
375 }, 385 },
376 children: [ 386 children: [
377 { 387 {
378 path: '401', 388 path: '401',
379 component: 'views/error-page/401', 389 component: 'views/error-page/401',
380 name: 'Page401', 390 name: 'Page401',
381 meta: { title: 'page401', noCache: true } 391 meta: { title: 'page401', noCache: true }
382 }, 392 },
383 { 393 {
384 path: '404', 394 path: '404',
385 component: 'views/error-page/404', 395 component: 'views/error-page/404',
386 name: 'Page404', 396 name: 'Page404',
387 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 }
388 } 404 }
389 ] 405 ]
390 }, 406 },
391 407
392 { 408 {
393 path: '/error-log', 409 path: '/error-log',
394 component: 'layout/Layout', 410 component: 'layout/Layout',
395 redirect: 'noRedirect', 411 redirect: 'noRedirect',
396 children: [ 412 children: [
397 { 413 {
398 path: 'log', 414 path: 'log',
399 component: 'views/error-log/index', 415 component: 'views/error-log/index',
400 name: 'ErrorLog', 416 name: 'ErrorLog',
401 meta: { title: 'errorLog', icon: 'bug' } 417 meta: { title: 'errorLog', icon: 'bug' }
402 } 418 }
403 ] 419 ]
404 }, 420 },
405 421
406 { 422 {
407 path: '/excel', 423 path: '/excel',
408 component: 'layout/Layout', 424 component: 'layout/Layout',
409 redirect: '/excel/export-excel', 425 redirect: '/excel/export-excel',
410 name: 'Excel', 426 name: 'Excel',
411 meta: { 427 meta: {
412 title: 'excel', 428 title: 'excel',
413 icon: 'excel' 429 icon: 'excel'
414 }, 430 },
415 children: [ 431 children: [
416 { 432 {
417 path: 'export-excel', 433 path: 'export-excel',
418 component: 'views/excel/export-excel', 434 component: 'views/excel/export-excel',
419 name: 'ExportExcel', 435 name: 'ExportExcel',
420 meta: { title: 'exportExcel' } 436 meta: { title: 'exportExcel' }
421 }, 437 },
422 { 438 {
423 path: 'export-selected-excel', 439 path: 'export-selected-excel',
424 component: 'views/excel/select-excel', 440 component: 'views/excel/select-excel',
425 name: 'SelectExcel', 441 name: 'SelectExcel',
426 meta: { title: 'selectExcel' } 442 meta: { title: 'selectExcel' }
427 }, 443 },
428 { 444 {
429 path: 'export-merge-header', 445 path: 'export-merge-header',
430 component: 'views/excel/merge-header', 446 component: 'views/excel/merge-header',
431 name: 'MergeHeader', 447 name: 'MergeHeader',
432 meta: { title: 'mergeHeader' } 448 meta: { title: 'mergeHeader' }
433 }, 449 },
434 { 450 {
435 path: 'upload-excel', 451 path: 'upload-excel',
436 component: 'views/excel/upload-excel', 452 component: 'views/excel/upload-excel',
437 name: 'UploadExcel', 453 name: 'UploadExcel',
438 meta: { title: 'uploadExcel' } 454 meta: { title: 'uploadExcel' }
439 } 455 }
440 ] 456 ]
441 }, 457 },
442 458
443 { 459 {
444 path: '/zip', 460 path: '/zip',
445 component: 'layout/Layout', 461 component: 'layout/Layout',
446 redirect: '/zip/download', 462 redirect: '/zip/download',
447 alwaysShow: true, 463 alwaysShow: true,
448 meta: { title: 'zip', icon: 'zip' }, 464 meta: { title: 'zip', icon: 'zip' },
449 children: [ 465 children: [
450 { 466 {
451 path: 'download', 467 path: 'download',
452 component: 'views/zip/index', 468 component: 'views/zip/index',
453 name: 'ExportZip', 469 name: 'ExportZip',
454 meta: { title: 'exportZip' } 470 meta: { title: 'exportZip' }
455 } 471 }
456 ] 472 ]
457 }, 473 },
458 474
459 { 475 {
460 path: '/pdf', 476 path: '/pdf',
461 component: 'layout/Layout', 477 component: 'layout/Layout',
462 redirect: '/pdf/index', 478 redirect: '/pdf/index',
463 children: [ 479 children: [
464 { 480 {
465 path: 'index', 481 path: 'index',
466 component: 'views/pdf/index', 482 component: 'views/pdf/index',
467 name: 'PDF', 483 name: 'PDF',
468 meta: { title: 'pdf', icon: 'pdf' } 484 meta: { title: 'pdf', icon: 'pdf' }
469 } 485 }
470 ] 486 ]
471 }, 487 },
472 { 488 {
473 path: '/pdf/download', 489 path: '/pdf/download',
474 component: 'views/pdf/download', 490 component: 'views/pdf/download',
475 hidden: true 491 hidden: true
476 }, 492 },
477 493
478 { 494 {
479 path: '/theme', 495 path: '/theme',
480 component: 'layout/Layout', 496 component: 'layout/Layout',
481 redirect: 'noRedirect', 497 redirect: 'noRedirect',
482 children: [ 498 children: [
483 { 499 {
484 path: 'index', 500 path: 'index',
485 component: 'views/theme/index', 501 component: 'views/theme/index',
486 name: 'Theme', 502 name: 'Theme',
487 meta: { title: 'theme', icon: 'theme' } 503 meta: { title: 'theme', icon: 'theme' }
488 } 504 }
489 ] 505 ]
490 }, 506 },
491 507
492 { 508 {
493 path: '/clipboard', 509 path: '/clipboard',
494 component: 'layout/Layout', 510 component: 'layout/Layout',
495 redirect: 'noRedirect', 511 redirect: 'noRedirect',
496 children: [ 512 children: [
497 { 513 {
498 path: 'index', 514 path: 'index',
499 component: 'views/clipboard/index', 515 component: 'views/clipboard/index',
500 name: 'ClipboardDemo', 516 name: 'ClipboardDemo',
501 meta: { title: 'clipboardDemo', icon: 'clipboard' } 517 meta: { title: 'clipboardDemo', icon: 'clipboard' }
502 } 518 }
503 ] 519 ]
504 }, 520 },
505 521
506 { 522 {
507 path: '/i18n', 523 path: '/i18n',
508 component: 'layout/Layout', 524 component: 'layout/Layout',
509 children: [ 525 children: [
510 { 526 {
511 path: 'index', 527 path: 'index',
512 component: 'views/i18n-demo/index', 528 component: 'views/i18n-demo/index',
513 name: 'I18n', 529 name: 'I18n',
514 meta: { title: 'i18n', icon: 'international' } 530 meta: { title: 'i18n', icon: 'international' }
515 } 531 }
516 ] 532 ]
517 }, 533 },
518 534
519 { 535 {
520 path: 'external-link', 536 path: 'external-link',
521 component: 'layout/Layout', 537 component: 'layout/Layout',
522 children: [ 538 children: [
523 { 539 {
524 path: 'https://github.com/PanJiaChen/vue-element-admin', 540 path: 'https://github.com/PanJiaChen/vue-element-admin',
525 meta: { title: 'externalLink', icon: 'link' } 541 meta: { title: 'externalLink', icon: 'link' }
526 } 542 }
527 ] 543 ]
528 }, 544 },
529 545
530 { path: '*', redirect: '/404', hidden: true } 546 { path: '*', redirect: '/404', hidden: true }
531 ] 547 ]
532 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 assistant: { 8 assistant: {
7 token: 'assistant-token' 9 token: 'assistant-token'
8 }, 10 },
9 runner: { 11 runner: {
10 token: 'runner-token' 12 token: 'runner-token'
11 }, 13 },
12 shoper: { 14 shoper: {
13 token: 'shoper-token' 15 token: 'shoper-token'
14 } 16 }
15 } 17 }
16 18
17 const users = { 19 const users = {
18 'admin-token': { 20 'admin-token': {
19 roles: ['admin'], 21 roles: ['admin'],
20 introduction: 'I am a super administrator', 22 introduction: 'I am a super administrator',
21 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 23 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
22 name: 'Super Admin' 24 name: 'Super Admin'
23 }, 25 },
24 'assistant-token': { 26 'assistant-token': {
25 roles: ['assistant'], 27 roles: ['assistant'],
26 introduction: 'I am an assistant', 28 introduction: 'I am an assistant',
27 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 29 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
28 name: 'Normal assistant' 30 name: 'Normal assistant'
29 }, 31 },
30 'runner-token': { 32 'runner-token': {
31 roles: ['runner'], 33 roles: ['runner'],
32 introduction: 'I am an runner', 34 introduction: 'I am an runner',
33 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 35 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
34 name: 'Normal runner' 36 name: 'Normal runner'
35 }, 37 },
36 'shoper-token': { 38 'shoper-token': {
37 roles: ['shoper'], 39 roles: ['shoper'],
38 introduction: 'I am an shoper', 40 introduction: 'I am an shoper',
39 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 41 avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
40 name: 'Normal shoper' 42 name: 'Normal shoper'
41 } 43 }
42 } 44 }
43 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
44 export default [ 76 export default [
45 // user login 77 // user login
46 { 78 {
47 url: '/vue-element-admin/user/login', 79 url: '/yp/user/login',
48 type: 'post', 80 type: 'post',
49 response: config => { 81 response: config => {
50 const { username } = config.body 82 const { username } = config.body
51 const token = tokens[username] 83 const token = tokens[username]
52 84
53 // mock error 85 // mock error
54 if (!token) { 86 if (!token) {
55 return { 87 return {
56 code: 60204, 88 code: 60204,
57 message: 'Account and password are incorrect.' 89 message: 'Account and password are incorrect.'
58 } 90 }
59 } 91 }
60 92
61 return { 93 return {
62 code: 20000, 94 code: 20000,
63 data: token 95 data: token
64 } 96 }
65 } 97 }
66 }, 98 },
67 99
68 // get user info 100 // get user info
69 { 101 {
70 url: '/vue-element-admin/user/info\.*', 102 url: '/yp/user/info\.*',
71 type: 'get', 103 type: 'get',
72 response: config => { 104 response: config => {
73 const { token } = config.query 105 const { token } = config.query
74 const info = users[token] 106 const info = users[token]
75 107
76 // mock error 108 // mock error
77 if (!info) { 109 if (!info) {
78 return { 110 return {
79 code: 50008, 111 code: 50008,
80 message: 'Login failed, unable to get user details.' 112 message: 'Login failed, unable to get user details.'
81 } 113 }
82 } 114 }
83 115
84 return { 116 return {
85 code: 20000, 117 code: 20000,
86 data: info 118 data: info
87 } 119 }
88 } 120 }
89 }, 121 },
90 122
91 // user logout 123 // user logout
92 { 124 {
93 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',
94 type: 'post', 148 type: 'post',
95 response: _ => { 149 response: _ => {
96 return { 150 return {
97 code: 20000, 151 code: 20000,
98 data: 'success' 152 data: 'success'
99 } 153 }
100 } 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 }
101 } 202 }
102 ] 203 ]
103 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
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/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/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' 14 import userRouter from './modules/user'
15 import systemRouter from './modules/system'
16 import prodRouter from './modules/prod'
17 import metaRouter from './modules/meta'
15 18
16 /** 19 /**
17 * Note: sub-menu only appear when route children.length >= 1 20 * Note: sub-menu only appear when route children.length >= 1
18 * 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
19 * 22 *
20 * 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)
21 * alwaysShow: true if set true, will always show the root menu 24 * alwaysShow: true if set true, will always show the root menu
22 * 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,
23 * it will becomes nested mode, otherwise not show the root menu 26 * it will becomes nested mode, otherwise not show the root menu
24 * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb 27 * redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
25 * 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!!!)
26 * meta : { 29 * meta : {
27 roles: ['admin','assistant','runner', 'shoper'] control the page roles (you can set multiple roles) 30 roles: ['admin','assistant','runner', 'shoper'] control the page roles (you can set multiple roles)
28 title: 'title' the name show in sidebar and breadcrumb (recommend set) 31 title: 'title' the name show in sidebar and breadcrumb (recommend set)
29 icon: 'svg-name' the icon show in the sidebar 32 icon: 'svg-name' the icon show in the sidebar
30 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)
31 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
32 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)
33 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
34 } 37 }
35 */ 38 */
36 39
37 /** 40 /**
38 * constantRoutes 41 * constantRoutes
39 * a base page that does not have permission requirements 42 * a base page that does not have permission requirements
40 * all roles can be accessed 43 * all roles can be accessed
41 */ 44 */
42 export const constantRoutes = [ 45 export const constantRoutes = [
43 { 46 {
44 path: '/redirect', 47 path: '/redirect',
45 component: Layout, 48 component: Layout,
46 hidden: true, 49 hidden: true,
47 children: [ 50 children: [
48 { 51 {
49 path: '/redirect/:path*', 52 path: '/redirect/:path*',
50 component: () => import('@/views/redirect/index') 53 component: () => import('@/views/redirect/index')
51 } 54 }
52 ] 55 ]
53 }, 56 },
54 { 57 {
55 path: '/login', 58 path: '/login',
56 component: () => import('@/views/login/index'), 59 component: () => import('@/views/login/index'),
57 hidden: true 60 hidden: true
58 }, 61 },
59 { 62 {
60 path: '/auth-redirect', 63 path: '/auth-redirect',
61 component: () => import('@/views/login/auth-redirect'), 64 component: () => import('@/views/login/auth-redirect'),
62 hidden: true 65 hidden: true
63 }, 66 },
64 { 67 {
65 path: '/404', 68 path: '/404',
66 component: () => import('@/views/error-page/404'), 69 component: () => import('@/views/error-page/404'),
67 hidden: true 70 hidden: true
68 }, 71 },
69 { 72 {
73 path: '/500',
74 component: () => import('@/views/error-page/500'),
75 hidden: true
76 },
77 {
70 path: '/401', 78 path: '/401',
71 component: () => import('@/views/error-page/401'), 79 component: () => import('@/views/error-page/401'),
72 hidden: true 80 hidden: true
73 }, 81 },
74 { 82 {
75 path: '/', 83 path: '/',
76 component: Layout, 84 component: Layout,
77 redirect: '/dashboard', 85 redirect: '/dashboard',
78 children: [ 86 children: [
79 { 87 {
80 path: 'dashboard', 88 path: 'dashboard',
81 component: () => import('@/views/dashboard/index'), 89 component: () => import('@/views/dashboard/index'),
82 name: 'Dashboard', 90 name: 'Dashboard',
83 meta: { title: 'dashboard', icon: 'dashboard', affix: true } 91 meta: { title: 'dashboard', icon: 'dashboard', affix: true }
84 } 92 }
85 ] 93 ]
86 }, 94 },
87 // { 95 // {
88 // path: '/documentation', 96 // path: '/documentation',
89 // component: Layout, 97 // component: Layout,
90 // children: [ 98 // children: [
91 // { 99 // {
92 // path: 'index', 100 // path: 'index',
93 // component: () => import('@/views/documentation/index'), 101 // component: () => import('@/views/documentation/index'),
94 // name: 'Documentation', 102 // name: 'Documentation',
95 // meta: { title: 'documentation', icon: 'documentation', affix: true } 103 // meta: { title: 'documentation', icon: 'documentation', affix: true }
96 // } 104 // }
97 // ] 105 // ]
98 // }, 106 // },
99 // {
100 // path: '/guide',
101 // component: Layout,
102 // redirect: '/guide/index',
103 // children: [
104 // {
105 // path: 'index',
106 // component: () => import('@/views/guide/index'),
107 // name: 'Guide',
108 // meta: { title: 'guide', icon: 'guide', noCache: true }
109 // }
110 // ]
111 // },
112 { 107 {
113 path: '/profile', 108 path: '/guide',
114 component: Layout, 109 component: Layout,
115 redirect: '/profile/index', 110 redirect: '/guide/index',
116 hidden: true,
117 children: [ 111 children: [
118 { 112 {
119 path: 'index', 113 path: 'index',
120 component: () => import('@/views/profile/index'), 114 component: () => import('@/views/guide/index'),
121 name: 'Profile', 115 name: 'Guide',
122 meta: { title: 'profile', icon: 'user', noCache: true } 116 meta: { title: 'guide', icon: 'guide', noCache: true }
123 } 117 }
124 ] 118 ]
125 } 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 // }
126 ] 134 ]
127 135
128 /** 136 /**
129 * asyncRoutes 137 * asyncRoutes
130 * 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
131 */ 139 */
132 export const asyncRoutes = [ 140 export const asyncRoutes = [
133 // { 141 // {
134 // path: '/permission', 142 // path: '/permission',
135 // component: Layout, 143 // component: Layout,
136 // redirect: '/permission/page', 144 // redirect: '/permission/page',
137 // alwaysShow: true, // will always show the root menu 145 // alwaysShow: true, // will always show the root menu
138 // name: 'Permission', 146 // name: 'Permission',
139 // meta: { 147 // meta: {
140 // title: 'permission', 148 // title: 'permission',
141 // icon: 'lock', 149 // icon: 'lock',
142 // roles: ['admin', 'assistant'] // you can set roles in root nav 150 // roles: ['admin', 'assistant'] // you can set roles in root nav
143 // }, 151 // },
144 // children: [ 152 // children: [
145 // { 153 // {
146 // path: 'page', 154 // path: 'page',
147 // component: () => import('@/views/permission/page'), 155 // component: () => import('@/views/permission/page'),
148 // name: 'PagePermission', 156 // name: 'PagePermission',
149 // meta: { 157 // meta: {
150 // title: 'pagePermission', 158 // title: 'pagePermission',
151 // roles: ['admin','assistant'] // or you can only set roles in sub nav 159 // roles: ['admin','assistant'] // or you can only set roles in sub nav
152 // } 160 // }
153 // }, 161 // },
154 // { 162 // {
155 // path: 'directive', 163 // path: 'directive',
156 // component: () => import('@/views/permission/directive'), 164 // component: () => import('@/views/permission/directive'),
157 // name: 'DirectivePermission', 165 // name: 'DirectivePermission',
158 // meta: { 166 // meta: {
159 // title: 'directivePermission', 167 // title: 'directivePermission',
160 // roles: ['admin', 'shoper'] 168 // roles: ['admin', 'shoper']
161 // // if do not set roles, means: this page does not require permission 169 // // if do not set roles, means: this page does not require permission
162 // } 170 // }
163 // }, 171 // },
164 // { 172 // {
165 // path: 'role', 173 // path: 'role',
166 // component: () => import('@/views/permission/role'), 174 // component: () => import('@/views/permission/role'),
167 // name: 'RolePermission', 175 // name: 'RolePermission',
168 // meta: { 176 // meta: {
169 // title: 'rolePermission', 177 // title: 'rolePermission',
170 // roles: ['admin', 'runner'] 178 // roles: ['admin', 'runner']
171 // } 179 // }
172 // } 180 // }
173 // ] 181 // ]
174 // }, 182 // },
183 tableRouter,
184 metaRouter,
185 userRouter,
186 prodRouter,
175 { 187 {
176 path: '/meta', 188 path: '/orders',
177 component: Layout,
178 redirect: '/meta/page',
179 alwaysShow: true, // will always show the root menu
180 name: 'Meta',
181 meta: {
182 title: 'Meta',
183 icon: 'lock',
184 roles: ['admin', 'assistant'] // you can set roles in root nav
185 },
186 children: [
187 {
188 path: 'page',
189 component: () => import('@/views/permission/page'),
190 name: 'MetaList',
191 meta: {
192 title: 'MetaList',
193 roles: ['admin', 'assistant'] // or you can only set roles in sub nav
194 }
195 },
196 {
197 path: 'defined',
198 component: () => import('@/views/permission/directive'),
199 name: 'MetaDefiend',
200 meta: {
201 title: 'MetaDefiend',
202 roles: ['admin', 'assistant']
203 // if do not set roles, means: this page does not require permission
204 }
205 }
206 ]
207 },
208 {
209 path: '/users',
210 component: Layout,
211 redirect: '/users/page',
212 alwaysShow: true, // will always show the root menu
213 name: 'Users',
214 meta: {
215 title: 'Users',
216 icon: 'lock',
217 roles: ['admin', 'assistant'] // you can set roles in root nav
218 },
219 children: [
220 {
221 path: 'page',
222 component: () => import('@/views/permission/page'),
223 name: 'UserList',
224 meta: {
225 title: 'UserList',
226 roles: ['admin', 'assistant'] // or you can only set roles in sub nav
227 }
228 },
229 {
230 path: 'defined',
231 component: () => import('@/views/permission/directive'),
232 name: 'UserDefiend',
233 meta: {
234 title: 'UserDefiend',
235 roles: ['admin', 'assistant']
236 // if do not set roles, means: this page does not require permission
237 }
238 }
239 ]
240 },
241 {
242 path: '/prod',
243 component: Layout,
244 redirect: '/prod/page',
245 alwaysShow: true, // will always show the root menu
246 name: 'Prod',
247 meta: {
248 title: 'Prod',
249 icon: 'lock',
250 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
251 },
252 children: [
253 {
254 path: 'page',
255 component: () => import('@/views/permission/page'),
256 name: 'ProdList',
257 meta: {
258 title: 'ProdList',
259 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
260 }
261 },
262 {
263 path: 'defined',
264 component: () => import('@/views/permission/directive'),
265 name: 'ProdDefiend',
266 meta: {
267 title: 'ProdDefiend',
268 roles: ['admin', 'assistant', 'shoper']
269 // if do not set roles, means: this page does not require permission
270 }
271 }
272 ]
273 },
274 {
275 path: '/order',
276 component: Layout, 189 component: Layout,
277 redirect: '/order/page', 190 redirect: '/order/page',
278 alwaysShow: true, // will always show the root menu 191 alwaysShow: true, // will always show the root menu
279 name: 'Order', 192 name: 'Order',
280 meta: { 193 meta: {
281 title: 'Order', 194 title: 'orders',
282 icon: 'lock', 195 icon: 'shopping',
283 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav 196 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
284 }, 197 },
285 children: [ 198 children: [
286 { 199 {
287 path: 'page', 200 path: 'page',
288 component: () => import('@/views/permission/page'), 201 component: () => import('@/views/permission/page'),
289 name: 'OrderList', 202 name: 'OrderList',
290 meta: { 203 meta: {
291 title: 'OrderList', 204 title: 'OrderList',
292 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav 205 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
293 } 206 }
294 }, 207 },
295 { 208 {
296 path: 'defined', 209 path: 'defined',
297 component: () => import('@/views/permission/directive'), 210 component: () => import('@/views/permission/directive'),
298 name: 'OrderDefiend', 211 name: 'OrderDefiend',
299 meta: { 212 meta: {
300 title: 'OrderDefiend', 213 title: 'OrderDefiend',
301 roles: ['admin', 'assistant', 'runner', 'shoper'] 214 roles: ['admin', 'assistant', 'runner', 'shoper']
302 // 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
303 } 216 }
304 } 217 }
305 ] 218 ]
306 }, 219 },
307 { 220 {
308 path: '/site', 221 path: '/sites',
309 component: Layout, 222 component: Layout,
310 redirect: '/site/page', 223 redirect: '/site/page',
311 alwaysShow: true, // will always show the root menu 224 alwaysShow: true, // will always show the root menu
312 name: 'Site', 225 name: 'Site',
313 meta: { 226 meta: {
314 title: 'Site', 227 title: 'sites',
315 icon: 'lock', 228 icon: 'people',
316 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav 229 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
317 }, 230 },
318 children: [ 231 children: [
319 { 232 {
320 path: 'page', 233 path: 'page',
321 component: () => import('@/views/permission/page'), 234 component: () => import('@/views/permission/page'),
322 name: 'SiteList', 235 name: 'SiteList',
323 meta: { 236 meta: {
324 title: 'SiteList', 237 title: 'SiteList',
325 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav 238 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
326 } 239 }
327 }, 240 },
328 { 241 {
329 path: 'defined', 242 path: 'defined',
330 component: () => import('@/views/permission/directive'), 243 component: () => import('@/views/permission/directive'),
331 name: 'SiteDefiend', 244 name: 'SiteDefiend',
332 meta: { 245 meta: {
333 title: 'SiteDefiend', 246 title: 'SiteDefiend',
334 roles: ['admin', 'assistant', 'runner'] 247 roles: ['admin', 'assistant', 'runner']
335 // if do not set roles, means: this page does not require permission 248 // if do not set roles, means: this page does not require permission
336 } 249 }
337 } 250 }
338 ] 251 ]
339 }, 252 },
340 { 253
341 path: '/system',
342 component: Layout,
343 redirect: '/system/page',
344 alwaysShow: true, // will always show the root menu
345 name: 'System',
346 meta: {
347 title: 'System',
348 icon: 'lock',
349 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
350 },
351 children: [
352 {
353 path: 'page',
354 component: () => import('@/views/permission/page'),
355 name: 'SystemList',
356 meta: {
357 title: 'SystemList',
358 roles: ['admin', 'assistant', 'runner'] // or you can only set roles in sub nav
359 }
360 },
361 {
362 path: 'defined',
363 component: () => import('@/views/permission/directive'),
364 name: 'SystemDefiend',
365 meta: {
366 title: 'SystemDefiend',
367 roles: ['admin', 'assistant', 'runner']
368 // if do not set roles, means: this page does not require permission
369 }
370 }
371 ]
372 },
373 // { 254 // {
374 // path: '/icon', 255 // path: '/icon',
375 // component: Layout, 256 // component: Layout,
376 // children: [ 257 // children: [
377 // { 258 // {
378 // path: 'index', 259 // path: 'index',
379 // component: () => import('@/views/icons/index'), 260 // component: () => import('@/views/icons/index'),
380 // name: 'Icons', 261 // name: 'Icons',
381 // meta: { title: 'icons', icon: 'icon', noCache: true } 262 // meta: { title: 'icons', icon: 'icon', noCache: true }
382 // } 263 // }
383 // ] 264 // ]
384 // }, 265 // },
385 266 systemRouter,
386 /** 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 **/
387 componentsRouter, 268 // componentsRouter,
388 chartsRouter, 269 // chartsRouter,
389 // nestedRouter, 270 // nestedRouter,
390 tableRouter, 271 // tableRouter,
391 userRouter,
392 272
393 // { 273 // {
394 // path: '/example', 274 // path: '/example',
395 // component: Layout, 275 // component: Layout,
396 // redirect: '/example/list', 276 // redirect: '/example/list',
397 // name: 'Example', 277 // name: 'Example',
398 // meta: { 278 // meta: {
399 // title: 'example', 279 // title: 'example',
400 // icon: 'example' 280 // icon: 'example'
401 // }, 281 // },
402 // children: [ 282 // children: [
403 // { 283 // {
404 // path: 'create', 284 // path: 'create',
405 // component: () => import('@/views/example/create'), 285 // component: () => import('@/views/example/create'),
406 // name: 'CreateArticle', 286 // name: 'CreateArticle',
407 // meta: { title: 'createArticle', icon: 'edit' } 287 // meta: { title: 'createArticle', icon: 'edit' }
408 // }, 288 // },
409 // { 289 // {
410 // path: 'edit/:id(\\d+)', 290 // path: 'edit/:id(\\d+)',
411 // component: () => import('@/views/example/edit'), 291 // component: () => import('@/views/example/edit'),
412 // name: 'EditArticle', 292 // name: 'EditArticle',
413 // meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' }, 293 // meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
414 // hidden: true 294 // hidden: true
415 // }, 295 // },
416 // { 296 // {
417 // path: 'list', 297 // path: 'list',
418 // component: () => import('@/views/example/list'), 298 // component: () => import('@/views/example/list'),
419 // name: 'ArticleList', 299 // name: 'ArticleList',
420 // meta: { title: 'articleList', icon: 'list' } 300 // meta: { title: 'articleList', icon: 'list' }
421 // } 301 // }
422 // ] 302 // ]
423 // }, 303 // },
424 304
425 // { 305 // {
426 // path: '/tab', 306 // path: '/tab',
427 // component: Layout, 307 // component: Layout,
428 // children: [ 308 // children: [
429 // { 309 // {
430 // path: 'index', 310 // path: 'index',
431 // component: () => import('@/views/tab/index'), 311 // component: () => import('@/views/tab/index'),
432 // name: 'Tab', 312 // name: 'Tab',
433 // meta: { title: 'tab', icon: 'tab' } 313 // meta: { title: 'tab', icon: 'tab' }
434 // } 314 // }
435 // ] 315 // ]
436 // }, 316 // },
437 317
438 // { 318 // {
439 // path: '/error', 319 // path: '/error',
440 // component: Layout, 320 // component: Layout,
441 // redirect: 'noRedirect', 321 // redirect: 'noRedirect',
442 // name: 'ErrorPages', 322 // name: 'ErrorPages',
443 // meta: { 323 // meta: {
444 // title: 'errorPages', 324 // title: 'errorPages',
445 // icon: '404' 325 // icon: '404'
446 // }, 326 // },
447 // children: [ 327 // children: [
448 // { 328 // {
449 // path: '401', 329 // path: '401',
450 // component: () => import('@/views/error-page/401'), 330 // component: () => import('@/views/error-page/401'),
451 // name: 'Page401', 331 // name: 'Page401',
452 // meta: { title: 'page401', noCache: true } 332 // meta: { title: 'page401', noCache: true }
453 // }, 333 // },
454 // { 334 // {
455 // path: '404', 335 // path: '404',
456 // component: () => import('@/views/error-page/404'), 336 // component: () => import('@/views/error-page/404'),
457 // name: 'Page404', 337 // name: 'Page404',
458 // meta: { title: 'page404', noCache: true } 338 // meta: { title: 'page404', noCache: true }
459 // } 339 // }
460 // ] 340 // ]
461 // }, 341 // },
462 342
463 // { 343 // {
464 // path: '/error-log', 344 // path: '/error-log',
465 // component: Layout, 345 // component: Layout,
466 // children: [ 346 // children: [
467 // { 347 // {
468 // path: 'log', 348 // path: 'log',
469 // component: () => import('@/views/error-log/index'), 349 // component: () => import('@/views/error-log/index'),
470 // name: 'ErrorLog', 350 // name: 'ErrorLog',
471 // meta: { title: 'errorLog', icon: 'bug' } 351 // meta: { title: 'errorLog', icon: 'bug' }
472 // } 352 // }
473 // ] 353 // ]
474 // }, 354 // },
475 355
476 // { 356 // {
477 // path: '/excel', 357 // path: '/excel',
478 // component: Layout, 358 // component: Layout,
479 // redirect: '/excel/export-excel', 359 // redirect: '/excel/export-excel',
480 // name: 'Excel', 360 // name: 'Excel',
481 // meta: { 361 // meta: {
482 // title: 'excel', 362 // title: 'excel',
483 // icon: 'excel' 363 // icon: 'excel'
484 // }, 364 // },
485 // children: [ 365 // children: [
486 // { 366 // {
487 // path: 'export-excel', 367 // path: 'export-excel',
488 // component: () => import('@/views/excel/export-excel'), 368 // component: () => import('@/views/excel/export-excel'),
489 // name: 'ExportExcel', 369 // name: 'ExportExcel',
490 // meta: { title: 'exportExcel' } 370 // meta: { title: 'exportExcel' }
491 // }, 371 // },
492 // { 372 // {
493 // path: 'export-selected-excel', 373 // path: 'export-selected-excel',
494 // component: () => import('@/views/excel/select-excel'), 374 // component: () => import('@/views/excel/select-excel'),
495 // name: 'SelectExcel', 375 // name: 'SelectExcel',
496 // meta: { title: 'selectExcel' } 376 // meta: { title: 'selectExcel' }
497 // }, 377 // },
498 // { 378 // {
499 // path: 'export-merge-header', 379 // path: 'export-merge-header',
500 // component: () => import('@/views/excel/merge-header'), 380 // component: () => import('@/views/excel/merge-header'),
501 // name: 'MergeHeader', 381 // name: 'MergeHeader',
502 // meta: { title: 'mergeHeader' } 382 // meta: { title: 'mergeHeader' }
503 // }, 383 // },
504 // { 384 // {
505 // path: 'upload-excel', 385 // path: 'upload-excel',
506 // component: () => import('@/views/excel/upload-excel'), 386 // component: () => import('@/views/excel/upload-excel'),
507 // name: 'UploadExcel', 387 // name: 'UploadExcel',
508 // meta: { title: 'uploadExcel' } 388 // meta: { title: 'uploadExcel' }
509 // } 389 // }
510 // ] 390 // ]
511 // }, 391 // },
512 392
513 // { 393 // {
514 // path: '/zip', 394 // path: '/zip',
515 // component: Layout, 395 // component: Layout,
516 // redirect: '/zip/download', 396 // redirect: '/zip/download',
517 // alwaysShow: true, 397 // alwaysShow: true,
518 // name: 'Zip', 398 // name: 'Zip',
519 // meta: { title: 'zip', icon: 'zip' }, 399 // meta: { title: 'zip', icon: 'zip' },
520 // children: [ 400 // children: [
521 // { 401 // {
522 // path: 'download', 402 // path: 'download',
523 // component: () => import('@/views/zip/index'), 403 // component: () => import('@/views/zip/index'),
524 // name: 'ExportZip', 404 // name: 'ExportZip',
525 // meta: { title: 'exportZip' } 405 // meta: { title: 'exportZip' }
526 // } 406 // }
527 // ] 407 // ]
528 // }, 408 // },
529 409
530 // { 410 // {
531 // path: '/pdf', 411 // path: '/pdf',
532 // component: Layout, 412 // component: Layout,
533 // redirect: '/pdf/index', 413 // redirect: '/pdf/index',
534 // children: [ 414 // children: [
535 // { 415 // {
536 // path: 'index', 416 // path: 'index',
537 // component: () => import('@/views/pdf/index'), 417 // component: () => import('@/views/pdf/index'),
538 // name: 'PDF', 418 // name: 'PDF',
539 // meta: { title: 'pdf', icon: 'pdf' } 419 // meta: { title: 'pdf', icon: 'pdf' }
540 // } 420 // }
541 // ] 421 // ]
542 // }, 422 // },
543 // { 423 // {
544 // path: '/pdf/download', 424 // path: '/pdf/download',
545 // component: () => import('@/views/pdf/download'), 425 // component: () => import('@/views/pdf/download'),
546 // hidden: true 426 // hidden: true
547 // }, 427 // },
548 428
549 // { 429 // {
550 // path: '/theme', 430 // path: '/theme',
551 // component: Layout, 431 // component: Layout,
552 // children: [ 432 // children: [
553 // { 433 // {
554 // path: 'index', 434 // path: 'index',
555 // component: () => import('@/views/theme/index'), 435 // component: () => import('@/views/theme/index'),
556 // name: 'Theme', 436 // name: 'Theme',
557 // meta: { title: 'theme', icon: 'theme' } 437 // meta: { title: 'theme', icon: 'theme' }
558 // } 438 // }
559 // ] 439 // ]
560 // }, 440 // },
561 441
562 // { 442 // {
563 // path: '/clipboard', 443 // path: '/clipboard',
564 // component: Layout, 444 // component: Layout,
565 // children: [ 445 // children: [
566 // { 446 // {
567 // path: 'index', 447 // path: 'index',
568 // component: () => import('@/views/clipboard/index'), 448 // component: () => import('@/views/clipboard/index'),
569 // name: 'ClipboardDemo', 449 // name: 'ClipboardDemo',
570 // meta: { title: 'clipboardDemo', icon: 'clipboard' } 450 // meta: { title: 'clipboardDemo', icon: 'clipboard' }
571 // } 451 // }
572 // ] 452 // ]
573 // }, 453 // },
574 454
575 // { 455 // {
576 // path: '/i18n', 456 // path: '/i18n',
577 // component: Layout, 457 // component: Layout,
578 // children: [ 458 // children: [
579 // { 459 // {
580 // path: 'index', 460 // path: 'index',
581 // component: () => import('@/views/i18n-demo/index'), 461 // component: () => import('@/views/i18n-demo/index'),
582 // name: 'I18n', 462 // name: 'I18n',
583 // meta: { title: 'i18n', icon: 'international' } 463 // meta: { title: 'i18n', icon: 'international' }
584 // } 464 // }
585 // ] 465 // ]
586 // }, 466 // },
587 467
588 // { 468 // {
589 // path: 'external-link', 469 // path: 'external-link',
590 // component: Layout, 470 // component: Layout,
591 // children: [ 471 // children: [
592 // { 472 // {
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
1 /** When your routing table is too long, you can split it into small modules**/ 1 /** When your routing table is too long, you can split it into small modules**/
2 2
3 import Layout from '@/layout' 3 import Layout from '@/layout'
4 4
5 const chartsRouter = { 5 const chartsRouter = {
6 path: '/users', 6 path: '/users',
7 component: Layout, 7 component: Layout,
8 redirect: 'noRedirect', 8 redirect: '/users/page',
9 alwaysShow: true, // will always show the root menu
9 name: 'Users', 10 name: 'Users',
10 meta: { 11 meta: {
11 title: '用户管理', 12 title: 'users',
12 icon: 'peoples' 13 icon: 'peoples',
14 roles: ['admin', 'assistant'] // you can set roles in root nav
13 }, 15 },
14 children: [ 16 children: [{
15 { 17 path: 'page',
16 path: 'keyboard', 18 component: () => import('@/views/users/list'),
17 component: () => import('@/views/charts/keyboard'), 19 name: 'UserList',
18 name: 'KeyboardChart', 20 meta: {
19 meta: { title: 'keyboardChart', noCache: true } 21 title: 'UserList',
20 }, 22 roles: ['admin', 'assistant', 'shoper', 'runner'] // or you can only set roles in sub nav
21 {
22 path: 'line',
23 component: () => import('@/views/charts/line'),
24 name: 'LineChart',
25 meta: { title: 'lineChart', noCache: true }
26 },
27 {
28 path: 'mix-chart',
29 component: () => import('@/views/charts/mix-chart'),
30 name: 'MixChart',
31 meta: { title: 'mixChart', noCache: true }
32 } 23 }
24 }
25 // ,{
26 // path: '/icons',
27 // component: () => import('@/views/icons/index'),
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/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/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;">{{ roles }}'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/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/error-page/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>
58 1 <template>
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
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/order/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/prod/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/system/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/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('assistant')).toBe(true)
5 expect(validUsername('runner')).toBe(true) 6 expect(validUsername('runner')).toBe(true)
7 expect(validUsername('shoper')).toBe(true)
6 // expect(validUsername('xxxx')).toBe(false) 8 // expect(validUsername('xxxx')).toBe(false)
7 // expect(validUsername('xxxx')).toBe(false) 9 // expect(validUsername('xxxx')).toBe(false)
8 // expect(validUsername('xxxx')).toBe(false) 10 // expect(validUsername('xxxx')).toBe(false)
9 }) 11 })
10 it('validURL', () => { 12 it('validURL', () => {
11 // expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true) 13 // expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
12 // expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true) 14 // expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
13 // expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false) 15 // expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
14 }) 16 })
15 it('validLowerCase', () => { 17 it('validLowerCase', () => {
16 expect(validLowerCase('abc')).toBe(true) 18 expect(validLowerCase('abc')).toBe(true)
17 expect(validLowerCase('Abc')).toBe(false) 19 expect(validLowerCase('Abc')).toBe(false)
18 expect(validLowerCase('123abc')).toBe(false) 20 expect(validLowerCase('123abc')).toBe(false)
19 }) 21 })
20 it('validUpperCase', () => { 22 it('validUpperCase', () => {
21 expect(validUpperCase('ABC')).toBe(true) 23 expect(validUpperCase('ABC')).toBe(true)
22 expect(validUpperCase('Abc')).toBe(false) 24 expect(validUpperCase('Abc')).toBe(false)
23 expect(validUpperCase('123ABC')).toBe(false) 25 expect(validUpperCase('123ABC')).toBe(false)
24 }) 26 })
25 it('validAlphabets', () => { 27 it('validAlphabets', () => {
26 expect(validAlphabets('ABC')).toBe(true) 28 expect(validAlphabets('ABC')).toBe(true)
27 expect(validAlphabets('Abc')).toBe(true) 29 expect(validAlphabets('Abc')).toBe(true)
28 expect(validAlphabets('123aBC')).toBe(false) 30 expect(validAlphabets('123aBC')).toBe(false)
29 }) 31 })
30 }) 32 })
31 33