joway 2 лет назад
Родитель
Сommit
56b6fc6b45
5 измененных файлов с 327 добавлено и 4 удалено
  1. 8 0
      src/api/ad.js
  2. 14 0
      src/lang/en.js
  3. 13 0
      src/lang/zh.js
  4. 64 4
      src/router/index.js
  5. 228 0
      src/views/ad/index.vue

+ 8 - 0
src/api/ad.js

@@ -0,0 +1,8 @@
+import request from '@/utils/request'
+
+export function fetchList(query) {
+  return request({
+    url: '/v1/ad/location',
+    method: 'get'
+  })
+}

+ 14 - 0
src/lang/en.js

@@ -79,6 +79,20 @@ export default {
     password: 'Password',
     verifyCode: 'Verification Code'
   },
+  ad: {
+    ad: 'Ad',
+    description: 'Description',
+    type: 'Type',
+    creator: 'Creator',
+    createTime: 'Create time',
+    action: 'Action',
+    view: 'View',
+    externalLinks: 'External Links',
+    article: 'Article',
+    slideshow: 'Slideshow',
+    image: 'Image'
+
+  },
   documentation: {
     documentation: 'Documentation',
     github: 'Github Repository'

+ 13 - 0
src/lang/zh.js

@@ -79,6 +79,19 @@ export default {
     password: '密码',
     verifyCode: '验证码'
   },
+  ad: {
+    ad: '广告名称',
+    description: '描述',
+    type: '类型',
+    creator: '创建人',
+    createTime: '创建时间',
+    action: '操作',
+    view: '查看详情',
+    externalLinks: '外部链接',
+    article: '文章',
+    slideshow: '幻灯',
+    image: '图片'
+  },
   documentation: {
     documentation: '文档',
     github: 'Github 地址'

+ 64 - 4
src/router/index.js

@@ -103,12 +103,74 @@ export const constantRoutes = [
  */
 export const asyncRoutes = [
   /** when your routing map is too long, you can split it into small modules **/
-
   // 会员
   memberRouter,
   // 设置
   configRouter,
-
+  {
+    path: '/example',
+    component: Layout,
+    redirect: '/example/list',
+    name: 'Example',
+    meta: {
+      title: 'example',
+      icon: 'el-icon-s-help'
+    },
+    children: [
+      {
+        path: 'create',
+        component: () => import('@/views/example/create'),
+        name: 'CreateArticle',
+        meta: { title: 'createArticle', icon: 'edit' }
+      },
+      {
+        path: 'edit/:id(\\d+)',
+        component: () => import('@/views/example/edit'),
+        name: 'EditArticle',
+        meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
+        hidden: true
+      },
+      {
+        path: 'list',
+        component: () => import('@/views/example/list'),
+        name: 'ArticleList',
+        meta: { title: 'articleList', icon: 'list' }
+      }
+    ]
+  },
+  {
+    path: '/ad',
+    component: Layout,
+    redirect: '/ad/list',
+    hidden: true,
+    children: [
+      {
+        path: 'location',
+        component: () => import('@/views/ad/index'),
+        name: 'Ad Location',
+        meta: { title: 'adLocation', icon: 'user', noCache: true }
+      },
+      {
+        path: 'list/:id(\\d+)',
+        component: () => import('@/views/ad/list'),
+        name: 'Ad List',
+        meta: { title: 'adList', noCache: true, activeMenu: '/ad/list' },
+        hidden: true
+      }
+    ]
+  },
+  {
+    path: '/tab',
+    component: Layout,
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/tab/index'),
+        name: 'Tab',
+        meta: { title: 'tab', icon: 'tab' }
+      }
+    ]
+  },
   {
     path: '/error',
     component: Layout,
@@ -133,7 +195,6 @@ export const asyncRoutes = [
       }
     ]
   },
-
   {
     path: '/error-log',
     component: Layout,
@@ -172,4 +233,3 @@ export function selfAddRoutes(params) {
 }
 
 export default router
-

+ 228 - 0
src/views/ad/index.vue

@@ -0,0 +1,228 @@
+<template>
+  <div class="app-container">
+    <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('ad.ad')" prop="id" align="center" :class-name="getSortClass('id')">
+        <template slot-scope="{row}">
+          <span>{{ row.LOCATION_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('ad.description')" prop="id" align="center" :class-name="getSortClass('id')">
+        <template slot-scope="{row}">
+          <span>{{ row.REMARK }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('ad.type')" align="center"> <!-- 类型 -->
+        <template slot-scope="{row}">
+          <template v-if="row.TYPE === '1'">
+            <el-tag type="success">Slideshow</el-tag> <!-- 外链 -->
+          </template>
+          <template v-else-if="row.TYPE === '2'">
+            <el-tag>Image</el-tag> <!-- 文章 -->
+          </template>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('ad.creator')" prop="id" align="center" width="80" :class-name="getSortClass('id')">
+        <template slot-scope="{row}">
+          <span>{{ row.CREATE_ADMIN_NAME }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('ad.createTime')" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.CREATED_AT | parseTime('{y}-{m}-{d} {h}:{i}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column :label="$t('ad.action')" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="{row}">
+          <el-button type="primary" size="mini" @click="handleView(row)">
+            {{ $t('ad.view') }}
+          </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 } from '@/api/ad'
+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' }
+]
+
+// 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.list
+        this.total = response.data.totalCount
+
+        // Just to simulate the time of the request
+        setTimeout(() => {
+          this.listLoading = false
+        }, 1.5 * 1000)
+      })
+    },
+    handleFilter() {
+      this.listQuery.page = 1
+      this.getList()
+    },
+    resetTemp() {
+      this.temp = {
+        id: undefined,
+        importance: 1,
+        remark: '',
+        timestamp: new Date(),
+        title: '',
+        status: 'published',
+        type: ''
+      }
+    },
+    handleView(row) {
+      this.$router.push(`/ad/list/${row.ID}`)
+    },
+    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>