2019-10-06 05:49:22 +00:00
|
|
|
<template>
|
2019-10-06 09:16:25 +00:00
|
|
|
<div>
|
2019-10-07 03:14:54 +00:00
|
|
|
<div class="d-flex align-items-center mb-2" v-if="showToolbar">
|
|
|
|
<div class="flex-fill">
|
2019-10-06 11:14:27 +00:00
|
|
|
<b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage"
|
2019-10-07 03:14:54 +00:00
|
|
|
class="mb-0" v-if="showPagination">
|
2019-10-06 11:14:27 +00:00
|
|
|
</b-pagination>
|
2019-10-07 03:14:54 +00:00
|
|
|
</div>
|
|
|
|
<div class="flex-shrink-1 pl-3">
|
2019-10-06 11:14:27 +00:00
|
|
|
<div class="input-group">
|
|
|
|
<span class="icon glyphicon input-group-addon search"></span>
|
|
|
|
<input type="text" v-model="filter" class="search-field form-control" placeholder="Search">
|
2019-10-06 05:49:22 +00:00
|
|
|
</div>
|
2019-10-07 03:14:54 +00:00
|
|
|
</div>
|
|
|
|
<div class="flex-shrink-1 pl-3 pr-3">
|
2019-10-06 09:16:25 +00:00
|
|
|
<div class="actions btn-group">
|
2019-10-07 02:13:19 +00:00
|
|
|
<button class="btn btn-default" type="button" title="Refresh"
|
|
|
|
@click.stop.prevent="onClickRefresh">
|
2019-10-06 09:16:25 +00:00
|
|
|
<i class="material-icons">refresh</i>
|
2019-10-06 05:49:22 +00:00
|
|
|
</button>
|
2019-10-07 02:13:19 +00:00
|
|
|
<div class="dropdown btn-group" v-if="paginated">
|
2019-10-06 09:16:25 +00:00
|
|
|
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
|
|
|
|
<span class="dropdown-text">{{ perPageLabel }}</span>
|
|
|
|
<span class="caret"></span>
|
|
|
|
</button>
|
|
|
|
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
|
|
|
<li v-for="pageOption in pageOptions" :class="{ active: (pageOption === perPage) }">
|
|
|
|
<a href="#" @click.prevent="setPerPage(pageOption)"
|
|
|
|
class="dropdown-item dropdown-item-button">
|
|
|
|
{{ getPerPageLabel(pageOption) }}
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
2019-10-06 05:49:22 +00:00
|
|
|
</div>
|
2019-10-07 03:14:54 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2019-10-06 05:49:22 +00:00
|
|
|
|
2019-10-06 11:14:27 +00:00
|
|
|
<b-table ref="table" show-empty striped hover :selectable="selectable" :api-url="apiUrl" :per-page="perPage"
|
2019-10-06 09:16:25 +00:00
|
|
|
:current-page="currentPage" @row-selected="onRowSelected" :items="loadItems" :fields="fields"
|
2019-10-06 11:14:27 +00:00
|
|
|
tbody-tr-class="align-middle" selected-variant=""
|
|
|
|
:filter="filter" :filter-debounce="200" @filtered="onFiltered">
|
2019-10-06 09:16:25 +00:00
|
|
|
<template v-slot:cell(selected)="{ rowSelected }">
|
2019-10-07 02:13:19 +00:00
|
|
|
<div class="custom-control custom-checkbox pl-0">
|
|
|
|
<input type="checkbox" class="custom-control-input position-static" :checked="rowSelected">
|
|
|
|
<label class="custom-control-label"></label>
|
2019-10-06 11:14:27 +00:00
|
|
|
</div>
|
2019-10-06 05:49:22 +00:00
|
|
|
</template>
|
2019-10-06 09:16:25 +00:00
|
|
|
<slot v-for="(_, name) in $slots" :name="name" :slot="name"/>
|
|
|
|
<template v-for="(_, name) in $scopedSlots" :slot="name" slot-scope="slotData">
|
|
|
|
<slot :name="name" v-bind="slotData"/>
|
2019-10-06 05:49:22 +00:00
|
|
|
</template>
|
2019-10-06 09:16:25 +00:00
|
|
|
</b-table>
|
2019-10-06 05:49:22 +00:00
|
|
|
|
2019-10-06 11:14:27 +00:00
|
|
|
<b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage"
|
2019-10-07 03:14:54 +00:00
|
|
|
class="mb-0 mt-2" v-if="showPagination">
|
2019-10-06 11:14:27 +00:00
|
|
|
</b-pagination>
|
2019-10-06 09:16:25 +00:00
|
|
|
</div>
|
2019-10-06 05:49:22 +00:00
|
|
|
</template>
|
|
|
|
|
2019-10-07 02:13:19 +00:00
|
|
|
<style lang="scss">
|
|
|
|
table.b-table-selectable {
|
|
|
|
tr > td:nth-child(1) {
|
|
|
|
padding-right: 0.75rem;
|
|
|
|
}
|
|
|
|
|
|
|
|
tr > td:nth-child(2) {
|
|
|
|
padding-left: 0.5rem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2019-10-06 05:49:22 +00:00
|
|
|
<script>
|
|
|
|
import axios from 'axios'
|
|
|
|
import store from 'store'
|
2019-10-07 02:13:19 +00:00
|
|
|
|
2019-10-06 09:16:25 +00:00
|
|
|
// import Vue from 'vue'
|
|
|
|
// import { LayoutPlugin, PaginationPlugin, TablePlugin } from 'bootstrap-vue'
|
2019-10-06 05:49:22 +00:00
|
|
|
|
2019-10-06 09:16:25 +00:00
|
|
|
/*
|
2019-10-06 05:49:22 +00:00
|
|
|
Vue.use(LayoutPlugin)
|
|
|
|
Vue.use(TablePlugin)
|
|
|
|
Vue.use(PaginationPlugin)
|
2019-10-06 09:16:25 +00:00
|
|
|
*/
|
2019-10-06 05:49:22 +00:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'DataTable',
|
|
|
|
props: {
|
|
|
|
id: String,
|
|
|
|
apiUrl: String,
|
2019-10-07 02:13:19 +00:00
|
|
|
paginated: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
showToolbar: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
|
|
|
},
|
2019-10-06 11:14:27 +00:00
|
|
|
defaultPerPage: {
|
|
|
|
type: Number,
|
|
|
|
default: 10
|
|
|
|
},
|
2019-10-06 05:49:22 +00:00
|
|
|
fields: Array,
|
2019-10-06 11:14:27 +00:00
|
|
|
selectable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
2019-10-06 05:49:22 +00:00
|
|
|
requestConfig: Function,
|
|
|
|
requestProcess: Function
|
|
|
|
},
|
|
|
|
data () {
|
|
|
|
return {
|
2019-10-07 02:13:19 +00:00
|
|
|
selected: [],
|
|
|
|
storeKey: 'datatable_' + this.id + '_perpage',
|
2019-10-06 05:49:22 +00:00
|
|
|
filter: null,
|
2019-10-07 02:13:19 +00:00
|
|
|
perPage: (this.paginated) ? this.defaultPerPage : 0,
|
2019-10-07 03:14:54 +00:00
|
|
|
pageOptions: [10, 25, 50, 0],
|
2019-10-06 05:49:22 +00:00
|
|
|
currentPage: 1,
|
|
|
|
totalRows: 0,
|
|
|
|
flushCache: false
|
|
|
|
}
|
|
|
|
},
|
2019-10-07 02:13:19 +00:00
|
|
|
mounted () {
|
|
|
|
if (store.enabled && store.get(this.storeKey) !== undefined) {
|
|
|
|
this.perPage = store.get(this.storeKey)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
perPage (newPerPage, oldPerPage) {
|
|
|
|
store.set(this.storeKey, newPerPage)
|
2019-10-06 05:49:22 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2019-10-07 03:14:54 +00:00
|
|
|
showPagination () {
|
|
|
|
return this.paginated && this.perPage !== 0
|
|
|
|
},
|
2019-10-06 05:49:22 +00:00
|
|
|
perPageLabel () {
|
|
|
|
return this.getPerPageLabel(this.perPage)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
getPerPageLabel (num) {
|
2019-10-07 03:14:54 +00:00
|
|
|
return (num === 0) ? 'All' : num
|
2019-10-06 05:49:22 +00:00
|
|
|
},
|
|
|
|
setPerPage (num) {
|
|
|
|
this.perPage = num
|
|
|
|
},
|
2019-10-07 02:13:19 +00:00
|
|
|
onClickRefresh (e) {
|
|
|
|
if (e.shiftKey) {
|
|
|
|
this.list()
|
|
|
|
} else {
|
|
|
|
this.refresh()
|
|
|
|
}
|
|
|
|
},
|
2019-10-06 05:49:22 +00:00
|
|
|
refresh () {
|
|
|
|
this.$refs.table.refresh()
|
|
|
|
},
|
|
|
|
list () {
|
|
|
|
this.filter = null
|
|
|
|
this.currentPage = 1
|
|
|
|
this.flushCache = true
|
|
|
|
this.refresh()
|
|
|
|
},
|
2019-10-06 11:14:27 +00:00
|
|
|
setFilter (newTerm) {
|
2019-10-06 05:49:22 +00:00
|
|
|
this.filter = newTerm
|
|
|
|
},
|
|
|
|
loadItems (ctx, callback) {
|
2019-10-07 02:13:19 +00:00
|
|
|
let queryParams = {}
|
|
|
|
|
|
|
|
if (this.paginated) {
|
|
|
|
queryParams.rowCount = ctx.perPage
|
|
|
|
queryParams.current = ctx.currentPage
|
2019-10-06 05:49:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.flushCache) {
|
2019-10-07 02:13:19 +00:00
|
|
|
queryParams.flushCache = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof ctx.filter === 'string') {
|
|
|
|
queryParams.searchPhrase = ctx.filter
|
2019-10-06 05:49:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ('' !== ctx.sortBy) {
|
2019-10-07 03:14:54 +00:00
|
|
|
queryParams.sort = ctx.sortBy
|
|
|
|
queryParams.sortOrder = (ctx.sortDesc) ? 'DESC' : 'ASC'
|
2019-10-06 05:49:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let requestConfig = { params: queryParams }
|
|
|
|
if (typeof this.requestConfig === 'function') {
|
|
|
|
requestConfig = this.requestConfig(requestConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
axios.get(ctx.apiUrl, requestConfig).then((resp) => {
|
|
|
|
this.flushCache = false
|
|
|
|
this.totalRows = resp.data.total
|
|
|
|
|
|
|
|
let rows = resp.data.rows
|
|
|
|
if (typeof this.requestProcess === 'function') {
|
|
|
|
rows = this.requestProcess(rows)
|
|
|
|
}
|
|
|
|
|
|
|
|
callback(rows)
|
|
|
|
}).catch((err) => {
|
|
|
|
this.flushCache = false
|
|
|
|
this.totalRows = 0
|
|
|
|
|
|
|
|
console.error(err.data.message)
|
|
|
|
callback([])
|
|
|
|
})
|
|
|
|
},
|
|
|
|
onRowSelected (items) {
|
|
|
|
this.selected = items
|
|
|
|
this.$emit('row-selected', items)
|
2019-10-06 09:16:16 +00:00
|
|
|
},
|
|
|
|
onFiltered (filter) {
|
|
|
|
this.$emit('filtered', filter)
|
2019-10-06 05:49:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|