Commit 8a0e4eede07d9836ba6ec1ead345155edcab531d
1 parent
fc0d443bb7
Exists in
master
产品列表页
Showing
3 changed files
with
592 additions
and
70 deletions
Show diff stats
mock/article.js
1 | import Mock from 'mockjs' | 1 | import Mock from 'mockjs' |
2 | // import logoPath from "~@/assets/img/yp_logo.jpeg" | 2 | // import logoPath from "~@/assets/img/yp_logo.jpeg" |
3 | 3 | ||
4 | const List = [] | 4 | const List = [] |
5 | const count = 100 | 5 | const count = 50 |
6 | 6 | ||
7 | const baseContent = '<p>I am testing data, I am testing data.</p><p></p>' | 7 | const baseContent = '<p>I am testing data, I am testing data.</p><p></p>' |
8 | // const image_uri = logoPath | 8 | // const image_uri = logoPath |
9 | const image_uri = 'https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif' | 9 | const image_uri = 'https://wpimg.wallstcn.com/360e4842-4db5-42d0-b078-f9a84a825546.gif' |
10 | 10 | ||
11 | for (let i = 0; i < count; i++) { | 11 | for (let i = 0; i < count; i++) { |
12 | List.push(Mock.mock({ | 12 | List.push(Mock.mock({ |
13 | id: '@increment', | 13 | id: '@increment', |
14 | timestamp: +Mock.Random.date('T'), | 14 | timestamp: +Mock.Random.date('T'), |
15 | author: '@first', | 15 | author: '@first', |
16 | reviewer: '@first', | 16 | reviewer: '@first', |
17 | title: '@title(5, 10)', | 17 | title: '@title(5, 10)', |
18 | content_short: 'mock data', | 18 | content_short: 'mock data', |
19 | content: baseContent, | 19 | content: baseContent, |
20 | forecast: '@float(0, 100, 2, 2)', | 20 | forecast: '@float(0, 100, 2, 2)', |
21 | importance: '@integer(1, 3)', | 21 | importance: '@integer(1, 3)', |
22 | 'type|1': ['CN', 'US', 'JP', 'EU'], | 22 | 'type|1': ['CN', 'US', 'JP', 'EU'], |
23 | 'status|1': ['published', 'draft'], | 23 | 'status|1': ['published', 'draft'], |
24 | display_time: '@datetime', | 24 | display_time: '@datetime', |
25 | comment_disabled: true, | 25 | comment_disabled: true, |
26 | pageviews: '@integer(300, 5000)', | 26 | pageviews: '@integer(300, 5000)', |
27 | image_uri, | 27 | image_uri, |
28 | platforms: ['a-platform'] | 28 | platforms: ['a-platform'] |
29 | })) | 29 | })) |
30 | } | 30 | } |
31 | 31 | ||
32 | export default [{ | 32 | export default [{ |
33 | url: '/yp/article/list', | 33 | url: '/yp/article/list', |
34 | type: 'get', | 34 | type: 'get', |
35 | response: config => { | 35 | response: config => { |
36 | const { | 36 | const { |
37 | importance, | 37 | importance, |
38 | type, | 38 | type, |
39 | title, | 39 | title, |
40 | page = 1, | 40 | page = 1, |
41 | limit = 20, | 41 | limit = 20, |
42 | sort | 42 | sort |
43 | } = config.query | 43 | } = config.query |
44 | 44 | ||
45 | let mockList = List.filter(item => { | 45 | let mockList = List.filter(item => { |
46 | if (importance && item.importance !== +importance) return false | 46 | if (importance && item.importance !== +importance) return false |
47 | if (type && item.type !== type) return false | 47 | if (type && item.type !== type) return false |
48 | if (title && item.title.indexOf(title) < 0) return false | 48 | if (title && item.title.indexOf(title) < 0) return false |
49 | return true | 49 | return true |
50 | }) | 50 | }) |
51 | 51 | ||
52 | if (sort === '-id') { | 52 | if (sort === '-id') { |
53 | mockList = mockList.reverse() | 53 | mockList = mockList.reverse() |
54 | } | 54 | } |
55 | 55 | ||
56 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) | 56 | const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) |
57 | 57 | ||
58 | return { | 58 | return { |
59 | code: 20000, | 59 | code: 20000, |
60 | data: { | 60 | data: { |
61 | total: mockList.length, | 61 | total: mockList.length, |
62 | items: pageList | 62 | items: pageList |
63 | } | 63 | } |
64 | } | 64 | } |
65 | } | 65 | } |
66 | }, | 66 | }, |
67 | 67 | ||
68 | { | 68 | { |
69 | url: '/yp/article/detail', | 69 | url: '/yp/article/detail', |
70 | type: 'get', | 70 | type: 'get', |
71 | response: config => { | 71 | response: config => { |
72 | const { | 72 | const { |
73 | id | 73 | id |
74 | } = config.query | 74 | } = config.query |
75 | for (const article of List) { | 75 | for (const article of List) { |
76 | if (article.id === +id) { | 76 | if (article.id === +id) { |
77 | return { | 77 | return { |
78 | code: 20000, | 78 | code: 20000, |
79 | data: article | 79 | data: article |
80 | } | 80 | } |
81 | } | 81 | } |
82 | } | 82 | } |
83 | } | 83 | } |
84 | }, | 84 | }, |
85 | 85 | ||
86 | { | 86 | { |
87 | url: '/yp/article/pv', | 87 | url: '/yp/article/pv', |
88 | type: 'get', | 88 | type: 'get', |
89 | response: _ => { | 89 | response: _ => { |
90 | return { | 90 | return { |
91 | code: 20000, | 91 | code: 20000, |
92 | data: { | 92 | data: { |
93 | pvData: [{ | 93 | pvData: [{ |
94 | key: 'PC', | 94 | key: 'PC', |
95 | pv: 1024 | 95 | pv: 1024 |
96 | }, | 96 | }, |
97 | { | 97 | { |
98 | key: 'mobile', | 98 | key: 'mobile', |
99 | pv: 1024 | 99 | pv: 1024 |
100 | }, | 100 | }, |
101 | { | 101 | { |
102 | key: 'ios', | 102 | key: 'ios', |
103 | pv: 1024 | 103 | pv: 1024 |
104 | }, | 104 | }, |
105 | { | 105 | { |
106 | key: 'android', | 106 | key: 'android', |
107 | pv: 1024 | 107 | pv: 1024 |
108 | } | 108 | } |
109 | ] | 109 | ] |
110 | } | 110 | } |
111 | } | 111 | } |
112 | } | 112 | } |
113 | }, | 113 | }, |
114 | 114 | ||
115 | { | 115 | { |
116 | url: '/yp/article/create', | 116 | url: '/yp/article/create', |
117 | type: 'post', | 117 | type: 'post', |
118 | response: _ => { | 118 | response: _ => { |
119 | return { | 119 | return { |
120 | code: 20000, | 120 | code: 20000, |
121 | data: 'success' | 121 | data: 'success' |
122 | } | 122 | } |
123 | } | 123 | } |
124 | }, | 124 | }, |
125 | 125 | ||
126 | { | 126 | { |
127 | url: '/yp/article/update', | 127 | url: '/yp/article/update', |
128 | type: 'post', | 128 | type: 'post', |
129 | response: _ => { | 129 | response: _ => { |
130 | return { | 130 | return { |
131 | code: 20000, | 131 | code: 20000, |
132 | data: 'success' | 132 | data: 'success' |
133 | } | 133 | } |
134 | } | 134 | } |
135 | } | 135 | } |
136 | ] | 136 | ] |
137 | 137 |
src/views/application/appList.vue
1 | <template> | 1 | <template> |
2 | <el-container style="height: 853px; border: 1px solid #eee"> | 2 | <el-container style="height: 853px; border: 1px solid #eee"> |
3 | <el-aside width="250px" style="background-color: rgb(238, 241, 246)"> | 3 | <el-aside width="250px" style="background-color: rgb(238, 241, 246)"> |
4 | <el-menu :default-openeds="['1','2', '3']"> | 4 | <el-menu :default-openeds="['1','2', '3']"> |
5 | <el-submenu index="1"> | 5 | <el-submenu index="1"> |
6 | <template slot="title"><i class="el-icon-message" />非常戴镜</template> | 6 | <template slot="title"><i class="el-icon-message" />非常戴镜</template> |
7 | <el-menu-item v-for="(item,i) in nav_menu_data" :key="i" :index="item.name">{{ item.title }}</el-menu-item> | 7 | <el-menu-item v-for="(item,i) in nav_menu_data" :key="i" :index="item.name">{{ item.title }}</el-menu-item> |
8 | </el-submenu> | 8 | </el-submenu> |
9 | <el-submenu index="2"> | 9 | <el-submenu index="2"> |
10 | <template slot="title"><i class="el-icon-menu" />亚当光学</template> | 10 | <template slot="title"><i class="el-icon-menu" />亚当光学</template> |
11 | <el-menu-item index="2-1">产品列表</el-menu-item> | 11 | <el-menu-item index="2-1">产品列表</el-menu-item> |
12 | <el-menu-item index="2-2">订单列表</el-menu-item> | 12 | <el-menu-item index="2-2">订单列表</el-menu-item> |
13 | <el-menu-item index="2-3">用户列表</el-menu-item> | 13 | <el-menu-item index="2-3">用户列表</el-menu-item> |
14 | <el-menu-item index="2-4">运行分析</el-menu-item> | 14 | <el-menu-item index="2-4">运行分析</el-menu-item> |
15 | </el-submenu> | 15 | </el-submenu> |
16 | <el-submenu index="3"> | 16 | <el-submenu index="3"> |
17 | <template slot="title"><i class="el-icon-setting" />秀野光学</template> | 17 | <template slot="title"><i class="el-icon-setting" />秀野光学</template> |
18 | <el-menu-item index="3-1">产品列表</el-menu-item> | 18 | <el-menu-item index="3-1">产品列表</el-menu-item> |
19 | <el-menu-item index="3-2">订单列表</el-menu-item> | 19 | <el-menu-item index="3-2">订单列表</el-menu-item> |
20 | <el-menu-item index="3-3">用户列表</el-menu-item> | 20 | <el-menu-item index="3-3">用户列表</el-menu-item> |
21 | <el-menu-item index="3-4">运行分析</el-menu-item> | 21 | <el-menu-item index="3-4">运行分析</el-menu-item> |
22 | </el-submenu> | 22 | </el-submenu> |
23 | </el-menu> | 23 | </el-menu> |
24 | </el-aside> | 24 | </el-aside> |
25 | 25 | ||
26 | <el-container> | 26 | <el-container> |
27 | <el-header style="text-align: center; font-size: 24px"> | 27 | <el-header style="text-align: center; font-size: 24px"> |
28 | <span>这里的title</span> | 28 | <span>这里的title</span> |
29 | </el-header> | 29 | </el-header> |
30 | 30 | ||
31 | <el-main> | 31 | <el-main> |
32 | <el-tabs v-model="activeName" tab-position="top" @tab-click="handleClick"> | 32 | <el-tabs v-model="activeName" tab-position="top" @tab-click="handleClick"> |
33 | <el-tab-pane label="产品列表" name="first"> | 33 | <el-tab-pane label="产品列表" name="first"> |
34 | <el-table :data="prodListTableData" stripe> | 34 | <el-table :data="prodListTableData" stripe> |
35 | <el-table-column prop="prodInfo" label="产品信息" width="340" /> | 35 | <el-table-column prop="prodInfo" label="产品信息" width="340" /> |
36 | <el-table-column prop="prodTag" label="产品标签" width="340" /> | 36 | <el-table-column prop="prodTag" label="产品标签" width="340" /> |
37 | <el-table-column prop="stock" label="库存" width="340" /> | 37 | <el-table-column prop="stock" label="库存" width="340" /> |
38 | <el-table-column label="操作"> | 38 | <el-table-column label="操作"> |
39 | <el-button type="text">从应用中删除</el-button> | 39 | <el-button type="text">从应用中删除</el-button> |
40 | </el-table-column> | 40 | </el-table-column> |
41 | </el-table> | 41 | </el-table> |
42 | </el-tab-pane> | 42 | </el-tab-pane> |
43 | <el-tab-pane label="订单列表" name="second"> | 43 | <el-tab-pane label="订单列表" name="second"> |
44 | <el-table :data="prodListTableData" stripe> | 44 | <el-table :data="prodListTableData" stripe> |
45 | <el-table-column prop="prodInfo" label="下单时间" width="220" /> | 45 | <el-table-column prop="prodInfo" label="下单时间" width="220" /> |
46 | <el-table-column prop="prodTag" label="金额" width="220" /> | 46 | <el-table-column prop="prodTag" label="金额" width="220" /> |
47 | <el-table-column prop="stock" label="产品id" width="220" /> | 47 | <el-table-column prop="stock" label="产品id" width="220" /> |
48 | <el-table-column prop="stock" label="订单号" width="220" /> | 48 | <el-table-column prop="stock" label="订单号" width="220" /> |
49 | <el-table-column prop="stock" label="状态" width="220" /> | 49 | <el-table-column prop="stock" label="状态" width="220" /> |
50 | <el-table-column label="操作"> | 50 | <el-table-column label="操作"> |
51 | <el-button type="text">从应用中删除</el-button> | 51 | <el-button type="text">从应用中删除</el-button> |
52 | </el-table-column> | 52 | </el-table-column> |
53 | </el-table> | 53 | </el-table> |
54 | </el-tab-pane> | 54 | </el-tab-pane> |
55 | <el-tab-pane label="用户列表" name="third"> | 55 | <el-tab-pane label="用户列表" name="third"> |
56 | <el-table :data="prodListTableData" stripe> | 56 | <el-table :data="prodListTableData" stripe> |
57 | <el-table-column prop="prodInfo" label="用户id" width="180" /> | 57 | <el-table-column prop="prodInfo" label="用户id" width="180" /> |
58 | <el-table-column prop="prodTag" label="加入时间" width="180" /> | 58 | <el-table-column prop="prodTag" label="加入时间" width="180" /> |
59 | <el-table-column prop="stock" label="引流人" width="180" /> | 59 | <el-table-column prop="stock" label="引流人" width="180" /> |
60 | <el-table-column prop="stock" label="引流渠道" width="180" /> | 60 | <el-table-column prop="stock" label="引流渠道" width="180" /> |
61 | <el-table-column prop="stock" label="消费额度" width="180" /> | 61 | <el-table-column prop="stock" label="消费额度" width="180" /> |
62 | <el-table-column prop="stock" label="访问时长" width="180" /> | 62 | <el-table-column prop="stock" label="访问时长" width="180" /> |
63 | <el-table-column prop="stock" label="带来流量" width="180" /> | 63 | <el-table-column prop="stock" label="带来流量" width="180" /> |
64 | <el-table-column label="操作"> | 64 | <el-table-column label="操作"> |
65 | <el-button type="text">从应用中删除</el-button> | 65 | <el-button type="text">从应用中删除</el-button> |
66 | </el-table-column> | 66 | </el-table-column> |
67 | </el-table> | 67 | </el-table> |
68 | </el-tab-pane> | 68 | </el-tab-pane> |
69 | <el-tab-pane label="运营分析" name="fourth"> | 69 | <el-tab-pane label="运营分析" name="fourth"> |
70 | <el-table :data="prodListTableData" stripe> | 70 | <el-table :data="prodListTableData" stripe> |
71 | <el-table-column prop="prodInfo" label="产品信息" width="340" /> | 71 | <el-table-column prop="prodInfo" label="产品信息" width="340" /> |
72 | <el-table-column prop="prodTag" label="产品标签" width="340" /> | 72 | <el-table-column prop="prodTag" label="产品标签" width="340" /> |
73 | <el-table-column prop="stock" label="库存" width="340" /> | 73 | <el-table-column prop="stock" label="库存" width="340" /> |
74 | <el-table-column label="操作"> | 74 | <el-table-column label="操作"> |
75 | <el-button type="text">从应用中删除</el-button> | 75 | <el-button type="text">从应用中删除</el-button> |
76 | </el-table-column> | 76 | </el-table-column> |
77 | </el-table> | 77 | </el-table> |
78 | </el-tab-pane> | 78 | </el-tab-pane> |
79 | </el-tabs> | 79 | </el-tabs> |
80 | </el-main> | 80 | </el-main> |
81 | </el-container> | 81 | </el-container> |
82 | </el-container> | 82 | </el-container> |
83 | 83 | ||
84 | </template> | 84 | </template> |
85 | 85 | ||
86 | <script> | 86 | <script> |
87 | export default { | 87 | export default { |
88 | data() { | 88 | data() { |
89 | return { | 89 | return { |
90 | activeName: 'second', | 90 | activeName: 'second', |
91 | path: '', | 91 | path: '', |
92 | nav_menu_data: [{ | 92 | nav_menu_data: [{ |
93 | title: '产品列表', | 93 | title: '产品列表', |
94 | path: '/Menu/appList' | 94 | name: 'appList' |
95 | }, { | 95 | }, { |
96 | title: '订单列表', | 96 | title: '订单列表', |
97 | path: '/Menu/orderList' | 97 | name: 'orderList' |
98 | }, { | 98 | }, { |
99 | title: '用户列表', | 99 | title: '用户列表', |
100 | path: '/Menu/userList' | 100 | name: 'userList' |
101 | }, { | 101 | }, { |
102 | title: '运营分析', | 102 | title: '运营分析', |
103 | path: '/Menu/analys' | 103 | name: 'analys' |
104 | }], | 104 | }], |
105 | prodListTableData: [{ | 105 | prodListTableData: [{ |
106 | prodInfo: 'pic', | 106 | prodInfo: 'pic', |
107 | prodTag: '非常带劲', | 107 | prodTag: '非常带劲', |
108 | stock: '102' | 108 | stock: '102' |
109 | }, | 109 | }, |
110 | { | 110 | { |
111 | prodInfo: 'pic', | 111 | prodInfo: 'pic', |
112 | prodTag: '非常带劲', | 112 | prodTag: '非常带劲', |
113 | stock: '4531' | 113 | stock: '4531' |
114 | }, | 114 | }, |
115 | { | 115 | { |
116 | prodInfo: 'pic', | 116 | prodInfo: 'pic', |
117 | prodTag: '非常带劲', | 117 | prodTag: '非常带劲', |
118 | stock: '531' | 118 | stock: '531' |
119 | }, | 119 | }, |
120 | { | 120 | { |
121 | prodInfo: 'pic', | 121 | prodInfo: 'pic', |
122 | prodTag: '非常带劲', | 122 | prodTag: '非常带劲', |
123 | stock: '768' | 123 | stock: '768' |
124 | }] | 124 | }] |
125 | } | 125 | } |
126 | }, | 126 | }, |
127 | watch: { | 127 | watch: { |
128 | }, | 128 | }, |
129 | created() { | 129 | created() { |
130 | }, | 130 | }, |
131 | method: { | 131 | method: { |
132 | onRouteChanged() { | 132 | onRouteChanged() { |
133 | const that = this | 133 | const that = this |
134 | that.path = that.$route.path | 134 | that.path = that.$route.path |
135 | }, | 135 | }, |
136 | handleClick(tab, event) { | 136 | handleClick(tab, event) { |
137 | console.log(tab, event) | 137 | console.log(tab, event) |
138 | } | 138 | } |
139 | } | 139 | } |
140 | } | 140 | } |
141 | 141 | ||
142 | </script> | 142 | </script> |
143 | 143 | ||
144 | <style> | 144 | <style> |
145 | .el-header { | 145 | .el-header { |
146 | background-color: #B3C0D1; | 146 | background-color: #B3C0D1; |
147 | color: #333; | 147 | color: #333; |
148 | line-height: 60px; | 148 | line-height: 60px; |
149 | } | 149 | } |
150 | 150 | ||
151 | .el-aside { | 151 | .el-aside { |
152 | color: #333; | 152 | color: #333; |
153 | } | 153 | } |
154 | </style> | 154 | </style> |
155 | 155 |
src/views/prod/list.vue
1 | <template> | 1 | <template> |
2 | <div class="app-container"> | 2 | <div class="app-container"> |
3 | <div class="filter-container"> | ||
4 | <!-- 搜索input --> | ||
5 | <el-input | ||
6 | v-model="listQuery.title" | ||
7 | :placeholder="$t('table.title')" | ||
8 | style="width: 200px;" | ||
9 | class="filter-item" | ||
10 | @keyup.enter.native="handleFilter" | ||
11 | /> | ||
12 | <!-- type选择 --> | ||
13 | <el-select | ||
14 | v-model="listQuery.type" | ||
15 | :placeholder="$t('table.type')" | ||
16 | clearable | ||
17 | class="filter-item" | ||
18 | style="width: 110px" | ||
19 | > | ||
20 | <el-option | ||
21 | v-for="item in calendarTypeOptions" | ||
22 | :key="item.key" | ||
23 | :label="item.display_name" | ||
24 | :value="item.key" | ||
25 | /> | ||
26 | </el-select> | ||
27 | |||
28 | <!-- imp选择 --> | ||
29 | <el-select | ||
30 | v-model="listQuery.importance" | ||
31 | :placeholder="$t('table.importance')" | ||
32 | clearable | ||
33 | filterable | ||
34 | style="width: 130px" | ||
35 | class="filter-item" | ||
36 | > | ||
37 | <!-- 分组tag筛选 --> | ||
38 | <el-option-group | ||
39 | v-for="group in importanceOptions" | ||
40 | :key="group.label" | ||
41 | :label="group.label" | ||
42 | > | ||
43 | <el-option | ||
44 | v-for="item in group.options" | ||
45 | :key="item.value" | ||
46 | :label="item.label" | ||
47 | :value="item.value" | ||
48 | /> | ||
49 | </el-option-group> | ||
50 | </el-select> | ||
51 | <!-- 排序 --> | ||
52 | <el-select | ||
53 | v-model="listQuery.sort" | ||
54 | style="width: 140px" | ||
55 | class="filter-item" | ||
56 | @change="handleFilter" | ||
57 | > | ||
58 | <el-option | ||
59 | v-for="item in sortOptions" | ||
60 | :key="item.key" | ||
61 | :label="item.label" | ||
62 | :value="item.key" | ||
63 | /> | ||
64 | </el-select> | ||
65 | <!-- search按钮 --> | ||
66 | <el-button | ||
67 | v-waves | ||
68 | class="filter-item" | ||
69 | type="primary" | ||
70 | icon="el-icon-search" | ||
71 | @click="handleFilter" | ||
72 | > | ||
73 | {{ $t('table.search') }} | ||
74 | </el-button> | ||
75 | <!-- add按钮 --> | ||
76 | <el-button | ||
77 | class="filter-item" | ||
78 | style="margin-left: 10px;" | ||
79 | type="primary" | ||
80 | icon="el-icon-edit" | ||
81 | @click="handleCreate" | ||
82 | > | ||
83 | {{ $t('table.add') }} | ||
84 | </el-button> | ||
85 | <!-- 导出为excel按钮 --> | ||
86 | <el-button | ||
87 | v-waves | ||
88 | :loading="downloadLoading" | ||
89 | class="filter-item" | ||
90 | type="primary" | ||
91 | icon="el-icon-download" | ||
92 | @click="handleDownload" | ||
93 | > | ||
94 | {{ $t('table.export') }} | ||
95 | </el-button> | ||
96 | <!-- 是否显示审核人 --> | ||
97 | <el-checkbox | ||
98 | v-model="showReviewer" | ||
99 | class="filter-item" | ||
100 | style="margin-left:15px;" | ||
101 | @change="tableKey=tableKey+1" | ||
102 | > | ||
103 | {{ $t('table.reviewer') }} | ||
104 | </el-checkbox> | ||
105 | </div> | ||
106 | |||
107 | <!-- 表格 --> | ||
3 | <el-table | 108 | <el-table |
109 | :key="tableKey" | ||
4 | v-loading="listLoading" | 110 | v-loading="listLoading" |
5 | :data="list" | 111 | :data="list" |
6 | border | 112 | border |
7 | fit | 113 | fit |
8 | highlight-current-row | 114 | highlight-current-row |
9 | style="width: 100%" | 115 | style="width: 100%;" |
116 | @sort-change="sortChange" | ||
10 | > | 117 | > |
118 | <!-- id列 --> | ||
11 | <el-table-column | 119 | <el-table-column |
120 | :label="$t('table.id')" | ||
121 | prop="id" | ||
122 | sortable="custom" | ||
12 | align="center" | 123 | align="center" |
13 | label="ID" | ||
14 | width="80" | 124 | width="80" |
125 | :class-name="getSortClass('id')" | ||
15 | > | 126 | > |
16 | <template slot-scope="scope"> | 127 | <template slot-scope="{row}"> |
17 | <span>{{ scope.row.id }}</span> | 128 | <span>{{ row.id }}</span> |
18 | </template> | 129 | </template> |
19 | </el-table-column> | 130 | </el-table-column> |
20 | 131 | <!-- date列 --> | |
21 | <el-table-column | 132 | <el-table-column |
22 | width="180px" | 133 | :label="$t('table.date')" |
134 | width="150px" | ||
23 | align="center" | 135 | align="center" |
24 | label="Date" | ||
25 | > | 136 | > |
26 | <template slot-scope="scope"> | 137 | <template slot-scope="{row}"> |
27 | <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> | 138 | <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> |
28 | </template> | 139 | </template> |
29 | </el-table-column> | 140 | </el-table-column> |
30 | 141 | <!-- title列 --> | |
142 | <el-table-column | ||
143 | :label="$t('table.title')" | ||
144 | min-width="150px" | ||
145 | > | ||
146 | <template slot-scope="{row}"> | ||
147 | <span | ||
148 | class="link-type" | ||
149 | @click="handleUpdate(row)" | ||
150 | >{{ row.title }}</span> | ||
151 | <el-tag>{{ row.type | typeFilter }}</el-tag> | ||
152 | </template> | ||
153 | </el-table-column> | ||
154 | <!-- author列 --> | ||
31 | <el-table-column | 155 | <el-table-column |
32 | width="120px" | 156 | :label="$t('table.author')" |
157 | width="110px" | ||
33 | align="center" | 158 | align="center" |
34 | label="Author" | ||
35 | > | 159 | > |
36 | <template slot-scope="scope"> | 160 | <template slot-scope="{row}"> |
37 | <span>{{ scope.row.author }}</span> | 161 | <span>{{ row.author }}</span> |
162 | </template> | ||
163 | </el-table-column> | ||
164 | <!-- reviewer列 --> | ||
165 | <el-table-column | ||
166 | v-if="showReviewer" | ||
167 | :label="$t('table.reviewer')" | ||
168 | width="110px" | ||
169 | align="center" | ||
170 | > | ||
171 | <template slot-scope="{row}"> | ||
172 | <span style="color:red;">{{ row.reviewer }}</span> | ||
38 | </template> | 173 | </template> |
39 | </el-table-column> | 174 | </el-table-column> |
40 | |||
41 | <el-table-column | 175 | <el-table-column |
42 | width="100px" | 176 | :label="$t('table.importance')" |
43 | label="Importance" | 177 | width="80px" |
44 | > | 178 | > |
45 | <template slot-scope="scope"> | 179 | <template slot-scope="{row}"> |
46 | <svg-icon | 180 | <svg-icon |
47 | v-for="n in +scope.row.importance" | 181 | v-for="n in +row.importance" |
48 | :key="n" | 182 | :key="n" |
49 | icon-class="star" | 183 | icon-class="star" |
50 | class="meta-item__icon" | 184 | class="meta-item__icon" |
51 | /> | 185 | /> |
52 | </template> | 186 | </template> |
53 | </el-table-column> | 187 | </el-table-column> |
54 | 188 | <!-- 阅读数列 --> | |
55 | <el-table-column | 189 | <el-table-column |
56 | class-name="status-col" | 190 | :label="$t('table.readings')" |
57 | label="Status" | 191 | align="center" |
58 | width="110" | 192 | width="95" |
59 | > | 193 | > |
60 | <template slot-scope="{row}"> | 194 | <template slot-scope="{row}"> |
61 | <el-tag :type="row.status | statusFilter"> | 195 | <span |
62 | {{ row.status }} | 196 | v-if="row.pageviews" |
63 | </el-tag> | 197 | class="link-type" |
198 | @click="handleFetchPv(row.pageviews)" | ||
199 | >{{ row.pageviews }}</span> | ||
200 | <span v-else>0</span> | ||
64 | </template> | 201 | </template> |
65 | </el-table-column> | 202 | </el-table-column> |
66 | 203 | ||
204 | <!-- 状态列 --> | ||
67 | <el-table-column | 205 | <el-table-column |
68 | min-width="300px" | 206 | :label="$t('table.status')" |
69 | label="Title" | 207 | class-name="status-col" |
208 | width="100" | ||
70 | > | 209 | > |
71 | <template slot-scope="{row}"> | 210 | <template slot-scope="{row}"> |
72 | <router-link | 211 | <el-tag :type="row.status | statusFilter"> |
73 | :to="'/example/edit/'+row.id" | 212 | {{ row.status }} |
74 | class="link-type" | 213 | </el-tag> |
75 | > | ||
76 | <span>{{ row.title }}</span> | ||
77 | </router-link> | ||
78 | </template> | 214 | </template> |
79 | </el-table-column> | 215 | </el-table-column> |
80 | 216 | <!-- 操作列 --> | |
81 | <el-table-column | 217 | <el-table-column |
218 | :label="$t('table.actions')" | ||
82 | align="center" | 219 | align="center" |
83 | label="Actions" | 220 | width="230" |
84 | width="120" | 221 | class-name="small-padding fixed-width" |
85 | > | 222 | > |
86 | <template slot-scope="scope"> | 223 | <template slot-scope="{row,$index}"> |
87 | <router-link :to="'/example/edit/'+scope.row.id"> | 224 | <el-button |
88 | <el-button | 225 | type="primary" |
89 | type="primary" | 226 | size="mini" |
90 | size="small" | 227 | @click="handleUpdate(row)" |
91 | icon="el-icon-edit" | 228 | > |
92 | > | 229 | {{ $t('table.edit') }} |
93 | Edit | 230 | </el-button> |
94 | </el-button> | 231 | <el-button |
95 | </router-link> | 232 | v-if="row.status!='published'" |
233 | size="mini" | ||
234 | type="success" | ||
235 | @click="handleModifyStatus(row,'published')" | ||
236 | > | ||
237 | {{ $t('table.publish') }} | ||
238 | </el-button> | ||
239 | <el-button | ||
240 | v-if="row.status!='draft'" | ||
241 | size="mini" | ||
242 | @click="handleModifyStatus(row,'draft')" | ||
243 | > | ||
244 | {{ $t('table.draft') }} | ||
245 | </el-button> | ||
246 | <el-button | ||
247 | v-if="row.status!='deleted'" | ||
248 | size="mini" | ||
249 | type="danger" | ||
250 | @click="handleDelete(row,$index)" | ||
251 | > | ||
252 | {{ $t('table.delete') }} | ||
253 | </el-button> | ||
96 | </template> | 254 | </template> |
97 | </el-table-column> | 255 | </el-table-column> |
98 | </el-table> | 256 | </el-table> |
99 | 257 | ||
258 | <!-- 分页器 --> | ||
100 | <pagination | 259 | <pagination |
101 | v-show="total>0" | 260 | v-show="total>0" |
102 | :total="total" | 261 | :total="total" |
103 | :page.sync="listQuery.page" | 262 | :page.sync="listQuery.page" |
104 | :limit.sync="listQuery.limit" | 263 | :limit.sync="listQuery.limit" |
105 | @pagination="getList" | 264 | @pagination="getList" |
106 | /> | 265 | /> |
266 | |||
267 | <el-dialog | ||
268 | :title="textMap[dialogStatus]" | ||
269 | :visible.sync="dialogFormVisible" | ||
270 | > | ||
271 | <el-form | ||
272 | ref="dataForm" | ||
273 | :rules="rules" | ||
274 | :model="temp" | ||
275 | label-position="left" | ||
276 | label-width="70px" | ||
277 | style="width: 400px; margin-left:50px;" | ||
278 | > | ||
279 | <el-form-item | ||
280 | :label="$t('table.type')" | ||
281 | prop="type" | ||
282 | > | ||
283 | <el-select | ||
284 | v-model="temp.type" | ||
285 | class="filter-item" | ||
286 | placeholder="Please select" | ||
287 | > | ||
288 | <el-option | ||
289 | v-for="item in calendarTypeOptions" | ||
290 | :key="item.key" | ||
291 | :label="item.display_name" | ||
292 | :value="item.key" | ||
293 | /> | ||
294 | </el-select> | ||
295 | </el-form-item> | ||
296 | <el-form-item | ||
297 | :label="$t('table.date')" | ||
298 | prop="timestamp" | ||
299 | > | ||
300 | <el-date-picker | ||
301 | v-model="temp.timestamp" | ||
302 | type="datetime" | ||
303 | placeholder="Please pick a date" | ||
304 | /> | ||
305 | </el-form-item> | ||
306 | <el-form-item | ||
307 | :label="$t('table.title')" | ||
308 | prop="title" | ||
309 | > | ||
310 | <el-input v-model="temp.title" /> | ||
311 | </el-form-item> | ||
312 | <el-form-item :label="$t('table.status')"> | ||
313 | <el-select | ||
314 | v-model="temp.status" | ||
315 | class="filter-item" | ||
316 | placeholder="Please select" | ||
317 | > | ||
318 | <el-option | ||
319 | v-for="item in statusOptions" | ||
320 | :key="item" | ||
321 | :label="item" | ||
322 | :value="item" | ||
323 | /> | ||
324 | </el-select> | ||
325 | </el-form-item> | ||
326 | <el-form-item :label="$t('table.importance')"> | ||
327 | <el-rate | ||
328 | v-model="temp.importance" | ||
329 | :colors="['#99A9BF', '#F7BA2A', '#FF9900']" | ||
330 | :max="3" | ||
331 | style="margin-top:8px;" | ||
332 | /> | ||
333 | </el-form-item> | ||
334 | <el-form-item :label="$t('table.remark')"> | ||
335 | <el-input | ||
336 | v-model="temp.remark" | ||
337 | :autosize="{ minRows: 2, maxRows: 4}" | ||
338 | type="textarea" | ||
339 | placeholder="Please input" | ||
340 | /> | ||
341 | </el-form-item> | ||
342 | </el-form> | ||
343 | <div | ||
344 | slot="footer" | ||
345 | class="dialog-footer" | ||
346 | > | ||
347 | <el-button @click="dialogFormVisible = false"> | ||
348 | {{ $t('table.cancel') }} | ||
349 | </el-button> | ||
350 | <el-button | ||
351 | type="primary" | ||
352 | @click="dialogStatus==='create'?createData():updateData()" | ||
353 | > | ||
354 | {{ $t('table.confirm') }} | ||
355 | </el-button> | ||
356 | </div> | ||
357 | </el-dialog> | ||
358 | |||
359 | <el-dialog | ||
360 | :visible.sync="dialogPvVisible" | ||
361 | title="Reading statistics" | ||
362 | > | ||
363 | <el-table | ||
364 | :data="pvData" | ||
365 | border | ||
366 | fit | ||
367 | highlight-current-row | ||
368 | style="width: 100%" | ||
369 | > | ||
370 | <el-table-column | ||
371 | prop="key" | ||
372 | label="Channel" | ||
373 | /> | ||
374 | <el-table-column | ||
375 | prop="pv" | ||
376 | label="Pv" | ||
377 | /> | ||
378 | </el-table> | ||
379 | <span | ||
380 | slot="footer" | ||
381 | class="dialog-footer" | ||
382 | > | ||
383 | <el-button | ||
384 | type="primary" | ||
385 | @click="dialogPvVisible = false" | ||
386 | >{{ $t('table.confirm') }}</el-button> | ||
387 | </span> | ||
388 | </el-dialog> | ||
107 | </div> | 389 | </div> |
108 | </template> | 390 | </template> |
109 | 391 | ||
110 | <script> | 392 | <script> |
111 | import { fetchList } from '@/api/article' | 393 | import { |
112 | import Pagination from '@/components/Pagination' // Secondary package based on el-pagination | 394 | fetchList, |
395 | fetchPv, | ||
396 | createArticle, | ||
397 | updateArticle | ||
398 | } from '@/api/article' | ||
399 | import waves from '@/directive/waves' // waves directive | ||
400 | import { parseTime } from '@/utils' | ||
401 | import Pagination from '@/components/Pagination' // secondary package based on el-pagination | ||
402 | |||
403 | const calendarTypeOptions = [ | ||
404 | { key: 'CN', display_name: '成镜' }, | ||
405 | { key: 'US', display_name: '镜片' }, | ||
406 | { key: 'JP', display_name: '隐形眼镜' }, | ||
407 | { key: 'EU', display_name: '特种镜' } | ||
408 | ] | ||
409 | |||
410 | // arr to obj, such as { CN : "China", US : "USA" } | ||
411 | const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { | ||
412 | acc[cur.key] = cur.display_name | ||
413 | return acc | ||
414 | }, {}) | ||
113 | 415 | ||
114 | export default { | 416 | export default { |
115 | name: 'ArticleList', | 417 | name: 'ComplexTable', |
116 | components: { Pagination }, | 418 | components: { Pagination }, |
419 | directives: { waves }, | ||
117 | filters: { | 420 | filters: { |
118 | statusFilter(status) { | 421 | statusFilter(status) { |
119 | const statusMap = { | 422 | const statusMap = { |
120 | published: 'success', | 423 | published: 'success', |
121 | draft: 'info', | 424 | draft: 'info', |
122 | deleted: 'danger' | 425 | deleted: 'danger' |
123 | } | 426 | } |
124 | return statusMap[status] | 427 | return statusMap[status] |
428 | }, | ||
429 | typeFilter(type) { | ||
430 | return calendarTypeKeyValue[type] | ||
125 | } | 431 | } |
126 | }, | 432 | }, |
127 | data() { | 433 | data() { |
128 | return { | 434 | return { |
435 | tableKey: 0, | ||
129 | list: null, | 436 | list: null, |
130 | total: 0, | 437 | total: 0, |
131 | listLoading: true, | 438 | listLoading: true, |
132 | listQuery: { | 439 | listQuery: { |
133 | page: 1, | 440 | page: 1, |
134 | limit: 20 | 441 | limit: 20, |
135 | } | 442 | importance: undefined, |
443 | title: undefined, | ||
444 | type: undefined, | ||
445 | sort: '+id' | ||
446 | }, | ||
447 | importanceOptions: [{ | ||
448 | label: '款式索引', | ||
449 | options: [{ | ||
450 | value: 'young', | ||
451 | label: '青春学子风' | ||
452 | }, { | ||
453 | value: 'leisure', | ||
454 | label: '休闲' | ||
455 | }, { | ||
456 | value: 'business', | ||
457 | label: '商务' | ||
458 | }, { | ||
459 | value: 'Retro', | ||
460 | label: '复古' | ||
461 | }, { | ||
462 | value: 'fashion', | ||
463 | label: '时尚' | ||
464 | }] | ||
465 | }, { | ||
466 | label: '颜色', | ||
467 | options: [{ | ||
468 | value: 'golden', | ||
469 | label: '金色' | ||
470 | }, { | ||
471 | value: 'silver', | ||
472 | label: '银色' | ||
473 | }, { | ||
474 | value: 'black', | ||
475 | label: '黑色' | ||
476 | }, { | ||
477 | value: 'multicolour', | ||
478 | label: '彩色' | ||
479 | }, { | ||
480 | value: 'gun', | ||
481 | label: '枪色' | ||
482 | }] | ||
483 | }], | ||
484 | calendarTypeOptions, | ||
485 | sortOptions: [ | ||
486 | { label: 'ID Ascending', key: '+id' }, | ||
487 | { label: 'ID Descending', key: '-id' } | ||
488 | ], | ||
489 | statusOptions: ['published', 'draft', 'deleted'], | ||
490 | showReviewer: false, | ||
491 | temp: { | ||
492 | id: undefined, | ||
493 | importance: 1, | ||
494 | remark: '', | ||
495 | timestamp: new Date(), | ||
496 | title: '', | ||
497 | type: '', | ||
498 | status: 'published' | ||
499 | }, | ||
500 | dialogFormVisible: false, | ||
501 | dialogStatus: '', | ||
502 | textMap: { | ||
503 | update: 'Edit', | ||
504 | create: 'Create' | ||
505 | }, | ||
506 | dialogPvVisible: false, | ||
507 | pvData: [], | ||
508 | rules: { | ||
509 | type: [ | ||
510 | { required: true, message: 'type is required', trigger: 'change' } | ||
511 | ], | ||
512 | timestamp: [ | ||
513 | { | ||
514 | type: 'date', | ||
515 | required: true, | ||
516 | message: 'timestamp is required', | ||
517 | trigger: 'change' | ||
518 | } | ||
519 | ], | ||
520 | title: [ | ||
521 | { required: true, message: 'title is required', trigger: 'blur' } | ||
522 | ] | ||
523 | }, | ||
524 | downloadLoading: false | ||
136 | } | 525 | } |
137 | }, | 526 | }, |
138 | created() { | 527 | created() { |
139 | this.getList() | 528 | this.getList() |
140 | }, | 529 | }, |
141 | methods: { | 530 | methods: { |
142 | getList() { | 531 | getList() { |
143 | this.listLoading = true | 532 | this.listLoading = true |
144 | fetchList(this.listQuery).then(response => { | 533 | fetchList(this.listQuery).then(response => { |
145 | this.list = response.data.items | 534 | this.list = response.data.items |
146 | this.total = response.data.total | 535 | this.total = response.data.total |
147 | this.listLoading = false | 536 | |
537 | // Just to simulate the time of the request | ||
538 | setTimeout(() => { | ||
539 | this.listLoading = false | ||
540 | }, 1.5 * 1000) | ||
541 | }) | ||
542 | }, | ||
543 | handleFilter() { | ||
544 | this.listQuery.page = 1 | ||
545 | this.getList() | ||
546 | }, | ||
547 | handleModifyStatus(row, status) { | ||
548 | this.$message({ | ||
549 | message: '操作成功', | ||
550 | type: 'success' | ||
551 | }) | ||
552 | row.status = status | ||
553 | }, | ||
554 | sortChange(data) { | ||
555 | const { prop, order } = data | ||
556 | if (prop === 'id') { | ||
557 | this.sortByID(order) | ||
558 | } | ||
559 | }, | ||
560 | sortByID(order) { | ||
561 | if (order === 'ascending') { | ||
562 | this.listQuery.sort = '+id' | ||
563 | } else { | ||
564 | this.listQuery.sort = '-id' | ||
565 | } | ||
566 | this.handleFilter() | ||
567 | }, | ||
568 | resetTemp() { | ||
569 | this.temp = { | ||
570 | id: undefined, | ||
571 | importance: 1, | ||
572 | remark: '', | ||
573 | timestamp: new Date(), | ||
574 | title: '', | ||
575 | status: 'published', | ||
576 | type: '' | ||
577 | } | ||
578 | }, | ||
579 | handleCreate() { | ||
580 | this.resetTemp() | ||
581 | this.dialogStatus = 'create' | ||
582 | this.dialogFormVisible = true | ||
583 | this.$nextTick(() => { | ||
584 | this.$refs['dataForm'].clearValidate() | ||
148 | }) | 585 | }) |
586 | }, | ||
587 | createData() { | ||
588 | this.$refs['dataForm'].validate(valid => { | ||
589 | if (valid) { | ||
590 | this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id | ||
591 | this.temp.author = '秀野堂主' | ||
592 | createArticle(this.temp).then(() => { | ||
593 | this.list.unshift(this.temp) | ||
594 | this.dialogFormVisible = false | ||
595 | this.$notify({ | ||
596 | title: '成功', | ||
597 | message: '创建成功', | ||
598 | type: 'success', | ||
599 | duration: 2000 | ||
600 | }) | ||
601 | }) | ||
602 | } | ||
603 | }) | ||
604 | }, | ||
605 | handleUpdate(row) { | ||
606 | this.temp = Object.assign({}, row) // copy obj | ||
607 | this.temp.timestamp = new Date(this.temp.timestamp) | ||
608 | this.dialogStatus = 'update' | ||
609 | this.dialogFormVisible = true | ||
610 | this.$nextTick(() => { | ||
611 | this.$refs['dataForm'].clearValidate() | ||
612 | }) | ||
613 | }, | ||
614 | updateData() { | ||
615 | this.$refs['dataForm'].validate(valid => { | ||
616 | if (valid) { | ||
617 | const tempData = Object.assign({}, this.temp) | ||
618 | tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464 | ||
619 | updateArticle(tempData).then(() => { | ||
620 | const index = this.list.findIndex(v => v.id === this.temp.id) | ||
621 | this.list.splice(index, 1, this.temp) | ||
622 | this.dialogFormVisible = false | ||
623 | this.$notify({ | ||
624 | title: '成功', | ||
625 | message: '更新成功', | ||
626 | type: 'success', | ||
627 | duration: 2000 | ||
628 | }) | ||
629 | }) | ||
630 | } | ||
631 | }) | ||
632 | }, | ||
633 | handleDelete(row, index) { | ||
634 | this.$notify({ | ||
635 | title: '成功', | ||
636 | message: '删除成功', | ||
637 | type: 'success', | ||
638 | duration: 2000 | ||
639 | }) | ||
640 | this.list.splice(index, 1) | ||
641 | }, | ||
642 | handleFetchPv(pv) { | ||
643 | fetchPv(pv).then(response => { | ||
644 | this.pvData = response.data.pvData | ||
645 | this.dialogPvVisible = true | ||
646 | }) | ||
647 | }, | ||
648 | handleDownload() { | ||
649 | this.downloadLoading = true | ||
650 | import('@/vendor/Export2Excel').then(excel => { | ||
651 | const tHeader = ['timestamp', 'title', 'type', 'importance', 'status'] | ||
652 | const filterVal = [ | ||
653 | 'timestamp', | ||
654 | 'title', | ||
655 | 'type', | ||
656 | 'importance', | ||
657 | 'status' | ||
658 | ] | ||
659 | const data = this.formatJson(filterVal) | ||
660 | excel.export_json_to_excel({ | ||
661 | header: tHeader, | ||
662 | data, | ||
663 | filename: 'table-list' | ||
664 | }) | ||
665 | this.downloadLoading = false | ||
666 | }) | ||
667 | }, | ||
668 | formatJson(filterVal) { | ||
669 | return this.list.map(v => | ||
670 | filterVal.map(j => { | ||
671 | if (j === 'timestamp') { | ||
672 | return parseTime(v[j]) | ||
673 | } else { | ||
674 | return v[j] | ||
675 | } | ||
676 | }) | ||
677 | ) | ||
678 | }, | ||
679 | getSortClass: function(key) { |