diff --git a/src/router/modules/order.js b/src/router/modules/order.js
new file mode 100644
index 0000000..d28741e
--- /dev/null
+++ b/src/router/modules/order.js
@@ -0,0 +1,27 @@
+/** When your routing table is too long, you can split it into small modules**/
+
+import Layout from '@/layout'
+
+const orderRouter = {
+  path: '/orders',
+  component: Layout,
+  redirect: '/order/page',
+  alwaysShow: true, // will always show the root menu
+  name: 'Order',
+  meta: {
+    title: 'orders',
+    icon: 'shopping',
+    roles: ['admin', 'assistant', 'runner', 'shoper'] // you can set roles in root nav
+  },
+  children: [{
+    path: 'page',
+    component: () => import('@/views/order/list'),
+    name: 'OrderList',
+    meta: {
+      title: 'OrderList',
+      roles: ['admin', 'assistant', 'runner', 'shoper'] // or you can only set roles in sub nav
+    }
+  }]
+}
+
+export default orderRouter
diff --git a/src/router/modules/sites.js b/src/router/modules/sites.js
new file mode 100644
index 0000000..6ce6943
--- /dev/null
+++ b/src/router/modules/sites.js
@@ -0,0 +1,26 @@
+import Layout from '@/layout'
+
+const sitesRouter = {
+  path: '/sites',
+  component: Layout,
+  redirect: '/site/page',
+  alwaysShow: true, // will always show the root menu
+  name: 'Site',
+  meta: {
+    title: 'sites',
+    icon: 'people',
+    roles: ['admin', 'assistant', 'runner'] // you can set roles in root nav
+  },
+  children: [{
+    path: 'page',
+    component: () => import('@/views/site/list'),
+    name: 'SiteList',
+    meta: {
+      title: '站点列表',
+      roles: ['admin', 'runner']
+
+    }
+  }]
+}
+
+export default sitesRouter
diff --git a/src/views/dashboard/runner/index.vue b/src/views/dashboard/runner/index.vue
new file mode 100755
index 0000000..e2085a6
--- /dev/null
+++ b/src/views/dashboard/runner/index.vue
@@ -0,0 +1,72 @@
+<template>
+  <div class="dashboard-editor-container">
+    <div class="clearfix">
+      <pan-thumb :image="avatar" style="float: left">
+        Your roles:
+        <span v-for="item in roles" :key="item" class="pan-info-roles">{{ item }}</span>
+      </pan-thumb>
+      <github-corner style="position: absolute; top: 0px; border: 0; right: 0;" />
+      <div class="info-container">
+        <span class="display_name">{{ name }}</span>
+        <span style="font-size:20px;padding-top:20px;display:inline-block;">{{ roles }}'s Dashboard</span>
+      </div>
+    </div>
+    <div>
+      <img :src="emptyGif" class="emptyGif">
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import PanThumb from '@/components/PanThumb'
+// import GithubCorner from '@/components/GithubCorner'
+
+export default {
+  name: 'DashboardEditor',
+  // components: { PanThumb, GithubCorner },
+  components: { PanThumb },
+  data() {
+    return {
+      emptyGif:
+        'https://wpimg.wallstcn.com/0e03b7da-db9e-4819-ba10-9016ddfdaed3'
+    }
+  },
+  computed: {
+    ...mapGetters(['name', 'avatar', 'roles'])
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.emptyGif {
+  display: block;
+  width: 45%;
+  margin: 0 auto;
+}
+
+.dashboard-editor-container {
+  background-color: #e3e3e3;
+  min-height: 100vh;
+  padding: 50px 60px 0px;
+  .pan-info-roles {
+    font-size: 12px;
+    font-weight: 700;
+    color: #333;
+    display: block;
+  }
+  .info-container {
+    position: relative;
+    margin-left: 190px;
+    height: 150px;
+    line-height: 200px;
+    .display_name {
+      font-size: 48px;
+      line-height: 48px;
+      color: #212121;
+      position: absolute;
+      top: 25px;
+    }
+  }
+}
+</style>
diff --git a/src/views/order/list.vue b/src/views/order/list.vue
new file mode 100755
index 0000000..f67b8cf
--- /dev/null
+++ b/src/views/order/list.vue
@@ -0,0 +1,621 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <el-input
+        v-model="listQuery.title"
+        :placeholder="$t('table.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
+      :key="tableKey"
+      v-loading="listLoading"
+      :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="80"
+        :class-name="getSortClass('id')"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.id }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        :label="$t('table.date')"
+        width="150px"
+        align="center"
+      >
+        <template slot-scope="{row}">
+          <span>{{ 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="{row}">
+          <span
+            class="link-type"
+            @click="handleUpdate(row)"
+          >{{ row.title }}</span>
+          <el-tag>{{ row.type | typeFilter }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column
+        :label="$t('table.author')"
+        width="110px"
+        align="center"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.author }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        v-if="showReviewer"
+        :label="$t('table.reviewer')"
+        width="110px"
+        align="center"
+      >
+        <template slot-scope="{row}">
+          <span style="color:red;">{{ row.reviewer }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        :label="$t('table.importance')"
+        width="80px"
+      >
+        <template slot-scope="{row}">
+          <svg-icon
+            v-for="n in +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="{row}">
+          <span
+            v-if="row.pageviews"
+            class="link-type"
+            @click="handleFetchPv(row.pageviews)"
+          >{{ 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="{row}">
+          <el-tag :type="row.status | statusFilter">
+            {{ 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="{row,$index}">
+          <el-button
+            type="primary"
+            size="mini"
+            @click="handleUpdate(row)"
+          >
+            {{ $t('table.edit') }}
+          </el-button>
+          <el-button
+            v-if="row.status!='published'"
+            size="mini"
+            type="success"
+            @click="handleModifyStatus(row,'published')"
+          >
+            {{ $t('table.publish') }}
+          </el-button>
+          <el-button
+            v-if="row.status!='draft'"
+            size="mini"
+            @click="handleModifyStatus(row,'draft')"
+          >
+            {{ $t('table.draft') }}
+          </el-button>
+          <el-button
+            v-if="row.status!='deleted'"
+            size="mini"
+            type="danger"
+            @click="handleDelete(row,$index)"
+          >
+            {{ $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
+            v-model="temp.remark"
+            :autosize="{ minRows: 2, maxRows: 4}"
+            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 = '秀野堂主'
+          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(() => {
+            const index = this.list.findIndex(v => v.id === this.temp.id)
+            this.list.splice(index, 1, this.temp)
+            this.dialogFormVisible = false
+            this.$notify({
+              title: '成功',
+              message: '更新成功',
+              type: 'success',
+              duration: 2000
+            })
+          })
+        }
+      })
+    },
+    handleDelete(row, index) {
+      this.$notify({
+        title: '成功',
+        message: '删除成功',
+        type: 'success',
+        duration: 2000
+      })
+      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)
+        excel.export_json_to_excel({
+          header: tHeader,
+          data,
+          filename: 'table-list'
+        })
+        this.downloadLoading = false
+      })
+    },
+    formatJson(filterVal) {
+      return this.list.map(v =>
+        filterVal.map(j => {
+          if (j === 'timestamp') {
+            return parseTime(v[j])
+          } else {
+            return v[j]
+          }
+        })
+      )
+    },
+    getSortClass: function(key) {
+      const sort = this.listQuery.sort
+      return sort === `+${key}` ? 'ascending' : 'descending'
+    }
+  }
+}
+</script>
diff --git a/src/views/prod/list.vue b/src/views/prod/list.vue
new file mode 100755
index 0000000..02cb401
--- /dev/null
+++ b/src/views/prod/list.vue
@@ -0,0 +1,203 @@
+<template>
+  <div class="app-container">
+    <!-- Note that row-key is necessary to get a correct row order. -->
+    <el-table
+      ref="dragTable"
+      v-loading="listLoading"
+      :data="list"
+      row-key="id"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%"
+    >
+      <el-table-column
+        align="center"
+        label="ID"
+        width="65"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.id }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="180px"
+        align="center"
+        label="Date"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        min-width="300px"
+        label="Title"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.title }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="110px"
+        align="center"
+        label="Author"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.author }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="100px"
+        label="Importance"
+      >
+        <template slot-scope="{row}">
+          <svg-icon
+            v-for="n in + row.importance"
+            :key="n"
+            icon-class="star"
+            class="icon-star"
+          />
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        align="center"
+        label="Readings"
+        width="95"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.pageviews }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        class-name="status-col"
+        label="Status"
+        width="110"
+      >
+        <template slot-scope="{row}">
+          <el-tag :type="row.status | statusFilter">
+            {{ row.status }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        align="center"
+        label="Drag"
+        width="80"
+      >
+        <template slot-scope="{}">
+          <svg-icon
+            class="drag-handler"
+            icon-class="drag"
+          />
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- $t is vue-i18n global function to translate lang (lang in @/lang)  -->
+    <div class="show-d">
+      <el-tag style="margin-right:12px;">{{ $t('table.dragTips1') }} :</el-tag> {{ oldList }}
+    </div>
+    <div class="show-d">
+      <el-tag>{{ $t('table.dragTips2') }} :</el-tag> {{ newList }}
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchList } from '@/api/article'
+import Sortable from 'sortablejs'
+
+export default {
+  name: 'DragTable',
+  filters: {
+    statusFilter(status) {
+      const statusMap = {
+        published: 'success',
+        draft: 'info',
+        deleted: 'danger'
+      }
+      return statusMap[status]
+    }
+  },
+  data() {
+    return {
+      list: null,
+      total: null,
+      listLoading: true,
+      listQuery: {
+        page: 1,
+        limit: 10
+      },
+      sortable: null,
+      oldList: [],
+      newList: []
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    async getList() {
+      this.listLoading = true
+      const { data } = await fetchList(this.listQuery)
+      this.list = data.items
+      this.total = data.total
+      this.listLoading = false
+      this.oldList = this.list.map(v => v.id)
+      this.newList = this.oldList.slice()
+      this.$nextTick(() => {
+        this.setSort()
+      })
+    },
+    setSort() {
+      const el = this.$refs.dragTable.$el.querySelectorAll(
+        '.el-table__body-wrapper > table > tbody'
+      )[0]
+      this.sortable = Sortable.create(el, {
+        ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
+        setData: function(dataTransfer) {
+          // to avoid Firefox bug
+          // Detail see : https://github.com/RubaXa/Sortable/issues/1012
+          dataTransfer.setData('Text', '')
+        },
+        onEnd: evt => {
+          const targetRow = this.list.splice(evt.oldIndex, 1)[0]
+          this.list.splice(evt.newIndex, 0, targetRow)
+
+          // for show the changes, you can delete in you code
+          const tempIndex = this.newList.splice(evt.oldIndex, 1)[0]
+          this.newList.splice(evt.newIndex, 0, tempIndex)
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style>
+.sortable-ghost {
+  opacity: 0.8;
+  color: #fff !important;
+  background: #42b983 !important;
+}
+</style>
+
+<style scoped>
+.icon-star {
+  margin-right: 2px;
+}
+.drag-handler {
+  width: 20px;
+  height: 20px;
+  cursor: pointer;
+}
+.show-d {
+  margin-top: 15px;
+}
+</style>
diff --git a/src/views/site/list.vue b/src/views/site/list.vue
new file mode 100644
index 0000000..a3fe0b7
--- /dev/null
+++ b/src/views/site/list.vue
@@ -0,0 +1,191 @@
+<template>
+  <div class="app-container">
+    <el-table
+      v-loading="listLoading"
+      :data="list"
+      border
+      fit
+      highlight-current-row
+      style="width: 100%"
+    >
+      <el-table-column
+        align="center"
+        label="ID"
+        width="80"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.id }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="180px"
+        align="center"
+        label="Date"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.timestamp | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="120px"
+        align="center"
+        label="Author"
+      >
+        <template slot-scope="{row}">
+          <span>{{ row.author }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        width="100px"
+        label="Importance"
+      >
+        <template slot-scope="{row}">
+          <svg-icon
+            v-for="n in + row.importance"
+            :key="n"
+            icon-class="star"
+            class="meta-item__icon"
+          />
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        class-name="status-col"
+        label="Status"
+        width="110"
+      >
+        <template slot-scope="{row}">
+          <el-tag :type="row.status | statusFilter">
+            {{ row.status }}
+          </el-tag>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        min-width="300px"
+        label="Title"
+      >
+        <template slot-scope="{row}">
+          <template v-if="row.edit">
+            <el-input
+              v-model="row.title"
+              class="edit-input"
+              size="small"
+            />
+            <el-button
+              class="cancel-btn"
+              size="small"
+              icon="el-icon-refresh"
+              type="warning"
+              @click="cancelEdit(row)"
+            >
+              cancel
+            </el-button>
+          </template>
+          <span v-else>{{ row.title }}</span>
+        </template>
+      </el-table-column>
+
+      <el-table-column
+        align="center"
+        label="Actions"
+        width="120"
+      >
+        <template slot-scope="{row}">
+          <el-button
+            v-if="row.edit"
+            type="success"
+            size="small"
+            icon="el-icon-circle-check-outline"
+            @click="confirmEdit(row)"
+          >
+            Ok
+          </el-button>
+          <el-button
+            v-else
+            type="primary"
+            size="small"
+            icon="el-icon-edit"
+            @click="row.edit=!row.edit"
+          >
+            Edit
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import { fetchList } from '@/api/article'
+
+export default {
+  name: 'InlineEditTable',
+  filters: {
+    statusFilter(status) {
+      const statusMap = {
+        published: 'success',
+        draft: 'info',
+        deleted: 'danger'
+      }
+      return statusMap[status]
+    }
+  },
+  data() {
+    return {
+      list: null,
+      listLoading: true,
+      listQuery: {
+        page: 1,
+        limit: 10
+      }
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    async getList() {
+      this.listLoading = true
+      const { data } = await fetchList(this.listQuery)
+      const items = data.items
+      this.list = items.map(v => {
+        this.$set(v, 'edit', false) // https://vuejs.org/v2/guide/reactivity.html
+        v.originalTitle = v.title //  will be used when user click the cancel botton
+        return v
+      })
+      this.listLoading = false
+    },
+    cancelEdit(row) {
+      row.title = row.originalTitle
+      row.edit = false
+      this.$message({
+        message: 'The title has been restored to the original value',
+        type: 'warning'
+      })
+    },
+    confirmEdit(row) {
+      row.edit = false
+      row.originalTitle = row.title
+      this.$message({
+        message: 'The title has been edited',
+        type: 'success'
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.edit-input {
+  padding-right: 100px;
+}
+.cancel-btn {
+  position: absolute;
+  right: 15px;
+  top: 10px;
+}
+</style>