Vue封装elementUI的表格控件,包含查询

控件结构

在这里插入图片描述

/TableAddQuery index.vue

<template>
  <div class="table-add-query">
    <Query ref="query" :show-search="queryOptions.showSearch" :select-lists="queryOptions.selectLists"
           :show-date-picker="queryOptions.showDatePicker" :picker-options="queryOptions.pickerOptions"
           @getList="getList"
    ></Query>
    <Table ref="table" :table-lists="tableOptions.tableLists" :table-lists-opt="tableOptions.tableListsOpt" @indexMethod="indexMethod">
      <template v-for="item in slotLists" :slot="item" slot-scope="{ row }"><slot :name="item" :row="row"></slot></template>
    </Table>
    <Pagination
      v-if="$refs.query"
      v-show="tableOptions.total > 0"
      :total="tableOptions.total"
      :page.sync="listQuery.page"
      :limit.sync="listQuery.limit"
      @pagination="getList"
    >
    </Pagination>
  </div>
</template>

<script>
import Pagination from '@/components/Pagination'
import Table from '@/components/TableAddQuery/components/Table'
import Query from '@/components/TableAddQuery/components/Query'

export default {
  name: "Index",
  components: {
    Pagination,
    Table,
    Query
  },
  props: {
    queryOptions: {
      type: Object,
      default: () => ({
        selectLists: {}
      })
    },
    tableOptions: {
      type: Object,
      default: () => ({
        total: 0,
        tableLists: [],
        tableListsOpt: {
          showIndex: false,
          content: []
        }
      })
    },
  },
  computed: {
    listQuery() {
      return this.$refs.query.listQuery
    },
    table() {
      return this.$refs.table
    },
    slotLists() {
      const content = this.tableOptions.tableListsOpt.content;
      const slotLists = []
      content.forEach(item => {
        Object.keys(item).forEach(temp => {
          if (temp === 'slot') {
            slotLists.push(item[temp]);
          }
        })
      })
      return slotLists
    }
  },
  mounted() {
    this.getList();
  },
  methods: {
    getList() {
      const listQuery = this.listQuery
      this.table.tableLoading = true;
      this.$emit('getList', listQuery, val => {
        if (val) {
          this.table.tableLoading = false;
        } else {
          this.getList();
        }
      })
    },
    indexMethod(idx, callBack) {
      callBack(idx + 1 + (this.listQuery.page - 1) * this.listQuery.limit);
    },
  }
}
</script>

/Query.vue

<template>
  <div class="filter-container">
    <el-input
      v-if="showSearch"
      v-model="listQuery.searchField"
      placeholder="搜索UID(精准查询)/用户名(模糊查询)"
      style="width: 300px;"
      class="search-input"
      prefix-icon="el-icon-search"
      @keyup.enter.native="handleFilter"
    />
    <div class="select-filter">
      <el-select v-for="(values, key, index) in selectLists" :key="index" v-model="listQuery[key]" class="search-input select-item" :placeholder="values.placeholder" clearable style="width: 140px">
        <el-option
          v-for="config in values.option"
          :key="config.value"
          :label="config.label"
          :value="config.value"
        />
      </el-select>
    </div>
    <!--suppress SpellCheckingInspection -->
    <el-date-picker
      v-if="showDatePicker"
      v-model="listQuery.timeBetween"
      type="datetimerange"
      :picker-options="pickerOptions"
      range-separator="至"
      start-placeholder="开始日期"
      end-placeholder="结束日期"
      :clearable="true"
      align="right"
    >
    </el-date-picker>
    <el-button v-waves type="primary" icon="el-icon-search" @click="handleFilter">
      查询
    </el-button>
  </div>
</template>

<script>
import waves from '@/directive/waves'
import { setZeroTime } from '@/utils/dateFormat'

export default {
  name: "Query",
  directives: { waves },
  props: {
    showSearch: {
      type: Boolean,
      default: true
    },
    selectLists: {
      type: Object,
      default: () => ({})
    },
    showDatePicker: {
      type: Boolean,
      default: false
    },
    pickerOptions: {
      type: Object,
      default: () => ({
        shortcuts: [{
          text: '最近一周',
          onClick(picker) {
            let now = new Date();
            now = now.setDate(now.getDate() + 1)
            now = new Date(now);
            const end = setZeroTime(now);
            const start = setZeroTime(new Date());
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近一个月',
          onClick(picker) {
            let now = new Date();
            now = now.setDate(now.getDate() + 1)
            now = new Date(now);
            const end = setZeroTime(now);
            const start = setZeroTime(new Date());
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近三个月',
          onClick(picker) {
            let now = new Date();
            now = now.setDate(now.getDate() + 1)
            now = new Date(now);
            const end = setZeroTime(now);
            const start = setZeroTime(new Date());
            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
            picker.$emit('pick', [start, end]);
          }
        }]
      })
    }
  },
  data() {
    return {
      listQuery: {
        page: 1,
        limit: 20,
        searchField: undefined,
        timeBetween: undefined
      }
    }
  },
  created() {
    const selectLists = this.selectLists;
    const listQuery = this.listQuery;
    Object.keys(selectLists).forEach(item => {
      this.$set(listQuery, item, undefined);
    })
  },
  methods: {
    handleFilter() {
      this.listQuery.page = 1
      // this.getList() 获取数据,修改为向父组件传递
      this.$emit('getList', this.listQuery)
    },
  }
}
</script>

<style scoped lang="scss">
  .search-input >>> .el-input__inner{
    height: 36px !important;
    line-height: 36px !important;
  }

  .select-filter{
    margin-top: 3px;
    display: inline-block;
  }

  .select-item:not(:last-of-type){
    margin-right: 4px;
  }
</style>

/Table.vue

<template>
  <el-table
    :key="tableKey"
    v-loading="tableLoading"
    :data="displayTableList"
    fit
    border
    highlight-current-row
    style="width: 100%;"
  >
    <el-table-column v-if="tableListsOpt.showIndex" :index="indexMethod" label="序号" type="index" align="center" width="50"></el-table-column>
    <el-table-column v-for="item in tableListsOpt.content" :key="item.key" :prop="item.prop" :label="item.label" :align="item.align" :min-width="item.minWidth">
      <template slot-scope="{ row }">
        <slot v-if="item.slot" :name="item.slot" :row="row"></slot>
        <span v-else>{{ row[item.prop] }}</span>
      </template>
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  name: "Table",
  props: {
    tableLists: {
      type: Array,
      default: () => []
    },
    tableListsOpt: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      tableKey: 0,
      tableLoading: true
    }
  },
  computed: {
    displayTableList() {
      return this.tableLists
    },
  },
  methods: {
    indexMethod(idx) {
      let index = null
      this.$emit('indexMethod', idx, val => {
        index = val
      })
      return index
    }
  }
}
</script>

/Pagination.vue

<template>
  <div :class="{'hidden':hidden}" class="pagination-container">
    <el-pagination
      :background="background"
      :current-page.sync="currentPage"
      :page-size.sync="pageSize"
      :layout="layout"
      :page-sizes="pageSizes"
      :total="total"
      v-bind="$attrs"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    />
  </div>
</template>

<script>
import { scrollTo } from '@/utils/scroll-to'

