| <template> | 
|   <div class="app-container"> | 
|     <div class="filter-container"> | 
|       <el-input :placeholder="$t('table.title')" v-model="listQuery.title" style="width: 200px;" class="filter-item" @keyup.enter.native="handleFilter"/> | 
|       <el-select v-model="listQuery.importance" :placeholder="$t('table.importance')" clearable style="width: 90px" class="filter-item"> | 
|         <el-option v-for="item in importanceOptions" :key="item" :label="item" :value="item"/> | 
|       </el-select> | 
|       <el-select v-model="listQuery.type" :placeholder="$t('table.type')" clearable class="filter-item" style="width: 130px"> | 
|         <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name+'('+item.key+')'" :value="item.key"/> | 
|       </el-select> | 
|       <el-select v-model="listQuery.sort" style="width: 140px" class="filter-item" @change="handleFilter"> | 
|         <el-option v-for="item in sortOptions" :key="item.key" :label="item.label" :value="item.key"/> | 
|       </el-select> | 
|       <el-button v-waves class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">{{ $t('table.search') }}</el-button> | 
|       <el-button class="filter-item" style="margin-left: 10px;" type="primary" icon="el-icon-edit" @click="handleCreate">{{ $t('table.add') }}</el-button> | 
|       <el-button v-waves :loading="downloadLoading" class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload">{{ $t('table.export') }}</el-button> | 
|       <el-checkbox v-model="showReviewer" class="filter-item" style="margin-left:15px;" @change="tableKey=tableKey+1">{{ $t('table.reviewer') }}</el-checkbox> | 
|     </div> | 
|   | 
|     <el-table | 
|       v-loading="listLoading" | 
|       :key="tableKey" | 
|       :data="list" | 
|       border | 
|       fit | 
|       highlight-current-row | 
|       style="width: 100%;" | 
|       @sort-change="sortChange"> | 
|       <el-table-column :label="$t('table.id')" prop="id" sortable="custom" align="center" width="65"> | 
|         <template slot-scope="scope"> | 
|           <span>{{ scope.row.id }}</span> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.date')" width="150px" align="center"> | 
|         <template slot-scope="scope"> | 
|           <span>{{ scope.row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.title')" min-width="150px"> | 
|         <template slot-scope="scope"> | 
|           <span class="link-type" @click="handleUpdate(scope.row)">{{ scope.row.title }}</span> | 
|           <el-tag>{{ scope.row.type | typeFilter }}</el-tag> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.author')" width="110px" align="center"> | 
|         <template slot-scope="scope"> | 
|           <span>{{ scope.row.author }}</span> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column v-if="showReviewer" :label="$t('table.reviewer')" width="110px" align="center"> | 
|         <template slot-scope="scope"> | 
|           <span style="color:red;">{{ scope.row.reviewer }}</span> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.importance')" width="80px"> | 
|         <template slot-scope="scope"> | 
|           <svg-icon v-for="n in +scope.row.importance" :key="n" icon-class="star" class="meta-item__icon"/> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.readings')" align="center" width="95"> | 
|         <template slot-scope="scope"> | 
|           <span v-if="scope.row.pageviews" class="link-type" @click="handleFetchPv(scope.row.pageviews)">{{ scope.row.pageviews }}</span> | 
|           <span v-else>0</span> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.status')" class-name="status-col" width="100"> | 
|         <template slot-scope="scope"> | 
|           <el-tag :type="scope.row.status | statusFilter">{{ scope.row.status }}</el-tag> | 
|         </template> | 
|       </el-table-column> | 
|       <el-table-column :label="$t('table.actions')" align="center" width="230" class-name="small-padding fixed-width"> | 
|         <template slot-scope="scope"> | 
|           <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{ $t('table.edit') }}</el-button> | 
|           <el-button v-if="scope.row.status!='published'" size="mini" type="success" @click="handleModifyStatus(scope.row,'published')">{{ $t('table.publish') }} | 
|           </el-button> | 
|           <el-button v-if="scope.row.status!='draft'" size="mini" @click="handleModifyStatus(scope.row,'draft')">{{ $t('table.draft') }} | 
|           </el-button> | 
|           <el-button v-if="scope.row.status!='deleted'" size="mini" type="danger" @click="handleModifyStatus(scope.row,'deleted')">{{ $t('table.delete') }} | 
|           </el-button> | 
|         </template> | 
|       </el-table-column> | 
|     </el-table> | 
|   | 
|     <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> | 
|   | 
|     <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible"> | 
|       <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="70px" style="width: 400px; margin-left:50px;"> | 
|         <el-form-item :label="$t('table.type')" prop="type"> | 
|           <el-select v-model="temp.type" class="filter-item" placeholder="Please select"> | 
|             <el-option v-for="item in calendarTypeOptions" :key="item.key" :label="item.display_name" :value="item.key"/> | 
|           </el-select> | 
|         </el-form-item> | 
|         <el-form-item :label="$t('table.date')" prop="timestamp"> | 
|           <el-date-picker v-model="temp.timestamp" type="datetime" placeholder="Please pick a date"/> | 
|         </el-form-item> | 
|         <el-form-item :label="$t('table.title')" prop="title"> | 
|           <el-input v-model="temp.title"/> | 
|         </el-form-item> | 
|         <el-form-item :label="$t('table.status')"> | 
|           <el-select v-model="temp.status" class="filter-item" placeholder="Please select"> | 
|             <el-option v-for="item in statusOptions" :key="item" :label="item" :value="item"/> | 
|           </el-select> | 
|         </el-form-item> | 
|         <el-form-item :label="$t('table.importance')"> | 
|           <el-rate v-model="temp.importance" :colors="['#99A9BF', '#F7BA2A', '#FF9900']" :max="3" style="margin-top:8px;"/> | 
|         </el-form-item> | 
|         <el-form-item :label="$t('table.remark')"> | 
|           <el-input :autosize="{ minRows: 2, maxRows: 4}" v-model="temp.remark" type="textarea" placeholder="Please input"/> | 
|         </el-form-item> | 
|       </el-form> | 
|       <div slot="footer" class="dialog-footer"> | 
|         <el-button @click="dialogFormVisible = false">{{ $t('table.cancel') }}</el-button> | 
|         <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">{{ $t('table.confirm') }}</el-button> | 
|       </div> | 
|     </el-dialog> | 
|   | 
|     <el-dialog :visible.sync="dialogPvVisible" title="Reading statistics"> | 
|       <el-table :data="pvData" border fit highlight-current-row style="width: 100%"> | 
|         <el-table-column prop="key" label="Channel"/> | 
|         <el-table-column prop="pv" label="Pv"/> | 
|       </el-table> | 
|       <span slot="footer" class="dialog-footer"> | 
|         <el-button type="primary" @click="dialogPvVisible = false">{{ $t('table.confirm') }}</el-button> | 
|       </span> | 
|     </el-dialog> | 
|   | 
|   </div> | 
| </template> | 
|   | 
| <script> | 
| import { fetchList, fetchPv, createArticle, updateArticle } from "@/api/article"; | 
| import waves from "@/directive/waves"; //  Waves directive | 
| import { parseTime } from "@/utils"; | 
| import Pagination from "@/components/Pagination"; //  Secondary package based on el-pagination | 
|   | 
| const calendarTypeOptions = [ | 
|   { key: "CN", display_name: "China" }, | 
|   { key: "US", display_name: "USA" }, | 
|   { key: "JP", display_name: "Japan" }, | 
|   { key: "EU", display_name: "Eurozone" } | 
| ]; | 
|   | 
| //  arr to obj ,such as { CN : "China", US : "USA" } | 
| const calendarTypeKeyValue = calendarTypeOptions.reduce((acc, cur) => { | 
|   acc[cur.key] = cur.display_name; | 
|   return acc; | 
| }, {}); | 
|   | 
| export default { | 
|   name: "ComplexTable", | 
|   components: { Pagination }, | 
|   directives: { waves }, | 
|   filters: { | 
|     statusFilter(status) { | 
|       const statusMap = { | 
|         published: "success", | 
|         draft: "info", | 
|         deleted: "danger" | 
|       }; | 
|       return statusMap[status]; | 
|     }, | 
|     typeFilter(type) { | 
|       return calendarTypeKeyValue[type]; | 
|     } | 
|   }, | 
|   data() { | 
|     return { | 
|       tableKey: 0, | 
|       list: null, | 
|       total: 0, | 
|       listLoading: true, | 
|       listQuery: { | 
|         page: 1, | 
|         limit: 20, | 
|         importance: undefined, | 
|         title: undefined, | 
|         type: undefined, | 
|         sort: "+id" | 
|       }, | 
|       importanceOptions: [1, 2, 3], | 
|       calendarTypeOptions, | 
|       sortOptions: [{ label: "ID Ascending", key: "+id" }, { label: "ID Descending", key: "-id" }], | 
|       statusOptions: ["published", "draft", "deleted"], | 
|       showReviewer: false, | 
|       temp: { | 
|         id: undefined, | 
|         importance: 1, | 
|         remark: "", | 
|         timestamp: new Date(), | 
|         title: "", | 
|         type: "", | 
|         status: "published" | 
|       }, | 
|       dialogFormVisible: false, | 
|       dialogStatus: "", | 
|       textMap: { | 
|         update: "Edit", | 
|         create: "Create" | 
|       }, | 
|       dialogPvVisible: false, | 
|       pvData: [], | 
|       rules: { | 
|         type: [{ required: true, message: "type is required", trigger: "change" }], | 
|         timestamp: [{ type: "date", required: true, message: "timestamp is required", trigger: "change" }], | 
|         title: [{ required: true, message: "title is required", trigger: "blur" }] | 
|       }, | 
|       downloadLoading: false | 
|     }; | 
|   }, | 
|   created() { | 
|     this.getList(); | 
|   }, | 
|   methods: { | 
|     getList() { | 
|       this.listLoading = true; | 
|       fetchList(this.listQuery).then(response => { | 
|         this.list = response.data.items; | 
|         this.total = response.data.total; | 
|   | 
|         //  Just to simulate the time of the request | 
|         setTimeout(() => { | 
|           this.listLoading = false; | 
|         }, 1.5 * 1000); | 
|       }); | 
|     }, | 
|     handleFilter() { | 
|       this.listQuery.page = 1; | 
|       this.getList(); | 
|     }, | 
|     handleModifyStatus(row, status) { | 
|       this.$message({ | 
|         message: "操作成功", | 
|         type: "success" | 
|       }); | 
|       row.status = status; | 
|     }, | 
|     sortChange(data) { | 
|       const { prop, order } = data; | 
|       if (prop === "id") { | 
|         this.sortByID(order); | 
|       } | 
|     }, | 
|     sortByID(order) { | 
|       if (order === "ascending") { | 
|         this.listQuery.sort = "+id"; | 
|       } else { | 
|         this.listQuery.sort = "-id"; | 
|       } | 
|       this.handleFilter(); | 
|     }, | 
|     resetTemp() { | 
|       this.temp = { | 
|         id: undefined, | 
|         importance: 1, | 
|         remark: "", | 
|         timestamp: new Date(), | 
|         title: "", | 
|         status: "published", | 
|         type: "" | 
|       }; | 
|     }, | 
|     handleCreate() { | 
|       this.resetTemp(); | 
|       this.dialogStatus = "create"; | 
|       this.dialogFormVisible = true; | 
|       this.$nextTick(() => { | 
|         this.$refs["dataForm"].clearValidate(); | 
|       }); | 
|     }, | 
|     createData() { | 
|       this.$refs["dataForm"].validate((valid) => { | 
|         if (valid) { | 
|           this.temp.id = parseInt(Math.random() * 100) + 1024; //  mock a id | 
|           this.temp.author = "vue-element-admin"; | 
|           createArticle(this.temp).then(() => { | 
|             this.list.unshift(this.temp); | 
|             this.dialogFormVisible = false; | 
|             this.$notify({ | 
|               title: "成功", | 
|               message: "创建成功", | 
|               type: "success", | 
|               duration: 2000 | 
|             }); | 
|           }); | 
|         } | 
|       }); | 
|     }, | 
|     handleUpdate(row) { | 
|       this.temp = Object.assign({}, row); //  copy obj | 
|       this.temp.timestamp = new Date(this.temp.timestamp); | 
|       this.dialogStatus = "update"; | 
|       this.dialogFormVisible = true; | 
|       this.$nextTick(() => { | 
|         this.$refs["dataForm"].clearValidate(); | 
|       }); | 
|     }, | 
|     updateData() { | 
|       this.$refs["dataForm"].validate((valid) => { | 
|         if (valid) { | 
|           const tempData = Object.assign({}, this.temp); | 
|           tempData.timestamp = +new Date(tempData.timestamp); //  change Thu Nov 30 2017 16:41:05 GMT+0800 (CST) to 1512031311464 | 
|           updateArticle(tempData).then(() => { | 
|             for (const v of this.list) { | 
|               if (v.id === this.temp.id) { | 
|                 const index = this.list.indexOf(v); | 
|                 this.list.splice(index, 1, this.temp); | 
|                 break; | 
|               } | 
|             } | 
|             this.dialogFormVisible = false; | 
|             this.$notify({ | 
|               title: "成功", | 
|               message: "更新成功", | 
|               type: "success", | 
|               duration: 2000 | 
|             }); | 
|           }); | 
|         } | 
|       }); | 
|     }, | 
|     handleDelete(row) { | 
|       this.$notify({ | 
|         title: "成功", | 
|         message: "删除成功", | 
|         type: "success", | 
|         duration: 2000 | 
|       }); | 
|       const index = this.list.indexOf(row); | 
|       this.list.splice(index, 1); | 
|     }, | 
|     handleFetchPv(pv) { | 
|       fetchPv(pv).then(response => { | 
|         this.pvData = response.data.pvData; | 
|         this.dialogPvVisible = true; | 
|       }); | 
|     }, | 
|     handleDownload() { | 
|       this.downloadLoading = true; | 
|       import("@/vendor/Export2Excel").then(excel => { | 
|         const tHeader = ["timestamp", "title", "type", "importance", "status"]; | 
|         const filterVal = ["timestamp", "title", "type", "importance", "status"]; | 
|         const data = this.formatJson(filterVal, this.list); | 
|         excel.export_json_to_excel({ | 
|           header: tHeader, | 
|           data, | 
|           filename: "table-list" | 
|         }); | 
|         this.downloadLoading = false; | 
|       }); | 
|     }, | 
|     formatJson(filterVal, jsonData) { | 
|       return jsonData.map(v => filterVal.map(j => { | 
|         if (j === "timestamp") { | 
|           return parseTime(v[j]); | 
|         } else { | 
|           return v[j]; | 
|         } | 
|       })); | 
|     } | 
|   } | 
| }; | 
| </script> |