Browse Source

Relatorio atendimentos abandonados

Felipe
Felipe Fontana 10 months ago
parent
commit
a2575df2f8
  1. 13
      app/Helpers/Helper.php
  2. 6
      app/Http/Controllers/Admin/DashboardController.php
  3. 49
      app/Http/Controllers/Admin/Relatorios/RelatorioAtendimentosAbandonadosController.php
  4. 8
      app/Models/Agentes.php
  5. 60
      app/Models/Atendimentos.php
  6. 6
      app/Models/Filas.php
  7. 2
      resources/views/admin/cadastros/channels.blade.php
  8. 100
      resources/views/admin/relatorios/abandonAtendimentos/abandonAtendimentos.blade.php
  9. 12
      resources/views/layouts/menu.blade.php
  10. 3
      routes/web.php

13
app/Helpers/Helper.php

@ -36,6 +36,19 @@ class Helper
return $id_empresa;
}
public static function getEmpresas()
{
$user = auth()->user();
$empresas = $user->empresa;
if ($empresas->count() > 1) {
return $empresas;
} else {
$empresa = Helper::getIdEmpresa();
return $empresa;
}
}
public static function Crypt()
{
return new Crypt('aes-256-cbc', config('constants.PASSWORD'));

6
app/Http/Controllers/Admin/DashboardController.php

@ -101,7 +101,7 @@ class DashboardController extends Controller
SUM(CASE WHEN evento = 'EMESPERA' THEN 1 ELSE 0 END) AS em_espera,
SUM(CASE WHEN evento = 'START' THEN 1 ELSE 0 END) AS iniciadas,
SUM(CASE WHEN evento = 'SENDED' THEN 1 ELSE 0 END) AS enviados,
SUM(CASE WHEN evento IN ('COMPLETE_AGENT','COMPLETE_CALLER') THEN 1 ELSE 0 END) AS finalizadas,
SUM(CASE WHEN evento IN ('COMPLETE_AGENT','COMPLETE_CALLER','TIMEOUT_CALLER') THEN 1 ELSE 0 END) AS finalizadas,
SUM(CASE WHEN evento = 'ABANDON' THEN 1 ELSE 0 END) AS abandonadas,
SUM(CASE WHEN evento = 'CANCELADO' THEN 1 ELSE 0 END) AS cancelado
FROM atendimento a
@ -168,7 +168,7 @@ class DashboardController extends Controller
inner join eventos_atendimento ea on a.uniqueid = ea.uniqueid
where a.data_reg::date >= :data_inicio and a.data_reg::date <= :data_fim
and ea.id = (select MAX(id) from eventos_atendimento ee where ee.uniqueid = ea.uniqueid)
and evento not in ('EMESPERA', 'LOST_CONNECTION', 'SENDED', 'CANCELADO', 'ABANDON', 'TIMEOUT_CALLER')
and evento not in ('EMESPERA', 'LOST_CONNECTION', 'SENDED', 'CANCELADO', 'ABANDON')
and id_empresa = :id_empresa
", ['id_empresa' => $id_empresa, 'data_inicio' => $data_inicio, 'data_fim' => $data_fim]);
@ -184,7 +184,7 @@ class DashboardController extends Controller
inner join eventos_atendimento ea on a.uniqueid = ea.uniqueid
where a.data_reg::date = :data_atual
and ea.id = (select MAX(id) from eventos_atendimento ee where ee.uniqueid = ea.uniqueid)
and evento not in ('EMESPERA', 'LOST_CONNECTION', 'SENDED', 'CANCELADO', 'ABANDON', 'TIMEOUT_CALLER')
and evento not in ('EMESPERA', 'LOST_CONNECTION', 'SENDED', 'CANCELADO', 'ABANDON')
and id_empresa = :id_empresa
", ['id_empresa' => $id_empresa, 'data_atual' => $data_atual]);

49
app/Http/Controllers/Admin/Relatorios/RelatorioAtendimentosAbandonadosController.php

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Admin\Relatorios;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Agentes;
use App\Models\Atendimentos;
use Illuminate\Contracts\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use App\Models\Filas;
class RelatorioAtendimentosAbandonadosController extends Controller
{
public function __construct(
protected Atendimentos $atendimentosRepository,
protected Agentes $agenteRepository,
protected Filas $filasRepository,
) {
}
public function index(Request $request): View
{
$user = auth()->user();
if (Gate::forUser($user)->denies('show_relatorios')) {
abort(404);
}
$selected = (object) $request->all();
$empresas = Helper::getEmpresas();
if (!is_int($empresas)){
$empresasIds = $empresas->pluck('id')->toArray();
} else {
$empresasIds = $empresas;
}
if ($request->empresa) {
$empresasIds = $request->empresa;
}
$filas = $this->filasRepository->list(["id_empresa" => $empresasIds]);
$agentes = $this->agenteRepository->list(["id_empresa" => $empresasIds]);
$atendimentos = $this->atendimentosRepository->getAbandonAtends(["empresa" => $empresasIds, "fila" => $request->fila, "atendente" => $request->atendente, "usuario" => $request->usuario, "dataInicio" => $request->dataInicio, "dataFim" => $request->dataFim]);
return view('admin.relatorios.abandonAtendimentos.abandonAtendimentos', compact('atendimentos', 'selected', 'empresas', 'filas', 'agentes'));
}
}

8
app/Models/Agentes.php

@ -64,9 +64,11 @@ class Agentes extends Model
->join('empresa as e', 'e.id', '=', 'ue.id_empresa')
->select('u.*', 'g.name as cargo');
if (isset($params['id_empresa'])) {
$agentes->where('ue.id_empresa', $params['id_empresa']);
}
if (is_array($params['id_empresa'])) {
$agentes->whereIn('ue.id_empresa', $params['id_empresa']);
} else {
$agentes->where('ue.id_empresa', $params['id_empresa']);
}
if (isset($params['matricula'])) {
$agentes->where('u.matricula', $params['matricula']);

60
app/Models/Atendimentos.php

@ -108,4 +108,64 @@ class Atendimentos extends Model
return $atendimento->get();
}
public function getAbandonAtends(array $params = [])
{
$atendimentos = DB::table('atendimento as a')
->join('eventos_atendimento as ea', function ($join) {
$join->on('ea.uniqueid', '=', 'a.uniqueid')
->where('ea.id', '=', function ($query) {
$query->select(DB::raw('MAX(id)'))
->from('eventos_atendimento as ee')
->whereRaw('ee.uniqueid = ea.uniqueid');
});
})
->join('queues as q', 'q.id', '=', 'ea.id_queue')
->leftJoin('usuarios as u', 'u.id', '=', 'a.id_usuario')
->leftJoin('protocolo_reg as pr','pr.uniqueid','=','a.uniqueid')
->select(
'a.uniqueid',
'a.matricula',
'a.cliente_id',
'u.nome as atendente',
'a.nome',
'q.nome as fila',
'a.data_reg',
'data_evento',
'pr.protocolo',
DB::raw('(SELECT count(*) FROM message m WHERE m.uniqueid = a.uniqueid AND type NOT IN (\'alert\') AND src <> cliente_id) AS interacao')
)
->whereIn('evento', ['ABANDON'])
->orderBy('a.id');
if (isset($params['dataInicio']) && isset($params['dataFim'])) {
$atendimentos->whereBetween(DB::raw('a.data_reg::DATE'), [$params['dataInicio'], $params['dataFim']]);
}
if (isset($params['dataInicio'])) {
$atendimentos->whereBetween(DB::raw('a.data_reg::DATE'), [$params['dataInicio'], DB::raw('CURRENT_DATE')]);
}
if (isset($params['dataFim'])) {
$atendimentos->whereBetween(DB::raw('a.data_reg::DATE'), ['0001-01-01', $params['dataFim']]);
}
if (isset($params['atendente'])) {
$atendimentos->where('u.id', '=', $params['atendente']);
}
if (isset($params['fila'])) {
$atendimentos->where('q.id', '=', $params['fila']);
}
if (isset($params['usuario'])) {
$atendimentos->where(DB::raw('lower(a.nome)'), 'like', '%' . strtolower($params['usuario']) . '%');
}
if (isset($params['empresa'])) {
$atendimentos->where('a.id_empresa', '=', $params['empresa']);
}
return $atendimentos->get();
}
}