export default {
  name: 'Pagination',
  props: {
    total: {
      required: true,
      type: Number
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 20
    },
    pageSizes: {
      type: Array,
      default() {
        // return [10, 20, 30, 50]
        return [10,20,30,40,50,100,200,500]
      }
    },
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper'
    },
    background: {
      type: Boolean,
      default: true
    },
    autoScroll: {
      type: Boolean,
      default: true
    },
    hidden: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    currentPage: {
      get() {
        return this.page
      },
      set(val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get() {
        return this.limit
      },
      set(val) {
        this.$emit('update:limit', val)
      }
    }
  },
  methods: {
    handleSizeChange(val) {
      this.$emit('pagination', { page: this.currentPage, limit: val })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    handleCurrentChange(val) {
      this.$emit('pagination', { page: val, limit: this.pageSize })
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>

<style scoped>
.pagination-container {
  background: #fff;
  padding: 10px 10px;
  border-radius: 8px;
  /* box-shadow: 0 0 6px 0 #dcded7; */
}
.pagination-container.hidden {
  display: none;
}
</style>

调用格式

/userlist.vue

export default {
  data() {
    return {
      queryOptions: {
        showSearch: true,
        showDatePicker: false,
      },
      tableOptions: {
        total: 0,
        tableLists: [],
        tableListsOpt: {
          showIndex: true,
          content: [
            {
              key: 1,
              label: '用户ID',
              prop: 'userid',
              align: 'center',
              minWidth: 140,
            },
            {
              key: 2,
              label: '用户名',
              prop: 'username',
              align: 'center',
              minWidth: 140,
            },
            {
              key: 3,
              label: '状态',
              align: 'center',
              minWidth: 100,
              slot: 'status'
            },
            {
              key: 4,
              label: '点数余额',
              align: 'center',
              minWidth: 120,
              slot: 'balance'
            },
            // {
            //   key: 5,
            //   label: '收点限制',
            //   prop: '',
            //   align: 'center',
            //   minWidth: 120,
            // },
            // {
            //   key: 6,
            //   label: '单笔最高转出',
            //   prop: '',
            //   align: 'center',
            //   minWidth: 150,
            // },
            // {
            //   key: 7,
            //   label: '单日累计最高转出',
            //   prop: '',
            //   align: 'center',
            //   minWidth: 180,
            // },
            {
              key: 8,
              label: '注册时间',
              prop: 'created_time',
              align: 'center',
              minWidth: 180,
            },
            {
              key: 9,
              label: '最近登陆',
              prop: 'current_login_time',
              align: 'center',
              minWidth: 180,
            },
            {
              key: 10,
              label: '操作',
              align: 'center',
              minWidth: 270,
              slot: 'options',
            },
          ],
        },
      },
    }
  },
}

/fundlist.vue

export default {
  name: 'Index',
  components: {
    TableAddQuery
  },
  data() {
    return {
      queryOptions: {
        showSearch: true,
        selectLists: {
          fundType: {
            placeholder: '全部类型',
            option: [
              {
                value: 0,
                name: 'shiftTo',
                label: '转入'
              },
              {
                value: 1,
                name: 'rollout',
                label: '转出'
              }
            ]
          },
          fundStatus: {
            placeholder: '订单状态',
            option: [
              {
                value: 0,
                name: 'new',
                label: '新建'
              },
              {
                value: 1,
                name: 'underway',
                label: '进行中'
              },
              {
                value: 2,
                name: 'completed',
                label: '已完成'
              },
              {
                value: 3,
                name: 'failed',
                label: '失败'
              }
            ]
          }
        },
        showDatePicker: true,
      },
      tableOptions: {
        total: 0,
        tableLists: [],
        tableListsOpt: {
          showIndex: true,
          content: [
            {
              key: 1,
              label: '订单编号',
              prop: 'id',
              align: 'center',
              minWidth: 140
            },
            {
              key: 2,
              label: '账户名称',
              prop: 'user',
              align: 'center',
              minWidth: 180
            },
            {
              key: 3,
              label: '订单类型',
              prop: 'type',
              align: 'center',
              minWidth: 180
            },
            {
              key: 4,
              label: '点数',
              prop: 'amount',
              align: 'center',
              minWidth: 180
            },
            {
              key: 5,
              label: '手续费',
              prop: 'fee',
              align: 'center',
              minWidth: 160
            },
            {
              key: 6,
              label: '状态',
              prop: 'status',
              align: 'center',
              minWidth: 140
            },
            {
              key: 7,
              label: '操作时间',
              prop: 'updated_time',
              align: 'center',
              minWidth: 180
            },
          ]
        }
      },
    }
  },
}

**

插槽代入

只需要在tableListsOpt.content里面配置slot属性就能使用具名插槽了,妙啊。**

<TableAddQuery :query-options="queryOptions" :table-options="tableOptions" @getList="getList">
    <template slot="status" slot-scope="{ row }">
      {{ row.status == 1?'正常':row.status == 2?'禁用':'' }}
    </template>
</TableAddQuery>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值