Change-Id: I15e9d100233408fbfe82cbb916c7d2fb76a311f8mr12.0
parent
8e7c0ad2b2
commit
177f01d535
@ -0,0 +1,313 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="row justify-center full-width q-gutter-x-sm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="col-xs-12 col-md-3"
|
||||||
|
>
|
||||||
|
<q-select
|
||||||
|
v-model="filterTypeModel"
|
||||||
|
dense
|
||||||
|
:options="filterTypeOptions"
|
||||||
|
:label="$t('Filter by')"
|
||||||
|
data-cy="csc-cdr-filter"
|
||||||
|
:disable="loading"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="filterType === 'timerange'"
|
||||||
|
class="row col-xs-12 col-md-6"
|
||||||
|
>
|
||||||
|
<q-input
|
||||||
|
v-model="dateStartFilter"
|
||||||
|
class="q-pr-sm col-6"
|
||||||
|
dense
|
||||||
|
:disable="loading || filterType === null"
|
||||||
|
:label="$t('From')"
|
||||||
|
data-cy="csc-cdr-filter-from"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon
|
||||||
|
name="event"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="loadFormattedDateStart()"
|
||||||
|
>
|
||||||
|
<q-popup-proxy
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
@hide="addFilter('startTime', dateStartFilter)"
|
||||||
|
>
|
||||||
|
<q-date
|
||||||
|
v-model="dateStartFilter"
|
||||||
|
mask="YYYY-MM-DD"
|
||||||
|
format24h
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn
|
||||||
|
v-close-popup
|
||||||
|
:label="$t('Close')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-date>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-input
|
||||||
|
v-model="dateEndFilter"
|
||||||
|
class="col-6"
|
||||||
|
dense
|
||||||
|
:disable="loading || filterType === null"
|
||||||
|
:label="$t('To')"
|
||||||
|
data-cy="csc-cdr-filter-to"
|
||||||
|
@input="triggerFilter"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<q-icon
|
||||||
|
name="event"
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="loadFormattedDateEnd()"
|
||||||
|
>
|
||||||
|
<q-popup-proxy
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="scale"
|
||||||
|
@hide="addFilter('endTime', dateEndFilter)"
|
||||||
|
>
|
||||||
|
<q-date
|
||||||
|
v-model="dateEndFilter"
|
||||||
|
mask="YYYY-MM-DD"
|
||||||
|
>
|
||||||
|
<div class="row items-center justify-end">
|
||||||
|
<q-btn
|
||||||
|
v-close-popup
|
||||||
|
:label="$t('Close')"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-date>
|
||||||
|
</q-popup-proxy>
|
||||||
|
</q-icon>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="false"
|
||||||
|
class="row col-xs-12 col-md-3"
|
||||||
|
>
|
||||||
|
<q-select
|
||||||
|
v-model="filterDirection"
|
||||||
|
class="full-width"
|
||||||
|
dense
|
||||||
|
:options="filterDirectionOptions"
|
||||||
|
:label="$t('In/Out')"
|
||||||
|
data-cy="csc-cdr-filter"
|
||||||
|
:disable="loading"
|
||||||
|
@update:model-value="triggerDirectionFilter"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="filterType === 'type'"
|
||||||
|
class="row col-xs-12 col-md-3"
|
||||||
|
>
|
||||||
|
<q-select
|
||||||
|
v-model="filterTypeField"
|
||||||
|
class="full-width"
|
||||||
|
dense
|
||||||
|
:options="filterTypeFieldOptions"
|
||||||
|
:label="$t('Type')"
|
||||||
|
data-cy="csc-cdr-filter"
|
||||||
|
:disable="loading"
|
||||||
|
@update:model-value="triggerTypeFieldFilter"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="row justify-center full-width q-gutter-x-sm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="col-xs-12 col-md-4"
|
||||||
|
>
|
||||||
|
<q-chip
|
||||||
|
v-for="({ filterInfo, id }) in filtersList"
|
||||||
|
:key="id"
|
||||||
|
:label="filterInfo"
|
||||||
|
:disable="false"
|
||||||
|
icon="filter_alt"
|
||||||
|
removable
|
||||||
|
dense
|
||||||
|
color="primary"
|
||||||
|
text-color="dark"
|
||||||
|
@remove="removeFilter(id)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CscCdrFilters',
|
||||||
|
props: {
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['filter'],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
filterTypeModel: null,
|
||||||
|
filterDirection: null,
|
||||||
|
filterTypeField: null,
|
||||||
|
dateStartFilter: null,
|
||||||
|
dateEndFilter: null,
|
||||||
|
filters: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters([
|
||||||
|
'getCurrentFormattedDateWithDash'
|
||||||
|
]),
|
||||||
|
filterType () {
|
||||||
|
return this.filterTypeModel && this.filterTypeModel.value
|
||||||
|
},
|
||||||
|
filterTypeOptions () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.$t('Timerange'),
|
||||||
|
value: 'timerange'
|
||||||
|
},
|
||||||
|
/* {
|
||||||
|
label: this.$t('Direction'),
|
||||||
|
value: 'direction'
|
||||||
|
}, */
|
||||||
|
{
|
||||||
|
label: this.$t('Type'),
|
||||||
|
value: 'type'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
filterDirectionOptions () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.$t('In'),
|
||||||
|
value: 'in'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Out'),
|
||||||
|
value: 'out'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
filterTypeFieldOptions () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: this.$t('Call'),
|
||||||
|
value: 'call'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Voicemail'),
|
||||||
|
value: 'voicemail'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Sms'),
|
||||||
|
value: 'sms'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.$t('Fax'),
|
||||||
|
value: 'fax'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
filtersList () {
|
||||||
|
return this.filters.map((filterItem) => {
|
||||||
|
const filterDisplayValue = filterItem.value
|
||||||
|
let filterName
|
||||||
|
switch (filterItem.name) {
|
||||||
|
case 'startTime':
|
||||||
|
filterName = this.$t('Start time')
|
||||||
|
break
|
||||||
|
case 'endTime' :
|
||||||
|
filterName = this.$t('End time')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
filterName = this.filterTypeOptions.find(option => option.value === filterItem.name).label
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: filterItem.name,
|
||||||
|
filterInfo: filterName + ': ' + filterDisplayValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
filterTypeModel () {
|
||||||
|
this.resetFilters()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
triggerDirectionFilter () {
|
||||||
|
this.addFilter(this.filterTypeModel?.value, this.filterDirection.value)
|
||||||
|
},
|
||||||
|
triggerTypeFieldFilter () {
|
||||||
|
this.addFilter(this.filterTypeModel?.value, this.filterTypeField.value)
|
||||||
|
},
|
||||||
|
removeFilter (name) {
|
||||||
|
this.filters = this.filters.filter(item => item.name !== name)
|
||||||
|
this.filter()
|
||||||
|
},
|
||||||
|
removeFilters () {
|
||||||
|
if (this.filters.length > 0) {
|
||||||
|
this.filters = []
|
||||||
|
this.filter()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addFilter (name, value) {
|
||||||
|
const valueTrimmed = _.trim(value)
|
||||||
|
if (valueTrimmed) {
|
||||||
|
this.resetFilters()
|
||||||
|
this.filters = this.filters.filter(item => item.name !== name)
|
||||||
|
const filter = {
|
||||||
|
name: name,
|
||||||
|
value: valueTrimmed
|
||||||
|
}
|
||||||
|
this.filters.push(filter)
|
||||||
|
this.filter()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filter () {
|
||||||
|
const params = {}
|
||||||
|
this.filters.forEach(filter => {
|
||||||
|
params[filter.name] = filter.value
|
||||||
|
})
|
||||||
|
this.$emit('filter', params)
|
||||||
|
},
|
||||||
|
resetFilters () {
|
||||||
|
this.typedFilter = null
|
||||||
|
this.dateStartFilter = null
|
||||||
|
this.dateEndFilter = null
|
||||||
|
this.filterDirection = null
|
||||||
|
this.filterTypeField = null
|
||||||
|
},
|
||||||
|
loadFormattedDateStart () {
|
||||||
|
const currentDate = this.getCurrentFormattedDateWithDash
|
||||||
|
if (!this.dateStartFilter) {
|
||||||
|
this.dateStartFilter = currentDate
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadFormattedDateEnd () {
|
||||||
|
const currentDate = this.getCurrentFormattedDateWithDash
|
||||||
|
if (!this.dateEndFilter) {
|
||||||
|
this.dateEndFilter = currentDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,221 @@
|
|||||||
|
<!-- eslint-disable vue/no-v-model-argument -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<csc-page-sticky
|
||||||
|
id="csc-page-pbx-statistics-cdr"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
#header
|
||||||
|
>
|
||||||
|
<q-btn
|
||||||
|
v-if="!showFilters"
|
||||||
|
icon="filter_alt"
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
:label="$t('Filter')"
|
||||||
|
@click="openFilters"
|
||||||
|
/>
|
||||||
|
<q-btn
|
||||||
|
v-if="showFilters"
|
||||||
|
icon="clear"
|
||||||
|
color="negative"
|
||||||
|
flat
|
||||||
|
:label="$t('Close filters')"
|
||||||
|
@click="closeFilters"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template
|
||||||
|
#toolbar
|
||||||
|
>
|
||||||
|
<csc-cdr-filters
|
||||||
|
v-if="showFilters"
|
||||||
|
ref="filters"
|
||||||
|
:loading="$wait.is('loadConversations')"
|
||||||
|
class="q-mb-md q-pa-md"
|
||||||
|
@filter="filterEvent"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<div class="q-pa-md">
|
||||||
|
<q-table
|
||||||
|
v-model:pagination="pagination"
|
||||||
|
class="no-shadow"
|
||||||
|
:columns="columns"
|
||||||
|
:rows="conversations"
|
||||||
|
:loading="$wait.is('loadConversations')"
|
||||||
|
row-key="id"
|
||||||
|
@request="fetchPaginatedConversations"
|
||||||
|
>
|
||||||
|
<template #loading>
|
||||||
|
<q-inner-loading
|
||||||
|
showing
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<csc-spinner />
|
||||||
|
</q-inner-loading>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #top-left>
|
||||||
|
<q-btn
|
||||||
|
icon="refresh"
|
||||||
|
size="sm"
|
||||||
|
flat
|
||||||
|
@click="refresh"
|
||||||
|
>
|
||||||
|
{{ $t('Refresh') }}
|
||||||
|
</q-btn>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</csc-page-sticky>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
import CscPageSticky from 'components/CscPageSticky'
|
||||||
|
import { mapWaitingActions } from 'vue-wait'
|
||||||
|
import CscSpinner from 'components/CscSpinner'
|
||||||
|
import { LIST_DEFAULT_ROWS } from 'src/api/common'
|
||||||
|
import CscCdrFilters from 'components/pages/PbxStatistics/CscCdrFilters'
|
||||||
|
|
||||||
|
import _ from 'lodash'
|
||||||
|
export default {
|
||||||
|
name: 'CscPagePbxStatisticsCdr',
|
||||||
|
components: {
|
||||||
|
CscSpinner,
|
||||||
|
CscPageSticky,
|
||||||
|
CscCdrFilters
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
pagination: {
|
||||||
|
sortBy: 'timestamp',
|
||||||
|
descending: true,
|
||||||
|
page: 1,
|
||||||
|
rowsPerPage: LIST_DEFAULT_ROWS,
|
||||||
|
rowsNumber: 0
|
||||||
|
},
|
||||||
|
showFilters: false,
|
||||||
|
filter: {
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
caller: null,
|
||||||
|
callee: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState('conversations', [
|
||||||
|
'conversations'
|
||||||
|
]),
|
||||||
|
columns () {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'start_time',
|
||||||
|
required: true,
|
||||||
|
label: this.$t('Start time'),
|
||||||
|
align: 'left',
|
||||||
|
field: row => this.$filters.smartTime(row.start_time),
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'type',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Type'),
|
||||||
|
field: row => _.capitalize(row.type),
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'caller',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Caller'),
|
||||||
|
field: row => row.caller,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'callee',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Callee'),
|
||||||
|
field: row => row.callee,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'direction',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Direction'),
|
||||||
|
field: row => row.direction,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'duration',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Duration'),
|
||||||
|
field: row => row.duration,
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'status',
|
||||||
|
required: true,
|
||||||
|
align: 'left',
|
||||||
|
label: this.$t('Status'),
|
||||||
|
field: row => row.status,
|
||||||
|
sortable: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
await this.refresh()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapWaitingActions('conversations', {
|
||||||
|
loadConversations: 'loadConversations'
|
||||||
|
}),
|
||||||
|
async refresh () {
|
||||||
|
await this.fetchPaginatedConversations({
|
||||||
|
pagination: this.pagination
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async fetchPaginatedConversations (props) {
|
||||||
|
const { page, rowsPerPage, sortBy, descending } = props.pagination
|
||||||
|
const { startTime, endTime, direction, type } = this.filter
|
||||||
|
const count = await this.loadConversations({
|
||||||
|
page,
|
||||||
|
rows: rowsPerPage,
|
||||||
|
order_by: sortBy,
|
||||||
|
order_by_direction: descending ? 'desc' : 'asc',
|
||||||
|
from: startTime,
|
||||||
|
to: endTime,
|
||||||
|
direction: direction,
|
||||||
|
type: type
|
||||||
|
})
|
||||||
|
this.pagination = { ...props.pagination }
|
||||||
|
this.pagination.rowsNumber = count
|
||||||
|
},
|
||||||
|
openFilters () {
|
||||||
|
this.showFilters = true
|
||||||
|
},
|
||||||
|
closeFilters () {
|
||||||
|
if (this.$refs.filters) {
|
||||||
|
this.$refs.filters.removeFilters()
|
||||||
|
}
|
||||||
|
this.showFilters = false
|
||||||
|
},
|
||||||
|
filterEvent (filter) {
|
||||||
|
this.$scrollTo(this.$parent.$el)
|
||||||
|
console.log(filter)
|
||||||
|
this.filter = filter
|
||||||
|
this.fetchPaginatedConversations({
|
||||||
|
pagination: this.pagination
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in new issue