6
app/Models/Filas.php

@ -24,7 +24,11 @@ class Filas extends Model
{
$filas = DB::table('queues as q')->select("q.id", "q.nome as name");
if (isset($params['id_empresa'])) {
if (is_array($params['id_empresa'])) {
// Se $params['id_empresa'] for um array, use a condição whereIn
$filas->whereIn('q.id_empresa', $params['id_empresa']);
} else {
// Se for um único valor, use a condição normal
$filas->where('q.id_empresa', $params['id_empresa']);
}

2
resources/views/admin/cadastros/channels.blade.php

@ -39,7 +39,6 @@
<th class="p-3 text-sm font-semibold tracking-wide text-left">Nome</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left pl-5">ID Empresa</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Número</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Token</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Channel</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Workspace</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Título</th>
@ -54,7 +53,6 @@
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->name}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 pl-5">{{$channel->id_empresa}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->number}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->token}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->channel}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->work_space}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$channel->title}}</td>

100
resources/views/admin/relatorios/abandonAtendimentos/abandonAtendimentos.blade.php

@ -0,0 +1,100 @@
<x-app-layout>
<div class="py-8 px-8">
<div class="header flex flex-col">
<div class="flex items-center gap-3 w-full mb-5 ">
<h1 class="text-gray-900 dark:text-gray-100 text-3xl font-bold text-center">
Atendimentos Abandonados
</h1>
</div>
<form class="filtros flex items-center gap-3 " method="get" action="{{route('relatorio.atendimentosAbandonados.index')}}">
@if (!is_int($empresas))
<div class="flex flex-col gap-2">
<select class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" name="empresa">
<option value="" {{ empty($selected->empresa) ? 'selected disabled' : '' }}>Todas Empresas</option>
@foreach($empresas as $empresa)
<option value="{{ $empresa->id}}" {{ !empty($selected->empresa) && ($empresa->id == $selected->empresa) ? 'selected' : '' }}>
{{ $empresa->nome }}
</option>
@endforeach
</select>
</div>
@endif
<div class="flex-1 flex flex-col gap-1">
<label>Data Inicio: </label>
<input type="date" class="w-full rounded-md p-2 dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" name="dataInicio" id="dataInicio" value="{{ $selected->dataInicio ?? '' }}" placeholder="Data de Início">
</div>
<div class="flex-1 flex flex-col gap-1">
<label>Data Fim: </label>
<input type="date" class="w-full rounded-md p-2 dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" name="dataFim" id="dataFim" value="{{ $selected->dataFim ?? '' }}" placeholder="Data de Fim">
</div>
<div class="flex-1 flex flex-col gap-1">
<label>Fila: </label>
<select class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" name="fila">
<option value="" {{ empty($selected->fila) ? 'selected disabled' : '' }}>--------------------</option>
@foreach($filas as $fila)
<option value="{{ $fila->id}}" {{ !empty($selected->fila) && ($fila->id == $selected->fila) ? 'selected' : '' }}>
{{ $fila->name }}
</option>
@endforeach
</select>
</div>
<div class="flex-1 flex flex-col gap-1">
<label>Agente: </label>
<select class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" name="atendente">
<option value="" {{ empty($selected->atendente) ? 'selected disabled' : '' }}>--------------------</option>
@foreach($agentes as $agente)
<option value="{{ $agente->id}}" {{ !empty($selected->atendente) && ($agente->id == $selected->atendente) ? 'selected' : '' }}>
{{ $agente->nome }}
</option>
@endforeach
</select>
</div>
<div class="flex-1 flex flex-col gap-1">
<label>Cliente: </label>
<input type="text" name="usuario" value="{{$selected->usuario ?? ""}}" class="w-full rounded-md p-2 dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100" placeholder="Cliente: ">
</div>
<button class="lg:ml-auto ml-0 bg-blue-900 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-lg overflow-hidden">Pesquisar</button>
</form>
</div>
<div class="body mt-4 overflow-auto rounded-lg shadow">
<table class="w-full">
<thead class="bg-gray-50 dark:bg-gray-700 dark:text-gray-100">
<tr>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Numero Cliente</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Nome Cliente</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Fila</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Protocolo</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Agente</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Interações</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Data Atendimento</th>
<th class="p-3 text-sm font-semibold tracking-wide text-left">Data Evento</th>
</tr>
</thead>
<tbody>
@forelse ($atendimentos as $atendimento)
<tr class="bg-white dark:bg-gray-800 dark:border-gray-600 border-b-2">
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->cliente_id ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->nome ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->fila ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->protocolo ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->atendente ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$atendimento->interacao ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{\Carbon\Carbon::parse($atendimento->data_reg)->format('Y-m-d H:i:s') ?? "-"}}</td>
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{\Carbon\Carbon::parse($atendimento->data_evento)->format('Y-m-d H:i:s') ?? "-"}}</td>
</tr>
@empty
<div class="flex flex-col gap-3 items-center h-[50vh] justify-center">
<div class="border-gray-500 border-4 rounded-full flex items-center justify-center px-5 py-5">
<img src="{{ asset('img/filtro-limpo.png') }}" alt="">
</div>
<h1 class="text-gray-100 text-xl">Nenhum registro foi encontrado</h1>
</div>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</x-app-layout>

