Commit 5cb37594009b8d245707447f26ee774ce0991401

Authored by Adam
1 parent f3ec4dd955
Exists in master

auto commit the code by alias command

src/router/modules/order.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 orderRouter = {
6 path: '/orders',
7 component: Layout,
8 redirect: '/order/page',
9 alwaysShow: true, // will always show the root menu
10 name: 'Order',
11 meta: {
12 title: 'orders',
13 icon: 'shopping',
14 roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
15 },
16 children: [{
17 path: 'page',
18 component: () => import('@/views/order/list'),
19 name: 'OrderList',
20 meta: {
21 title: 'OrderList',
22 roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
23 }
24 }]
25 }
26
27 export default orderRouter
28
src/router/modules/sites.js
File was created 1 import Layout from '@/layout'
2
3 const sitesRouter = {
4 path: '/sites',
5 component: Layout,
6 redirect: '/site/page',
7 alwaysShow: true, // will always show the root menu
8 name: 'Site',
9 meta: {
10 title: 'sites',
11 icon: 'people',
12 roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
13 },
14 children: [{
15 path: 'page',
16 component: () => import('@/views/site/list'),
17 name: 'SiteList',
18 meta: {
19 title: '站点列表',
20 roles: ['admin', 'runner']
21
22 }
23 }]
24 }
25
26 export default sitesRouter
27
src/views/dashboard/runner/index.vue
File was created 1 <template>
2 <div class="dashboard-editor-container">
3 <div class="clearfix">
4 <pan-thumb :image="avatar" style="float: left">
5 Your roles:
6 <span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
7 </pan-thumb>
8 <github-corner style="position: absolute; top: 0px; border: 0; right: 0;" />
9 <div class="info-container">
10 <span class="display_name">{{ name }}</span>
11 <span style="font-size:20px;padding-top:20px;display:inline-block;">{{ roles }}'s Dashboard</span>
12 </div>
13 </div>
14 <div>
15 <img :src="emptyGif" class="emptyGif">
16 </div>
17 </div>
18 </template>
19
20 <script>
21 import { mapGetters } from 'vuex'
22 import PanThumb from '@/components/PanThumb'
23 // import GithubCorner from '@/components/GithubCorner'
24
25 export default {
26 name: 'DashboardEditor',
27 // components: { PanThumb, GithubCorner },
28 components: { PanThumb },
29 data() {
30 return {
31 emptyGif:
32 'https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3'
33 }
34 },
35 computed: {
36 ...mapGetters(['name', 'avatar', 'roles'])
37 }
38 }
39 </script>
40
41 <style lang="scss" scoped>
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;
56 display: block;
57 }
58 .info-container {
59 position: relative;
60 margin-left: 190px;
61 height: 150px;
62 line-height: 200px;
63 .display_name {
64 font-size: 48px;
65 line-height: 48px;
66 color: #212121;
67 position: absolute;
68 top: 25px;
69 }
70 }
71 }
72 </style>
73
src/views/order/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.id')"
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.id }}</span>
110 </template>
111 </el-table-column>
112 <el-table-column
113 :label="$t('table.date')"
114 width="150px"
115 align="center"
116 >
117 <template slot-scope="{row}">
118 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
119 </template>
120 </el-table-column>
121 <el-table-column
122 :label="$t('table.title')"
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 <el-tag>{{ row.type | typeFilter }}</el-tag>
131 </template>
132 </el-table-column>
133 <el-table-column
134 :label="$t('table.author')"
135 width="110px"
136 align="center"
137 >
138 <template slot-scope="{row}">
139 <span>{{ row.author }}</span>
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.readings')"
167 align="center"
168 width="95"
169 >
170 <template slot-scope="{row}">
171 <span
172 v-if="row.pageviews"
173 class="link-type"
174 @click="handleFetchPv(row.pageviews)"
175 >{{ row.pageviews }}</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">
186 {{ row.status }}
187 </el-tag>
188 </template>
189 </el-table-column>
190 <el-table-column
191 :label="$t('table.actions')"
192 align="center"
193 width="230"
194 class-name="small-padding fixed-width"
195 >
196 <template slot-scope="{row,$index}">
197 <el-button
198 type="primary"
199 size="mini"
200 @click="handleUpdate(row)"
201 >
202 {{ $t('table.edit') }}
203 </el-button>
204 <el-button
205 v-if="row.status!='published'"
206 size="mini"
207 type="success"
208 @click="handleModifyStatus(row,'published')"
209 >
210 {{ $t('table.publish') }}
211 </el-button>
212 <el-button
213 v-if="row.status!='draft'"
214 size="mini"
215 @click="handleModifyStatus(row,'draft')"
216 >
217 {{ $t('table.draft') }}
218 </el-button>
219 <el-button
220 v-if="row.status!='deleted'"
221 size="mini"
222 type="danger"
223 @click="handleDelete(row,$index)"
224 >
225 {{ $t('table.delete') }}
226 </el-button>
227 </template>
228 </el-table-column>
229 </el-table>
230
231 <pagination
232 v-show="total>0"
233 :total="total"
234 :page.sync="listQuery.page"
235 :limit.sync="listQuery.limit"
236 @pagination="getList"
237 />
238
239 <el-dialog
240 :title="textMap[dialogStatus]"
241 :visible.sync="dialogFormVisible"
242 >
243 <el-form
244 ref="dataForm"
245 :rules="rules"
246 :model="temp"
247 label-position="left"
248 label-width="70px"
249 style="width: 400px; margin-left:50px;"
250 >
251 <el-form-item
252 :label="$t('table.type')"
253 prop="type"
254 >
255 <el-select
256 v-model="temp.type"
257 class="filter-item"
258 placeholder="Please select"
259 >
260 <el-option
261 v-for="item in calendarTypeOptions"
262 :key="item.key"
263 :label="item.display_name"
264 :value="item.key"
265 />
266 </el-select>
267 </el-form-item>
268 <el-form-item
269 :label="$t('table.date')"
270 prop="timestamp"
271 >
272 <el-date-picker
273 v-model="temp.timestamp"
274 type="datetime"
275 placeholder="Please pick a date"
276 />
277 </el-form-item>
278 <el-form-item
279 :label="$t('table.title')"
280 prop="title"
281 >
282 <el-input v-model="temp.title" />
283 </el-form-item>
284 <el-form-item :label="$t('table.status')">
285 <el-select
286 v-model="temp.status"
287 class="filter-item"
288 placeholder="Please select"
289 >
290 <el-option
291 v-for="item in statusOptions"
292 :key="item"
293 :label="item"
294 :value="item"
295 />
296 </el-select>
297 </el-form-item>
298 <el-form-item :label="$t('table.importance')">
299 <el-rate
300 v-model="temp.importance"
301 :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
302 :max="3"
303 style="margin-top:8px;"
304 />
305 </el-form-item>
306 <el-form-item :label="$t('table.remark')">
307 <el-input
308 v-model="temp.remark"
309 :autosize="{ minRows: 2, maxRows: 4}"
310 type="textarea"
311 placeholder="Please input"
312 />
313 </el-form-item>
314 </el-form>
315 <div
316 slot="footer"
317 class="dialog-footer"
318 >
319 <el-button @click="dialogFormVisible = false">
320 {{ $t('table.cancel') }}
321 </el-button>
322 <el-button
323 type="primary"
324 @click="dialogStatus==='create'?createData():updateData()"
325 >
326 {{ $t('table.confirm') }}
327 </el-button>
328 </div>
329 </el-dialog>
330
331 <el-dialog
332 :visible.sync="dialogPvVisible"
333 title="Reading statistics"
334 >
335 <el-table
336 :data="pvData"
337 border
338 fit
339 highlight-current-row
340 style="width: 100%"
341 >
342 <el-table-column
343 prop="key"
344 label="Channel"
345 />
346 <el-table-column
347 prop="pv"
348 label="Pv"
349 />
350 </el-table>
351 <span
352 slot="footer"
353 class="dialog-footer"
354 >
355 <el-button
356 type="primary"
357 @click="dialogPvVisible = false"
358 >{{ $t('table.confirm') }}</el-button>
359 </span>
360 </el-dialog>
361 </div>
362 </template>
363
364 <script>
365 import {
366 fetchList,
367 fetchPv,
368 createArticle,
369 updateArticle
370 } from '@/api/article'
371 import waves from '@/directive/waves' // waves directive
372 import { parseTime } from '@/utils'
373 import Pagination from '@/components/Pagination' // secondary package based on el-pagination
374
375 const calendarTypeOptions = [
376 { key: 'CN', display_name: 'China' },
377 { key: 'US', display_name: 'USA' },
378 { key: 'JP', display_name: 'Japan' },
379 { key: 'EU', display_name: 'Eurozone' }
380 ]
381
382 // arr to obj, such as { CN : "China", US : "USA" }
383 const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => {
384 acc[cur.key] = cur.display_name
385 return acc
386 }, {})
387
388 export default {
389 name: 'ComplexTable',
390 components: { Pagination },
391 directives: { waves },
392 filters: {
393 statusFilter(status) {
394 const statusMap = {
395 published: 'success',
396 draft: 'info',
397 deleted: 'danger'
398 }
399 return statusMap[status]
400 },
401 typeFilter(type) {
402 return calendarTypeKeyValue[type]
403 }
404 },
405 data() {
406 return {
407 tableKey: 0,
408 list: null,
409 total: 0,
410 listLoading: true,
411 listQuery: {
412 page: 1,
413 limit: 20,
414 importance: undefined,
415 title: undefined,
416 type: undefined,
417 sort: '+id'
418 },
419 importanceOptions: [1, 2, 3],
420 calendarTypeOptions,
421 sortOptions: [
422 { label: 'ID Ascending', key: '+id' },
423 { label: 'ID Descending', key: '-id' }
424 ],
425 statusOptions: ['published', 'draft', 'deleted'],
426 showReviewer: false,
427 temp: {
428 id: undefined,
429 importance: 1,
430 remark: '',
431 timestamp: new Date(),
432 title: '',
433 type: '',
434 status: 'published'
435 },
436 dialogFormVisible: false,
437 dialogStatus: '',
438 textMap: {
439 update: 'Edit',
440 create: 'Create'
441 },
442 dialogPvVisible: false,
443 pvData: [],
444 rules: {
445 type: [
446 { required: true, message: 'type is required', trigger: 'change' }
447 ],
448 timestamp: [
449 {
450 type: 'date',
451 required: true,
452 message: 'timestamp is required',
453 trigger: 'change'
454 }
455 ],
456 title: [
457 { required: true, message: 'title is required', trigger: 'blur' }
458 ]
459 },
460 downloadLoading: false
461 }
462 },
463 created() {
464 this.getList()
465 },
466 methods: {
467 getList() {
468 this.listLoading = true
469 fetchList(this.listQuery).then(response => {
470 this.list = response.data.items
471 this.total = response.data.total
472
473 // Just to simulate the time of the request
474 setTimeout(() => {
475 this.listLoading = false
476 }, 1.5 * 1000)
477 })
478 },
479 handleFilter() {
480 this.listQuery.page = 1
481 this.getList()
482 },
483 handleModifyStatus(row, status) {
484 this.$message({
485 message: '操作成功',
486 type: 'success'
487 })
488 row.status = status
489 },
490 sortChange(data) {
491 const { prop, order } = data
492 if (prop === 'id') {
493 this.sortByID(order)
494 }
495 },
496 sortByID(order) {
497 if (order === 'ascending') {
498 this.listQuery.sort = '+id'
499 } else {
500 this.listQuery.sort = '-id'
501 }
502 this.handleFilter()
503 },
504 resetTemp() {
505 this.temp = {
506 id: undefined,
507 importance: 1,
508 remark: '',
509 timestamp: new Date(),
510 title: '',
511 status: 'published',
512 type: ''
513 }
514 },
515 handleCreate() {
516 this.resetTemp()
517 this.dialogStatus = 'create'
518 this.dialogFormVisible = true
519 this.$nextTick(() => {
520 this.$refs['dataForm'].clearValidate()
521 })
522 },
523 createData() {
524 this.$refs['dataForm'].validate(valid => {
525 if (valid) {
526 this.temp.id = parseInt(Math.random() * 100) + 1024 // mock a id
527 this.temp.author = '秀野堂主'
528 createArticle(this.temp).then(() => {
529 this.list.unshift(this.temp)
530 this.dialogFormVisible = false
531 this.$notify({
532 title: '成功',
533 message: '创建成功',
534 type: 'success',
535 duration: 2000
536 })
537 })
538 }
539 })
540 },
541 handleUpdate(row) {
542 this.temp = Object.assign({}, row) // copy obj
543 this.temp.timestamp = new Date(this.temp.timestamp)
544 this.dialogStatus = 'update'
545 this.dialogFormVisible = true
546 this.$nextTick(() => {
547 this.$refs['dataForm'].clearValidate()
548 })
549 },
550 updateData() {
551 this.$refs['dataForm'].validate(valid => {
552 if (valid) {
553 const tempData = Object.assign({}, this.temp)
554 tempData.timestamp = +new Date(tempData.timestamp) // change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464
555 updateArticle(tempData).then(() => {
556 const index = this.list.findIndex(v => v.id === this.temp.id)
557 this.list.splice(index, 1, this.temp)
558 this.dialogFormVisible = false
559 this.$notify({
560 title: '成功',
561 message: '更新成功',
562 type: 'success',
563 duration: 2000
564 })
565 })
566 }
567 })
568 },
569 handleDelete(row, index) {
570 this.$notify({
571 title: '成功',
572 message: '删除成功',
573 type: 'success',
574 duration: 2000
575 })
576 this.list.splice(index, 1)
577 },
578 handleFetchPv(pv) {
579 fetchPv(pv).then(response => {
580 this.pvData = response.data.pvData
581 this.dialogPvVisible = true
582 })
583 },
584 handleDownload() {
585 this.downloadLoading = true
586 import('@/vendor/Export2Excel').then(excel => {
587 const tHeader = ['timestamp', 'title', 'type', 'importance', 'status']
588 const filterVal = [
589 'timestamp',
590 'title',
591 'type',
592 'importance',
593 'status'
594 ]
595 const data = this.formatJson(filterVal)
596 excel.export_json_to_excel({
597 header: tHeader,
598 data,
599 filename: 'table-list'
600 })
601 this.downloadLoading = false
602 })
603 },
604 formatJson(filterVal) {
605 return this.list.map(v =>
606 filterVal.map(j => {
607 if (j === 'timestamp') {
608 return parseTime(v[j])
609 } else {
610 return v[j]
611 }
612 })
613 )
614 },
615 getSortClass: function(key) {
616 const sort = this.listQuery.sort
617 return sort === `+${key}` ? 'ascending' : 'descending'
618 }
619 }
620 }
621 </script>
622
src/views/prod/list.vue
File was created 1 <template>
2 <div class="app-container">
3 <!-- Note that row-key is necessary to get a correct row order. -->
4 <el-table
5 ref="dragTable"
6 v-loading="listLoading"
7 :data="list"
8 row-key="id"
9 border
10 fit
11 highlight-current-row
12 style="width: 100%"
13 >
14 <el-table-column
15 align="center"
16 label="ID"
17 width="65"
18 >
19 <template slot-scope="{row}">
20 <span>{{ row.id }}</span>
21 </template>
22 </el-table-column>
23
24 <el-table-column
25 width="180px"
26 align="center"
27 label="Date"
28 >
29 <template slot-scope="{row}">
30 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
31 </template>
32 </el-table-column>
33
34 <el-table-column
35 min-width="300px"
36 label="Title"
37 >
38 <template slot-scope="{row}">
39 <span>{{ row.title }}</span>
40 </template>
41 </el-table-column>
42
43 <el-table-column
44 width="110px"
45 align="center"
46 label="Author"
47 >
48 <template slot-scope="{row}">
49 <span>{{ row.author }}</span>
50 </template>
51 </el-table-column>
52
53 <el-table-column
54 width="100px"
55 label="Importance"
56 >
57 <template slot-scope="{row}">
58 <svg-icon
59 v-for="n in + row.importance"
60 :key="n"
61 icon-class="star"
62 class="icon-star"
63 />
64 </template>
65 </el-table-column>
66
67 <el-table-column
68 align="center"
69 label="Readings"
70 width="95"
71 >
72 <template slot-scope="{row}">
73 <span>{{ row.pageviews }}</span>
74 </template>
75 </el-table-column>
76
77 <el-table-column
78 class-name="status-col"
79 label="Status"
80 width="110"
81 >
82 <template slot-scope="{row}">
83 <el-tag :type="row.status | statusFilter">
84 {{ row.status }}
85 </el-tag>
86 </template>
87 </el-table-column>
88
89 <el-table-column
90 align="center"
91 label="Drag"
92 width="80"
93 >
94 <template slot-scope="{}">
95 <svg-icon
96 class="drag-handler"
97 icon-class="drag"
98 />
99 </template>
100 </el-table-column>
101 </el-table>
102 <!-- $t is vue-i18n global function to translate lang (lang in @/lang) -->
103 <div class="show-d">
104 <el-tag style="margin-right:12px;">{{ $t('table.dragTips1') }} :</el-tag> {{ oldList }}
105 </div>
106 <div class="show-d">
107 <el-tag>{{ $t('table.dragTips2') }} :</el-tag> {{ newList }}
108 </div>
109 </div>
110 </template>
111
112 <script>
113 import { fetchList } from '@/api/article'
114 import Sortable from 'sortablejs'
115
116 export default {
117 name: 'DragTable',
118 filters: {
119 statusFilter(status) {
120 const statusMap = {
121 published: 'success',
122 draft: 'info',
123 deleted: 'danger'
124 }
125 return statusMap[status]
126 }
127 },
128 data() {
129 return {
130 list: null,
131 total: null,
132 listLoading: true,
133 listQuery: {
134 page: 1,
135 limit: 10
136 },
137 sortable: null,
138 oldList: [],
139 newList: []
140 }
141 },
142 created() {
143 this.getList()
144 },
145 methods: {
146 async getList() {
147 this.listLoading = true
148 const { data } = await fetchList(this.listQuery)
149 this.list = data.items
150 this.total = data.total
151 this.listLoading = false
152 this.oldList = this.list.map(v => v.id)
153 this.newList = this.oldList.slice()
154 this.$nextTick(() => {
155 this.setSort()
156 })
157 },
158 setSort() {
159 const el = this.$refs.dragTable.$el.querySelectorAll(
160 '.el-table__body-wrapper > table > tbody'
161 )[0]
162 this.sortable = Sortable.create(el, {
163 ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
164 setData: function(dataTransfer) {
165 // to avoid Firefox bug
166 // Detail see : https://github.com/RubaXa/Sortable/issues/1012
167 dataTransfer.setData('Text', '')
168 },
169 onEnd: evt => {
170 const targetRow = this.list.splice(evt.oldIndex, 1)[0]
171 this.list.splice(evt.newIndex, 0, targetRow)
172
173 // for show the changes, you can delete in you code
174 const tempIndex = this.newList.splice(evt.oldIndex, 1)[0]
175 this.newList.splice(evt.newIndex, 0, tempIndex)
176 }
177 })
178 }
179 }
180 }
181 </script>
182
183 <style>
184 .sortable-ghost {
185 opacity: 0.8;
186 color: #fff !important;
187 background: #42b983 !important;
188 }
189 </style>
190
191 <style scoped>
192 .icon-star {
193 margin-right: 2px;
194 }
195 .drag-handler {
196 width: 20px;
197 height: 20px;
198 cursor: pointer;
199 }
200 .show-d {
201 margin-top: 15px;
202 }
203 </style>
204
src/views/site/list.vue
File was created 1 <template>
2 <div class="app-container">
3 <el-table
4 v-loading="listLoading"
5 :data="list"
6 border
7 fit
8 highlight-current-row
9 style="width: 100%"
10 >
11 <el-table-column
12 align="center"
13 label="ID"
14 width="80"
15 >
16 <template slot-scope="{row}">
17 <span>{{ row.id }}</span>
18 </template>
19 </el-table-column>
20
21 <el-table-column
22 width="180px"
23 align="center"
24 label="Date"
25 >
26 <template slot-scope="{row}">
27 <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
28 </template>
29 </el-table-column>
30
31 <el-table-column
32 width="120px"
33 align="center"
34 label="Author"
35 >
36 <template slot-scope="{row}">
37 <span>{{ row.author }}</span>
38 </template>
39 </el-table-column>
40
41 <el-table-column
42 width="100px"
43 label="Importance"
44 >
45 <template slot-scope="{row}">
46 <svg-icon
47 v-for="n in + row.importance"
48 :key="n"
49 icon-class="star"
50 class="meta-item__icon"
51 />
52 </template>
53 </el-table-column>
54
55 <el-table-column
56 class-name="status-col"
57 label="Status"
58 width="110"
59 >
60 <template slot-scope="{row}">
61 <el-tag :type="row.status | statusFilter">
62 {{ row.status }}
63 </el-tag>
64 </template>
65 </el-table-column>
66
67 <el-table-column
68 min-width="300px"
69 label="Title"
70 >
71 <template slot-scope="{row}">
72 <template v-if="row.edit">
73 <el-input
74 v-model="row.title"
75 class="edit-input"
76 size="small"
77 />
78 <el-button
79 class="cancel-btn"
80 size="small"
81 icon="el-icon-refresh"
82 type="warning"
83 @click="cancelEdit(row)"
84 >
85 cancel
86 </el-button>
87 </template>
88 <span v-else>{{ row.title }}</span>
89 </template>
90 </el-table-column>
91
92 <el-table-column
93 align="center"
94 label="Actions"
95 width="120"
96 >
97 <template slot-scope="{row}">
98 <el-button
99 v-if="row.edit"
100 type="success"
101 size="small"
102 icon="el-icon-circle-check-outline"
103 @click="confirmEdit(row)"
104 >
105 Ok
106 </el-button>
107 <el-button
108 v-else
109 type="primary"
110 size="small"
111 icon="el-icon-edit"
112 @click="row.edit=!row.edit"
113 >
114 Edit
115 </el-button>
116 </template>
117 </el-table-column>
118 </el-table>
119 </div>
120 </template>
121
122 <script>
123 import { fetchList } from '@/api/article'
124
125 export default {
126 name: 'InlineEditTable',
127 filters: {
128 statusFilter(status) {
129 const statusMap = {
130 published: 'success',
131 draft: 'info',
132 deleted: 'danger'
133 }
134 return statusMap[status]
135 }
136 },
137 data() {
138 return {
139 list: null,
140 listLoading: true,
141 listQuery: {
142 page: 1,
143 limit: 10
144 }
145 }
146 },
147 created() {
148 this.getList()
149 },
150 methods: {
151 async getList() {
152 this.listLoading = true
153 const { data } = await fetchList(this.listQuery)
154 const items = data.items
155 this.list = items.map(v => {
156 this.$set(v, 'edit', false) // https://vuejs.org/v2/guide/reactivity.html
157 v.originalTitle = v.title // will be used when user click the cancel botton
158 return v
159 })
160 this.listLoading = false
161 },
162 cancelEdit(row) {
163 row.title = row.originalTitle
164 row.edit = false
165 this.$message({
166 message: 'The title has been restored to the original value',
167 type: 'warning'
168 })
169 },
170 confirmEdit(row) {
171 row.edit = false
172 row.originalTitle = row.title
173 this.$message({
174 message: 'The title has been edited',
175 type: 'success'
176 })
177 }
178 }
179 }
180 </script>
181
182 <style scoped>
183 .edit-input {
184 padding-right: 100px;
185 }
186 .cancel-btn {
187 position: absolute;
188 right: 15px;
189 top: 10px;
190 }
191 </style>
192