控件结构
/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>