Compare commits
83 Commits
@ -0,0 +1,60 @@
|
||||
<?php |
||||
|
||||
namespace App\Console\Commands; |
||||
|
||||
use App\Models\Templates; |
||||
use Illuminate\Console\Command; |
||||
use Illuminate\Support\Facades\Http; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class AtualizaTemplates extends Command |
||||
{ |
||||
/** |
||||
* The name and signature of the console command. |
||||
* |
||||
* @var string |
||||
*/ |
||||
protected $signature = 'app:atualiza-templates'; |
||||
|
||||
/** |
||||
* The console command description. |
||||
* |
||||
* @var string |
||||
*/ |
||||
protected $description = 'Requisição assincrona que recupera todos os templates e depois atualiza os que estão cadastrados no banco'; |
||||
|
||||
/** |
||||
* Execute the console command. |
||||
*/ |
||||
public function handle() |
||||
{ |
||||
$empresas = DB::table('empresa')->orderBy('id', 'desc')->get(); |
||||
foreach ($empresas as $empresa){ |
||||
$channels = DB::table('number_channel')->where('id_empresa', $empresa->id) |
||||
->where('channel', 'positus')->get(); |
||||
foreach ($channels as $channel) { |
||||
$data = $this->getTemplates($channel); |
||||
if ($data) { |
||||
foreach ($data as $value) { |
||||
$template = Templates::findById($value['id']); |
||||
if($template){ |
||||
Templates::where("id", $value['id']) |
||||
->update([ |
||||
'status' => $value['status']['code'], |
||||
]); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
private function getTemplates($channel){ |
||||
$response = Http::withToken($channel->token)->get("https://api.positus.global/v2/workspaces/{$channel->work_space}/message-templates"); |
||||
if (isset($response->json()['data'])){ |
||||
return $response->json()['data']; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,161 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Agentes; |
||||
use App\Models\Grupos; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use Illuminate\Validation\Rule; |
||||
|
||||
class AgentesController extends Controller |
||||
{ |
||||
|
||||
public function __construct( |
||||
protected Agentes $agenteRepository, |
||||
protected Grupos $gruposRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_agentes')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$search = strtolower($request->pesquisa); |
||||
$status = $request->status === "desativado" ? false : true; |
||||
$grupos = $this->gruposRepository->getPermissoesCriarGrupo($user); |
||||
$agentes = $this->agenteRepository->list(["id_empresa" => $id_empresa, "status" => $status, "search" => $search]); |
||||
$consulta_matricula = $this->agenteRepository->getMaiorMatricula($id_empresa); |
||||
$maior_matricula = $consulta_matricula->maior_matricula + 1; |
||||
|
||||
$grupoId = $this->gruposRepository->getUserGrupoID($user->id); |
||||
$changePassword = false; |
||||
|
||||
if ($grupoId == 4 || $grupoId == 1) { |
||||
$changePassword = true; |
||||
} |
||||
|
||||
return view('admin.cadastros.users', compact('agentes', 'status', 'maior_matricula', 'search', 'grupos', 'changePassword')); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_agentes')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'nome' => ['required'], |
||||
'email' => ['required', Rule::unique('usuarios')], |
||||
'senha' => ['required'], |
||||
'matricula' => ['required'], |
||||
'status' => ['required'], |
||||
'id_grupo' => ['required'], |
||||
]); |
||||
|
||||
$status = $request->status === 'on' ? true : false; |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$isMatriculaRegister = $this->agenteRepository->get(['matricula' => $request->matricula]); |
||||
if ($isMatriculaRegister) { |
||||
return redirect()->back()->with('status', ' matricula vinculada com outro agente'); |
||||
} |
||||
|
||||
$created = $this->agenteRepository->create($request->nome, $request->email, $request->senha, $request->matricula, $status, $id_empresa, $request->id_grupo); |
||||
if(!$created){ |
||||
return redirect()->back()->with('status', 'Erro ao tentar criar agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', ' Cadastrado com sucesso'); |
||||
} |
||||
|
||||
public function edit($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
$grupo_id = $this->gruposRepository->getUserGrupoID($id); |
||||
|
||||
if(Gate::forUser($user)->denies('edit_agentes')){ |
||||
abort(404); |
||||
} |
||||
|
||||
if (empty($id)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
$userData = Agentes::find($id); |
||||
$userData->grupo_id = $grupo_id; |
||||
$response = [ |
||||
'status' => true, |
||||
'data' => $userData |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function destroy($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('destroy_agentes')){ |
||||
abort(404); |
||||
} |
||||
|
||||
if (empty($id)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
Agentes::where('id', $id)->update([ |
||||
"status" => false |
||||
]); |
||||
|
||||
return redirect('users')->with('status', 'desativado com sucesso'); |
||||
} |
||||
|
||||
public function update(Request $request, $id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('update_agentes')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
"nome" => ['required'], |
||||
"status" => ['required'], |
||||
"id_grupo" => ['required'], |
||||
"email" => ['required'], |
||||
"matricula" => ['required'] |
||||
]); |
||||
|
||||
if (empty($id) || empty($request->nome)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
|
||||
$agente_matricula = Agentes::select('matricula') |
||||
->where('id', $id) |
||||
->get() |
||||
->first(); |
||||
|
||||
if ($agente_matricula->matricula != $request->matricula) { |
||||
$isMatriculaRegister = Agentes::where('matricula', $request->matricula)->get()->count(); |
||||
|
||||
if ($isMatriculaRegister > 0) { |
||||
return redirect()->back()->with('status', ' matricula vinculada com outro agente'); |
||||
} |
||||
|
||||
$this->agenteRepository->edit($id, $request->nome, $request->id_grupo, $status, $request->senha, $request->matricula, $request->email); |
||||
|
||||
} else { |
||||
$this->agenteRepository->edit($id, $request->nome, $request->id_grupo, $status, $request->senha, $request->matricula, $request->email); |
||||
} |
||||
|
||||
return redirect('users')->with('status', 'atualizado com sucesso'); |
||||
} |
||||
} |
@ -0,0 +1,77 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Filas; |
||||
use App\Models\NumberChannel; |
||||
use App\Models\Tokens; |
||||
use App\Traits\AuthToken; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Auth; |
||||
|
||||
class ConectarAgenteController extends Controller |
||||
{ |
||||
use AuthToken; |
||||
|
||||
public function __construct( |
||||
protected Filas $queueRepository, |
||||
protected NumberChannel $numberChannelRepository, |
||||
protected Tokens $tokenRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index(){ |
||||
$idEmpresa = Helper::getIdEmpresa(); |
||||
$filas = $this->queueRepository->list(["id_empresa" => $idEmpresa, "status" => true]); |
||||
$channels = $this->numberChannelRepository->list(["id_empresa" => $idEmpresa, "status" => true]); |
||||
|
||||
return view("admin.conectarAgente.conectarAgente", compact('filas', 'channels')); |
||||
} |
||||
|
||||
public function conectar(Request $request){ |
||||
$queueId = $request->queue_id; |
||||
|
||||
if(empty($queueId)){ |
||||
return response()->json("Parametro id é obrigatório", 404); |
||||
} |
||||
|
||||
$fila = $this->queueRepository->get(["id" => $queueId]); |
||||
if(empty($fila)){ |
||||
return response()->json("Fila não foi encontrada", 404); |
||||
} |
||||
|
||||
$user = Auth::user(); |
||||
if(empty($user)){ |
||||
return response()->json("Usuário não foi encontrado", 404); |
||||
} |
||||
|
||||
$idEmpresa = Helper::getIdEmpresa(); |
||||
if ($request->channel_id) { |
||||
$numberChannelId = $request->channel_id; |
||||
} else { |
||||
$numberChannelId = $this->numberChannelRepository->where('id_empresa', $idEmpresa)->where('status', true)->value('id'); |
||||
} |
||||
|
||||
if(empty($numberChannelId)){ |
||||
return response()->json("Numberchannel não foi encontrado", 404); |
||||
} |
||||
|
||||
$tokenDB = $this->getToken($user->id); |
||||
$info = [ |
||||
"id_empresa" => $idEmpresa, |
||||
"id_number" => $numberChannelId, |
||||
"fila" => $queueId, |
||||
"servidor" => env('APP_URL'), |
||||
"websocket" => env('APP_URL_WEBSOCKET'), |
||||
"matricula" => $user->matricula, |
||||
"token" => $tokenDB->token, |
||||
"expire" => $tokenDB->expired_at, |
||||
]; |
||||
|
||||
$tokenAgente = Helper::Crypt()->encrypt(json_encode($info, true)); |
||||
|
||||
return response()->json($tokenAgente); |
||||
} |
||||
} |
@ -1,57 +1,46 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\ConfigAtendimento; |
||||
use Illuminate\Http\Request; |
||||
|
||||
class ConfigAtendimentoController extends Controller |
||||
{ |
||||
/** |
||||
* Display a listing of the resource. |
||||
*/ |
||||
public function index() |
||||
{ |
||||
$user = auth()->user(); |
||||
|
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$configAtendimento = ConfigAtendimento::where('id_empresa', $id_empresa)->first(); |
||||
|
||||
return view('admin.configs', compact('configAtendimento')); |
||||
return view('admin.configs.configs', compact('configAtendimento')); |
||||
} |
||||
|
||||
/** |
||||
* Show the form for creating a new resource. |
||||
*/ |
||||
public function create(Request $request) |
||||
{ |
||||
// |
||||
|
||||
|
||||
$request->validate([ |
||||
"qtde_atendimento" => ['required'], |
||||
"timeout_cliente" => ['required'], |
||||
"timeout_agente" => ['required'], |
||||
"timeout_espera" => ['required'], |
||||
"timeout_supervisor" => ['required'], |
||||
"id_empresa" => ['required'] |
||||
]); |
||||
|
||||
|
||||
if (empty($request->qtde_atendimento) || empty($request->timeout_cliente) || empty($request->timeout_agente) || empty($request->id_empresa)) { |
||||
if (empty($request->qtde_atendimento) || empty($request->timeout_cliente) || empty($request->timeout_espera) || empty($request->timeout_agente) || empty($request->id_empresa) || empty($request->timeout_supervisor)) { |
||||
return redirect('configs'); |
||||
} |
||||
|
||||
|
||||
|
||||
ConfigAtendimento::where('id_empresa', '=', $request->id_empresa) |
||||
->update([ |
||||
"quantidade_simutaneo" => $request->qtde_atendimento, |
||||
"timeout_client" => $request->timeout_cliente, |
||||
"timeout_agent" => $request->timeout_agente |
||||
"timeout_agent" => $request->timeout_agente, |
||||
"timeout_espera" => $request->timeout_espera, |
||||
"timeout_supervisor" => $request->timeout_supervisor, |
||||
]); |
||||
|
||||
return redirect('configs'); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,149 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Agentes; |
||||
use App\Models\Contatos; |
||||
use App\Models\User; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use Illuminate\Validation\Rule; |
||||
|
||||
class ContatosController extends Controller |
||||
{ |
||||
public function index(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_contatos')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$search = strtolower($request->pesquisa); |
||||
$status = $request->status === "desativado" ? false : true; |
||||
|
||||
$contatos = Contatos::where(function ($query) use ($search, $id_empresa, $status){ |
||||
$query->where('status', $status); |
||||
$query->where("id_empresa", $id_empresa); |
||||
|
||||
if($search){ |
||||
$query->where(DB::raw('LOWER(nome)'), 'LIKE', "%{$search}%"); |
||||
$query->orWhere('email', $search); |
||||
} |
||||
})->get(); |
||||
|
||||
foreach ($contatos as $contato) { |
||||
$contato->formated_date = $contato->created_at->format('d M Y'); |
||||
} |
||||
|
||||
return view("admin.cadastros.contatos", compact('contatos', 'status')); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_contatos')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'nome' => ['required'], |
||||
'email' => ['nullable', 'email', Rule::unique('contatos')], |
||||
'contato' => ['required', Rule::unique('contatos')], |
||||
'status' => ['required'], |
||||
]); |
||||
|
||||
$status = $request->status === 'on' ? true : false; |
||||
$user = auth()->user(); |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$telefoneDesformatado = preg_replace('/[^0-9]/', '', $request->contato); |
||||
|
||||
Contatos::create([ |
||||
'nome' => $request->nome, |
||||
'email' => $request->email, |
||||
'contato' => $telefoneDesformatado, |
||||
'status' => $status, |
||||
'notes' => $request->descricao, |
||||
'id_empresa' => $id_empresa, |
||||
'id_agente' => $user->id, |
||||
]); |
||||
|
||||
return redirect()->back()->with('status', 'Contato cadastrado'); |
||||
} |
||||
|
||||
public function edit($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('edit_contatos')){ |
||||
abort(404); |
||||
} |
||||
|
||||
if (empty($id)) { |
||||
return response()->json(['data' => 'Parametro ID_CONTATO é obrigatório']); |
||||
} |
||||
|
||||
$contatosData = Contatos::find($id); |
||||
$response = [ |
||||
'data' => [ |
||||
'status' => true, |
||||
'contato_data' => $contatosData |
||||
], |
||||
|
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function update(Request $request, $id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('update_contatos')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'nome' => ['required'], |
||||
'email' => ['nullable', 'email', Rule::unique('contatos')], |
||||
'contato' => ['required'], |
||||
'status' => ['required'], |
||||
]); |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
$telefoneDesformatado = preg_replace('/[^0-9]/', '', $request->contato); |
||||
|
||||
Contatos::where("id", $id) |
||||
->update([ |
||||
'nome' => $request->nome, |
||||
'email' => $request->email, |
||||
'contato' => $telefoneDesformatado, |
||||
'status' => $status, |
||||
'notes' => $request->descricao, |
||||
]); |
||||
|
||||
return redirect()->back()->with('status', 'Atualizado com sucesso'); |
||||
} |
||||
|
||||
public function destroy($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('destroy_contatos')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$contato = Contatos::where('id', $id); |
||||
$rowCount = $contato->count(); |
||||
|
||||
if ($rowCount > 0) { |
||||
$contato->update([ |
||||
'status' => false |
||||
]); |
||||
return redirect()->back()->with('status', 'Contato desativado'); |
||||
} |
||||
|
||||
return redirect()->back(); |
||||
} |
||||
} |
@ -0,0 +1,390 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Filas; |
||||
use App\Models\Pausas; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Http\Request; |
||||
use GuzzleHttp\Client; |
||||
use App\Models\Tokens; |
||||
use App\Traits\AuthToken; |
||||
|
||||
class DashboardController extends Controller |
||||
{ |
||||
use AuthToken; |
||||
|
||||
public function __construct( |
||||
protected Filas $queueRepository, |
||||
protected Tokens $tokenRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index() |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_dashboard')){ |
||||
return redirect('conectarAgente'); |
||||
} |
||||
|
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$pausas = Pausas::where(["id_empresa" => $id_empresa, "is_ativo" => true])->get(); |
||||
|
||||
return view('admin.dashboard.dashboard', compact('pausas')); |
||||
} |
||||
|
||||
public function getRelatorioDados() |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$atendimentosData = DB::table('usuarios as u') |
||||
->leftJoin('atendimento as a', 'u.id', '=', 'a.id_usuario') |
||||
->select('u.nome', DB::raw('count(a.id_usuario) as qtde_atendimento')) |
||||
->where('a.id_empresa', $id_empresa) |
||||
->groupBy('u.nome') |
||||
->get(); |
||||
|
||||
$atendimentosStatusData = DB::table('usuarios as u') |
||||
->join('usuario_empresa as ue', 'ue.id_usuario', '=', 'u.id') |
||||
->join('eventos_atendimento as ea', 'ea.id_usuario', '=', 'u.id') |
||||
->select('ea.evento', DB::raw('count(ea.evento) as qtde_usados')) |
||||
->where('ue.id_empresa', $id_empresa) |
||||
->groupBy('ea.evento') |
||||
->get(); |
||||
|
||||
$filasMaisUsadas = DB::table('queues as q') |
||||
->join('eventos_atendimento as ea', 'ea.id_queue', '=', 'q.id') |
||||
->select('q.nome', DB::raw('count(ea.id_queue) as qtde_fila')) |
||||
->where('q.id_empresa', $id_empresa) |
||||
->groupBy('q.nome') |
||||
->get(); |
||||
|
||||
$data_inicio = date("Y-m-01"); |
||||
$data_atual = date('Y-m-d'); |
||||
$data_fim = Helper::last_date_in_mouth(); |
||||
|
||||
$atendimentosPorMes = $this->getAtendimentosMes($data_inicio, $data_fim); |
||||
$atendimentosDia = $this->getAtendimentoDia($data_atual); |
||||
$totalAgentesOperantes = $this->getAgentesOperantes(); |
||||
$totalAgentesInoperantes = $this->getAgentesInoperantes(); |
||||
|
||||
$relatoriosAtendimento = $this->relatoriosDados(); |
||||
|
||||
$total_atendimentos = $this->totalAtendimentos($atendimentosData); |
||||
|
||||
$data = [ |
||||
'atendimentosData' => $atendimentosData, |
||||
'atendimentosStatusData' => $atendimentosStatusData, |
||||
'filasMaisUsadas' => $filasMaisUsadas, |
||||
'atendimentosPorMes' => $atendimentosPorMes, |
||||
'atendimentosDia' => $atendimentosDia, |
||||
'totalAgentesOperantes' => $totalAgentesOperantes, |
||||
'totalAgentesInoperantes' => $totalAgentesInoperantes, |
||||
'relatoriosAtendimento' => $relatoriosAtendimento, |
||||
'total_atendimentos' => $total_atendimentos, |
||||
]; |
||||
|
||||
|
||||
return response()->json(['status' => true, 'data' => $data]); |
||||
} |
||||
|
||||
private function totalAtendimentos($atendimentos) |
||||
{ |
||||
$total_atendimentos = 0; |
||||
|
||||
foreach ($atendimentos as $atendimento) { |
||||
$total_atendimentos += $atendimento->qtde_atendimento; |
||||
} |
||||
|
||||
return $total_atendimentos; |
||||
} |
||||
|
||||
private function relatoriosDados() |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$relatorios = DB::select(" |
||||
SELECT |
||||
q.id, q.nome, |
||||
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','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 |
||||
INNER JOIN eventos_atendimento ea ON ea.uniqueid = a.uniqueid and ea.id = (SELECT MAX(id) FROM eventos_atendimento ee WHERE ee.uniqueid = ea.uniqueid) |
||||
INNER JOIN queues q on q.id = ea.id_queue |
||||
WHERE a.data_reg::date = CURRENT_DATE |
||||
AND a.id_empresa = :id_empresa |
||||
GROUP BY q.nome, q.id |
||||
ORDER BY q.id |
||||
", ['id_empresa' => $id_empresa]); |
||||
|
||||
$filas = DB::select(" |
||||
SELECT |
||||
q.nome, q.id, count(s.nome) as agentes |
||||
FROM |
||||
queues q |
||||
LEFT JOIN supervisor s on s.fila = q.nome |
||||
WHERE q.id_empresa = :id_empresa AND q.is_ativa = true |
||||
GROUP BY q.nome, q.id |
||||
", ['id_empresa' => $id_empresa]); |
||||
|
||||
$relatoriosPorId = []; |
||||
|
||||
foreach ($relatorios as $relatorio) { |
||||
$relatoriosPorId[$relatorio->id] = [ |
||||
'em_espera' => $relatorio->em_espera, |
||||
'iniciadas' => $relatorio->iniciadas, |
||||
'enviadas' => $relatorio->enviados, |
||||
'finalizadas' => $relatorio->finalizadas, |
||||
'abandonadas' => $relatorio->abandonadas, |
||||
'canceladas' => $relatorio->cancelado, |
||||
]; |
||||
} |
||||
|
||||
foreach ($filas as &$fila) { |
||||
$idFila = $fila->id; |
||||
|
||||
if (isset($relatoriosPorId[$idFila])) { |
||||
$fila->em_espera = $relatoriosPorId[$idFila]['em_espera']; |
||||
$fila->iniciadas = $relatoriosPorId[$idFila]['iniciadas']; |
||||
$fila->enviadas = $relatoriosPorId[$idFila]['enviadas']; |
||||
$fila->finalizadas = $relatoriosPorId[$idFila]['finalizadas']; |
||||
$fila->abandonadas = $relatoriosPorId[$idFila]['abandonadas']; |
||||
$fila->canceladas = $relatoriosPorId[$idFila]['canceladas']; |
||||
} else { |
||||
$fila->em_espera = 0; |
||||
$fila->iniciadas = 0; |
||||
$fila->enviadas = 0; |
||||
$fila->finalizadas = 0; |
||||
$fila->abandonadas = 0; |
||||
$fila->canceladas = 0; |
||||
} |
||||
} |
||||
|
||||
return $filas; |
||||
} |
||||
|
||||
private function getAtendimentosMes($data_inicio, $data_fim) |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$atendimentosPorMes = DB::select(" |
||||
select count (*) as total from atendimento a |
||||
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') |
||||
and id_empresa = :id_empresa |
||||
", ['id_empresa' => $id_empresa, 'data_inicio' => $data_inicio, 'data_fim' => $data_fim]); |
||||
|
||||
return $atendimentosPorMes[0]->total; |
||||
} |
||||
|
||||
private function getAtendimentoDia($data_atual) |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$atendimentoDia = DB::select(" |
||||
select count (*) as total from atendimento a |
||||
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') |
||||
and id_empresa = :id_empresa |
||||
", ['id_empresa' => $id_empresa, 'data_atual' => $data_atual]); |
||||
|
||||
return $atendimentoDia[0]->total; |
||||
} |
||||
|
||||
private function getAgentesOperantes() |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$totalAgentesOperantes = DB::select(" |
||||
SELECT COUNT(DISTINCT s.id_usuario) AS total |
||||
FROM supervisor s |
||||
INNER JOIN atendimento a ON a.matricula = s.matricula |
||||
LEFT JOIN eventos_atendimento ea ON ea.uniqueid = a.uniqueid |
||||
WHERE ea.id = (SELECT MAX(id) FROM eventos_atendimento ee WHERE ee.uniqueid = ea.uniqueid) |
||||
AND (evento = 'START' AND status IN ('INDISPONIVEL') AND s.id_empresa = :id_empresa) OR |
||||
(status IN ('LIVRE', 'OCUPADO') AND s.id_empresa = :id_empresa) |
||||
", ['id_empresa' => $id_empresa]); |
||||
|
||||
return $totalAgentesOperantes[0]->total; |
||||
} |
||||
|
||||
private function getAgentesInoperantes() |
||||
{ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
|
||||
$totalAgentesInoperantes = DB::select(" |
||||
SELECT COUNT(s.id_usuario) AS total |
||||
FROM supervisor s |
||||
WHERE status IN ('INDISPONIVEL', 'PAUSA') |
||||
AND NOT EXISTS ( |
||||
SELECT 1 |
||||
FROM atendimento a |
||||
LEFT JOIN eventos_atendimento ea ON ea.uniqueid = a.uniqueid |
||||
WHERE ea.id = (SELECT MAX(id) FROM eventos_atendimento ee WHERE ee.uniqueid = ea.uniqueid) |
||||
AND evento = 'START' |
||||
AND a.matricula = s.matricula |
||||
) |
||||
AND s.id_empresa = :id_empresa |
||||
", ['id_empresa' => $id_empresa]); |
||||
|
||||
return $totalAgentesInoperantes[0]->total; |
||||
} |
||||
|
||||
public function agentesLogados($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return redirect()->back(); |
||||
} |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$fila = Filas::where(['id' => $id, 'id_empresa' => $id_empresa])->first(); |
||||
$pausas = Pausas::where(["id_empresa" => $id_empresa, "is_ativo" => true])->get(); |
||||
$filas = $this->queueRepository->list(['id_empresa' => $id_empresa]); |
||||
$atendimentos_espera = $this->getAtendimentosEmEsperaFila($id); |
||||
|
||||
return view('admin.dashboard.agentesLogados', compact('fila', 'pausas', 'atendimentos_espera', 'filas')); |
||||
} |
||||
|
||||
public function relatoriosFilas($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return response()->json(['data' => "Parametro ID é obrigatorio"]); |
||||
} |
||||
|
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$fila = Filas::where('id', $id)->where('id_empresa', $id_empresa)->first(); |
||||
$agentesNaFila = DB::table("supervisor as s") |
||||
->leftJoin("queues as q", "q.nome", "=", "s.fila") |
||||
->join("tokens as t", "t.id_usuario", "=", "s.id_usuario") |
||||
->select( |
||||
"s.id", |
||||
"s.nome", |
||||
"s.matricula", |
||||
"s.motivo_pausa", |
||||
"s.fila", |
||||
"s.status", |
||||
"t.token", |
||||
"q.id as id_queue", |
||||
DB::raw("(now() - s.tempo_login) AS login"), |
||||
DB::raw( |
||||
"( |
||||
SELECT COUNT(*) |
||||
FROM atendimento AS ma |
||||
JOIN ( |
||||
SELECT uniqueid, MAX(id) AS max_id |
||||
FROM eventos_atendimento |
||||
GROUP BY uniqueid |
||||
) AS m2_max |
||||
ON ma.uniqueid = m2_max.uniqueid |
||||
JOIN eventos_atendimento AS m2 |
||||
ON ma.uniqueid = m2.uniqueid AND m2.id = m2_max.max_id |
||||
WHERE ma.matricula = s.matricula AND m2.evento = 'START' |
||||
) as atendimentos_atuais" |
||||
) |
||||
) |
||||
->where([ |
||||
["s.id_empresa", "=", $id_empresa], |
||||
['q.nome', $fila->nome], |
||||
]) |
||||
->groupBy('s.id', 't.token', "q.id") |
||||
->get(); |
||||
|
||||
return response()->json(['data' => $agentesNaFila]); |
||||
} |
||||
|
||||
public function getAtendimentosEmEsperaFila($id_fila) |
||||
{ |
||||
$atendimentos_espera = DB::select(" |
||||
SELECT |
||||
ea.uniqueid, ea.id, a.nome, a.cliente_id, ea.data_evento |
||||
FROM atendimento a |
||||
INNER JOIN eventos_atendimento ea ON ea.uniqueid = a.uniqueid and ea.id = (SELECT MAX(id) FROM eventos_atendimento ee WHERE ee.uniqueid = ea.uniqueid) |
||||
WHERE |
||||
ea.id_queue = :id_fila and ea.evento = 'EMESPERA' |
||||
ORDER BY ea.id |
||||
", ['id_fila' => $id_fila]); |
||||
|
||||
return $atendimentos_espera; |
||||
} |
||||
|
||||
public function transferirFilaAtendimento(Request $request) |
||||
{ |
||||
DB::beginTransaction(); |
||||
try { |
||||
DB::table('eventos_atendimento')->where("uniqueid", $request->unique_id) |
||||
->update([ |
||||
"id_queue" => $request->fila |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return redirect()->back()->with('status', 'Atendimento transferido'); |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return redirect()->back()->with('status', 'Erro ao transferir atendimento'); |
||||
} |
||||
} |
||||
|
||||
public function agenteAtendimentos($id, $matricula_agente) |
||||
{ |
||||
if (empty($matricula_agente) || empty($id)) { |
||||
return response()->json(['data' => "Parametro ID é obrigatorio"]); |
||||
} |
||||
|
||||
$atendimentos_agente = DB::select(" |
||||
SELECT * |
||||
FROM atendimento AS ma |
||||
JOIN ( |
||||
SELECT uniqueid, MAX(id) AS max_id |
||||
FROM eventos_atendimento |
||||
GROUP BY uniqueid |
||||
) AS m2_max |
||||
ON ma.uniqueid = m2_max.uniqueid |
||||
JOIN eventos_atendimento AS m2 |
||||
ON ma.uniqueid = m2.uniqueid AND m2.id = m2_max.max_id |
||||
WHERE ma.matricula = :matricula_agente AND m2.evento = 'START' |
||||
", ['matricula_agente' => $matricula_agente]); |
||||
|
||||
return response()->json(['data' => $atendimentos_agente]); |
||||
} |
||||
|
||||
public function transferirAtendimento(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
$tokenDB = $this->getToken($user->id); |
||||
|
||||
$httpClient = new Client(); |
||||
|
||||
$check = true; |
||||
|
||||
$url = env('APP_URL'); |
||||
$response = $httpClient->post("$url/api/v1/atendimentos/transferir", [ |
||||
'headers' => [ |
||||
'Authorization' => "Bearer $tokenDB->token", |
||||
], |
||||
'json' => [ |
||||
'matricula_origem' => $request->origem, |
||||
'matricula_destino' => $request->destino, |
||||
'uniqueid' => $request->atendimento_unique_id |
||||
], |
||||
]); |
||||
|
||||
if (!($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) { |
||||
$check = false; |
||||
} |
||||
|
||||
if (!$check) { |
||||
return redirect()->back()->with('status', 'Erro ao tentar transferir o atendimento'); |
||||
} else { |
||||
return redirect()->back()->with('status', 'O atendimento foi transferido com sucesso!'); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,101 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Http\Controllers\Controller; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use Illuminate\Http\Request; |
||||
|
||||
class GraficosController extends Controller |
||||
{ |
||||
public function index() |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_analytics')){ |
||||
abort(404); |
||||
} |
||||
|
||||
return view("admin.graficos.graficos"); |
||||
} |
||||
|
||||
public function show(Request $request) |
||||
{ |
||||
$data = $this->getRelatorioDados($request->dataInicio, $request->dataFim); |
||||
|
||||
return response()->json(['status' => true, 'data' => $data]); |
||||
} |
||||
|
||||
private function getRelatorioDados($dataInicio, $dataFim) |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$atendimentosData = DB::table('usuarios as u') |
||||
->leftJoin('atendimento as a', 'u.id', '=', 'a.id_usuario') |
||||
->select('u.nome', DB::raw('count(a.id_usuario) as qtde_atendimento')) |
||||
->where('a.id_empresa', $id_empresa); |
||||
|
||||
if ($dataInicio && $dataFim) { |
||||
$atendimentosData->whereBetween(DB::raw('a.data_reg::DATE'), [$dataInicio, $dataFim]); |
||||
} elseif ($dataInicio) { |
||||
$atendimentosData->where(DB::raw('a.data_reg::DATE'), '>=', $dataInicio); |
||||
} elseif ($dataFim) { |
||||
$atendimentosData->where(DB::raw('a.data_reg::DATE'), '<=', $dataFim); |
||||
} |
||||
|
||||
$atendimentosData = $atendimentosData |
||||
->groupBy('u.nome') |
||||
->get(); |
||||
|
||||
$atendimentosStatusData = DB::table('usuarios as u') |
||||
->join('usuario_empresa as ue', 'ue.id_usuario', '=', 'u.id') |
||||
->join('eventos_atendimento as ea', 'ea.id_usuario', '=', 'u.id') |
||||
->select('ea.evento', DB::raw('count(ea.evento) as qtde_usados')) |
||||
->where([ |
||||
['ue.id_empresa', '=', $id_empresa], |
||||
['ea.evento', '<>', config('event.CONF_EVENT_ESPERA')], |
||||
]); |
||||
|
||||
if ($dataInicio && $dataFim) { |
||||
$atendimentosStatusData->whereBetween(DB::raw('ea.data_reg::DATE'), [$dataInicio, $dataFim]); |
||||
} elseif ($dataInicio) { |
||||
$atendimentosStatusData->where(DB::raw('ea.data_reg::DATE'), '>=', $dataInicio); |
||||
} elseif ($dataFim) { |
||||
$atendimentosStatusData->where(DB::raw('ea.data_reg::DATE'), '<=', $dataFim); |
||||
} |
||||
|
||||
$atendimentosStatusData = $atendimentosStatusData |
||||
->groupBy('ea.evento') |
||||
->get(); |
||||
|
||||
$filasMaisUsadas = DB::table('queues as q') |
||||
->join('eventos_atendimento as ea', 'ea.id_queue', '=', 'q.id') |
||||
->select('q.nome', DB::raw('count(ea.id_queue) as qtde_fila')) |
||||
->where('q.id_empresa', $id_empresa); |
||||
|
||||
if ($dataInicio && $dataFim) { |
||||
$filasMaisUsadas->whereBetween(DB::raw('ea.data_reg::DATE'), [$dataInicio, $dataFim]); |
||||
} elseif ($dataInicio) { |
||||
$filasMaisUsadas->where(DB::raw('ea.data_reg::DATE'), '>=', $dataInicio); |
||||
} elseif ($dataFim) { |
||||
$filasMaisUsadas->where(DB::raw('ea.data_reg::DATE'), '<=', $dataFim); |
||||
} |
||||
|
||||
$filasMaisUsadas = $filasMaisUsadas |
||||
->groupBy('q.nome') |
||||
->get(); |
||||
|
||||
$data = [ |
||||
'atendimentosData' => $atendimentosData, |
||||
'atendimentosStatusData' => $atendimentosStatusData, |
||||
'filasMaisUsadas' => $filasMaisUsadas, |
||||
]; |
||||
|
||||
return $data; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,205 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use App\Models\Types; |
||||
use App\Models\NumberChannel; |
||||
use App\Models\Horario; |
||||
use App\Models\Agentes; |
||||
use App\Models\Filas; |
||||
use App\Models\Redirect; |
||||
use App\Models\HorarioOption; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class HorariosController extends Controller |
||||
{ |
||||
public function __construct( |
||||
protected Horario $horarioRepository, |
||||
protected Agentes $agenteRepository, |
||||
protected Filas $queueRepository, |
||||
protected Redirect $redirectRepository, |
||||
protected HorarioOption $horarioOptionRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_redirect')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$id_empresa = Helper::getEmpresas(); |
||||
|
||||
if (!is_int($id_empresa)){ |
||||
$empresasIds = $id_empresa->pluck('id')->toArray(); |
||||
} else { |
||||
$empresasIds = $id_empresa; |
||||
} |
||||
|
||||
$types = Types::all(); |
||||
$horarios = $this->horarioRepository->list(["id_empresa" => $empresasIds]); |
||||
$numberChannels = NumberChannel::whereIn('id_empresa', $empresasIds)->get(); |
||||
|
||||
return view('admin.cadastros.horarios', compact('horarios', 'numberChannels', 'types')); |
||||
} |
||||
|
||||
public function show(Request $request) |
||||
{ |
||||
$data = $request->all(); |
||||
$id_type = $request->segment(2); |
||||
|
||||
if (empty($id_type)) { |
||||
return response()->json(['data' => 'Parametro ID_TYPE é obrigatório']); |
||||
} |
||||
|
||||
$type = DB::table('types')->where([['id', $id_type], ['status', true]])->first(); |
||||
$typeName = $type->name; |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$data = null; |
||||
switch ($typeName) { |
||||
case 'queue': |
||||
$data = $this->queueRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
case 'redirect': |
||||
$data = $this->redirectRepository->list(["id_empresa" => $id_empresa]); |
||||
break; |
||||
case 'agent': |
||||
$data = $this->agenteRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
case 'horario': |
||||
$data = $this->horarioRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
default: |
||||
$data = null; |
||||
break; |
||||
} |
||||
|
||||
$response = [ |
||||
'data' => [ |
||||
'status' => true, |
||||
'data' => $data, |
||||
], |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_redirect')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'id_number' => ['required'], |
||||
'nome' => ['required', 'string'], |
||||
'opcao' => ['required'], |
||||
'acao' => ['required'], |
||||
'status' => ['required'] |
||||
]); |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
$id = $request->acao; |
||||
if ($request->opcao == 3) { |
||||
$id = $this->agenteRepository->get(["id" => $request->acao])->matricula; |
||||
} |
||||
|
||||
$created = $this->horarioRepository->create($request->id_number, strtoupper($request->nome), $request->opcao, $id, $status); |
||||
|
||||
if(!$created){ |
||||
redirect()->back()->with('status', 'Erro ao tentar cadastrar horário'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Cadastrado com sucesso!'); |
||||
} |
||||
|
||||
public function edit(Request $request) |
||||
{ |
||||
$id = $request->segment(2); |
||||
if (empty($id)) { |
||||
return response()->json(['data' => 'Parametro ID é obrigatório']); |
||||
} |
||||
|
||||
$optionData = Horario::find($id); |
||||
|
||||
$types = Types::all(); |
||||
|
||||
$id_empresa = Helper::getEmpresas(); |
||||
|
||||
if (!is_int($id_empresa)){ |
||||
$empresasIds = $id_empresa->pluck('id')->toArray(); |
||||
} else { |
||||
$empresasIds = $id_empresa; |
||||
} |
||||
|
||||
$numberChannels = NumberChannel::whereIn('id_empresa', $empresasIds)->get(); |
||||
|
||||
$response = [ |
||||
'data' => [ |
||||
'status' => true, |
||||
'option_data' => $optionData, |
||||
'types' => $types, |
||||
'numberChannels' => $numberChannels |
||||
], |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function update(Request $request) |
||||
{ |
||||
$id = $request->segment(2); |
||||
if (!$id) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'id_number' => ['required'], |
||||
'nome' => ['required', 'string'], |
||||
'opcao' => ['required'], |
||||
'acao' => ['required'], |
||||
'status' => ['required'] |
||||
]); |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
$acao = $request->acao; |
||||
if ($request->opcao == 3) { |
||||
$acao = $this->agenteRepository->get(["id" => $request->acao])->matricula; |
||||
} |
||||
|
||||
$created = $this->horarioRepository->atualizar($id, $request->id_number, $request->nome, $request->opcao, $acao, $status); |
||||
|
||||
if(!$created){ |
||||
redirect()->back()->with('status', 'Erro ao tentar atualizar Horario'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Atualizado com sucesso'); |
||||
} |
||||
|
||||
public function destroy($horario_id) |
||||
{ |
||||
if (!$horario_id) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
$horariosOptions = $this->horarioOptionRepository->list(['id_horario' => $horario_id]); |
||||
|
||||
if (count($horariosOptions) > 0) { |
||||
return redirect()->back()->with('status', 'É necessário deletar todos os subitens primeiro!'); |
||||
} |
||||
|
||||
$deleted = $this->horarioRepository->deletar($horario_id); |
||||
|
||||
if(!$deleted){ |
||||
return redirect()->back()->with('status', 'Erro ao tentar deletar horário'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Deletado com sucesso!'); |
||||
} |
||||
} |
@ -0,0 +1,192 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Agentes; |
||||
use App\Models\Filas; |
||||
use App\Models\Horario; |
||||
use App\Models\HorarioOption; |
||||
use App\Models\Types; |
||||
use App\Models\Redirect; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Support\Facades\Gate; |
||||
|
||||
class HorariosOptionController extends Controller |
||||
{ |
||||
public function __construct( |
||||
protected Agentes $agenteRepository, |
||||
protected Filas $queueRepository, |
||||
protected Horario $horarioRepository, |
||||
protected HorarioOption $horariosOptionsRepository, |
||||
protected Redirect $redirectRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return redirect('horarios'); |
||||
} |
||||
$options = $this->horariosOptionsRepository->list(["id_horario" => $id]); |
||||
$types = Types::all(); |
||||
$id_horario = $id; |
||||
|
||||
return view('admin.cadastros.horariosOption', compact('options', 'id_horario', 'types')); |
||||
} |
||||
|
||||
public function show(Request $request) |
||||
{ |
||||
$id_type = $request->segment(4); |
||||
|
||||
if (empty($id_type)) { |
||||
return response()->json(['data' => 'Parametro ID_TYPE é obrigatório']); |
||||
} |
||||
|
||||
$type = DB::table('types')->where([['id', $id_type], ['status', true]])->first(); |
||||
$typeName = $type->name; |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$data = null; |
||||
switch ($typeName) { |
||||
case 'queue': |
||||
$data = $this->queueRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
case 'redirect': |
||||
$data = $this->redirectRepository->list(["id_empresa" => $id_empresa]); |
||||
break; |
||||
case 'agent': |
||||
$data = $this->agenteRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
case 'horario': |
||||
$data = $this->horarioRepository->list(["id_empresa" => $id_empresa, "status" => true]); |
||||
break; |
||||
default: |
||||
$data = null; |
||||
break; |
||||
} |
||||
|
||||
$response = [ |
||||
'data' => [ |
||||
'status' => true, |
||||
'data' => $data, |
||||
], |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_redirect')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'id_horario' => ['required'], |
||||
'horario_inicio' => ['required'], |
||||
'horario_fim' => ['required'], |
||||
'feriado' => ['required'], |
||||
'todos_dias_semana' => ['required'], |
||||
'todos_meses' => ['required'], |
||||
'todos_dias_mes' => ['required'], |
||||
]); |
||||
|
||||
$id = $request->destino; |
||||
if ($request->type == 3) { |
||||
$id = $this->agenteRepository->get(["id" => $request->destino])->matricula; |
||||
} |
||||
|
||||
$todos_dias_semana = $request->todos_dias_semana === "Sim" ? true : false; |
||||
$todos_meses = $request->todos_meses === "Sim" ? true : false; |
||||
$todos_dias_mes = $request->todos_dias_mes === "Sim" ? true : false; |
||||
$feriado = $request->feriado === "Sim" ? true : false; |
||||
|
||||
$created = $this->horariosOptionsRepository->create($request->id_horario, $request->horario_inicio, $request->horario_fim, $todos_dias_semana, $request->dias_semana, |
||||
$request->dias_semana_fim, $todos_dias_mes, $request->dias_mes, $request->dias_mes_fim, $todos_meses, $request->meses, $request->meses_fim, |
||||
$request->type, $id, $feriado); |
||||
|
||||
if(!$created){ |
||||
redirect()->back()->with('status', 'Erro ao tentar cadastrar regra'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Cadastrado com sucesso'); |
||||
} |
||||
|
||||
public function destroy($id_horario, $id_horario_option) |
||||
{ |
||||
if (!$id_horario_option) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
$deleted = $this->horariosOptionsRepository->deletar($id_horario_option); |
||||
|
||||
if(!$deleted){ |
||||
redirect()->back()->with('status', 'Erro ao tentar deletar horário'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Deletado com sucesso!'); |
||||
} |
||||
|
||||
public function edit(Request $request) |
||||
{ |
||||
$id = $request->segment(4); |
||||
if (empty($id)) { |
||||
return response()->json(['data' => 'Parametro ID é obrigatório']); |
||||
} |
||||
|
||||
$optionData = HorarioOption::find($id); |
||||
|
||||
$types = Types::all(); |
||||
|
||||
$response = [ |
||||
'data' => [ |
||||
'status' => true, |
||||
'option_data' => $optionData, |
||||
'types' => $types, |
||||
], |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function update(Request $request) |
||||
{ |
||||
$id = $request->segment(4); |
||||
if (!$id) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'horario_inicio' => ['required'], |
||||
'horario_fim' => ['required'], |
||||
'feriado' => ['required'], |
||||
'todos_dias_semana' => ['required'], |
||||
'todos_meses' => ['required'], |
||||
'todos_dias_mes' => ['required'], |
||||
]); |
||||
|
||||
$destino = $request->destino; |
||||
if ($request->type == 3) { |
||||
$destino = $this->agenteRepository->get(["id" => $request->destino])->matricula; |
||||
} |
||||
|
||||
$todos_dias_semana = $request->todos_dias_semana === "Sim" ? true : false; |
||||
$todos_meses = $request->todos_meses === "Sim" ? true : false; |
||||
$todos_dias_mes = $request->todos_dias_mes === "Sim" ? true : false; |
||||
$feriado = $request->feriado === "Sim" ? true : false; |
||||
|
||||
$created = $this->horariosOptionsRepository->atualizar($id, $request->horario_inicio, $request->horario_fim, $todos_dias_semana, $request->dias_semana, |
||||
$request->dias_semana_fim, $todos_dias_mes, $request->dias_mes, $request->dias_mes_fim, $todos_meses, $request->meses, $request->meses_fim, |
||||
$request->type, $destino, $feriado); |
||||
|
||||
if(!$created){ |
||||
redirect()->back()->with('status', 'Erro ao tentar atualizar regra'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Atualizado com sucesso'); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,142 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\NumberChannel; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Gate; |
||||
|
||||
class NumberChannelController extends Controller |
||||
{ |
||||
|
||||
public function __construct( |
||||
protected NumberChannel $numberChannelRepository, |
||||
) { |
||||
} |
||||
|
||||
public function index(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_channels')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$empresas = Helper::getEmpresas(); |
||||
|
||||
if (!is_int($empresas)){ |
||||
$empresasIds = $empresas->pluck('id')->toArray(); |
||||
} else { |
||||
$empresasIds = $empresas; |
||||
} |
||||
|
||||
if ($request->empresa) { |
||||
$empresasIds = $request->empresa; |
||||
} |
||||
$search = strtolower($request->pesquisa); |
||||
$status = $request->status === "desativado" ? false : true; |
||||
|
||||
$channels = $this->numberChannelRepository->list(["id_empresa" => $empresasIds, "status" => $status, "search" => $search]); |
||||
|
||||
return view('admin.cadastros.channels', compact('channels', 'status', 'search')); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_channels')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'name' => ['required'], |
||||
'id_empresa' => ['required'], |
||||
'number' => ['required'], |
||||
'token' => ['required'], |
||||
'channel' => ['required'], |
||||
'work_space' => ['required'], |
||||
'title' => ['required'], |
||||
]); |
||||
|
||||
|
||||
$status = $request->status === 'on' ? true : false; |
||||
$created = $this->numberChannelRepository->create($request->name, $request->id_empresa, $request->number, $request->token, $request->channel, $request->work_space, $request->title, $status); |
||||
if(!$created){ |
||||
return redirect()->back()->with('status', 'Erro ao tentar criar channel'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', ' Cadastrado com sucesso'); |
||||
} |
||||
|
||||
public function edit($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('edit_channels')){ |
||||
abort(404); |
||||
} |
||||
|
||||
if (empty($id)) { |
||||
return redirect('channels'); |
||||
} |
||||
|
||||
$channelData = NumberChannel::find($id); |
||||
$response = [ |
||||
'status' => true, |
||||
'data' => $channelData |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
public function destroy($id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('destroy_channels')){ |
||||
abort(404); |
||||
} |
||||
|
||||
if (empty($id)) { |
||||
return redirect('channels'); |
||||
} |
||||
|
||||
NumberChannel::where('id', $id)->update([ |
||||
"status" => false |
||||
]); |
||||
|
||||
return redirect('channels')->with('status', 'desativado com sucesso'); |
||||
} |
||||
|
||||
public function update(Request $request, $id) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('update_channels')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$request->validate([ |
||||
'name' => ['required'], |
||||
'id_empresa' => ['required'], |
||||
'number' => ['required'], |
||||
'token' => ['required'], |
||||
'channel' => ['required'], |
||||
'work_space' => ['required'], |
||||
'title' => ['required'], |
||||
]); |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
|
||||
NumberChannel::where("id", $id)->update([ |
||||
'name' => $request->name, |
||||
'id_empresa' => $request->id_empresa, |
||||
'number' => $request->number, |
||||
'token' => $request->token, |
||||
'channel' => $request->channel, |
||||
'work_space' => $request->work_space, |
||||
'title' => $request->title, |
||||
'status' => $status, |
||||
]); |
||||
|
||||
return redirect('channels')->with('status', 'atualizado com sucesso'); |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Http\Controllers\Controller; |
||||
use App\Http\Requests\ProfileUpdateRequest; |
||||
use Illuminate\Http\RedirectResponse; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Auth; |
||||
use Illuminate\Support\Facades\Redirect; |
||||
use Illuminate\View\View; |
||||
|
||||
class ProfileController extends Controller |
||||
{ |
||||
/** |
||||
* Display the user's profile form. |
||||
*/ |
||||
public function edit(Request $request): View |
||||
{ |
||||
return view('profile.edit', [ |
||||
'user' => $request->user(), |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Update the user's profile information. |
||||
*/ |
||||
public function update(ProfileUpdateRequest $request): RedirectResponse |
||||
{ |
||||
$request->user()->fill($request->validated()); |
||||
|
||||
$request->user()->save(); |
||||
|
||||
return Redirect::route('profile.edit')->with('status', 'profile-updated'); |
||||
} |
||||
|
||||
/** |
||||
* Delete the user's account. |
||||
*/ |
||||
public function destroy(Request $request): RedirectResponse |
||||
{ |
||||
$request->validateWithBag('userDeletion', [ |
||||
'password' => ['required', 'current_password'], |
||||
]); |
||||
|
||||
$user = $request->user(); |
||||
|
||||
Auth::logout(); |
||||
|
||||
$user->delete(); |
||||
|
||||
$request->session()->invalidate(); |
||||
$request->session()->regenerateToken(); |
||||
|
||||
return Redirect::to('/'); |
||||
} |
||||
} |
@ -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')); |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
<?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 App\Models\Contatos; |
||||
use App\Models\Messages; |
||||
use Illuminate\Contracts\View\View; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Gate; |
||||
|
||||
class RelatorioHistoricoAtendimentoController extends Controller |
||||
{ |
||||
public function __construct( |
||||
protected Atendimentos $atendimentosRepository, |
||||
protected Messages $messageRepository, |
||||
protected Contatos $contatosRepository, |
||||
protected Agentes $agenteRepository |
||||
) { |
||||
} |
||||
|
||||
public function index(Request $request): View |
||||
{ |
||||
$user = auth()->user(); |
||||
if (Gate::forUser($user)->denies('show_relatorio_historico_atendimento')) { |
||||
abort(404); |
||||
} |
||||
|
||||
$selected = (object) $request->all(); |
||||
$idEmpresa = Helper::getIdEmpresa(); |
||||
$atendimentos = $this->atendimentosRepository->getCompletAtend(["id_empresa" => $idEmpresa, "protocolo" => $request->protocolo, |
||||
"atendente" => $request->atendente, "usuario" => $request->usuario, "dataInicio" => $request->dataInicio, |
||||
"dataFim" => $request->dataFim]); |
||||
|
||||
return view('admin.relatorios.historicoAtendimentos.historicoAtendimentos', compact('atendimentos', 'selected')); |
||||
} |
||||
|
||||
public function show($uniqueid): View |
||||
{ |
||||
if (empty($uniqueid)) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
$idEmpresa = Helper::getIdEmpresa(); |
||||
$messages = $this->messageRepository->get($uniqueid); |
||||
$atendimento = $this->atendimentosRepository->get(["uniqueid" => $uniqueid]); |
||||
|
||||
$contato = $this->contatosRepository->get(["id_empresa" => $idEmpresa, "contato" => $atendimento->cliente_id]); |
||||
if (empty($contato)) { |
||||
$contato = (object) [ |
||||
"nome" => $atendimento->nome, |
||||
"contato" => $atendimento->cliente_id, |
||||
]; |
||||
} |
||||
$atendentes = $this->atendimentosRepository->findAgentByAtend($uniqueid); |
||||
|
||||
return view('admin.relatorios.historicoAtendimentos.historicoAtendimento', compact('messages', 'contato', 'atendentes')); |
||||
} |
||||
} |
@ -0,0 +1,54 @@
|
||||
<?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 RelatorioProducaoAgenteController 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]); |
||||
|
||||
if (empty($request->all())) { |
||||
$atendimentos = []; |
||||
} else { |
||||
$atendimentos = $this->atendimentosRepository->getProducaoAgente(["fila" => $request->fila, "atendente" => $request->atendente, "dataInicio" => $request->dataInicio, "dataFim" => $request->dataFim]); |
||||
} |
||||
|
||||
return view('admin.relatorios.producaoAgentes.producaoAgentes', compact('atendimentos', 'selected', 'filas', 'agentes')); |
||||
} |
||||
} |
@ -0,0 +1,129 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Filas; |
||||
use App\Models\Pausas; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\DB; |
||||
use GuzzleHttp\Client; |
||||
use App\Traits\AuthToken; |
||||
use App\Models\Tokens; |
||||
|
||||
class SupervisorController extends Controller |
||||
{ |
||||
use AuthToken; |
||||
|
||||
public function __construct( |
||||
protected Filas $queueRepository, |
||||
protected Tokens $tokenRepository, |
||||
) { |
||||
} |
||||
|
||||
public function desconectarAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$deleted = DB::table("supervisor as s")->where("s.id", $request->supervisor_id)->delete(); |
||||
|
||||
if(!$deleted){ |
||||
return redirect()->back()->with('status', 'Erro ao desconectar agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Desconectado com sucesso'); |
||||
} |
||||
|
||||
public function pausaAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'pausa' => ['string', 'required'], |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$pausa = Pausas::where("id", $request->pausa)->first(); |
||||
$user = auth()->user(); |
||||
$tokenDB = $this->getToken($user->id); |
||||
$httpClient = new Client(); |
||||
$agente = DB::table("supervisor as s") |
||||
->where("s.id", $request->supervisor_id) |
||||
->first(); |
||||
|
||||
$url = env('APP_URL'); |
||||
$response = $httpClient->post("$url/api/v1/agente/entrarPausa", [ |
||||
'headers' => [ |
||||
'Authorization' => "Bearer $tokenDB->token", |
||||
], |
||||
'json' => [ |
||||
'id_pausa' => $pausa->id, |
||||
'matricula' => $agente->matricula, |
||||
], |
||||
]); |
||||
|
||||
if (!($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) { |
||||
return redirect()->back()->with('status', 'Erro ao tentar pausar o agente'); |
||||
} else { |
||||
return redirect()->back()->with('status', 'O agente foi colocado em pausa'); |
||||
} |
||||
} |
||||
|
||||
public function retirarPausaAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$updated = DB::table("supervisor as s")->where("s.id", $request->supervisor_id)->update([ |
||||
'motivo_pausa' => null, |
||||
'status' => "LIVRE", |
||||
]); |
||||
|
||||
if(!$updated){ |
||||
return redirect()->back()->with('status', 'Erro ao retirar pausa do agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Pausa retirada com sucesso'); |
||||
} |
||||
|
||||
public function pausarTodosAgentes(Request $request, $id) |
||||
{ |
||||
$user = auth()->user(); |
||||
$tokenDB = $this->getToken($user->id); |
||||
|
||||
$httpClient = new Client(); |
||||
|
||||
$check = true; |
||||
|
||||
$fila = Filas::where("id", $id)->first(); |
||||
$pausa = Pausas::where("id", $request->pausa)->first(); |
||||
|
||||
$agentes = DB::table("supervisor as s") |
||||
->where("s.fila", $fila->nome) |
||||
->get(); |
||||
|
||||
foreach ($agentes as $agente) { |
||||
$url = env('APP_URL'); |
||||
$response = $httpClient->post("$url/api/v1/agente/entrarPausa", [ |
||||
'headers' => [ |
||||
'Authorization' => "Bearer $tokenDB->token", |
||||
], |
||||
'json' => [ |
||||
'id_pausa' => $pausa->id, |
||||
'matricula' => $agente->matricula, |
||||
], |
||||
]); |
||||
|
||||
if (!($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) { |
||||
$check = false; |
||||
} |
||||
|
||||
if (!$check) { |
||||
return redirect()->back()->with('status', 'Erro ao tentar pausar todos os agentes'); |
||||
} else { |
||||
return redirect()->back()->with('status', 'Todos os agentes foram colocados em pausa'); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,83 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers\Admin; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Models\Templates; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\Gate; |
||||
use App\Models\NumberChannel; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class TemplatesController extends Controller |
||||
{ |
||||
|
||||
public function index() |
||||
{ |
||||
$user = auth()->user(); |
||||
|
||||
if(Gate::forUser($user)->denies('show_templates')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$channel_token = session('channel_token'); |
||||
$channel_number = session('channel_number'); |
||||
$workspace = session('workspace'); |
||||
|
||||
return view("admin.cadastros.templates", ["channel_token" => $channel_token, "channel_number" => $channel_number, "workspace" => $workspace]); |
||||
} |
||||
|
||||
public function show() |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('show_templates')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$templates = DB::select(" |
||||
SELECT * |
||||
FROM templates |
||||
WHERE id_empresa = :id_empresa |
||||
", ['id_empresa' => $id_empresa]); |
||||
|
||||
return response()->json(["data" => $templates]); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$user = auth()->user(); |
||||
if(Gate::forUser($user)->denies('store_templates')){ |
||||
abort(404); |
||||
} |
||||
|
||||
$data = $request->all(); |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$componentsJson = json_encode($data["components"]); |
||||
|
||||
Templates::create([ |
||||
"id" => $data["id"], |
||||
"name" => $data["name"], |
||||
"category" => $data["category"]["description"], |
||||
"language" => $data["language"]["name"], |
||||
"status" => $data["status"]["code"], |
||||
"components" => $componentsJson, |
||||
"id_empresa" => $id_empresa, |
||||
]); |
||||
|
||||
return response()->json(["message" => "Template foi cadastrado com sucesso"]); |
||||
} |
||||
|
||||
public function deletar($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return redirect()->back(); |
||||
} |
||||
|
||||
Templates::where("id", $id) |
||||
->delete(); |
||||
|
||||
return redirect()->back()->with('status', 'Deletado com sucesso'); |
||||
} |
||||
} |
@ -1,193 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use App\Models\Agentes; |
||||
use App\Models\GrupoUsuario; |
||||
use App\Models\UsuarioEmpresa; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\DB; |
||||
use Illuminate\Support\Facades\Hash; |
||||
|
||||
class AgentesController extends Controller |
||||
{ |
||||
public function index(Request $request) |
||||
{ |
||||
$selected = (object) ['isSelected' => false, 'isAtivo' => 'ativo']; |
||||
$maior_matricula = null; |
||||
|
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$agentes = DB::table('grupo_usuario as gu') |
||||
->join('usuarios as u', 'u.id', '=', 'gu.id_usuario') |
||||
->join('grupo as g', 'g.id', '=', 'gu.id_grupo') |
||||
->join('usuario_empresa as ue', 'u.id', '=', 'ue.id_usuario') |
||||
->join('empresa as e', 'e.id', '=', 'ue.id_empresa') |
||||
->select('u.*', 'g.name') |
||||
->where('e.id', $id_empresa); |
||||
|
||||
$consulta_matricula = DB::table('usuarios as u') |
||||
->join('usuario_empresa as ue', 'ue.id_usuario', '=', 'u.id') |
||||
->select(DB::raw('MAX(matricula) as maior_matricula')) |
||||
->where('ue.id_empresa', $id_empresa) |
||||
->first(); |
||||
|
||||
if ($request->status) { |
||||
$status = $request->status == 'ativo' ? true : false; |
||||
$selected = (object) ['isSelected' => true, 'isAtivo' => $request->status]; |
||||
$agentes->where('u.status', $status); |
||||
} else { |
||||
$agentes->where('u.status', true); |
||||
} |
||||
|
||||
if ($request->pesquisa) { |
||||
$pesquisa = strtolower($request->pesquisa); |
||||
$agentes->where(DB::raw('LOWER(u.nome)'), 'like', "%$pesquisa%"); |
||||
} |
||||
|
||||
$agentes = $agentes->orderBy('u.nome', 'asc')->get(); |
||||
|
||||
$maior_matricula = $consulta_matricula->maior_matricula + 1; |
||||
|
||||
return view('admin.users', compact('agentes', 'selected', 'maior_matricula')); |
||||
} |
||||
|
||||
public function store(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'nome' => ['required'], |
||||
'email' => ['required', 'unique:'.User::class], |
||||
'matricula' => ['required'], |
||||
'status' => ['required'], |
||||
]); |
||||
|
||||
$status = $request->status === 'on' ? true : false; |
||||
|
||||
$isMatriculaRegister = Agentes::where('matricula', $request->matricula)->get()->count(); |
||||
|
||||
if ($isMatriculaRegister > 0) { |
||||
return redirect('/users')->with('status', ' matricula vinculada com outro agente'); |
||||
} |
||||
|
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
$agente = Agentes::create([ |
||||
"nome" => $request->nome, |
||||
"email" => $request->email, |
||||
"matricula" => $request->matricula, |
||||
"status" => $status, |
||||
"password" => Hash::make('123'), |
||||
]); |
||||
|
||||
GrupoUsuario::create([ |
||||
'id_usuario' => $agente->id, |
||||
'id_grupo' => 3 |
||||
]); |
||||
|
||||
UsuarioEmpresa::create([ |
||||
'id_usuario' => $agente->id, |
||||
'id_empresa' => $id_empresa, |
||||
'is_ativo' => true |
||||
]); |
||||
|
||||
DB::commit(); |
||||
|
||||
return redirect('users')->with('status', 'Agente cadastrado'); |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
dd($th->getMessage()); |
||||
return redirect('users')->with('status', 'Erro ao tentar cadastrar agente'); |
||||
} |
||||
} |
||||
|
||||
|
||||
public function edit($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
$userData = Agentes::find($id); |
||||
|
||||
|
||||
$response = [ |
||||
'status' => true, |
||||
'data' => $userData |
||||
]; |
||||
|
||||
return response()->json($response); |
||||
} |
||||
|
||||
|
||||
|
||||
public function destroy($id) |
||||
{ |
||||
if (empty($id)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
Agentes::where('id', $id)->update([ |
||||
"status" => false |
||||
]); |
||||
|
||||
return redirect('users')->with('status', 'desativado com sucesso'); |
||||
} |
||||
|
||||
|
||||
public function update(Request $request, $id) |
||||
{ |
||||
|
||||
$request->validate([ |
||||
"nome" => ['required'], |
||||
|
||||
"status" => ['required'], |
||||
]); |
||||
|
||||
|
||||
if (empty($id) || empty($request->nome)) { |
||||
return redirect('users'); |
||||
} |
||||
|
||||
$status = $request->status === "on" ? true : false; |
||||
|
||||
$agente_matricula = Agentes::select('matricula') |
||||
->where('id', $id) |
||||
->get() |
||||
->first(); |
||||
|
||||
|
||||
if ($agente_matricula->matricula != $request->matricula) { |
||||
|
||||
$isMatriculaRegister = Agentes::where('matricula', $request->matricula)->get()->count(); |
||||
|
||||
|
||||
if ($isMatriculaRegister > 0) { |
||||
|
||||
return redirect('/users/editar/' . $id)->with('status', ' matricula vinculada com outro agente'); |
||||
} |
||||
|
||||
Agentes::where("id", $id) |
||||
->update([ |
||||
"nome" => $request->nome, |
||||
"status" => $status, |
||||
]); |
||||
|
||||
} else { |
||||
|
||||
Agentes::where("id", $id) |
||||
->update([ |
||||
"nome" => $request->nome, |
||||
"status" => $status, |
||||
]); |
||||
} |
||||
|
||||
|
||||
|
||||
return redirect('users')->with('status', 'atualizado com sucesso'); |
||||
} |
||||
} |
@ -1,210 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use App\Helpers\Helper; |
||||
use App\Models\Atendimentos; |
||||
use App\Models\Filas; |
||||
use App\Models\Pausas; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class DashboardController extends Controller |
||||
{ |
||||
public function index() |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
$pausas = Pausas::where(["id_empresa" => $id_empresa, "is_ativo" => true])->get(); |
||||
|
||||
return view('admin.dashboard', compact('pausas')); |
||||
} |
||||
|
||||
public function getRelatorioDados() |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$atendimentosData = DB::table('usuarios as u') |
||||
->leftJoin('atendimento as a', 'u.id', '=', 'a.id_usuario') |
||||
->select('u.nome', DB::raw('count(a.id_usuario) as qtde_atendimento')) |
||||
->where('a.id_empresa', $id_empresa) |
||||
->groupBy('u.nome') |
||||
->get(); |
||||
|
||||
$atendimentosStatusData = DB::table('usuarios as u') |
||||
->join('usuario_empresa as ue', 'ue.id_usuario', '=', 'u.id') |
||||
->join('eventos_atendimento as ea', 'ea.id_usuario', '=', 'u.id') |
||||
->select('b.evento', DB::raw('count(b.evento) as qtde_usados')) |
||||
->where('a.id_empresa', $id_empresa) |
||||
->groupBy('b.evento') |
||||
->get(); |
||||
|
||||
$filasMaisUsadas = DB::table('queues as q') |
||||
->join('eventos_atendimento as ea', 'ea.id_queue', '=', 'q.id') |
||||
->select('q.nome', DB::raw('count(ea.id_queue) as qtde_fila')) |
||||
->where('q.id_empresa', $id_empresa) |
||||
->groupBy('q.nome') |
||||
->get(); |
||||
|
||||
$data_inicio = date("Y-m-01"); |
||||
$data_atual = date('Y-m-d'); |
||||
$data_fim = Helper::last_date_in_mouth(); |
||||
|
||||
$atendimentosPorMes = $this->getAtendimentosMes($data_inicio, $data_fim); |
||||
$atendimentosDia = $this->getAtendimentoDia($data_atual); |
||||
$totalAgentesAtivos = $this->getAgentesAtivos(); |
||||
$totalAgentesPausa = $this->getAgentesPausa(); |
||||
|
||||
$relatoriosAtendimento = $this->relatoriosDados(); |
||||
|
||||
$total_atendimentos = $this->totalAtendimentos($atendimentosData); |
||||
|
||||
$data = [ |
||||
'atendimentosData' => $atendimentosData, |
||||
'atendimentosStatusData' => $atendimentosStatusData, |
||||
'filasMaisUsadas' => $filasMaisUsadas, |
||||
'atendimentosPorMes' => $atendimentosPorMes, |
||||
'atendimentosDia' => $atendimentosDia, |
||||
'totalAgentesAtivos' => $totalAgentesAtivos, |
||||
'totalAgentesPausa' => $totalAgentesPausa, |
||||
'relatoriosAtendimento' => $relatoriosAtendimento, |
||||
'total_atendimentos' => $total_atendimentos, |
||||
]; |
||||
|
||||
|
||||
return response()->json(['status' => true, 'data' => $data]); |
||||
} |
||||
|
||||
private function totalAtendimentos($atendimentos) |
||||
{ |
||||
$total_atendimentos = 0; |
||||
|
||||
foreach ($atendimentos as $atendimento) { |
||||
$total_atendimentos += $atendimento->qtde_atendimento; |
||||
} |
||||
|
||||
return $total_atendimentos; |
||||
} |
||||
|
||||
private function relatoriosDados() |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$relatorio = DB::table('queues as q') |
||||
->leftJoin('supervisor as s', 's.fila', '=', 'q.nome') |
||||
->leftJoin('atendimento as a', 'a.id_usuario', '=', 's.id_usuario') |
||||
->select('q.id as fila_id', 'q.nome as fila', DB::raw('count( DISTINCT s.id) as quantidade_supervisores'), DB::raw('COALESCE(COUNT(a.id), 0) AS quantidade_atendimentos')) |
||||
->where([ |
||||
['q.id_empresa', $id_empresa], |
||||
['q.is_ativa', true], |
||||
]) |
||||
->groupBy('q.nome', 'q.id') |
||||
->orderBy('q.nome', 'asc') |
||||
->get(); |
||||
|
||||
return $relatorio; |
||||
} |
||||
|
||||
private function getAtendimentosMes($data_inicio, $data_fim) |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$atendimentosPorMes = Atendimentos::whereDate('data_reg', '>=', $data_inicio) |
||||
->whereDate('data_reg', '<=', $data_fim) |
||||
->where('id_empresa', $id_empresa) |
||||
->count(); |
||||
|
||||
return $atendimentosPorMes; |
||||
} |
||||
|
||||
|
||||
private function getAtendimentoDia($data_atual) |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$atendimentoDia = Atendimentos::whereDate('data_reg', '=', $data_atual) |
||||
->where('id_empresa', $id_empresa) |
||||
->count(); |
||||
|
||||
return $atendimentoDia; |
||||
} |
||||
|
||||
private function getAgentesAtivos() |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$totalAgentesAtivos = DB::table('supervisor as s') |
||||
->where([ |
||||
['s.id_empresa', $id_empresa], |
||||
]) |
||||
->count(); |
||||
|
||||
return $totalAgentesAtivos; |
||||
} |
||||
|
||||
private function getAgentesPausa() |
||||
{ |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$totalAgentesPausa = DB::table('supervisor as s') |
||||
->where([ |
||||
['s.id_empresa', $id_empresa], |
||||
['s.status', 'PAUSA'], |
||||
]) |
||||
->count(); |
||||
|
||||
return $totalAgentesPausa; |
||||
} |
||||
|
||||
|
||||
public function agentesLogados($id) |
||||
{ |
||||
if(empty($id)) |
||||
{ |
||||
return redirect()->back(); |
||||
} |
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
$fila = Filas::where(['id' => $id, 'id_empresa' => $id_empresa])->first(); |
||||
$pausas = Pausas::where(["id_empresa" => $id_empresa, "is_ativo" => true])->get(); |
||||
|
||||
return view('admin.agentesLogados', compact('fila', 'pausas')); |
||||
} |
||||
|
||||
public function relatoriosFilas($id) |
||||
{ |
||||
|
||||
if(empty($id)){ |
||||
return response()->json(['data' => "Parametro ID é obrigatorio"]); |
||||
} |
||||
|
||||
$user = auth()->user(); |
||||
$id_empresa = $user->empresa->first()->id; |
||||
|
||||
$fila = Filas::where('id', $id)->where('id_empresa', $id_empresa)->first(); |
||||
|
||||
$agentesNaFila = DB::table('supervisor as s') |
||||
->leftJoin('atendimento as a', function ($join) { |
||||
$data_atual = date('Y-m-d h:i:s'); |
||||
|
||||
$join->on('s.id_usuario', '=', 'a.id_usuario') |
||||
->where(DB::raw('DATE(a.data_reg)'), $data_atual); |
||||
}) |
||||
->select(DB::raw("(now() - s.tempo_login) AS login"), DB::raw('COALESCE(COUNT(a.id), 0) AS qtde_atendimento'), 's.*') |
||||
->where([ |
||||
['s.id_empresa', $id_empresa], |
||||
['fila', $fila->nome], |
||||
]) |
||||
->groupBy('s.id') |
||||
->get(); |
||||
|
||||
|
||||
return response()->json(['data' => $agentesNaFila]); |
||||
|
||||
} |
||||
} |
@ -1,10 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use Illuminate\Http\Request; |
||||
|
||||
class GruposController extends Controller |
||||
{ |
||||
// |
||||
} |
@ -1,97 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
use App\Models\Filas; |
||||
use App\Models\Pausas; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class SupervisorController extends Controller |
||||
{ |
||||
|
||||
public function desconectarAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$deleted = DB::table("supervisor as s")->where("s.id", $request->supervisor_id)->delete(); |
||||
|
||||
if(!$deleted){ |
||||
return redirect()->back()->with('status', 'Erro ao desconectar agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Desconectado com sucesso'); |
||||
} |
||||
|
||||
public function pausaAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'pausa' => ['string', 'required'], |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$pausa = Pausas::where("id", $request->pausa)->first(); |
||||
$updated = DB::table("supervisor as s")->where("s.id", $request->supervisor_id)->update([ |
||||
'motivo_pausa' => strtoupper($pausa->motivo), |
||||
'status' => "PAUSA", |
||||
]); |
||||
|
||||
if(!$updated){ |
||||
return redirect()->back()->with('status', 'Erro ao pausar agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Pausado com sucesso'); |
||||
} |
||||
|
||||
public function retirarPausaAgente(Request $request) |
||||
{ |
||||
$request->validate([ |
||||
'supervisor_id' => ['required'], |
||||
]); |
||||
|
||||
$updated = DB::table("supervisor as s")->where("s.id", $request->supervisor_id)->update([ |
||||
'motivo_pausa' => null, |
||||
'status' => "LIVRE", |
||||
]); |
||||
|
||||
if(!$updated){ |
||||
return redirect()->back()->with('status', 'Erro ao retirar pausa do agente'); |
||||
} |
||||
|
||||
return redirect()->back()->with('status', 'Pausa retirada com sucesso'); |
||||
} |
||||
|
||||
public function pausarTodosAgentes(Request $request, $id) |
||||
{ |
||||
$fila = Filas::where("id", $id)->first(); |
||||
$pausa = Pausas::where("id", $request->pausa)->first(); |
||||
|
||||
$agentes = DB::table("supervisor as s") |
||||
->where("s.fila", $fila->nome) |
||||
->get(); |
||||
|
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
foreach ($agentes as $agente) { |
||||
DB::table("supervisor as s") |
||||
->where('s.id', $agente->id) |
||||
->update([ |
||||
'motivo_pausa' => strtoupper($pausa->motivo), |
||||
'status' => "PAUSA", |
||||
]); |
||||
} |
||||
|
||||
DB::commit(); |
||||
|
||||
return redirect()->back()->with('status', 'Todos os agentes foram colocados em pausa'); |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
dd($th->getMessage()); |
||||
return redirect('users')->with('status', 'Erro ao tentar pausar todos os agentes'); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,43 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class Contatos extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
protected $table = "contatos"; |
||||
public $timestamps = true; |
||||
|
||||
protected $fillable = [ |
||||
"nome", |
||||
"email", |
||||
"contato", |
||||
"id_empresa", |
||||
"id_agente", |
||||
"status", |
||||
"notes", |
||||
]; |
||||
|
||||
public function get(array $params = []){ |
||||
$contato = DB::table('contatos as c'); |
||||
|
||||
if(!empty($params['id_empresa'])){ |
||||
$contato->where('id_empresa', $params['id_empresa']); |
||||
} |
||||
|
||||
if (!empty($params['contato'])) { |
||||
$contato->where('contato', $params['contato']); |
||||
} |
||||
|
||||
if (!empty($params['id'])) { |
||||
$contato->where('id', $params['id']); |
||||
} |
||||
|
||||
return $contato->first(); |
||||
} |
||||
} |
@ -0,0 +1,109 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class Horario extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
protected $table = "horarios"; |
||||
public $timestamps = false; |
||||
|
||||
protected $fillable = [ |
||||
'id_number', |
||||
'nome', |
||||
'opcao', |
||||
'acao', |
||||
'status', |
||||
]; |
||||
|
||||
public function list(array $params) |
||||
{ |
||||
$horarios = DB::table('horarios as h') |
||||
->join('number_channel as nc', 'nc.id', '=', 'h.id_number') |
||||
->select('h.*'); |
||||
|
||||
if (is_array($params['id_empresa'])) { |
||||
$horarios->whereIn('nc.id_empresa', $params['id_empresa']); |
||||
} else { |
||||
$horarios->where('nc.id_empresa', $params['id_empresa']); |
||||
} |
||||
|
||||
if(isset($params['id_number'])){ |
||||
$horarios->where('h.id_number', $params['id_number']); |
||||
} |
||||
|
||||
if(isset($params['nome'])){ |
||||
$horarios->where('h.nome', $params['nome']); |
||||
} |
||||
|
||||
if(isset($params['status'])){ |
||||
$horarios->where('h.status', $params['status']); |
||||
} |
||||
|
||||
return $horarios->get(); |
||||
} |
||||
|
||||
public function create(int $id_number, string $nome, string $opcao, string $acao, bool $status) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table('horarios')->insert([ |
||||
'id_number' => $id_number, |
||||
'nome' => strtoupper($nome), |
||||
'opcao' => $opcao, |
||||
'acao' => $acao, |
||||
'status' => $status |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public function deletar($id_horario) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table('horarios')->delete([ |
||||
'id' => $id_horario |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public function atualizar(int $id, int $id_number, string $nome, string $opcao, string $acao, bool $status) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table("horarios")->where("id", $id)->update([ |
||||
'id_number' => $id_number, |
||||
'nome' => strtoupper($nome), |
||||
'opcao' => $opcao, |
||||
'acao' => $acao, |
||||
'status' => $status |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,126 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Support\Facades\DB; |
||||
|
||||
class HorarioOption extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
protected $table = "horarios_itens"; |
||||
public $timestamps = false; |
||||
|
||||
protected $fillable = [ |
||||
'id_horario', |
||||
'horario_inicio', |
||||
'horario_fim', |
||||
'todos_dias_semana', |
||||
'semana', |
||||
'semana_fim', |
||||
'todos_dias_mes', |
||||
'dias_mes', |
||||
'dias_mes_fim', |
||||
'todos_mes', |
||||
'mes', |
||||
'mes_fim', |
||||
'opcao', |
||||
'acao', |
||||
'feriado' |
||||
]; |
||||
|
||||
public function list(array $params) |
||||
{ |
||||
$options = DB::table('horarios_itens as hi') |
||||
->join("horarios as h", "h.id", "=", "hi.id_horario") |
||||
->select("hi.*", "h.nome as horario_nome"); |
||||
|
||||
if (isset($params['id_horario'])) { |
||||
$options->where('hi.id_horario', $params['id_horario']); |
||||
} |
||||
|
||||
return $options->orderBy('id', 'asc')->get(); |
||||
} |
||||
|
||||
public function create(int $id_horario, string $horario_inicio, string $horario_fim, bool $todos_dias_semana, ?string $semana, ?string $semana_fim, bool $todos_dias_mes, |
||||
?int $dias_mes, ?int $dias_mes_fim, bool $todos_mes, ?string $mes, ?string $mes_fim, string $opcao, string $acao, bool $feriado) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table("horarios_itens")->insert([ |
||||
'id_horario' => $id_horario, |
||||
'horario_inicio'=> $horario_inicio, |
||||
'horario_fim' => $horario_fim, |
||||
'todos_dias_semana' => $todos_dias_semana, |
||||
'semana' => $semana, |
||||
'semana_fim'=> $semana_fim, |
||||
'todos_dias_mes'=> $todos_dias_mes, |
||||
'dias_mes' => $dias_mes, |
||||
'dias_mes_fim' => $dias_mes_fim, |
||||
'todos_mes' => $todos_mes, |
||||
'mes' => $mes, |
||||
'mes_fim'=> $mes_fim, |
||||
'opcao' => $opcao, |
||||
'acao' => $acao, |
||||
'feriado' => $feriado |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public function deletar($id_horario_option) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table('horarios_itens')->delete([ |
||||
'id' => $id_horario_option |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public function atualizar(int $id, string $horario_inicio, string $horario_fim, bool $todos_dias_semana, ?string $semana, ?string $semana_fim, bool $todos_dias_mes, |
||||
?int $dias_mes, ?int $dias_mes_fim, bool $todos_mes, ?string $mes, ?string $mes_fim, string $opcao, string $acao, bool $feriado) |
||||
{ |
||||
DB::beginTransaction(); |
||||
|
||||
try { |
||||
DB::table("horarios_itens")->where("id", $id)->update([ |
||||
'horario_inicio'=> $horario_inicio, |
||||
'horario_fim' => $horario_fim, |
||||
'todos_dias_semana' => $todos_dias_semana, |
||||
'semana' => $semana, |
||||
'semana_fim'=> $semana_fim, |
||||
'todos_dias_mes'=> $todos_dias_mes, |
||||
'dias_mes' => $dias_mes, |
||||
'dias_mes_fim' => $dias_mes_fim, |
||||
'todos_mes' => $todos_mes, |
||||
'mes' => $mes, |
||||
'mes_fim'=> $mes_fim, |
||||
'opcao' => $opcao, |
||||
'acao' => $acao, |
||||
'feriado' => $feriado |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Messages extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
public $timestamps = false; |
||||
protected $table = "message"; |
||||
|
||||
protected $fillable = [ |
||||
'uniquedid', |
||||
'src', |
||||
'dst', |
||||
'type', |
||||
'content', |
||||
'profile_name', |
||||
'msg_date', |
||||
'media', |
||||
'status', |
||||
'file_name', |
||||
'eventos_atendimento', |
||||
'id_provedor', |
||||
'mimetype', |
||||
]; |
||||
|
||||
public function get(string $uniqueid) |
||||
{ |
||||
$messages = Messages::where('uniqueid', $uniqueid) |
||||
->orderBy('id') |
||||
->get(); |
||||
|
||||
return $messages; |
||||
} |
||||
} |
@ -1,23 +0,0 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class numberChanel extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
public $timestamps = false; |
||||
protected $table = "number_channel"; |
||||
|
||||
protected $fillable = [ |
||||
'id_empresa', |
||||
'number', |
||||
'token', |
||||
'channel', |
||||
'work_space', |
||||
'title' |
||||
]; |
||||
} |
@ -0,0 +1,107 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use App\Helpers\Helper; |
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Support\Facades\DB; |
||||
class NumberChannel extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
public $timestamps = false; |
||||
protected $table = "number_channel"; |
||||
|
||||
protected $fillable = [ |
||||
'id_empresa', |
||||
'number', |
||||
'token', |
||||
'channel', |
||||
'work_space', |
||||
'title' |
||||
]; |
||||
|
||||
public function get(array $params) |
||||
{ |
||||
$channels = DB::table('number_channel as nc') |
||||
->join('empresa as e', 'e.id', '=', 'nc.id_empresa') |
||||
->select('nc.*'); |
||||
|
||||
if (isset($params['id_empresa'])) { |
||||
$channels->where('nc.id_empresa', $params['id_empresa']); |
||||
} |
||||
|
||||
return $channels->orderBy('nc.name', 'asc')->first(); |
||||
} |
||||
|
||||
public function list(array $params) |
||||
{ |
||||
$channels = DB::table('number_channel as nc') |
||||
->join('empresa as e', 'e.id', '=', 'nc.id_empresa') |
||||
->select('nc.*'); |
||||
|
||||
if (is_array($params['id_empresa'])) { |
||||
// Se $params['id_empresa'] for um array, use a condição whereIn |
||||
$channels->whereIn('nc.id_empresa', $params['id_empresa']); |
||||
} else { |
||||
// Se for um único valor, use a condição normal |
||||
$channels->where('nc.id_empresa', $params['id_empresa']); |
||||
} |
||||
|
||||
if (isset($params['search'])) { |
||||
$channels->where(DB::raw('LOWER(nc.name)'), 'LIKE', "%{$params['search']}%"); |
||||
} |
||||
|
||||
if (isset($params['status'])) { |
||||
$channels->where('nc.status', $params['status']); |
||||
} |
||||
|
||||
|
||||
return $channels->orderBy('nc.name', 'asc')->get(); |
||||
} |
||||
|
||||
public function create(string $name, int $id_empresa, string $number, string $token, string $chanel, string $work_space, string $title, bool $status) |
||||
{ |
||||
DB::beginTransaction(); |
||||
try { |
||||
DB::table('number_channel')->insert([ |
||||
'name' => $name, |
||||
'id_empresa' => $id_empresa, |
||||
'number' => $number, |
||||
'token' => $token, |
||||
'channel' => $chanel, |
||||
'work_space' => $work_space, |
||||
'title' => $title, |
||||
'status' => $status, |
||||
]); |
||||
|
||||
DB::commit(); |
||||
return true; |
||||
} catch (\Throwable $th) { |
||||
DB::rollBack(); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static function getToken(){ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$token = NumberChannel::where("id_empresa", $id_empresa)->first()->token; |
||||
|
||||
return $token; |
||||
} |
||||
|
||||
public static function getNumber(){ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$number = NumberChannel::where("id_empresa", $id_empresa)->first()->number; |
||||
|
||||
return $number; |
||||
} |
||||
|
||||
public static function getWorkspace(){ |
||||
$id_empresa = Helper::getIdEmpresa(); |
||||
$workspace = NumberChannel::where("id_empresa", $id_empresa)->first()->work_space; |
||||
|
||||
return $workspace; |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
||||
|
||||
class Permissoes extends Model |
||||
{ |
||||
protected $table = "permissoes"; |
||||
|
||||
use HasFactory; |
||||
|
||||
protected $fillable = [ |
||||
'nome', |
||||
'status', |
||||
]; |
||||
|
||||
public function grupos(): BelongsToMany |
||||
{ |
||||
return $this->BelongsToMany(Grupos::class,'grupo_permissoes', 'id_grupo', 'id_permissao'); |
||||
} |
||||
} |
@ -0,0 +1,32 @@
|
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Templates extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
protected $table = "templates"; |
||||
public $timestamps = true; |
||||
|
||||
protected $fillable = [ |
||||
"id", |
||||
'name', |
||||
'status', |
||||
'category', |
||||
'language', |
||||
'components', |
||||
'id_empresa', |
||||
]; |
||||
|
||||
|
||||
public static function findById($id) |
||||
{ |
||||
$template = Templates::where('id', $id)->first(); |
||||
|
||||
return $template; |
||||
} |
||||
} |
@ -0,0 +1,52 @@
|
||||
<?php |
||||
|
||||
namespace App\Traits; |
||||
|
||||
use App\Helpers\Helper; |
||||
use Illuminate\Support\Facades\Http; |
||||
use App\Models\NumberChannel; |
||||
|
||||
trait AuthToken |
||||
{ |
||||
public function generateToken($user) |
||||
{ |
||||
$data = [ |
||||
"email" => $user->email, |
||||
"senha" => $user->password ?? $user->senha, |
||||
]; |
||||
|
||||
session()->put('user_data', Helper::Crypt()->encrypt(json_encode($data, true))); |
||||
$response = Http::post("" . env('APP_URL') . "/access/login", $data); |
||||
|
||||
$responseDecode = json_decode($response); |
||||
if($responseDecode->status === "error"){ |
||||
return false; |
||||
} |
||||
|
||||
$token = NumberChannel::getToken(); |
||||
$number = NumberChannel::getNumber(); |
||||
$workspace = NumberChannel::getWorkspace(); |
||||
session()->put('channel_token', $token); |
||||
session()->put('channel_number', $number); |
||||
session()->put('workspace', $workspace); |
||||
|
||||
return $responseDecode; |
||||
} |
||||
|
||||
public function getToken($user_id) |
||||
{ |
||||
$tokenDB = $this->tokenRepository->where('id_usuario', $user_id)->first(); |
||||
if (empty($tokenDB)) { |
||||
$encrypt = session('user_data'); |
||||
$userData = Helper::Crypt()->decrypt($encrypt); |
||||
$user = json_decode($userData); |
||||
$this->generateToken($user); |
||||
$tokenDB = $this->tokenRepository->where('id_usuario', $user_id)->first(); |
||||
if (empty($tokenDB)) { |
||||
return response()->json("Não foi possivel gerar o token", 404); |
||||
} |
||||
} |
||||
|
||||
return $tokenDB; |
||||
} |
||||
} |
@ -0,0 +1,5 @@
|
||||
<?php |
||||
return [ |
||||
"PASSWORD" => '#S1mpl3S_C0nn3ct@R00t', |
||||
|
||||
]; |
@ -0,0 +1,23 @@
|
||||
<?php |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Eventos |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Eventos utilizados pelo gerenciamento dos atendimentos. |
||||
| |
||||
*/ |
||||
return [ |
||||
"CONF_EVENT_ESPERA" => "EMESPERA", |
||||
"CONF_EVENT_TIMEOUT_CLIENTE" => "TIMEOUT_CALLER", |
||||
"CONF_EVENT_TIMEOUT_AGENTE" => "TIMEOUT_AGENT", |
||||
"CONF_EVENT_TIMERMINO_CLIENTE" => "COMPLETE_CALLER", |
||||
"CONF_EVENT_TIMERMINO_AGENTE" => "COMPLETE_AGENT", |
||||
"CONF_EVENT_CANCELADO" => "CANCELADO", |
||||
"CONF_EVENT_TRANSFER" => "TRANSFER", |
||||
"CONF_EVENT_START" => "START", |
||||
"CONF_EVENT_ERRO_ATEND" => "LOST_CONNECTION", |
||||
"CONF_EVENT_SEND_HSM" => "SENDED", |
||||
"CONF_EVENT_ABANDON" => "ABANDON", |
||||
]; |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 8.3 KiB |
@ -0,0 +1,7 @@
|
||||
|
||||
function clickedAccordion(event){ |
||||
const target = event.currentTarget; |
||||
target.querySelector('.accordion-body').classList.toggle('hidden'); |
||||
console.log(target.querySelector('.icon')); |
||||
target.querySelector('.icon').classList.toggle('rotate-90'); |
||||
} |
@ -0,0 +1,152 @@
|
||||
const chat = document.querySelector('.chat'); |
||||
const icontypes = ['csv', 'doc', 'pdf', 'txt', 'xls', 'zip', 'ppt'] |
||||
|
||||
function montaChat(messages, cliente_id) { |
||||
messages.forEach((message) => { |
||||
const datesend = converdata(new Date(message.msg_date).getTime()); |
||||
let typesend = cliente_id == message.src ? "sender" : "receiver"; |
||||
let statusMessage = message.status != 'error' ? datesend : '<span class="message-error" style="color:red">Mensagem não foi enviada!</span>'; |
||||
|
||||
if (message.type == "text") { |
||||
chat.innerHTML += ` |
||||
<div class="${typesend}"> |
||||
<span class="${typesend}-message">${message.profile_name}: ${message.content.replace(/\r?\n/g, "")}</span> |
||||
<br/> |
||||
<span class="message-time">${statusMessage}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
} |
||||
if (message.type == "transfer") { |
||||
chat.innerHTML += ` |
||||
<div class="events"> |
||||
<span class="events-message">${message.content} por ${message.profile_name}, ${datesend}.</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
} |
||||
if (message.type == "finish" || message.type == "re_start" || message.type == "recover") { |
||||
chat.innerHTML += ` |
||||
<div class="events"> |
||||
<span class="events-message">${message.content}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
} |
||||
if (message.type != "text") { |
||||
const sendobj = { |
||||
filename: message.file_name, |
||||
id_provedor: message.id_provedor, |
||||
type: message.type, |
||||
mimetype: message.mimetype, |
||||
from: typesend, |
||||
profile_name: message.profile_name |
||||
}; |
||||
messageTypeMedia(sendobj); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function addZero(time) { |
||||
if (time < 10) { |
||||
time = "0" + time |
||||
} |
||||
return time |
||||
} |
||||
|
||||
function converdata(timestamp, horario_server = false) { |
||||
if (horario_server) { |
||||
timestamp = timestamp * 1000 |
||||
} |
||||
let date = new Date(timestamp); |
||||
let day = addZero(date.getDate()) |
||||
let month = addZero(date.getMonth() + 1) |
||||
let hours = date.getHours(); |
||||
let minutes = date.getMinutes(); |
||||
let formattedTime = `${day}/${month} ` + addZero(hours) + ':' + addZero(minutes) |
||||
return formattedTime |
||||
} |
||||
|
||||
/** |
||||
* ENVIA AS MENSAGEM DO TIPO MIDIA (RECEPTIVO) |
||||
* @param {*} id_provedor |
||||
* @param {*} type |
||||
* @param {*} mimetype |
||||
* @param {*} delivery |
||||
* @returns |
||||
*/ |
||||
const messageTypeMedia = (obj) => { |
||||
const fileDownload = |
||||
"http://" + server_api + "/link/" + obj.id_provedor + "/" + window.btoa(obj.mimetype); |
||||
|
||||
if (obj.type == "voice" || obj.type == "audio") { |
||||
chat.innerHTML += ` |
||||
<div class="${obj.from} "> |
||||
<span>${obj.profile_name}: </span> |
||||
<span class="${obj.from}-message audio"> |
||||
<audio controls><source src="${fileDownload}" type="${obj.mimetype}"></audio> |
||||
</span> |
||||
<span class="message-time">${converdata(Date.now())}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
|
||||
return; |
||||
} |
||||
if (obj.type == "video") { |
||||
chat.innerHTML += ` |
||||
<div class="${obj.from}"> |
||||
<span>${obj.profile_name}: </span> |
||||
<span class="${obj.from}-message"> |
||||
<video controls> |
||||
<source src="${fileDownload}" type="${obj.mimetype}"> |
||||
</video> |
||||
</span> |
||||
<br/> |
||||
<span class="message-time">${converdata(Date.now())}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
|
||||
return; |
||||
} |
||||
if (obj.type == "document") { |
||||
const typefile = obj.filename.split(".")[1]; |
||||
let icon; |
||||
if (icontypes.indexOf(typefile) >= 0) { |
||||
icon = `<img src="${path}img/icons/${typefile}-file.png" style="max-width: 60px"></img>`; |
||||
} else { |
||||
icon = `<img src="${path}img/icons/notfound-file.png" style="max-width: 60px"></img>`; |
||||
} |
||||
|
||||
chat.innerHTML += ` |
||||
<div class="${obj.from}"> |
||||
<span>${obj.profile_name}: </span> |
||||
<span class="${obj.from}-message message-column"> |
||||
<a href="${fileDownload}" target="_blank"> |
||||
${icon} |
||||
</a> |
||||
</span> |
||||
<span class="fz-12">${obj.filename}</span> |
||||
<br/> |
||||
<span class="message-time">${converdata(Date.now())}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
|
||||
return; |
||||
} |
||||
if (obj.type == "image" || obj.type == "sticker") { |
||||
chat.innerHTML += ` |
||||
<div class="${obj.from}"> |
||||
<span>${obj.profile_name}: </span> |
||||
<span class="${obj.from}-message message-column"> |
||||
<img src="${fileDownload}" style="max-width: 200px; max-height: 150px" " > |
||||
</span> |
||||
<span class="message-time">${converdata(Date.now())}</span> |
||||
</div> |
||||
<br/> |
||||
`;
|
||||
return; |
||||
} |
||||
}; |
@ -0,0 +1,37 @@
|
||||
function atualizaUsuario(id_user) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `users/editar/${id_user}`, |
||||
success: function ({ |
||||
data |
||||
}) { |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector('form').action = `/users/editar/${data.id}`; |
||||
modal.querySelector("input[name='nome']").value = data.nome; |
||||
modal.querySelector("input[name='email']").value = data.email; |
||||
modal.querySelector("input[name='matricula']").value = data.matricula; |
||||
|
||||
// Seleciona o elemento <select>
|
||||
const selectGrupo = modal.querySelector("select[name='id_grupo']"); |
||||
|
||||
// Define o valor do <select> com base no data.grupo_id
|
||||
if (data.grupo_id && selectGrupo.querySelector(`option[value='${data.grupo_id}']`)) { |
||||
selectGrupo.value = data.grupo_id; |
||||
} |
||||
|
||||
// Desativa o <select> se data.grupo_id não existir
|
||||
selectGrupo.disabled = !data.grupo_id || !selectGrupo.querySelector(`option[value='${data.grupo_id}']`); |
||||
|
||||
const containerCheckbox = modal.querySelector(".container-checkbox"); |
||||
if (!data.status) { |
||||
containerCheckbox.innerHTML = `<input type="radio" name="status" value="on"> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>`; |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,230 @@
|
||||
const colorStatus = { |
||||
LIVRE: "green-500", |
||||
OCUPADO: "red-500", |
||||
PAUSA: "red-500", |
||||
INDISPONIVEL: "orange-400", |
||||
CHAMANDO: "orange-400", |
||||
} |
||||
|
||||
function getFilaId() { |
||||
const url = window.location.href; |
||||
const splitUrl = url.split('/'); |
||||
const id = splitUrl[splitUrl.length - 1]; |
||||
return id; |
||||
} |
||||
|
||||
function getDadosRelatorioDB(fila_id) { |
||||
return new Promise(function (resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `/dashboard/agentes/${fila_id}/fila`, |
||||
success: function (response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
async function montarRelatorios() { |
||||
const id = getFilaId(); |
||||
const data = await getDadosRelatorioDB(id); |
||||
let elementsTable = ""; |
||||
data.forEach(supervisor => { |
||||
const tempoFormatado = supervisor.login.split(".")[0]; |
||||
const btnPlay = ` |
||||
<button class="bg-blue-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer" onclick="retirarPausa(${supervisor.matricula}, '${supervisor.token}')"> |
||||
<i class="fas fa-play-circle"></i> |
||||
</button> |
||||
` |
||||
const btnAtend = ` |
||||
<button class="bg-blue-600 text-white flex-1 rounded text-xl text-center py-2 px-3" onclick="atendimentosAgente(${id}, ${supervisor.matricula}, '${supervisor.token}')"> |
||||
<i class="fas fa-exchange-alt"></i> |
||||
</button> |
||||
` |
||||
|
||||
const btnPausa = `<a class="bg-blue-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer" title="Colocar em Pausa?" onclick="selecionaAgente(${supervisor.id})"><i class="fas fa-pause"></i></a>`; |
||||
const agenteIsPausa = supervisor.status === "PAUSA" ? btnPlay : btnPausa; |
||||
const agenteAtendimentos = supervisor.atendimentos_atuais > 0 ? btnAtend : ''; |
||||
elementsTable += ` |
||||
<tr class="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 text-center"> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.id}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.nome}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.matricula}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${tempoFormatado}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.motivo_pausa ?? "Sem Pausa"}</td> |
||||
<td class="p-3 text-sm text-${colorStatus[supervisor.status]}">${supervisor.status}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.atendimentos_atuais}</td> |
||||
<td class="p-3 text-sm font-bold flex items-center gap-2 flex-wrap"> |
||||
${agenteAtendimentos} |
||||
${agenteIsPausa} |
||||
<button class="bg-red-600 text-white flex-1 rounded text-xl text-center py-2 px-3" onclick="desconectarAgente(${supervisor.matricula}, '${supervisor.token}')"> |
||||
<i class="fas fa-power-off"></i> |
||||
</button> |
||||
</td> |
||||
</tr> |
||||
` |
||||
}); |
||||
$(".table-relatorio").html(elementsTable); |
||||
} |
||||
|
||||
async function desconectarAgente(matricula, token) { |
||||
if (confirm("Deseja realmente desconectar do sistema?")) { |
||||
logoff(matricula, token).then(() => { |
||||
montarRelatorios(); |
||||
}) |
||||
} |
||||
} |
||||
|
||||
async function retirarPausa(matricula, token) { |
||||
if (confirm("Deseja retirar a pausa do agente?")) { |
||||
sairPausa(matricula, token).then(() => { |
||||
montarRelatorios(); |
||||
}) |
||||
} |
||||
} |
||||
|
||||
const sairPausa = (matricula, token) => new Promise((resolve) => { |
||||
$.ajax({ |
||||
url: `${server_api}/api/v1/agente/sairPausa`, |
||||
type: "POST", |
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token, |
||||
"ngrok-skip-browser-warning":"any" |
||||
}, |
||||
data: JSON.stringify({ |
||||
matricula |
||||
}), |
||||
success: function (res) { |
||||
alert('Pausa removida do Agente!') |
||||
resolve(res) |
||||
}, |
||||
error: function (res) { |
||||
alert('Nao foi possivel retirar de pausa.') |
||||
} |
||||
}); |
||||
}) |
||||
|
||||
const logoff = (matricula, token) => new Promise((resolve) => { |
||||
$.ajax({ |
||||
type: "POST", |
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token, |
||||
"ngrok-skip-browser-warning":"any" |
||||
}, |
||||
url: `${server_api}/access/logoff`, |
||||
data: JSON.stringify({ |
||||
matricula |
||||
}), |
||||
success: function (res) { |
||||
alert('Desconectado com sucesso'); |
||||
resolve(res) |
||||
}, |
||||
error: function (res) { |
||||
alert('Não foi possivel deslogar do sistema.') |
||||
} |
||||
}); |
||||
}) |
||||
|
||||
async function atendimentosAgente(fila_id, supervisor_matricula, token) { |
||||
const modal = document.querySelector(".modal3"); |
||||
data = await getAtendimentos(fila_id, supervisor_matricula); |
||||
const tabelaAtendimentos = document.querySelector('.table-atendimentos'); |
||||
tabelaAtendimentos.innerHTML = ''; // Limpa o conteúdo atual da tabela
|
||||
let elementsTable = ""; |
||||
|
||||
// Itera sobre os dados e cria as linhas da tabela
|
||||
data.forEach((item) => { |
||||
// Adiciona as células com os dados
|
||||
elementsTable += ` |
||||
<tr class="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 text-center"> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${item.id}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${item.nome}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">+${item.cliente_id}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${item.data_reg.split('.')[0]}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100"> |
||||
<button class="bg-blue-600 text-white flex-1 rounded text-xl text-center py-2 px-3" title="Transferir de fila?" onclick="transferirAtendimento('${item.uniqueid}', '${supervisor_matricula}', '${token}')"> |
||||
<i class="fas fa-exchange-alt"></i> |
||||
</button> |
||||
</td> |
||||
</tr> |
||||
`;
|
||||
}); |
||||
|
||||
$(".table-atendimentos").html(elementsTable); |
||||
|
||||
modal.style.display = "block"; |
||||
} |
||||
|
||||
function selecionaAgente(supervisor_id) { |
||||
const modal = document.querySelector(".modal"); |
||||
modal.style.display = "block"; |
||||
modal.querySelector("form").action = `/dashboard/agentes/{{$fila->nome}}/pausar`; |
||||
modal.querySelector("input[name='supervisor_id']").value = supervisor_id; |
||||
} |
||||
|
||||
function selecionaFila(unique_id) { |
||||
const modal = document.querySelector(".modal2"); |
||||
modal.style.display = "block"; |
||||
modal.querySelector("input[name='unique_id']").value = unique_id; |
||||
} |
||||
|
||||
function getAtendimentos(fila_id, supervisor_matricula) { |
||||
return new Promise(function (resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `/dashboard/agentes/${fila_id}/fila/${supervisor_matricula}`, |
||||
success: function (response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
async function transferirAtendimento(unique_id, origem, token) { |
||||
agentesLivres = await getAtendentesLivres(token); |
||||
|
||||
const selectAgente = document.querySelector('select[name="destino"]'); |
||||
|
||||
// Limpa as opções existentes (caso haja alguma)
|
||||
selectAgente.innerHTML = ''; |
||||
|
||||
// Preenche as opções com os dados recebidos
|
||||
agentesLivres.forEach((agente) => { |
||||
const option = document.createElement('option'); |
||||
option.value = agente.matricula; // Substitua com o campo apropriado do objeto agente
|
||||
option.textContent = agente.nome; // Substitua com o campo apropriado do objeto agente
|
||||
selectAgente.appendChild(option); |
||||
}); |
||||
|
||||
const modal = document.querySelector(".modal4"); |
||||
modal.style.display = "block"; |
||||
modal.querySelector("input[name='origem']").value = origem; |
||||
modal.querySelector("input[name='atendimento_unique_id']").value = unique_id; |
||||
} |
||||
|
||||
function getAtendentesLivres(token) { |
||||
return new Promise((resolve) => { |
||||
$.ajax({ |
||||
url: `${server_api}/api/v1/supervisor/agentes/status/livre`, |
||||
type: "GET", |
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + token, |
||||
"ngrok-skip-browser-warning":"any" |
||||
}, |
||||
success: function (response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
}, |
||||
error: function (response) { |
||||
alert('Nao foi possivel carregar as listas de agentes.') |
||||
} |
||||
}); |
||||
}) |
||||
} |
@ -0,0 +1,7 @@
|
||||
function selectTheme() { |
||||
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { |
||||
document.documentElement.classList.add('dark') |
||||
} else { |
||||
document.documentElement.classList.remove('dark') |
||||
} |
||||
} |
@ -0,0 +1,29 @@
|
||||
function atualizaChannel(id_channel) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `channels/editar/${id_channel}`, |
||||
success: function ({ |
||||
data |
||||
}) { |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector('form').action = `/channels/editar/${data.id}`; |
||||
modal.querySelector("input[name='name']").value = data.name; |
||||
modal.querySelector("input[name='id_empresa']").value = data.id_empresa; |
||||
modal.querySelector("input[name='number']").value = data.number; |
||||
modal.querySelector("input[name='token']").value = data.token; |
||||
modal.querySelector("select[name='channel']").value = data.channel; |
||||
modal.querySelector("input[name='work_space']").value = data.work_space; |
||||
modal.querySelector("input[name='title']").value = data.title; |
||||
const containerCheckbox = modal.querySelector(".container-checkbox"); |
||||
if (!data.status) { |
||||
containerCheckbox.innerHTML = `<input type="radio" name="status" value="on"> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>` |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,31 @@
|
||||
function atualizaContato(id_contato) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `contatos/${id_contato}/edit`, |
||||
success: function({ |
||||
data |
||||
}) { |
||||
const contato_data = data.contato_data; |
||||
$(".modal-edit").show(); |
||||
$(".modal-edit").find('form').attr('action', `contatos/${id_contato}`); |
||||
$(".modal-edit").find("input[name='nome']").val(contato_data.nome); |
||||
$(".modal-edit").find("input[name='email']").val(contato_data.email); |
||||
$(".modal-edit").find("textarea[name='descricao']").val(contato_data.notes); |
||||
const numeroFormatado = $(".modal-edit").find("input[name='contato']").masked(contato_data.contato);
|
||||
$(".modal-edit").find("input[name='contato']").val(numeroFormatado); |
||||
if (contato_data.status) { |
||||
$(".modal-edit").find(".container-radio"). |
||||
html(`<input type="radio" name="status" value="on" checked> <span class="mr-3 dark:text-gray-100">Sim</span><input type="radio" name="status" value="off" > <span class="dark:text-gray-100">Não</span>`) |
||||
|
||||
} else { |
||||
$(".modal-edit").find(".container-radio"). |
||||
html(`<input type="radio" name="status" value="on" > <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>`) |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,66 @@
|
||||
const eventos = { |
||||
EMESPERA: 'Em espera', |
||||
TRANSFER: 'Transferidos', |
||||
COMPLETE_CALLER: 'Finalizadas pelo cliente', |
||||
LOST_CONNECTION: 'Desconectadas', |
||||
COMPLETE_AGENT: 'Finalizas pelo Agente', |
||||
START: 'Iniciadas', |
||||
} |
||||
|
||||
function getDadosRelatorioDB() { |
||||
return new Promise(function(resolve, reject){ |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `dashboard/getRelatorioDados`, |
||||
success: function(response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
async function montarRelatorios()
|
||||
{ |
||||
const data = await getDadosRelatorioDB(); |
||||
$(".text-operantes").text(data.totalAgentesOperantes); |
||||
$(".text-inoperantes").text(data.totalAgentesInoperantes); |
||||
$(".text-atendimentoDia").text(data.atendimentosDia); |
||||
$(".text-atendimentosMes").text(data.atendimentosPorMes); |
||||
let elementsTable = ""; |
||||
data.relatoriosAtendimento.forEach(relatorio => { |
||||
elementsTable += ` |
||||
<tr class="bg-white dark:bg-gray-800 dark:border-gray-600 border-b-2"> |
||||
<td class="text-center" title="Ativar essa fila"> |
||||
<a href="dashboard/agentes/${relatorio.id}" class="text-xl p-2 hover:bg-gray-700 rounded-full"> |
||||
<i class="fas fa-play-circle text-gray-900 dark:text-gray-100"> |
||||
</i> |
||||
</a> |
||||
</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-left">${relatorio.nome}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.agentes}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.em_espera}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.iniciadas}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.finalizadas}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.abandonadas}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.enviadas}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 text-center">${relatorio.canceladas}</td> |
||||
<td class="text-center" title="Colocar fila em pausa"> |
||||
<button onclick="selecionaFila(${relatorio.id})" class="text-xl p-2 hover:bg-gray-700 rounded-full"> |
||||
<i class="fas fa-pause-circle text-gray-900 dark:text-gray-100"> |
||||
</i> |
||||
</button> |
||||
</td> |
||||
</tr> |
||||
` |
||||
}); |
||||
$(".table-relatorio").html(elementsTable); |
||||
} |
||||
|
||||
function selecionaFila(fila_id){ |
||||
const modal = document.querySelector(".modal"); |
||||
modal.style.display = "block"; |
||||
modal.querySelector("form").action = `/dashboard/agentes/${fila_id}/pausarAgentesFila`; |
||||
} |
||||
|
@ -0,0 +1,21 @@
|
||||
function atualizaEmpresa(empresa_id) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `empresas/${empresa_id}/edit`, |
||||
success: function({data}) { |
||||
const empresa_data = data.empresa_data; |
||||
$(".modal-edit").show(); |
||||
$(".modal-edit").find('form').attr('action', `empresas/${empresa_id}`); |
||||
$(".modal-edit").find("input[name='nome']").val(empresa_data.nome); |
||||
$(".modal-edit").find("input[name='token']").val(empresa_data.token); |
||||
$(".modal-edit").find("input[name='email']").val(empresa_data.email); |
||||
const cnpjFormatado = $(".modal-edit").find("input[name='cnpj']").masked(empresa_data.cnpj);
|
||||
$(".modal-edit").find("input[name='cnpj']").val(cnpjFormatado); |
||||
if (empresa_data.status) { |
||||
$(".modal-edit").find("input[name='status'][value='on']").prop("checked", true); |
||||
} else { |
||||
$(".modal-edit").find("input[name='status'][value='off']").prop("checked", true); |
||||
} |
||||
} |
||||
}); |
||||
} |
@ -0,0 +1,26 @@
|
||||
function atualizarFila(id_fila) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `filas/editar/${id_fila}`, |
||||
success: function({ |
||||
data |
||||
}) { |
||||
console.log(data) |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector('form').action = `/filas/editar/${data.id}`; |
||||
modal.querySelector("input[name='nome']").value = data.nome; |
||||
const containerCheckbox = modal.querySelector(".container-checkbox"); |
||||
if (!data.is_ativa) { |
||||
containerCheckbox.innerHTML = `<input type="radio" name="status" value="on"> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>` |
||||
} |
||||
|
||||
} |
||||
|
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,204 @@
|
||||
const eventos = { |
||||
EMESPERA: 'Em espera', |
||||
TRANSFER: 'Transferidos', |
||||
COMPLETE_CALLER: 'Finalizadas pelo cliente', |
||||
LOST_CONNECTION: 'Desconectadas', |
||||
COMPLETE_AGENT: 'Finalizas pelo Agente', |
||||
START: 'Iniciadas', |
||||
ABANDON: 'Abandonadas', |
||||
SENDED: 'Enviadas pelo agente', |
||||
TIMEOUT_ESPERA: 'Tempo de espera excedido', |
||||
TIMEOUT_CALLER: 'Tempo de resposta excedido', |
||||
CANCELADO: 'Cancelado pelo cliente', |
||||
|
||||
} |
||||
|
||||
function getDadosRelatorioDB(dataInicio, dataFim) { |
||||
return new Promise(function(resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `graficos/getDados`, |
||||
data: { |
||||
dataInicio: dataInicio, |
||||
dataFim: dataFim |
||||
}, |
||||
success: function(response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
function montaGrafico1(dataDB) { |
||||
let labels = dataDB.map((value) => value.nome) |
||||
let data = dataDB.map((value) => value.qtde_atendimento) |
||||
const ctx = document.getElementById('myChart'); |
||||
|
||||
let chartStatus = Chart.getChart("myChart");
|
||||
if (chartStatus != undefined) { |
||||
chartStatus.destroy(); |
||||
} |
||||
|
||||
var myChart = new Chart(ctx, { |
||||
type: 'bar', |
||||
data: { |
||||
labels: labels, |
||||
datasets: [{ |
||||
data: data, |
||||
label: "Atendimento Por Agente", |
||||
font: 90, |
||||
borderWidth: 1, |
||||
backgroundColor: [ |
||||
'rgba(255, 159, 64, 0.7)', |
||||
'rgba(255, 99, 132, 0.7)', |
||||
'rgba(75, 192, 192, 0.7)', |
||||
'rgba(255, 205, 86, 0.7)', |
||||
'rgba(54, 162, 235, 0.7)', |
||||
'rgba(201, 203, 207, 0.7)', |
||||
'rgba(153, 102, 255, 0.7)', |
||||
], |
||||
borderColor: [ |
||||
'rgb(255, 159, 64)', |
||||
'rgb(255, 99, 132)', |
||||
'rgb(75, 192, 192)', |
||||
'rgb(255, 205, 86)', |
||||
'rgb(54, 162, 235)', |
||||
'rgb(201, 203, 207)', |
||||
'rgb(153, 102, 255)', |
||||
], |
||||
}], |
||||
}, |
||||
options: { |
||||
color: '#fff', |
||||
plugins: { |
||||
legend: { |
||||
labels: { |
||||
font: { |
||||
size: 15 |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
scales: { |
||||
y: { |
||||
beginAtZero: true, |
||||
}, |
||||
x: { |
||||
ticks: { |
||||
color: '#91a0a7', |
||||
font: { |
||||
size: 13 |
||||
}, |
||||
} |
||||
} |
||||
}, |
||||
}, |
||||
}); |
||||
} |
||||
|
||||
function montaGrafico2(dataDB) { |
||||
const ctx2 = document.getElementById('myChart2'); |
||||
const somaPorEvento = {}; |
||||
dataDB.forEach(element => { |
||||
if (somaPorEvento[element.evento]) { |
||||
somaPorEvento[element.evento] += element.qtde_usados; |
||||
} else { |
||||
somaPorEvento[element.evento] = element.qtde_usados; |
||||
} |
||||
}); |
||||
let labels = Object.keys(somaPorEvento).map(label => eventos[label]); |
||||
let data = Object.values(somaPorEvento); |
||||
|
||||
let chartStatus = Chart.getChart("myChart2");
|
||||
if (chartStatus != undefined) { |
||||
chartStatus.destroy(); |
||||
} |
||||
|
||||
var myChart2 = new Chart(ctx2, { |
||||
type: 'doughnut', |
||||
data: { |
||||
labels: labels, |
||||
datasets: [{ |
||||
data: data, |
||||
borderWidth: 1, |
||||
backgroundColor: [ |
||||
'rgba(255, 159, 64, 0.7)', |
||||
'rgba(255, 99, 132, 0.7)', |
||||
'rgba(75, 192, 192, 0.7)', |
||||
'rgba(255, 205, 86, 0.7)', |
||||
'rgba(54, 162, 235, 0.7)', |
||||
'rgba(201, 203, 207, 0.7)', |
||||
'rgba(153, 102, 255, 0.7)', |
||||
], |
||||
borderColor: [ |
||||
'rgb(255, 159, 64)', |
||||
'rgb(255, 99, 132)', |
||||
'rgb(75, 192, 192)', |
||||
'rgb(255, 205, 86)', |
||||
'rgb(54, 162, 235)', |
||||
'rgb(201, 203, 207)', |
||||
'rgb(153, 102, 255)', |
||||
], |
||||
}] |
||||
}, |
||||
|
||||
options: { |
||||
color: '#91a0a7', |
||||
|
||||
scales: { |
||||
y: { |
||||
beginAtZero: true |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function montaGrafico3(dataDB) { |
||||
const ctx3 = document.getElementById('myChart3'); |
||||
let labels3 = dataDB.map((value) => value.nome) |
||||
let data3 = dataDB.map((value) => value.qtde_fila) |
||||
|
||||
let chartStatus = Chart.getChart("myChart3");
|
||||
if (chartStatus != undefined) { |
||||
chartStatus.destroy(); |
||||
} |
||||
|
||||
var myChart3= new Chart(ctx3, { |
||||
type: 'pie', |
||||
data: { |
||||
labels: labels3, |
||||
datasets: [{ |
||||
label: 'Quantidade de atendimento', |
||||
data: data3, |
||||
borderWidth: 1, |
||||
backgroundColor: [ |
||||
'rgb(255, 99, 132)', |
||||
'rgb(54, 162, 235)', |
||||
'rgb(255, 205, 86)' |
||||
], |
||||
fontColor: '#fff', |
||||
}] |
||||
}, |
||||
options: { |
||||
color: '#91a0a7', |
||||
scales: { |
||||
y: { |
||||
beginAtZero: true |
||||
} |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
async function graficos() { |
||||
document.getElementById('graficos').hidden = false; |
||||
var dataInicio = document.getElementById('dataInicio').value; |
||||
var dataFim = document.getElementById('dataFim').value; |
||||
const data = await getDadosRelatorioDB(dataInicio, dataFim); |
||||
montaGrafico1(data.atendimentosData); |
||||
montaGrafico2(data.atendimentosStatusData); |
||||
montaGrafico3(data.filasMaisUsadas); |
||||
} |
@ -0,0 +1,59 @@
|
||||
function atualizaHorarios(horario_id) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `horarios/${horario_id}/edit`, |
||||
success: async function({ |
||||
data |
||||
}) { |
||||
const option_data = data.option_data; |
||||
const types = data.types; |
||||
const channels = data.numberChannels; |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector("input[name='nome']").value = option_data.nome; |
||||
modal.querySelector('form').action = `horarios/${horario_id}`; |
||||
if (option_data.status) { |
||||
modal.querySelector(".container-radio").innerHTML = |
||||
`<input type='radio' name='status' checked value='on'> <span class='mr-3 dark:text-gray-100'>Sim</span>
|
||||
<input type='radio' name='status' value='off'> <span class='mr-3 dark:text-gray-100'>Não</span>` |
||||
} else { |
||||
modal.querySelector(".container-radio").innerHTML = |
||||
`<input type='radio' name='status' value='on'> <span class='mr-3 dark:text-gray-100'>Sim</span>
|
||||
<input type='radio' name='status' checked value='off'> <span class='mr-3 dark:text-gray-100'>Não</span>`; |
||||
} |
||||
let containerTypes = ''; |
||||
types.forEach(type => { |
||||
if (option_data.opcao_nao == type.id) { |
||||
containerTypes += |
||||
` <option value="${type.id}" selected>${type.name}</option>` |
||||
} else { |
||||
containerTypes += |
||||
` <option value="${type.id}">${type.name}</option>` |
||||
} |
||||
}); |
||||
modal.querySelector(".select-types").innerHTML = containerTypes; |
||||
|
||||
let containerChannels = ''; |
||||
channels.forEach(channel => { |
||||
if (option_data.id_number === channel.id) { |
||||
containerChannels += |
||||
` <option value="${channel.id}" selected>${channel.name}</option>` |
||||
} else { |
||||
containerChannels += |
||||
` <option value="${channel.id}">${channel.name}</option>` |
||||
} |
||||
}); |
||||
modal.querySelector(".select-channels").innerHTML = containerChannels; |
||||
montaSelectDestino(option_data.opcao, modal, option_data.acao); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
document.querySelectorAll('.select-types').forEach(el => { |
||||
el.addEventListener('change', (e) => { |
||||
const select = e.target; |
||||
const modal = select.closest('.modal') ?? select.closest('.modal-edit'); |
||||
const id_redirect = select.value; |
||||
montaSelectDestino(id_redirect, modal); |
||||
}) |
||||
}) |
@ -0,0 +1,36 @@
|
||||
async function montaSelectDestino(id_type, modal, code_id = null) { |
||||
const data = await requestType(id_type); |
||||
const selectDestino = modal.querySelector(".select-destino"); |
||||
const inputDestino = modal.querySelector(".input-destino"); |
||||
if (!data) { |
||||
selectDestino.style.display = 'none'; |
||||
selectDestino.disabled = true; |
||||
inputDestino.disabled = false; |
||||
inputDestino.style.display = 'block'; |
||||
|
||||
return; |
||||
} |
||||
selectDestino.style.display = 'block'; |
||||
selectDestino.disabled = false; |
||||
inputDestino.disabled = true; |
||||
inputDestino.style.display = 'none'; |
||||
let selectElements = ""; |
||||
|
||||
if (code_id) { |
||||
data.forEach(element => { |
||||
let matriculaOrId = element.matricula ?? element.id; |
||||
if (matriculaOrId.toString() === code_id.toString()) { |
||||
selectElements += |
||||
` <option value="${element.id}" selected>${element.name ?? element.nome}</option>` |
||||
} else { |
||||
selectElements += |
||||
` <option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
} |
||||
}) |
||||
} else { |
||||
data.forEach(element => { |
||||
selectElements += `<option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
}); |
||||
} |
||||
selectDestino.innerHTML = selectElements; |
||||
} |
@ -0,0 +1,13 @@
|
||||
function requestType(id_type) { |
||||
return new Promise(function(resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `horarios/${id_type}`, |
||||
success: function(response) { |
||||
const data = response.data.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}); |
||||
} |
@ -0,0 +1,88 @@
|
||||
function atualizaHorariosOptions(horario_option_id) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `options/${horario_option_id}/edit`, |
||||
success: async function({ |
||||
data |
||||
}) { |
||||
const option_data = data.option_data; |
||||
const types = data.types; |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector("input[name='horario_inicio']").value = option_data.horario_inicio; |
||||
modal.querySelector("input[name='horario_fim']").value = option_data.horario_fim; |
||||
var selectSemana = document.getElementById("dias_semana2"); |
||||
var selectSemanaFim = document.getElementById("dias_semana_fim2"); |
||||
var selectMes = document.getElementById("meses2"); |
||||
var selectMesFim = document.getElementById("meses_fim2"); |
||||
var selectDia = document.getElementById("dias_mes2"); |
||||
var selectDiaFim = document.getElementById("dias_mes_fim2"); |
||||
modal.querySelector('form').action = `options/${horario_option_id}`; |
||||
|
||||
if (option_data.feriado) { |
||||
modal.querySelector("input[id='feriado_sim']").checked = true; |
||||
} else { |
||||
modal.querySelector("input[id='feriado_nao']").checked = true; |
||||
} |
||||
|
||||
if (option_data.todos_mes) { |
||||
modal.querySelector("input[id='todos_mes']").checked = true; |
||||
selectMes.disabled = true; |
||||
selectMesFim.disabled = true; |
||||
selectMes.selectedIndex = -1; |
||||
selectMesFim.selectedIndex = -1; |
||||
} else { |
||||
modal.querySelector("input[id='todos_mes_nao']").checked = true; |
||||
selectMes.selectedIndex = option_data.mes - 1; |
||||
selectMesFim.selectedIndex = option_data.mes_fim - 1; |
||||
} |
||||
|
||||
if (option_data.todos_dias_semana) { |
||||
modal.querySelector("input[id='todos_dias_semana']").checked = true; |
||||
selectSemana.disabled = true; |
||||
selectSemanaFim.disabled = true; |
||||
selectSemana.selectedIndex = -1; |
||||
selectSemanaFim.selectedIndex = -1; |
||||
} else { |
||||
modal.querySelector("input[id='todos_dias_semana_nao']").checked = true; |
||||
selectSemana.selectedIndex = option_data.semana - 1; |
||||
selectSemanaFim.selectedIndex = option_data.semana_fim - 1; |
||||
} |
||||
|
||||
if (option_data.todos_dias_mes) { |
||||
modal.querySelector("input[id='todos_dias_mes']").checked = true; |
||||
selectDia.disabled = true; |
||||
selectDiaFim.disabled = true; |
||||
selectDia.selectedIndex = -1; |
||||
selectDiaFim.selectedIndex = -1; |
||||
} else { |
||||
modal.querySelector("input[id='todos_dias_mes_nao']").checked = true; |
||||
selectDia.selectedIndex = option_data.dias_mes - 1; |
||||
selectDiaFim.selectedIndex = option_data.dias_mes_fim - 1; |
||||
} |
||||
|
||||
let containerTypes = ''; |
||||
types.forEach(type => { |
||||
if (option_data.opcao == type.id) { |
||||
containerTypes += |
||||
` <option value="${type.id}" selected>${type.name}</option>` |
||||
} else { |
||||
containerTypes += |
||||
` <option value="${type.id}">${type.name}</option>` |
||||
} |
||||
}); |
||||
modal.querySelector(".select-types").innerHTML = containerTypes; |
||||
|
||||
montaSelectDestino(option_data.opcao, modal, option_data.acao); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
document.querySelectorAll('.select-types').forEach(el => { |
||||
el.addEventListener('change', (e) => { |
||||
const select = e.target; |
||||
const modal = select.closest('.modal') ?? select.closest('.modal-edit'); |
||||
const id_redirect = select.value; |
||||
montaSelectDestino(id_redirect, modal); |
||||
}) |
||||
}) |
@ -0,0 +1,37 @@
|
||||
async function montaSelectDestino(id_type, modal, code_id=null) { |
||||
const data = await requestType(id_type); |
||||
const selectDestino = modal.querySelector(".select-destino"); |
||||
const inputDestino = modal.querySelector(".input-destino"); |
||||
if (!data) { |
||||
selectDestino.style.display = 'none'; |
||||
selectDestino.disabled = true; |
||||
inputDestino.disabled = false; |
||||
inputDestino.style.display = 'block'; |
||||
|
||||
return; |
||||
} |
||||
selectDestino.style.display = 'block'; |
||||
selectDestino.disabled = false; |
||||
inputDestino.disabled = true; |
||||
inputDestino.style.display = 'none'; |
||||
let selectElements = ""; |
||||
|
||||
if (code_id) { |
||||
data.forEach(element => { |
||||
let matriculaOrId = element.matricula ?? element.id; |
||||
if (matriculaOrId.toString() === code_id.toString()) { |
||||
selectElements += |
||||
` <option value="${element.id}" selected>${element.name ?? element.nome}</option>` |
||||
} else { |
||||
selectElements += |
||||
` <option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
} |
||||
}) |
||||
} else { |
||||
data.forEach(element => { |
||||
selectElements += `<option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
}); |
||||
} |
||||
|
||||
selectDestino.innerHTML = selectElements; |
||||
} |
@ -0,0 +1,13 @@
|
||||
function requestType(id_type) { |
||||
return new Promise(function(resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `options/${id_type}`, |
||||
success: function(response) { |
||||
const data = response.data.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}); |
||||
} |
@ -0,0 +1,12 @@
|
||||
function clickedMenu(event) { |
||||
const parent = event.currentTarget; |
||||
parent.querySelector(".submenu").classList.toggle('hidden'); |
||||
parent.querySelector(".dropIcon").classList.toggle('selected'); |
||||
} |
||||
|
||||
function responsiveSidebar(event) { |
||||
const shadow = event.currentTarget; |
||||
const sidebar = document.querySelector('.sidebar'); |
||||
sidebar.classList.remove('show'); |
||||
shadow.classList.add('hidden'); |
||||
} |
@ -0,0 +1,20 @@
|
||||
const sidebar = document.querySelector('.sidebar'); |
||||
const shadow = document.querySelector('.shadowSidebar'); |
||||
|
||||
function toogleTheme() { |
||||
let value = localStorage.theme === 'dark' ? 'light' : 'dark'; |
||||
document.querySelector('.btn-theme').innerHTML = value === 'dark' ? '<i class="fas fa-moon text-xl"></i>' : '<i class="fas fa-sun text-xl" ></i>'; |
||||
|
||||
localStorage.setItem('theme', value); |
||||
selectTheme(); |
||||
} |
||||
function showSidebar() { |
||||
const larguraJanela = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; |
||||
if (larguraJanela < 650) { |
||||
sidebar.classList.add('show'); |
||||
shadow.classList.toggle('hidden'); |
||||
} else { |
||||
sidebar.classList.toggle('hidden'); |
||||
sidebar.classList.remove('show'); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
function atualizarPausa(id_user) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `pausas/editar/${id_user}`, |
||||
success: function({ |
||||
data |
||||
}) { |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector('form').action = `/pausas/editar/${data.id}`; |
||||
modal.querySelector("input[name='motivo']").value = data.motivo; |
||||
const containerCheckbox = modal.querySelector(".container-checkbox"); |
||||
if (!data.is_ativo) { |
||||
containerCheckbox.innerHTML = `<input type="radio" name="status" value="on"> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>` |
||||
} |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,59 @@
|
||||
function atualizaRedirect(id_redirect) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `redirects/${id_redirect}/edit`, |
||||
success: function({ |
||||
data |
||||
}) { |
||||
const redirect_data = data.redirect_data; |
||||
const numbers_channels = data.numbers; |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.querySelector('form').action = `redirects/${id_redirect}`; |
||||
|
||||
modal.querySelector("input[name='nome']").value = redirect_data.name; |
||||
modal.querySelector("textarea[name='descricao']").value = redirect_data.description; |
||||
|
||||
const containerRadioStatus = document.querySelector(".container-radio-status"); |
||||
const containerRadioInitial = document.querySelector(".container-radio-initial"); |
||||
|
||||
if (redirect_data.status) { |
||||
containerRadioStatus.innerHTML = |
||||
`<input type="radio" name="status" value="on" checked> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" > <span class="dark:text-gray-100">Não</span>` |
||||
} else { |
||||
containerRadioStatus.innerHTML = |
||||
`<input type="radio" name="status" value="on" > <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>` |
||||
} |
||||
|
||||
if (redirect_data.initial) { |
||||
containerRadioInitial.innerHTML = |
||||
`<input type="radio" name="initial" value="on" checked> <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="initial" value="off" > <span class="dark:text-gray-100">Não</span>` |
||||
} else { |
||||
containerRadioInitial.innerHTML = |
||||
`<input type="radio" name="initial" value="on" > <span class="mr-3 dark:text-gray-100">Sim</span>
|
||||
<input type="radio" name="initial" value="off" checked> <span class="dark:text-gray-100">Não</span>` |
||||
} |
||||
|
||||
const containerChannels = modal.querySelector("select[name='channel']"); |
||||
numbers_channels.forEach(channel => { |
||||
if (redirect_data.id_number === channel.id) { |
||||
containerChannels.innerHTML = |
||||
` <option value="${channel.id}" selected>${channel.title}</option>` |
||||
|
||||
} else { |
||||
containerChannels.innerHTML = |
||||
` <option value="${channel.id}">${channel.title}</option>` |
||||
|
||||
} |
||||
}) |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fecharModal() { |
||||
document.querySelector('.modal-edit').style.display = 'none'; |
||||
} |
@ -0,0 +1,48 @@
|
||||
function atualizaRedirectOption(option_id) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `options/${option_id}/edit`, |
||||
success: async function({ |
||||
data |
||||
}) { |
||||
const option_data = data.option_data; |
||||
const types = data.types |
||||
const modal = document.querySelector('.modal-edit'); |
||||
modal.style.display = 'block'; |
||||
modal.setAttribute('data-sequenceDB', option_data.sequence); |
||||
modal.querySelector("input[name='sequencia']").value = option_data.sequence; |
||||
modal.querySelector("textarea[name='descricao']").value = option_data.description; |
||||
modal.querySelector('form').action = `options/${option_id}`; |
||||
if (option_data.hide) { |
||||
modal.querySelector(".container-radio").innerHTML = |
||||
`<input type="radio" name="status" value="on"> <span class="mr-3 dark:text-gray-100" >Sim</span>
|
||||
<input type="radio" name="status" value="off" checked> <span class="dark:text-gray-100">Não</span>`; |
||||
} else { |
||||
modal.querySelector(".container-radio").innerHTML = |
||||
`<input type="radio" name="status" value="on" checked> <span class="mr-3 dark:text-gray-100" >Sim</span>
|
||||
<input type="radio" name="status" value="off" > <span class="dark:text-gray-100">Não</span>`; |
||||
} |
||||
let containerTypes = ''; |
||||
types.forEach(type => { |
||||
if (option_data.id_type === type.id) { |
||||
containerTypes += |
||||
` <option value="${type.id}" selected>${type.name}</option>` |
||||
} else { |
||||
containerTypes += |
||||
` <option value="${type.id}">${type.name}</option>` |
||||
} |
||||
}) |
||||
modal.querySelector(".select-types").innerHTML = containerTypes; |
||||
montaSelectDestino(option_data.id_type, modal, option_data.code_id); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
document.querySelectorAll('.select-types').forEach(el => { |
||||
el.addEventListener('change', (e) => { |
||||
const select = e.target; |
||||
const modal = select.closest('.modal') ?? select.closest('.modal-edit'); |
||||
const id_redirect = select.value; |
||||
montaSelectDestino(id_redirect, modal); |
||||
}) |
||||
}) |
@ -0,0 +1,35 @@
|
||||
async function montaSelectDestino(id_type, modal, code_id = null) { |
||||
const data = await requestType(id_type); |
||||
const selectDestino = modal.querySelector(".select-destino"); |
||||
const inputDestino = modal.querySelector(".input-destino"); |
||||
if (!data) { |
||||
selectDestino.style.display = 'none'; |
||||
selectDestino.disabled = true; |
||||
inputDestino.disabled = false; |
||||
inputDestino.style.display = 'block'; |
||||
|
||||
return; |
||||
} |
||||
selectDestino.style.display = 'block'; |
||||
selectDestino.disabled = false; |
||||
inputDestino.disabled = true; |
||||
inputDestino.style.display = 'none'; |
||||
let selectElements = ""; |
||||
if (code_id) { |
||||
data.forEach(element => { |
||||
let matriculaOrId = element.matricula ?? element.id; |
||||
if (matriculaOrId.toString() === code_id.toString()) { |
||||
selectElements += |
||||
` <option value="${element.id}" selected>${element.name ?? element.nome}</option>` |
||||
} else { |
||||
selectElements += |
||||
` <option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
} |
||||
}) |
||||
} else { |
||||
data.forEach(element => { |
||||
selectElements += `<option value="${element.id}">${element.name ?? element.nome}</option>` |
||||
}); |
||||
} |
||||
selectDestino.innerHTML = selectElements; |
||||
} |
@ -0,0 +1,13 @@
|
||||
function requestType(id_type) { |
||||
return new Promise(function(resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `options/${id_type}`, |
||||
success: function(response) { |
||||
const data = response.data.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}); |
||||
} |
@ -0,0 +1,351 @@
|
||||
const modal = document.querySelector('.modal'); |
||||
const form = document.querySelector("#cadastro-template"); |
||||
const steps = modal.querySelectorAll('.step'); |
||||
const channel_token = document.currentScript.getAttribute('channel_token'); |
||||
const channel_number = document.currentScript.getAttribute('channel_number'); |
||||
const workspace = document.currentScript.getAttribute('workspace'); |
||||
|
||||
function deletarTemplate(id) { |
||||
if(!confirm('Deseja realmente deletar esse template?')) return false; |
||||
const csrfToken = document.querySelector("input[name='_token']").value; |
||||
|
||||
$.ajax({ |
||||
type: "delete", |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("Authorization", "Bearer " + channel_token) |
||||
}, |
||||
url: `https://api.positus.global/v2/workspaces/${workspace}/message-templates/${id}`, |
||||
error: function (error) { |
||||
console.log(error); |
||||
} |
||||
}); |
||||
|
||||
$.ajax({ |
||||
type: "delete", |
||||
headers: { |
||||
"X-CSRF-Token": csrfToken |
||||
}, |
||||
url: `templates/deletar/${id}`, |
||||
error: function (error) { |
||||
console.log(error); |
||||
} |
||||
}); |
||||
|
||||
|
||||
} |
||||
|
||||
/* Events */ |
||||
function nextStep() { |
||||
const currentStep = getCurrentStep() === 1; |
||||
const isValidated = currentStep ? validationInput() : validationTextArea(); |
||||
if (isValidated) { |
||||
toogleNextStep(); |
||||
} |
||||
} |
||||
|
||||
function backStep() { |
||||
toogleBackStep(); |
||||
} |
||||
|
||||
function showInput(e) { |
||||
const target = e.target; |
||||
const labelSwitch = target.parentNode; |
||||
const containerToogle = labelSwitch.parentNode; |
||||
labelSwitch.querySelector('span').classList.toggle('hidden'); |
||||
containerToogle.querySelector('p').classList.toggle('hidden'); |
||||
containerToogle.querySelector('.input-text').classList.toggle('hidden'); |
||||
} |
||||
|
||||
function showButtons(e) { |
||||
const target = e.target; |
||||
const labelSwitch = target.parentNode; |
||||
const btnAdd = document.querySelector('.btn-add'); |
||||
const containerInputs = document.querySelector('.container-inputs'); |
||||
containerInputs.classList.toggle('hidden'); |
||||
labelSwitch.querySelector('span').classList.toggle('hidden'); |
||||
btnAdd.classList.toggle('hidden'); |
||||
} |
||||
|
||||
function cadastroTemplate(e) { |
||||
e.preventDefault(); |
||||
const components = montaComponents(); |
||||
const data = createFormData(components); |
||||
handleBtnCadastro(); |
||||
fetchCadastroPositus(data, channel_token); |
||||
} |
||||
|
||||
function addInput() { |
||||
const containerInputs = document.querySelector('.container-inputs'); |
||||
const inputs = [...containerInputs.querySelectorAll('.input')]; |
||||
const countInputs = inputs.length; |
||||
if (countInputs > 2) { |
||||
return; |
||||
} |
||||
const input = `<div class="flex-col gap-2 border border-slate-500 p-3 mb-2 input relative">
|
||||
<i class="fas fa-times dark:text-gray-100 absolute right-[-22px] top-7 cursor-pointer p-1" onclick="removeInput(event)"></i> |
||||
<input type="text" |
||||
class="w-full dark:bg-gray-800 placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100 input-text" |
||||
placeholder="texto do botão " name="footer" oninput="caracteLimit(event)"> |
||||
<p class="mt-2 dark:bg-gray-80 dark:text-gray-100 text-sm flex justify-end" data-limit="25">Limite de caracteres 0/60</p> |
||||
</div> |
||||
`;
|
||||
containerInputs.insertAdjacentHTML("beforeend", input); |
||||
} |
||||
|
||||
function removeInput(e) { |
||||
const target = e.target; |
||||
const containerInputClicked = target.parentNode; |
||||
const containerInputs = document.querySelector('.container-inputs'); |
||||
const inputs = containerInputs.querySelectorAll('.input'); |
||||
const countInputs = inputs.length; |
||||
if (countInputs <= 1) { |
||||
return; |
||||
} |
||||
containerInputClicked.remove(); |
||||
} |
||||
|
||||
function caracteLimit(e) { |
||||
const target = e.target; |
||||
const containerName = target.parentNode; |
||||
let inputContent = target.value; |
||||
const contentCount = inputContent.length; |
||||
const paragraph = containerName.querySelector('p'); |
||||
const limit = paragraph.getAttribute("data-limit"); |
||||
if (contentCount > limit) { |
||||
target.value = inputContent.slice(0, limit); |
||||
return; |
||||
} |
||||
|
||||
atualizaContador(contentCount, limit, paragraph); |
||||
} |
||||
|
||||
/* Functions */ |
||||
function toogleNextStep() { |
||||
let selected; |
||||
let next; |
||||
for (let i = 0; i < steps.length; i++) { |
||||
const isHidden = steps[i].classList.contains('hidden'); |
||||
if (!isHidden) { |
||||
selected = steps[i]; |
||||
next = steps[i + 1]; |
||||
} |
||||
} |
||||
selected.classList.toggle('hidden'); |
||||
next.classList.toggle('hidden'); |
||||
const [btnStep, btnBackStep, btnCadastro] = getButtons(); |
||||
/* True adiciona Classe | false remove Classe*/ |
||||
const isStep3 = next.classList.contains('step-3'); |
||||
btnCadastro.classList.toggle("hidden", !isStep3); |
||||
btnStep.classList.toggle("hidden", isStep3); |
||||
const isHidden = btnCadastro.classList.contains('hidden'); |
||||
if (isHidden) { |
||||
btnBackStep.classList.remove('hidden') |
||||
} |
||||
} |
||||
|
||||
function toogleBackStep() { |
||||
let selected; |
||||
let back; |
||||
for (let i = 0; i < steps.length; i++) { |
||||
const isHidden = steps[i].classList.contains('hidden'); |
||||
if (!isHidden) { |
||||
selected = steps[i]; |
||||
back = steps[i - 1]; |
||||
} |
||||
} |
||||
selected.classList.toggle('hidden'); |
||||
back.classList.toggle('hidden'); |
||||
const [btnStep, btnBackStep, btnCadastro] = getButtons(); |
||||
const isHidden = btnCadastro.classList.contains('hidden'); |
||||
/* True adiciona Classe | false remove Classe*/ |
||||
const isStep3 = back.classList.contains('step-3'); |
||||
btnCadastro.classList.toggle("hidden", !isStep3); |
||||
btnStep.classList.remove("hidden", isStep3); |
||||
if (isHidden) { |
||||
btnBackStep.classList.toggle('hidden') |
||||
} |
||||
} |
||||
|
||||
function atualizaContador(count, limit, p) { |
||||
p.innerText = `Limite de caracteres ${count}/${limit}`; |
||||
} |
||||
|
||||
function toogleInputAction(input, status = false) { |
||||
input.disabled = status; |
||||
} |
||||
|
||||
function validationInput() { |
||||
const input = modal.querySelector("input[name='name']"); |
||||
if (input.value.length < 1) { |
||||
input.classList.add('border-2', 'border-red-500'); |
||||
return false; |
||||
} |
||||
input.classList.remove('border-2', 'border-red-500'); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
function validationTextArea() { |
||||
const textArea = modal.querySelector("textarea[name='body']"); |
||||
if (textArea.value.length < 1) { |
||||
textArea.classList.add('border-2', 'border-red-500'); |
||||
return false; |
||||
} |
||||
textArea.classList.remove('border-2', 'border-red-500'); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
function getButtons() { |
||||
const btnStep = modal.querySelector('.btn-step'); |
||||
const btnBackStep = modal.querySelector('.btn-back-step'); |
||||
const btnCadastro = modal.querySelector('.btn-cadastro'); |
||||
|
||||
return [btnStep, btnBackStep, btnCadastro]; |
||||
} |
||||
|
||||
function getCurrentStep() { |
||||
let selected; |
||||
for (let i = 0; i < steps.length; i++) { |
||||
const isHidden = steps[i].classList.contains('hidden'); |
||||
if (!isHidden) { |
||||
selected = i + 1; |
||||
} |
||||
} |
||||
|
||||
return selected; |
||||
} |
||||
|
||||
function fetchCadastroPositus(data, token) { |
||||
$.ajax({ |
||||
type: "post", |
||||
data: data, |
||||
processData: false, |
||||
contentType: false, |
||||
beforeSend: function (xhr) { |
||||
xhr.setRequestHeader("Authorization", "Bearer " + token) |
||||
}, |
||||
url: `https://api.positus.global/v2/workspaces/${workspace}/message-templates`, |
||||
success: function (data) { |
||||
handleBtnCadastro(); |
||||
fetchCadastroDB(data.data); |
||||
}, |
||||
error: function (error) { |
||||
handleBtnCadastro(); |
||||
console.log(error); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function fetchCadastroDB(data) { |
||||
const csrfToken = document.querySelector("input[name='_token']").value; |
||||
$.ajax({ |
||||
type: "post", |
||||
data: data, |
||||
headers: { |
||||
"X-CSRF-Token": csrfToken |
||||
}, |
||||
url: `/templates`, |
||||
success: function (data) { |
||||
cadastroSucess(data.message); |
||||
}, |
||||
error: function (error) { |
||||
console.log(error); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
function cadastroSucess(message) { |
||||
fechaModal(); |
||||
montaTemplates(); |
||||
const header = document.querySelector(".header"); |
||||
const div = document.createElement('div'); |
||||
div.classList.add("w-full", "p-5", "bg-blue-600", "mb-5", "text-white", "rounded", "uppercase", "font-bold", "text-lg"); |
||||
div.innerHTML = message; |
||||
header.parentNode.insertBefore(div, header); |
||||
} |
||||
|
||||
function fechaModal() { |
||||
modal.style.display = 'none'; |
||||
} |
||||
|
||||
function montaComponents() { |
||||
const components = [] |
||||
const checkedHeader = document.querySelector('.header-checkbox').checked; |
||||
if (checkedHeader) { |
||||
components.push({ |
||||
type: 'HEADER', |
||||
format: 'TEXT', |
||||
text: document.querySelector("input[name='header']").value, |
||||
}); |
||||
} |
||||
components.push( |
||||
{ |
||||
type: 'BODY', |
||||
text: document.querySelector("textarea[name='body']").value, |
||||
}, |
||||
); |
||||
const checkedFooter = document.querySelector('.footer-checkbox').checked; |
||||
if (checkedFooter) { |
||||
components.push({ |
||||
type: 'FOOTER', |
||||
text: document.querySelector("input[name='footer']"), |
||||
}); |
||||
} |
||||
const buttonCheckbox = document.querySelector('.button-checkbox').checked; |
||||
if (buttonCheckbox) { |
||||
const inputs = [...document.querySelectorAll('.input')]; |
||||
const formatedArray = inputs.map(input => { |
||||
const inputValue = input.querySelector('.input-text').value; |
||||
return { |
||||
text: inputValue, |
||||
type: "QUICK_REPLY" |
||||
} |
||||
}); |
||||
components.push( |
||||
{ |
||||
type: "BUTTONS", |
||||
buttons: formatedArray |
||||
} |
||||
) |
||||
} |
||||
|
||||
return components; |
||||
} |
||||
|
||||
function createFormData(formDataArray) { |
||||
const formData = new FormData(); |
||||
|
||||
const category = form.querySelector("select[name='category']").value; |
||||
const name = form.querySelector("input[name='name']").value; |
||||
const language = form.querySelector("select[name='language']").value; |
||||
|
||||
formData.append('category', category); |
||||
formData.append('name', name); |
||||
formData.append('language', language); |
||||
|
||||
formDataArray.forEach((obj, index) => { |
||||
for (const key in obj) { |
||||
if (Array.isArray(obj[key])) { |
||||
obj[key].forEach((item, subIndex) => { |
||||
for (const subKey in item) { |
||||
formData.append(`components[${index}][${key}][${subIndex}][${subKey}]`, item[subKey]); |
||||
} |
||||
}); |
||||
} else { |
||||
formData.append(`components[${index}][${key}]`, obj[key]); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
return formData; |
||||
} |
||||
|
||||
|
||||
function handleBtnCadastro(){ |
||||
const btn = modal.querySelector('.btn-cadastro'); |
||||
const text = btn.querySelectorAll('div'); |
||||
text.forEach(text => { |
||||
text.classList.toggle('hidden'); |
||||
}); |
||||
} |
@ -0,0 +1,109 @@
|
||||
function getTemplates() { |
||||
return new Promise(function (resolve, reject) { |
||||
$.ajax({ |
||||
type: "get", |
||||
url: `/templates/buscarTemplates`, |
||||
success: function (response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
const colors = { |
||||
APPROVED: "green-500", |
||||
REJECTED: "red-500", |
||||
PENDING: "orange-500", |
||||
} |
||||
|
||||
function montaBody(components) { |
||||
let body = ''; |
||||
components.forEach(component => { |
||||
if (component.type === 'BODY') { |
||||
body = component.text.replace(/\r?\n/g, "<br>"); |
||||
} |
||||
}); |
||||
|
||||
return body; |
||||
} |
||||
function montaHeader(components) { |
||||
let header = ''; |
||||
components.forEach(component => { |
||||
if (component.type === 'HEADER') { |
||||
header = component.text.replace(/\r?\n/g, "<br>"); |
||||
} |
||||
}); |
||||
|
||||
return header; |
||||
} |
||||
function montaFooter(components) { |
||||
let footer = ''; |
||||
components.forEach(component => { |
||||
if (component.type === 'FOOTER') { |
||||
footer = component.text.replace(/\r?\n/g, "<br>"); |
||||
} |
||||
}); |
||||
|
||||
return footer; |
||||
} |
||||
function montaButtons(components) { |
||||
let buttons = ``; |
||||
components.forEach(component => { |
||||
if (component.type === 'BUTTONS') { |
||||
component.buttons.forEach(button => { |
||||
buttons += `<span class="bg-blue-600 p-2 rounded flex-1">${button.text}</span>` |
||||
}) |
||||
} |
||||
}); |
||||
return buttons; |
||||
} |
||||
|
||||
async function montaTemplates() { |
||||
|
||||
const templates = await getTemplates(); |
||||
let elementsTable = ""; |
||||
|
||||
templates.forEach(template => { |
||||
if(template.status === "PENDING_DELETION") return; |
||||
var dataAtualizada = new Date(template.created_at); |
||||
|
||||
function adicionarZero(numero) { |
||||
return numero < 10 ? '0' + numero : numero; |
||||
} |
||||
|
||||
var dataFormatada = `${dataAtualizada.getFullYear()}-${adicionarZero(dataAtualizada.getMonth() + 1)}-${adicionarZero(dataAtualizada.getDate())} ${adicionarZero(dataAtualizada.getHours())}:${adicionarZero(dataAtualizada.getMinutes())}:${adicionarZero(dataAtualizada.getSeconds())}`; |
||||
let decodeComponents = JSON.parse(template.components); |
||||
elementsTable += ` |
||||
<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 pl-5">${template.name}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${template.category}</td> |
||||
<td class="p-3 text-sm text-gray-100 w-[150px]"> |
||||
<div class="bg-blue-600 p-3 rounded"> |
||||
<div class="header"> |
||||
${montaHeader(decodeComponents)} |
||||
</div> |
||||
<div class="body"> |
||||
${montaBody(decodeComponents)} |
||||
</div> |
||||
<div class="footer"> |
||||
${montaFooter(decodeComponents)}
|
||||
</div> |
||||
</div> |
||||
<div class="buttons flex flex-wrap gap-2 mt-3 text-center"> |
||||
${montaButtons(decodeComponents)} |
||||
</div> |
||||
</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100"> ${template.language}</td> |
||||
<td class="p-3 text-sm text-${colors[template.status]}"> ${template.status}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100"> ${dataFormatada}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100"> |
||||
<button onclick="deletarTemplate('${template.id}')" class="bg-red-600 text-white p-2 rounded text-lg w-full"> |
||||
<i class="fas fa-trash"></i> |
||||
</button> |
||||
</td> |
||||
</tr>` |
||||
}); |
||||
|
||||
$(".table-templates").html(elementsTable); |
||||
} |
@ -1,6 +1,81 @@
|
||||
|
||||
|
||||
@tailwind base; |
||||
@tailwind components; |
||||
@tailwind utilities; |
||||
|
||||
.dropIcon { |
||||
@apply text-gray-300; |
||||
} |
||||
|
||||
.dropIcon.selected { |
||||
@apply text-gray-100 rotate-90; |
||||
} |
||||
|
||||
@media (max-width:640px) { |
||||
.sidebar { |
||||
@apply hidden; |
||||
} |
||||
} |
||||
|
||||
@media (min-width:640px) { |
||||
.shadowSidebar { |
||||
@apply hidden |
||||
} |
||||
} |
||||
|
||||
.sidebar.show { |
||||
@apply block !important; |
||||
} |
||||
|
||||
@layer components { |
||||
.tooltip { |
||||
@apply bg-gray-700 absolute p-3 rounded-md left-8 bottom-[-20px] w-[300px] text-center hidden |
||||
} |
||||
|
||||
.info-box:hover .tooltip { |
||||
@apply block |
||||
} |
||||
} |
||||
|
||||
.sender, |
||||
.receiver, |
||||
.events { |
||||
border-radius: 1rem; |
||||
padding: 0.8rem; |
||||
margin-bottom: 1rem; |
||||
/* word-break: break-all; */ |
||||
word-wrap: break-word; |
||||
position: relative; |
||||
max-width: 80%; |
||||
} |
||||
|
||||
.sender { |
||||
border-bottom-left-radius: 0px; |
||||
@apply bg-gray-700 text-gray-100 mr-auto; |
||||
} |
||||
|
||||
.receiver { |
||||
border-bottom-right-radius: 0px; |
||||
@apply text-gray-100 ml-auto bg-indigo-500; |
||||
} |
||||
|
||||
.events { |
||||
@apply bg-gray-700 text-gray-100 self-center; |
||||
} |
||||
|
||||
.sender-message, |
||||
.receiver-message { |
||||
font-size: 1rem; |
||||
margin-right: 2rem; |
||||
display: block; |
||||
/* word-wrap: break-word; */ |
||||
} |
||||
|
||||
|
||||
.scrollbar::-webkit-scrollbar { |
||||
width: 0.6rem; |
||||
height: 5rem; |
||||
} |
||||
|
||||
.scrollbar::-webkit-scrollbar-thumb { |
||||
@apply bg-gray-600 |
||||
} |
@ -1,158 +0,0 @@
|
||||
<x-app-layout> |
||||
<div class="py-8 px-8"> |
||||
<div class="header flex flex-col items-center gap-4"> |
||||
<a href="{{route('dashboard')}}" style="margin-right: auto;" class="text-blue-500 hover:underline">Voltar</a> |
||||
|
||||
@if(session('status')) |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||
{{session('status')}} |
||||
</div> |
||||
@endif |
||||
<h1 class="mb-5 text-gray-900 dark:text-gray-100 text-3xl font-bold text-center"> |
||||
Agentes na Fila - {{$fila->nome}} |
||||
</h1> |
||||
<form action="{{route('filas')}}" method="GET" class="flex w-full gap-3 flex-col lg:flex-row "> |
||||
<div class="search bg-white dark:bg-gray-800 rounded px-3 py-1 overflow-hidden"> |
||||
<i class="fas fa-search dark:text-gray-100"></i> |
||||
<input type="text" name="pesquisa" class="border-none bg-transparent focus:ring-transparent |
||||
placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100 " placeholder="Pesquise filas"> |
||||
</div> |
||||
<select class="border-none rounded overflow-hidden dark:bg-gray-800 dark:text-gray-100" name="status"> |
||||
<option value="ativo">Livres</option> |
||||
<option value="desativado" selected>Ocupados</option> |
||||
</select> |
||||
<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-8 overflow-auto rounded-lg shadow bg-gray-50 dark:bg-gray-800"> |
||||
<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-center">ID</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">NOME</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">MATRICULA</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">LOGIN</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">MOTIVO PAUSA</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">STATUS</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">ATENDIMENTOS</th> |
||||
{{-- <th class="p-3 text-sm font-semibold tracking-wide text-center">TMA</th> --}} |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-center">AÇÕES</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody class="table-relatorio"> |
||||
|
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
|
||||
@push('agentesLogados') |
||||
|
||||
<script> |
||||
const colorStatus = { |
||||
LIVRE: "green-500", |
||||
OCUPADO: "red-500", |
||||
PAUSA: "red-500", |
||||
INDISPONIVEL: "orange-400", |
||||
CHAMANDO: "orange-400", |
||||
} |
||||
|
||||
function getFilaId() |
||||
{ |
||||
const url = window.location.href; |
||||
const splitUrl = url.split('/'); |
||||
const id = splitUrl[splitUrl.length - 1]; |
||||
return id; |
||||
} |
||||
|
||||
function getDadosRelatorioDB(fila_id) { |
||||
return new Promise(function(resolve, reject){ |
||||
$.ajax({ |
||||
type: "get", |
||||
dataType: 'json', |
||||
url: `/dashboard/agentes/${fila_id}/fila`, |
||||
success: function(response) { |
||||
const data = response.data; |
||||
resolve(data); |
||||
} |
||||
}); |
||||
}) |
||||
} |
||||
|
||||
async function montarRelatorios() |
||||
{ |
||||
const id = getFilaId(); |
||||
const data = await getDadosRelatorioDB(id); |
||||
let elementsTable = ""; |
||||
|
||||
data.forEach(supervisor => { |
||||
|
||||
const tempoFormatado = supervisor.login.split(".")[0]; |
||||
|
||||
const btnPlay = ` |
||||
<form method="POST" action="/dashboard/agentes/{{$fila->id}}/retirarPausa" title="Retirar Pausa?" class="bg-blue-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer" > |
||||
@csrf |
||||
<input type="hidden" name="supervisor_id" value="${supervisor.id}"> |
||||
<button > |
||||
<i class="fas fa-play-circle"></i> |
||||
</button> |
||||
</form> |
||||
` |
||||
const btnPausa = `<a class="bg-blue-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer" title="Colocar em Pausa?" onclick="selecionaAgente(${supervisor.id})"><i class="fas fa-pause"></i></a>`; |
||||
|
||||
const agenteIsPausa = supervisor.status === "PAUSA" ? btnPlay : btnPausa; |
||||
|
||||
elementsTable += ` |
||||
<tr class="bg-gray-50 dark:bg-gray-800 dark:text-gray-100 text-center"> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.id}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.nome}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.matricula}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${tempoFormatado}</td> |
||||
|
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.motivo_pausa ?? "Sem Pausa"}</td> |
||||
|
||||
<td class="p-3 text-sm text-${colorStatus[supervisor.status]}">${supervisor.status}</td> |
||||
|
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">${supervisor.qtde_atendimento}</td> |
||||
|
||||
<td class="p-3 text-sm font-bold flex items-center gap-2 flex-wrap"> |
||||
${agenteIsPausa} |
||||
|
||||
|
||||
<form method="POST" action="/dashboard/agentes/{{$fila->id}}/desconectar" title="Desconectar Pausa?" class="bg-red-600 text-white flex-1 rounded text-xl text-center py-2 px-3" > |
||||
@csrf |
||||
<input type="hidden" name="supervisor_id" value="${supervisor.id}"> |
||||
<button > |
||||
<i class="fas fa-power-off"></i> |
||||
</button> |
||||
</form> |
||||
</td> |
||||
</tr> |
||||
` |
||||
}); |
||||
|
||||
|
||||
$(".table-relatorio").html(elementsTable); |
||||
} |
||||
|
||||
function selecionaAgente(supervisor_id){ |
||||
console.log(supervisor_id); |
||||
const modal = document.querySelector(".modal"); |
||||
modal.style.display = "block"; |
||||
modal.querySelector("form").action = `/dashboard/agentes/{{$fila->nome}}/pausar`; |
||||
modal.querySelector("input[name='supervisor_id']").value = supervisor_id; |
||||
} |
||||
|
||||
montarRelatorios(); |
||||
|
||||
setInterval(() => { |
||||
montarRelatorios(); |
||||
}, 10000); |
||||
|
||||
</script> |
||||
@endpush |
||||
|
||||
<x-modalPausarAgente :pausas="$pausas"></x-modalPausarAgente> |
||||
</x-app-layout> |
@ -0,0 +1,93 @@
|
||||
<x-app-layout> |
||||
<div class="py-8 px-8"> |
||||
@if(session('status')) |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||
{{session('status')}} |
||||
</div> |
||||
@endif |
||||
<div class="header flex flex-col items-center gap-4 "> |
||||
<div class="flex justify-between items-center w-full mb-5"> |
||||
<h1 class=" text-gray-900 dark:text-gray-100 text-3xl font-bold text-center"> |
||||
Channels |
||||
</h1> |
||||
@can('store_channels') |
||||
<button class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-base overflow-hidden" @click="modal = !modal" type="button">Cadastrar Channel</button> |
||||
@endcan |
||||
</div> |
||||
<form action="{{route('channels')}}" method="GET" class="flex w-full gap-3 flex-col lg:flex-row "> |
||||
<div class="search bg-white dark:bg-gray-800 rounded px-3 py-1 overflow-hidden"> |
||||
<i class="fas fa-search dark:text-gray-100"></i> |
||||
<input type="text" name="pesquisa" class="border-none bg-transparent focus:ring-transparent placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100 " placeholder="Pesquise channels" value="{{$search}}"> |
||||
</div> |
||||
<select class="border-none rounded overflow-hidden dark:bg-gray-800 dark:text-gray-100" name="status"> |
||||
@if($status) |
||||
<option value="ativo" selected>Ativos</option> |
||||
<option value="desativado">Desativados</option> |
||||
@else |
||||
<option value="ativo">Ativos</option> |
||||
<option value="desativado" selected>Desativados</option> |
||||
@endif |
||||
</select> |
||||
<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 pl-5">ID</th> |
||||
<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">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> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Status</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Ações</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
@foreach($channels as $channel) |
||||
<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 pl-5">{{$channel->id}}</td> |
||||
<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->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> |
||||
@if($channel->status) |
||||
<td class="p-3 text-sm text-green-500 font-bold">ATIVO</td> |
||||
@else |
||||
<td class="p-3 text-sm text-red-500 font-bold">DESATIVADO</td> |
||||
@endif |
||||
<td class="p-3 text-sm font-bold w-32"> |
||||
@can('edit_channels') |
||||
<button class="bg-blue-600 text-white p-2 rounded text-lg text-center w-full mb-2" onclick="atualizaChannel(<?= $channel->id ?>)" title="editar channel"><i class="fas fa-edit"></i></button>
|
||||
@endcan |
||||
|
||||
@if($channel->status) |
||||
@can('destroy_channels') |
||||
<form method="POST" id="formulario" action="channels/deletar/{{$channel->id}}" title="desativar channel" onclick="javascript: if(!confirm('Deseja desativar esse channel?')) return false;"> |
||||
@csrf |
||||
@method('delete') |
||||
<button class="bg-red-600 text-white p-2 rounded text-lg w-full"> |
||||
<i class="fas fa-ban"></i> |
||||
</button> |
||||
</form> |
||||
@endcan |
||||
@endif |
||||
</td> |
||||
</tr> |
||||
@endforeach |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
|
||||
<x-modal.insert.modalChannels></x-modal> |
||||
<x-modal.edit.modalEditChannels></x-modalEditChannels> |
||||
|
||||
<script src="{{ asset('js/views/channels/atualizaChannel.js') }}"></script> |
||||
|
||||
</x-app-layout> |
@ -0,0 +1,85 @@
|
||||
<x-app-layout> |
||||
<div class="py-8 px-8"> |
||||
@if(session('status')) |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||
{{session('status')}} |
||||
</div> |
||||
@endif |
||||
<div class="header flex flex-col items-center gap-4 "> |
||||
<div class="flex justify-between items-center w-full mb-5"> |
||||
<h1 class=" text-gray-900 dark:text-gray-100 text-3xl font-bold text-center"> |
||||
Contatos |
||||
</h1> |
||||
@can('store_contatos') |
||||
<button class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-base overflow-hidden" @click="modal = !modal" type="button">Cadastrar Contato</button> |
||||
@endcan |
||||
</div> |
||||
<form action="{{route('contatos.index')}}" method="GET" class="flex w-full gap-3 flex-col lg:flex-row "> |
||||
<div class="search bg-white dark:bg-gray-800 rounded px-3 py-1 overflow-hidden"> |
||||
<i class="fas fa-search dark:text-gray-100"></i> |
||||
<input type="text" name="pesquisa" class="border-none bg-transparent focus:ring-transparent placeholder:text-gray-800 dark:placeholder:text-gray-100 dark:text-gray-100 " placeholder="Pesquise contatos"> |
||||
</div> |
||||
<select class="border-none rounded overflow-hidden dark:bg-gray-800 dark:text-gray-100" name="status"> |
||||
@if($status) |
||||
<option value="ativo" selected>Ativos</option> |
||||
<option value="desativado">Desativados</option> |
||||
@else |
||||
<option value="ativo">Ativos</option> |
||||
<option value="desativado" selected>Desativados</option> |
||||
@endif |
||||
</select> |
||||
<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 pl-5">Nome</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Numero</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Email</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Data Cadastro</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Status</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Ações</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
@foreach($contatos as $contato) |
||||
<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 pl-5">{{$contato->nome}}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100" data-mask="+00 00 0000-0000">{{$contato->contato}}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{$contato->email}}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{ $contato->formated_date }}</td> |
||||
@if($contato->status) |
||||
<td class="p-3 text-sm text-green-500 font-bold">ATIVO</td> |
||||
@else |
||||
<td class="p-3 text-sm text-red-500 font-bold">DESATIVADO</td> |
||||
@endif |
||||
<td class="p-3 text-sm font-bold w-28"> |
||||
@can('store_contatos') |
||||
<button onclick="atualizaContato({{ $contato->id }})" class="bg-blue-600 text-white p-2 rounded text-lg text-center w-full mb-2" title="editar contato"><i class="fas fa-edit"></i></button> |
||||
@endcan |
||||
|
||||
@can('store_contatos') |
||||
<form action="{{ route('contatos.destroy', ['contato' => $contato->id]) }}" method="POST" title="desativar contato" onclick="javascript: if(!confirm('Deseja desativar esse contato?')) |
||||
return false;"> |
||||
@method('delete') |
||||
@csrf |
||||
<button class="bg-red-600 dark:bg-red-700 text-white p-2 rounded text-lg w-full"> |
||||
<i class="fas fa-ban"></i> |
||||
</button> |
||||
</form> |
||||
@endcan |
||||
</td> |
||||
</tr> |
||||
@endforeach |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
<x-modal.insert.modalContatos></x-modalContatos> |
||||
<x-modal.edit.modalEditContatos></x-modalEditContatos> |
||||
|
||||
<script src="{{ asset('js/views/contatos/atualizaContato.js') }}"></script> |
||||
|
||||
</x-app-layout> |
@ -0,0 +1,102 @@
|
||||
<?php |
||||
$tipos = [ |
||||
1 => 'QUEUE', |
||||
2 => 'REDIRECT', |
||||
3 => 'AGENT', |
||||
4 => 'TEXT', |
||||
5 => 'HORARIO' |
||||
]; |
||||
?> |
||||
<x-app-layout> |
||||
<div class="py-8 px-8"> |
||||
@if (session('status')) |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg"> |
||||
{{ session('status') }} |
||||
</div> |
||||
@endif |
||||
<div class="header flex flex-col items-center gap-4 mt-2 mb-8"> |
||||
<div class="flex justify-between items-center w-full mb-5"> |
||||
<h1 class=" text-gray-900 dark:text-gray-100 text-3xl font-bold text-center"> |
||||
Horários |
||||
</h1> |
||||
@can('store_redirect') |
||||
<button |
||||
class="bg-blue-500 hover:bg-opacity-90 transition-all text-white py-2 px-6 rounded text-base overflow-hidden" |
||||
@click="modal = !modal" type="button">Cadastrar Horários</button> |
||||
@endcan |
||||
</div> |
||||
</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 ">ID</th> |
||||
<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">ID Canal</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Opção Fora de Horário</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Ação</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Status</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Opções</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left">Ações</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
@foreach ($horarios as $horario) |
||||
<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">{{ $horario->id }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{ $horario->nome }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{ $horario->id_number }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{ $tipos[$horario->opcao] }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100">{{ $horario->acao }}</td> |
||||
@if ($horario->status) |
||||
<td class="p-3 text-sm text-green-500 font-bold">ATIVO</td> |
||||
@else |
||||
<td class="p-3 text-sm text-red-500 font-bold">DESATIVADO</td> |
||||
@endif |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100"> |
||||
@can('show_redirect_option') |
||||
<a |
||||
href="{{ route('horarios.options.index', ['horario' => $horario->id]) }}" |
||||
class="text-blue-500 hover:underline">Editar Horários Disponíveis</a> |
||||
@endcan |
||||
</td> |
||||
<td class="p-3 text-sm font-bold flex-wrap w-32"> |
||||
@can('edit_redirect') |
||||
<button class="bg-blue-600 text-white p-2 rounded text-lg w-full mb-2" title="editar horário" |
||||
onclick="atualizaHorarios( {{ $horario->id }})"><i |
||||
class="fas fa-edit"></i></button> |
||||
@endcan |
||||
@can('destroy_redirect') |
||||
<form method="POST" |
||||
action="{{ route('horarios.destroy', ['horario' => $horario->id]) }}" |
||||
class="flex-1 flex" title="deletar horário" |
||||
onclick="javascript: if(!confirm('Deseja deletar esses dados?')) return false;"> |
||||
@csrf |
||||
@method('delete') |
||||
<button class="bg-red-600 text-white p-2 rounded text-lg w-full"> |
||||
<i class="fas fa-trash"></i> |
||||
</button> |
||||
</form> |
||||
@endcan |
||||
</td> |
||||
</tr> |
||||
@endforeach |
||||
</tbody> |
||||
</table> |
||||
</div> |
||||
</div> |
||||
<x-modal.insert.modalHorarios :types="$types" :numberChannels="$numberChannels"></x-modalHorarios> |
||||
<x-modal.edit.modalEditHorarios :types="$types" :numberChannels="$numberChannels"></x-modalEditHorarios> |
||||
|
||||
<script src="{{ asset('js/views/horarios/montaSelect.js') }}"></script> |
||||
<script src="{{ asset('js/views/horarios/requestType.js') }}"></script> |
||||
<script src="{{ asset('js/views/horarios/atualizaHorarios.js') }}"></script> |
||||
|
||||
<script> |
||||
const modal = document.querySelector(".modal"); |
||||
const id_type = 1; |
||||
|
||||
montaSelectDestino(id_type, modal); |
||||
</script> |
||||
</x-app-layout> |
@ -0,0 +1,140 @@
|
||||
<?php |
||||
$tipos = [ |
||||
1 => 'QUEUE', |
||||
2 => 'REDIRECT', |
||||
3 => 'AGENT', |
||||
4 => 'TEXT', |
||||
5 => 'HORARIO' |
||||
]; |
||||
|
||||
$semana = [ |
||||
'' => '', |
||||
1 => 'Segunda', |
||||
2 => 'Terça', |
||||
3 => 'Quarta', |
||||
4 => 'Quinta', |
||||
5 => 'Sexta', |
||||
6 => 'Sábado', |
||||
7 => 'Domingo', |
||||
]; |
||||
|
||||
$meses = ['' => '', 1 => 'Janeiro', 2 => 'Fevereiro', 3 => 'Março', 4 => 'Abril', 5 => 'Maio', 6 => 'Junho', 7 => 'Julho', 8 => 'Agosto', 9 => 'Setembro', 10 => 'Outubro', 11 => 'Novembro', 12 => 'Dezembro']; |
||||
?> |
||||
|
||||
<x-app-layout> |
||||
<div class="py-8 px-8"> |
||||
<a href="{{ route('horarios.index') }}" style="margin-right: auto;" |
||||
class="text-blue-500 hover:underline mb-5 block">Voltar</a> |
||||
|
||||
@if (session('status')) |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg alert"> |
||||
{{ session('status') }} |
||||
</div> |
||||
@endif |
||||
<div class="w-full p-5 bg-blue-600 mb-5 text-white rounded uppercase font-bold text-lg alert hidden act"> |
||||
|
||||
</div> |
||||
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg "> |
||||
<div class="p-6 text-gray-900 dark:text-gray-100"> |
||||
|
||||
<div class="flex items-center"> |
||||
<div> |
||||
<h1 class="text-2xl font-bold">Horários Disponíveis</h1> |
||||
</div> |
||||
@can('store_redirect_option') |
||||
<button class="ml-auto mt-2 bg-blue-600 text-white py-2 px-6 rounded-md text-lg" |
||||
@click="modal = !modal">Adicionar</button> |
||||
@endcan |
||||
</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 border text-center">Feriado</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center" colspan="2">Horário</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center" colspan="3">Dia da Semana</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center" colspan="3">Dia do Mês</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center" colspan="3">Meses</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center" colspan="2">Caso Combine</th> |
||||
<th class="p-3 text-sm font-semibold tracking-wide text-left border text-center">Ações</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr class="bg-white dark:bg-gray-800 dark:border-gray-600 border-b-2"> |
||||
<td></td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Início</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Fim</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Todos</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Inicio</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Fim</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Todos</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Inicio</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Fim</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Todos</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Inicio</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Fim</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Opção</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">Destino</td> |
||||
<td></td> |
||||
</tr> |
||||
</tbody> |
||||
|
||||
@foreach ($options as $option) |
||||
<tbody> |
||||
<tr class="bg-white dark:bg-gray-800 dark:border-gray-600 border-b-2"> |
||||
<td class="p-3 text-sm {{ $option->feriado == '1' ? 'text-green-500' : 'text-red-500' }} font-bold text-center">{{ $option->feriado == '1' ? 'SIM' : 'NÃO' }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $option->horario_inicio }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $option->horario_fim }}</td> |
||||
<td class="p-3 text-sm {{ $option->todos_dias_semana == '1' ? 'text-green-500' : 'text-red-500' }} font-bold border text-center">{{ $option->todos_dias_semana == '1' ? 'SIM' : 'NÃO' }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $semana[$option->semana] }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $semana[$option->semana_fim] }}</td> |
||||
<td class="p-3 text-sm {{ $option->todos_dias_mes == '1' ? 'text-green-500' : 'text-red-500' }} font-bold border text-center">{{ $option->todos_dias_mes == '1' ? 'SIM' : 'NÃO' }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $option->dias_mes }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $option->dias_mes_fim }}</td> |
||||
<td class="p-3 text-sm {{ $option->todos_mes == '1' ? 'text-green-500' : 'text-red-500' }} font-bold border text-center">{{ $option->todos_mes == '1' ? 'SIM' : 'NÃO' }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $meses[$option->mes] }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $meses[$option->mes_fim] }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 uppercase border text-center">{{ $tipos[$option->opcao] }}</td> |
||||
<td class="p-3 text-sm text-gray-700 dark:text-gray-100 border text-center">{{ $option->acao }}</td> |
||||
<td class="p-3 text-sm font-bold flex items-center gap-2 flex-wrap"> |
||||
<button class="bg-blue-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer title="editar horário" |
||||
onclick="atualizaHorariosOptions( {{ $option->id }})"> |
||||
<i class="fas fa-edit"></i> |
||||
</button> |
||||
@can('destroy_redirect') |
||||
<form method="POST" |
||||
action="{{ route('horarios.options.destroy', ['horario' => $id_horario, 'option' => $option->id]) }}" |
||||
class="flex-1 flex" title="deletar horário" |
||||
onclick="javascript: if(!confirm('Deseja deletar esses dados?')) return false;"> |
||||
@csrf |
||||
@method('delete') |
||||
<button class="bg-red-600 text-white rounded flex-1 text-xl text-center py-2 px-3 cursor-pointer"> |
||||
<i class="fas fa-trash"></i> |
||||
</button> |
||||
</form> |
||||
@endcan |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
@endforeach |
||||
</table> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<x-modal.insert.modalHorariosOption :id_horario="$id_horario" :types="$types"></x-modalHorarioOption> |
||||
<x-modal.edit.modalEditHorariosOptions :types="$types"></x-modalEditHorariosOptions> |
||||
|
||||
<script src="{{ asset('js/views/horariosOption/atualizaHorariosOptions.js') }}"></script> |
||||
<script src="{{ asset('js/views/horariosOption/montaSelect.js') }}"></script> |
||||
<script src="{{ asset('js/views/horariosOption/requestType.js') }}"></script> |
||||
|
||||
<script> |
||||
const modal = document.querySelector(".modal"); |
||||
const id_type = 1; |
||||
|
||||
montaSelectDestino(id_type, modal); |
||||
</script> |
||||
</x-app-layout> |