Some dashboard calculation improvements.
This commit is contained in:
parent
7560efbe4c
commit
3561c3769d
9 changed files with 71 additions and 23 deletions
|
@ -12,10 +12,11 @@ class App.DashboardStats extends App.Controller
|
||||||
@bind('dashboard_stats_rebuild', @render)
|
@bind('dashboard_stats_rebuild', @render)
|
||||||
|
|
||||||
render: (data = {}) ->
|
render: (data = {}) ->
|
||||||
if !data.StatsTicketWaitingTime
|
if !data.TicketResponseTime
|
||||||
data.StatsTicketWaitingTime =
|
data.TicketResponseTime =
|
||||||
handling_time: 0
|
handling_time: 0
|
||||||
average: 0
|
average: 0
|
||||||
|
average_per_agent: 0
|
||||||
if !data.StatsTicketEscalation
|
if !data.StatsTicketEscalation
|
||||||
data.StatsTicketEscalation =
|
data.StatsTicketEscalation =
|
||||||
state: 'supergood'
|
state: 'supergood'
|
||||||
|
@ -45,22 +46,22 @@ class App.DashboardStats extends App.Controller
|
||||||
percent: 0
|
percent: 0
|
||||||
own: 0
|
own: 0
|
||||||
total: 0
|
total: 0
|
||||||
average: 0
|
average_per_agent: 0
|
||||||
if !data.StatsTicketInProcess
|
if !data.StatsTicketInProcess
|
||||||
data.StatsTicketInProcess =
|
data.StatsTicketInProcess =
|
||||||
state: 'supergood'
|
state: 'supergood'
|
||||||
percent: 0
|
percent: 0
|
||||||
average_percent: 0
|
average_per_agent: 0
|
||||||
if !data.StatsTicketReopen
|
if !data.StatsTicketReopen
|
||||||
data.StatsTicketReopen =
|
data.StatsTicketReopen =
|
||||||
state: 'supergood'
|
state: 'supergood'
|
||||||
percent: 0
|
percent: 0
|
||||||
average_percent: 0
|
average_per_agent: 0
|
||||||
|
|
||||||
@html App.view('dashboard/stats')(data)
|
@html App.view('dashboard/stats')(data)
|
||||||
|
|
||||||
if data.StatsTicketWaitingTime
|
if data.TicketResponseTime
|
||||||
@renderWidgetClockFace data.StatsTicketWaitingTime.handling_time
|
@renderWidgetClockFace data.TicketResponseTime.handling_time
|
||||||
|
|
||||||
renderWidgetClockFace: (time) =>
|
renderWidgetClockFace: (time) =>
|
||||||
canvas = @el.find 'canvas'
|
canvas = @el.find 'canvas'
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
<div class="stat-amount"></div>
|
<div class="stat-amount"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-label"><%- @T('My handling time: %s minutes', @StatsTicketWaitingTime.handling_time) %></div>
|
<div class="stat-label"><%- @T('My handling time: %s minutes', @TicketResponseTime.handling_time) %></div>
|
||||||
<div class="stat-detail"><%- @T('Average: %s minutes', @StatsTicketWaitingTime.average) %></div>
|
<div class="stat-detail"><%- @T('Average: %s minutes', @TicketResponseTime.average_per_agent) %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
<%- @Icon('total-tickets', 'total-tickets') %>
|
<%- @Icon('total-tickets', 'total-tickets') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-label"><%- @T('Tickets assigned to me: %s of %s', @StatsTicketLoadMeasure.own, @StatsTicketLoadMeasure.total) %></div>
|
<div class="stat-label"><%- @T('Tickets assigned to me: %s of %s', @StatsTicketLoadMeasure.own, @StatsTicketLoadMeasure.total) %></div>
|
||||||
<div class="stat-detail"><%- @T('Average: %s', @StatsTicketLoadMeasure.average) %></div>
|
<div class="stat-detail"><%- @T('Average: %s', @StatsTicketLoadMeasure.average_per_agent) %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
<%- @Icon('in-process', "in-process-icon state-color #{@StatsTicketInProcess.state}-state") %>
|
<%- @Icon('in-process', "in-process-icon state-color #{@StatsTicketInProcess.state}-state") %>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-label" title="<%- @T('%s of your Tickets are currently in process.', @StatsTicketInProcess.in_process) %>"><%- @T('%s% are currently in process', @StatsTicketInProcess.percent) %></div>
|
<div class="stat-label" title="<%- @T('%s of your Tickets are currently in process.', @StatsTicketInProcess.in_process) %>"><%- @T('%s% are currently in process', @StatsTicketInProcess.percent) %></div>
|
||||||
<div class="stat-detail"><%- @T('Average: %s%', @StatsTicketInProcess.average_percent) %></div>
|
<div class="stat-detail"><%- @T('Average: %s%', @StatsTicketInProcess.average_per_agent) %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
@ -72,6 +72,6 @@
|
||||||
<%- @Icon('reopening', "reopening-icon state-color #{@StatsTicketReopen.state}-state") %>
|
<%- @Icon('reopening', "reopening-icon state-color #{@StatsTicketReopen.state}-state") %>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-label"><%- @T('%s% are being reopened', @StatsTicketReopen.percent) %></div>
|
<div class="stat-label"><%- @T('%s% are being reopened', @StatsTicketReopen.percent) %></div>
|
||||||
<div class="stat-detail"><%- @T('Average: %s%', @StatsTicketReopen.average_percent) %></div>
|
<div class="stat-detail"><%- @T('Average: %s%', @StatsTicketReopen.average_per_agent) %></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -9,7 +9,7 @@ class Ticket::State < ApplicationModel
|
||||||
|
|
||||||
list tickets by customer
|
list tickets by customer
|
||||||
|
|
||||||
states = Ticket::State.by_category('open') # open|closed|work_on|pending_reminder
|
states = Ticket::State.by_category('open') # open|closed|work_on|work_on_all|pending_reminder
|
||||||
|
|
||||||
returns:
|
returns:
|
||||||
|
|
||||||
|
@ -30,6 +30,10 @@ returns:
|
||||||
return Ticket::State.where(
|
return Ticket::State.where(
|
||||||
state_type_id: Ticket::StateType.where( name: ['new', 'open'] )
|
state_type_id: Ticket::StateType.where( name: ['new', 'open'] )
|
||||||
)
|
)
|
||||||
|
elsif category == 'work_on_all'
|
||||||
|
return Ticket::State.where(
|
||||||
|
state_type_id: Ticket::StateType.where( name: ['new', 'open', 'pending reminder'] )
|
||||||
|
)
|
||||||
elsif category == 'closed'
|
elsif category == 'closed'
|
||||||
return Ticket::State.where(
|
return Ticket::State.where(
|
||||||
state_type_id: Ticket::StateType.where( name: ['closed'] )
|
state_type_id: Ticket::StateType.where( name: ['closed'] )
|
||||||
|
|
36
lib/stats.rb
36
lib/stats.rb
|
@ -26,20 +26,54 @@ returns
|
||||||
Stats::TicketReopen,
|
Stats::TicketReopen,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# generate stats per agent
|
||||||
users = User.of_role('Agent')
|
users = User.of_role('Agent')
|
||||||
|
agent_count = 0
|
||||||
|
user_result = {}
|
||||||
users.each {|user|
|
users.each {|user|
|
||||||
next if user.id == 1
|
next if user.id == 1
|
||||||
|
next if !user.active
|
||||||
|
agent_count += 1
|
||||||
data = {}
|
data = {}
|
||||||
backends.each {|backend|
|
backends.each {|backend|
|
||||||
data[backend.to_app_model] = backend.generate(user)
|
data[backend.to_app_model] = backend.generate(user)
|
||||||
}
|
}
|
||||||
|
user_result[user.id] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate average
|
||||||
|
backend_average_sum = {}
|
||||||
|
user_result.each {|user_id, data|
|
||||||
|
data.each {|backend_model, backend_result|
|
||||||
|
next if !backend_result.has_key?(:used_for_average)
|
||||||
|
if !backend_average_sum[backend_model]
|
||||||
|
backend_average_sum[backend_model] = 0
|
||||||
|
end
|
||||||
|
backend_average_sum[backend_model] += backend_result[:used_for_average]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate average stats
|
||||||
|
backend_average_sum.each {|backend_model_average, result|
|
||||||
|
average = ( result.to_f / agent_count.to_f ).round(1)
|
||||||
|
user_result.each {|user_id, data|
|
||||||
|
data.each {|backend_model_data, backend_result|
|
||||||
|
next if backend_model_data != backend_model_average
|
||||||
|
next if !backend_result.has_key?(:used_for_average)
|
||||||
|
backend_result[:average_per_agent] = average
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_result.each {|user_id, data|
|
||||||
StatsStore.sync(
|
StatsStore.sync(
|
||||||
object: 'User',
|
object: 'User',
|
||||||
o_id: user.id,
|
o_id: user_id,
|
||||||
key: 'dashboard',
|
key: 'dashboard',
|
||||||
data: data,
|
data: data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,9 @@ class Stats::TicketEscalation
|
||||||
end
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
|
used_for_average: own_escalated,
|
||||||
|
average_per_agent: average,
|
||||||
state: state,
|
state: state,
|
||||||
average: average,
|
|
||||||
own: own_escalated,
|
own: own_escalated,
|
||||||
total: all_escalated,
|
total: all_escalated,
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,11 @@ class Stats::TicketInProcess
|
||||||
end
|
end
|
||||||
|
|
||||||
{
|
{
|
||||||
|
used_for_average: in_process_precent,
|
||||||
|
average_per_agent: average_in_percent,
|
||||||
state: state,
|
state: state,
|
||||||
in_process: count,
|
in_process: count,
|
||||||
percent: in_process_precent,
|
percent: in_process_precent,
|
||||||
average_percent: average_in_percent,
|
|
||||||
total: total,
|
total: total,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Stats::TicketLoadMeasure
|
||||||
|
|
||||||
def self.generate(user)
|
def self.generate(user)
|
||||||
|
|
||||||
open_state_ids = Ticket::State.by_category('open').map(&:id)
|
open_state_ids = Ticket::State.by_category('work_on_all').map(&:id)
|
||||||
|
|
||||||
# owned tickets
|
# owned tickets
|
||||||
count = Ticket.where(owner_id: user.id, state_id: open_state_ids).count
|
count = Ticket.where(owner_id: user.id, state_id: open_state_ids).count
|
||||||
|
@ -31,11 +31,12 @@ class Stats::TicketLoadMeasure
|
||||||
total = count
|
total = count
|
||||||
end
|
end
|
||||||
|
|
||||||
if count != 0 && total != 0
|
if total != 0
|
||||||
load_measure_precent = (count * 1000) / ((total * 1000) / 100)
|
load_measure_precent = (count * 1000) / ((total * 1000) / 100)
|
||||||
end
|
end
|
||||||
{
|
{
|
||||||
average: average,
|
used_for_average: load_measure_precent,
|
||||||
|
average_per_agent: average,
|
||||||
percent: load_measure_precent,
|
percent: load_measure_precent,
|
||||||
state: state,
|
state: state,
|
||||||
own: count,
|
own: count,
|
||||||
|
|
|
@ -11,11 +11,12 @@ class Stats::TicketReopen
|
||||||
end: Time.zone.now,
|
end: Time.zone.now,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
used_for_average: 0,
|
||||||
|
average_per_agent: '',
|
||||||
state: 'good',
|
state: 'good',
|
||||||
own: count,
|
own: count,
|
||||||
total: 0,
|
total: 0,
|
||||||
percent: 0,
|
percent: 0,
|
||||||
average_percent: '-',
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ class Stats::TicketResponseTime
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.generate(user)
|
def self.generate(user)
|
||||||
items = Stats.where('action_at > ? AND action_at < ?', Time.zone.now - 7.days, Time.zone.now).where(key: 'ticket:response_time')
|
items = StatsStore.where('created_at > ? AND created_at < ?', Time.zone.now - 7.days, Time.zone.now).where(key: 'ticket:response_time')
|
||||||
count_total = items.count
|
count_total = items.count
|
||||||
total = 0
|
total = 0
|
||||||
count_own = 0
|
count_own = 0
|
||||||
|
@ -35,9 +35,14 @@ class Stats::TicketResponseTime
|
||||||
end
|
end
|
||||||
total += data[:time]
|
total += data[:time]
|
||||||
}
|
}
|
||||||
|
if total != 0
|
||||||
|
own = (own / count_own).round
|
||||||
|
end
|
||||||
{
|
{
|
||||||
own: (own / count_own).round,
|
used_for_average: 0,
|
||||||
total: (total / count_total).round,
|
average_per_agent: '-',
|
||||||
|
own: own,
|
||||||
|
total: total,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue