mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
feat: Add report on customer waiting time (#7545)
This commit is contained in:
@@ -20,7 +20,7 @@ class V2::ReportBuilder
|
||||
|
||||
# For backward compatible with old report
|
||||
def build
|
||||
if %w[avg_first_response_time avg_resolution_time].include?(params[:metric])
|
||||
if %w[avg_first_response_time avg_resolution_time reply_time].include?(params[:metric])
|
||||
timeseries.each_with_object([]) do |p, arr|
|
||||
arr << { value: p[1], timestamp: p[0].in_time_zone(@timezone).to_i, count: @grouped_values.count[p[0]] }
|
||||
end
|
||||
@@ -38,7 +38,8 @@ class V2::ReportBuilder
|
||||
outgoing_messages_count: outgoing_messages.count,
|
||||
avg_first_response_time: avg_first_response_time_summary,
|
||||
avg_resolution_time: avg_resolution_time_summary,
|
||||
resolutions_count: resolutions.count
|
||||
resolutions_count: resolutions.count,
|
||||
reply_time: reply_time_summary
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -56,6 +56,13 @@ module ReportHelper
|
||||
grouped_reporting_events.average(:value)
|
||||
end
|
||||
|
||||
def reply_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'reply_time', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
|
||||
grouped_reporting_events.average(:value)
|
||||
end
|
||||
|
||||
def avg_resolution_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
@@ -77,6 +84,16 @@ module ReportHelper
|
||||
avg_rt
|
||||
end
|
||||
|
||||
def reply_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'reply_time', account_id: account.id, created_at: range)
|
||||
reply_time = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if reply_time.blank?
|
||||
|
||||
reply_time
|
||||
end
|
||||
|
||||
def avg_first_response_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'first_response', account_id: account.id, created_at: range)
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
"RESOLUTION_COUNT": {
|
||||
"NAME": "Resolution Count",
|
||||
"DESC": "( Total )"
|
||||
},
|
||||
"REPLY_TIME": {
|
||||
"NAME": "Customer waiting time",
|
||||
"TOOLTIP_TEXT": "Waiting time is %{metricValue} (based on %{conversationCount} conversations)"
|
||||
}
|
||||
},
|
||||
"DATE_RANGE_OPTIONS": {
|
||||
|
||||
@@ -7,19 +7,13 @@ export default {
|
||||
accountSummary: 'getAccountSummary',
|
||||
accountReport: 'getAccountReports',
|
||||
}),
|
||||
calculateTrend() {
|
||||
return metric_key => {
|
||||
if (!this.accountSummary.previous[metric_key]) return 0;
|
||||
const diff =
|
||||
this.accountSummary[metric_key] -
|
||||
this.accountSummary.previous[metric_key];
|
||||
return Math.round(
|
||||
(diff / this.accountSummary.previous[metric_key]) * 100
|
||||
);
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
calculateTrend(key) {
|
||||
if (!this.accountSummary.previous[key]) return 0;
|
||||
const diff = this.accountSummary[key] - this.accountSummary.previous[key];
|
||||
return Math.round((diff / this.accountSummary.previous[key]) * 100);
|
||||
},
|
||||
displayMetric(key) {
|
||||
if (this.isAverageMetricType(key)) {
|
||||
return formatTime(this.accountSummary[key]);
|
||||
@@ -39,7 +33,11 @@ export default {
|
||||
return '';
|
||||
},
|
||||
isAverageMetricType(key) {
|
||||
return ['avg_first_response_time', 'avg_resolution_time'].includes(key);
|
||||
return [
|
||||
'avg_first_response_time',
|
||||
'avg_resolution_time',
|
||||
'reply_time',
|
||||
].includes(key);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@ const REPORTS_KEYS = {
|
||||
FIRST_RESPONSE_TIME: 'avg_first_response_time',
|
||||
RESOLUTION_TIME: 'avg_resolution_time',
|
||||
RESOLUTION_COUNT: 'resolutions_count',
|
||||
REPLY_TIME: 'reply_time',
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -78,6 +79,7 @@ export default {
|
||||
'FIRST_RESPONSE_TIME',
|
||||
'RESOLUTION_TIME',
|
||||
'RESOLUTION_COUNT',
|
||||
'REPLY_TIME',
|
||||
].forEach(async key => {
|
||||
try {
|
||||
await this.$store.dispatch('fetchAccountReport', {
|
||||
|
||||
@@ -44,6 +44,7 @@ const REPORTS_KEYS = {
|
||||
FIRST_RESPONSE_TIME: 'avg_first_response_time',
|
||||
RESOLUTION_TIME: 'avg_resolution_time',
|
||||
RESOLUTION_COUNT: 'resolutions_count',
|
||||
REPLY_TIME: 'reply_time',
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -60,6 +61,7 @@ export default {
|
||||
const reportKeys = [
|
||||
'CONVERSATIONS',
|
||||
'FIRST_RESPONSE_TIME',
|
||||
'REPLY_TIME',
|
||||
'RESOLUTION_TIME',
|
||||
'RESOLUTION_COUNT',
|
||||
'INCOMING_MESSAGES',
|
||||
|
||||
@@ -38,6 +38,7 @@ const REPORTS_KEYS = {
|
||||
FIRST_RESPONSE_TIME: 'avg_first_response_time',
|
||||
RESOLUTION_TIME: 'avg_resolution_time',
|
||||
RESOLUTION_COUNT: 'resolutions_count',
|
||||
REPLY_TIME: 'reply_time',
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -106,6 +107,7 @@ export default {
|
||||
'FIRST_RESPONSE_TIME',
|
||||
'RESOLUTION_TIME',
|
||||
'RESOLUTION_COUNT',
|
||||
'REPLY_TIME',
|
||||
].forEach(async key => {
|
||||
try {
|
||||
const { from, to, groupBy, businessHours } = this;
|
||||
|
||||
@@ -151,78 +151,48 @@ export const DEFAULT_CHART = {
|
||||
},
|
||||
};
|
||||
|
||||
const TIME_CHART_CONFIG = {
|
||||
datasets: [DEFAULT_BAR_CHART],
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
id: 'y-left',
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
callback: (value, index, values) => {
|
||||
if (!index || index === values.length - 1) {
|
||||
return formatTime(value);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const METRIC_CHART = {
|
||||
conversations_count: DEFAULT_CHART,
|
||||
incoming_messages_count: DEFAULT_CHART,
|
||||
outgoing_messages_count: DEFAULT_CHART,
|
||||
avg_first_response_time: {
|
||||
datasets: [DEFAULT_BAR_CHART],
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
id: 'y-left',
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
callback: (value, index, values) => {
|
||||
if (!index || index === values.length - 1) {
|
||||
return formatTime(value);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
avg_resolution_time: {
|
||||
datasets: [DEFAULT_BAR_CHART],
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
id: 'y-left',
|
||||
type: 'linear',
|
||||
position: 'left',
|
||||
ticks: {
|
||||
fontFamily: CHART_FONT_FAMILY,
|
||||
callback: (value, index, values) => {
|
||||
if (!index || index === values.length - 1) {
|
||||
return formatTime(value);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
gridLines: {
|
||||
drawOnChartArea: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
avg_first_response_time: TIME_CHART_CONFIG,
|
||||
reply_time: TIME_CHART_CONFIG,
|
||||
avg_resolution_time: TIME_CHART_CONFIG,
|
||||
resolutions_count: DEFAULT_CHART,
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ const state = {
|
||||
avg_first_response_time: false,
|
||||
avg_resolution_time: false,
|
||||
resolutions_count: false,
|
||||
reply_time: false,
|
||||
},
|
||||
data: {
|
||||
conversations_count: [],
|
||||
@@ -27,6 +28,7 @@ const state = {
|
||||
avg_first_response_time: [],
|
||||
avg_resolution_time: [],
|
||||
resolutions_count: [],
|
||||
reply_time: [],
|
||||
},
|
||||
},
|
||||
accountSummary: {
|
||||
@@ -35,6 +37,7 @@ const state = {
|
||||
conversations_count: 0,
|
||||
incoming_messages_count: 0,
|
||||
outgoing_messages_count: 0,
|
||||
reply_time: 0,
|
||||
resolutions_count: 0,
|
||||
previous: {},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user