12
resources/views/layouts/menu.blade.php

@ -138,10 +138,14 @@
</x-nav-link>
</li>
@endcan
{{-- <x-nav-link class="p-2 mt-3 ml-4 flex items-center flex-row rounded-md px-2 md:px-4 duration-300 cursor-pointer hover:bg-blue-600 text-white" :href="route('graficos.index')" :active="request()->routeIs('graficos.index')">
<i class="fas fa-chart-bar text-sm"></i>
<span class="text-[14px] ml-2 text-gray-300">Produção Agente</span>
</x-nav-link> --}}
<li>
<x-nav-link class="p-2 mt-3 ml-4 flex items-center flex-row rounded-md px-2 md:px-4 duration-300 cursor-pointer hover:bg-blue-600 text-white" :href="route('relatorio.atendimentosAbandonados.index')" :active="request()->routeIs('relatorio.atendimentosAbandonados.index')">
<i class="fas fa-window-close text-sm"></i>
<span class="text-[14px] ml-2 text-gray-300">Atendimentos Abandonado</span>
</x-nav-link>
</li>
</ul>
</div>
@endcan

3
routes/web.php

@ -13,6 +13,7 @@ use App\Http\Controllers\Admin\GraficosController;
use App\Http\Controllers\Admin\RedirectController;
use App\Http\Controllers\Admin\RedirectOptionController;
use App\Http\Controllers\Admin\Relatorios\RelatorioHistoricoAtendimentoController;
use App\Http\Controllers\Admin\Relatorios\RelatorioAtendimentosAbandonadosController;
use App\Http\Controllers\Admin\SupervisorController;
use App\Http\Controllers\Admin\SystemMessageController;
use App\Http\Controllers\Admin\TemplatesController;
@ -32,6 +33,8 @@ Route::middleware(['auth', 'verified'])->group(function () {
Route::get("relatorio/historicoAtendimento", [RelatorioHistoricoAtendimentoController::class, 'index'])->name('relatorio.historicoAtendimento.index');
Route::get("relatorio/historicoAtendimento/{id}", [RelatorioHistoricoAtendimentoController::class, 'show'])->name('relatorio.historicoAtendimento.show');
Route::get("relatorio/atendimentosAbandonados", [RelatorioAtendimentosAbandonadosController::class, 'index'])->name('relatorio.atendimentosAbandonados.index');
Route::get('/conectarAgente', [ConectarAgenteController::class, 'index'])->name('conectarAgente.index');
Route::post('/conectarAgente', [ConectarAgenteController::class, 'conectar'])->name('conectarAgente.conectar');

Loading…
Cancel
Save