add chat direct

This commit is contained in:
amazuecos
2025-05-20 00:01:26 +02:00
parent 976c7980d4
commit 5f76e0e437
8 changed files with 140 additions and 61 deletions

View File

@ -646,6 +646,8 @@ $routes->group('messages', ['namespace' => 'App\Controllers\Chat'], function ($r
$routes->get('datatable/pedido', 'ChatController::datatable_pedido_messages', ['as' => 'getDatatablePedidoMessages']);
$routes->get('datatable/factura', 'ChatController::datatable_factura_messages', ['as' => 'getDatatableFacturaMessages']);
$routes->get('datatable/ots', 'ChatController::datatable_ot_messages', ['as' => 'getDatatableOtMessages']);
$routes->get('datatable/direct', 'ChatController::datatable_direct_messages', ['as' => 'getDatatableDirectMessages']);
$routes->post('direct', 'ChatController::store_new_direct_message', ['as' => 'storeNewDirectMessage']);
$routes->post('direct/client', 'ChatController::store_new_direct_message_client', ['as' => 'storeNewDirectMessageClient']);

View File

@ -363,14 +363,13 @@ class ChatController extends BaseController
$query = $this->userModel->builder()->select(
[
"id",
"CONCAT(first_name,' ',last_name,'(',username,')') as name"
"CONCAT(first_name,' ',last_name) as name"
]
)
->where("deleted_at", null)
->whereNotIn("id", [auth()->user()->id]);
if ($this->request->getGet("q")) {
$query->groupStart()
->orLike("users.username", $this->request->getGet("q"))
->orLike("CONCAT(first_name,' ',last_name)", $this->request->getGet("q"))
->groupEnd();
}
@ -538,6 +537,23 @@ class ChatController extends BaseController
->toJson(true);
}
public function datatable_direct_messages()
{
$auth_user_id = auth()->user()->id;
$isAdmin = auth()->user()->inGroup('admin');
$query = $this->chatModel->getQueryDatatableDirectMessages($auth_user_id);
return DataTable::of($query)
->edit('created_at', fn($q) => $q->created_at ? Time::createFromFormat('Y-m-d H:i:s', $q->created_at)->format("d/m/Y H:i") : "")
->edit('updated_at', fn($q) => $q->updated_at ? Time::createFromFormat('Y-m-d H:i:s', $q->updated_at)->format("d/m/Y H:i") : "")
->edit("creator",fn($q) => $q->userId == $auth_user_id ? '<span class="badge text-bg-success w-100">'.lang("App.me").'</span>' : $q->creator)
->add("viewed", fn($q) => $this->chatModel->isMessageChatViewed($q->chatMessageId))
->add("action", fn($q) => ["type" => "direct", "modelId" => $q->id, "isAdmin" => $isAdmin,"chatMessageId" => $q->chatMessageId, "lang" => [
"view_chat" => lang('Chat.view_chat'),
"view_by_alt_message" => lang('Chat.view_by_alt_message')
]])
->toJson(true);
}
public function get_notifications_not_viewed_from_message(int $chat_message_id)
{
$unviewedNotifications = $this->chatModel->getUsersNotificationNotViewedFromChat($chat_message_id);
@ -605,14 +621,13 @@ class ChatController extends BaseController
$query = $this->userModel->builder()->select(
[
"id",
"CONCAT(first_name,' ',last_name,'(',username,')') as name"
"CONCAT(first_name,' ',last_name) as name"
]
)
->where("deleted_at", null)
->whereNotIn("id", $chat_users_id);
if ($this->request->getGet("q")) {
$query->groupStart()
->orLike("users.username", $this->request->getGet("q"))
->orLike("CONCAT(first_name,' ',last_name)", $this->request->getGet("q"))
->groupEnd();
}

View File

@ -60,6 +60,7 @@ return [
"subscribe_admin_chat_wrong" => "Tienes que seleccionar un usuario.",
"help_select_chat_department_user" => "Solamente son listados los usuarios que pertenecen al personal. Los clientes no son listados, para añadirlos a la conversación se realiza desde la sección de mensajería de las diferentes secciones(presupuesto,pedido,factura ...)",
"store_department" => "Crear departamento",
"direct_messsages" => "Mensajes directos",
"mail" => [
"mail_subject" => "Nuevo mensaje"
]

View File

@ -136,7 +136,7 @@ class ChatModel extends Model
$chatDeparmentModel = model(ChatDeparmentModel::class);
$ot = $model->find($orden_trabajo_id);
return $this->insert([
"title" => "[OT]".$ot->id . "[" . $chatDeparmentModel->getDisplay($chat_department_id) . "]",
"title" => "[OT]" . $ot->id . "[" . $chatDeparmentModel->getDisplay($chat_department_id) . "]",
"orden_trabajo_id" => $orden_trabajo_id,
"chat_department_id" => $chat_department_id
]);
@ -381,8 +381,7 @@ class ChatModel extends Model
$row->title = $row->facturaId;
$rows_new[] = $row;
}
elseif ($row->ordenTrabajoId) {
} elseif ($row->ordenTrabajoId) {
// $row->model = $facturaModel->find($row->facturaId);
$row->uri = "/chat/ot/" . $row->ordenTrabajoId . "#accordionChatOrdenTrabajo";
$row->avatar = "OT";
@ -439,8 +438,7 @@ class ChatModel extends Model
$row->chatDisplay .= "[INTERNAL]";
$row->title = $row->facturaId;
$rows_new[] = $row;
}
elseif ($row->ordenTrabajoId) {
} elseif ($row->ordenTrabajoId) {
$row->uri = "/produccion/ordentrabajo/edit/" . $row->ordenTrabajoId . "#accordionChatOrdenTrabajo";
$row->avatar = "OT";
$row->chatDisplay .= "[INTERNAL]";
@ -847,7 +845,7 @@ class ChatModel extends Model
->join("users u", "u.id = cm.sender_id", 'left')
->where("chats.presupuesto_id is NOT NULL", NULL, FALSE);
if (auth()->user()->inGroup("cliente-administrador","cliente")) {
if (auth()->user()->inGroup("cliente-administrador", "cliente")) {
$query->where('presupuestos.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
@ -878,7 +876,7 @@ class ChatModel extends Model
->join("presupuestos", "presupuestos.id = pedidos_linea.presupuesto_id", 'left')
->where("chats.pedido_id is NOT NULL", NULL, FALSE);
if (auth()->user()->inGroup("cliente-administrador","cliente")) {
if (auth()->user()->inGroup("cliente-administrador", "cliente")) {
$query->where('presupuestos.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
@ -908,10 +906,10 @@ class ChatModel extends Model
->join("facturas", "facturas.id = chats.factura_id", "left")
->where("chats.factura_id is NOT NULL", NULL, FALSE);
if (auth()->user()->inGroup("cliente-administrador","cliente")) {
$query->where('facturas.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
if (auth()->user()->inGroup("cliente-administrador", "cliente")) {
$query->where('facturas.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
return $query->groupBy('chatMessageId');
}
public function getQueryDatatableMessageOrdenTrabajo(int $user_id): BaseBuilder
@ -938,10 +936,42 @@ class ChatModel extends Model
->join("ordenes_trabajo", "ordenes_trabajo.id = chats.orden_trabajo_id", "left")
->where("chats.orden_trabajo_id is NOT NULL", NULL, FALSE);
if (auth()->user()->inGroup("cliente-administrador","cliente")) {
$query->where('facturas.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
if (auth()->user()->inGroup("cliente-administrador", "cliente")) {
$query->where('facturas.cliente_id', auth()->user()->cliente_id)
->where("chats.chat_department_id is NOT NULL", NULL, FALSE);
}
return $query->groupBy('chatMessageId');
}
public function getQueryDatatableDirectMessages(): BaseBuilder
{
$query = $this->builder()
->select([
"chats.id",
"cm.id as chatMessageId",
"u.id as userId",
"cm.message",
"chats.created_at",
"
(
SELECT cm2.updated_at
FROM chat_messages cm2
WHERE cm2.chat_id = chats.id
ORDER BY cm2.updated_at DESC LIMIT 1
) as updated_at",
"CONCAT(u.first_name,' ',u.last_name) as creator",
"chats.title as title",
])
->join("chat_messages cm", "chats.id = cm.chat_id", "left")
->join("users u", "u.id = cm.sender_id", 'left')
->where("chats.presupuesto_id", NULL)
->where("chats.pedido_id", NULL)
->where("chats.factura_id", NULL)
->where("chats.orden_trabajo_id", NULL)
->groupStart()
->orWhere("cm.receiver_id",auth()->user()->id)
->orWhere("cm.sender_id",auth()->user()->id)
->groupEnd();
return $query->groupBy('chatMessageId');
}
public function createNewDirectChat(string $title, string $message, array $users)

View File

@ -15,26 +15,33 @@ use Config\App;
<div class="nav-tabs-shadow nav-align-top">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<button type="button" class="nav-link active" role="tab" id="navs-top-align-all-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-all"><?=lang('App.global_all')?></button>
<button type="button" class="nav-link active" role="tab" id="navs-top-align-all-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-all"><?= lang('App.global_all') ?></button>
</li>
<li class="nav-item">
<button type="button" class="nav-link" role="tab" id="navs-top-align-presupuestos-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-presupuestos"><?=lang('App.permisos_presupuestos')?></button>
<button type="button" class="nav-link" role="tab" id="navs-top-align-direct-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-direct"><?= lang('Chat.direct_messsages') ?></button>
</li>
<li class="nav-item">
<button type="button" class="nav-link" role="tab" id="navs-top-align-pedidos-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-pedidos"><?=lang('App.permisos_pedidos')?></button>
<button type="button" class="nav-link" role="tab" id="navs-top-align-presupuestos-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-presupuestos"><?= lang('App.permisos_presupuestos') ?></button>
</li>
<li class="nav-item">
<button type="button" class="nav-link" role="tab" id="navs-top-align-facturas-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-facturas"><?=lang('App.menu_facturas')?></button>
<button type="button" class="nav-link" role="tab" id="navs-top-align-pedidos-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-pedidos"><?= lang('App.permisos_pedidos') ?></button>
</li>
<li class="nav-item">
<button type="button" class="nav-link" role="tab" id="navs-top-align-ot-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-ots"><?=lang('Produccion.ots')?></button>
<button type="button" class="nav-link" role="tab" id="navs-top-align-facturas-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-facturas"><?= lang('App.menu_facturas') ?></button>
</li>
<li class="nav-item">
<button type="button" class="nav-link" role="tab" id="navs-top-align-ot-tab" data-bs-toggle="tab" data-bs-target="#navs-top-align-ots"><?= lang('Produccion.ots') ?></button>
</li>
</ul>
<div class="tab-content" id="message-datatables-container">
<div class="tab-pane fade show active" id="navs-top-align-all">
<div class="tab-pane fade show active" id="navs-top-align-all">
<?= view("themes/vuexy/components/tables/messages_table", ["id" => "tableAllMessages"]) ?>
</div>
<div class="tab-pane fade show" id="navs-top-align-direct">
<button class="btn-primary btn" id="btn-new-message"><span><?= lang('Chat.modal.new_message') ?></span></button>
<?= view("themes/vuexy/components/tables/messages_table", ["id" => "tableDirectMessages"]) ?>
</div>
<div class="tab-pane fade show" id="navs-top-align-presupuestos">
<?= view("themes/vuexy/components/tables/messages_table", ["id" => "tablePresupuestoMessages"]) ?>
</div>
@ -70,7 +77,8 @@ use Config\App;
<script src="<?= site_url("themes/vuexy/vendor/libs/formvalidation/dist/js/plugins/Bootstrap5.min.js") ?>"></script>
<script src="<?= site_url("themes/vuexy/vendor/libs/formvalidation/dist/js/plugins/AutoFocus.min.js") ?>"></script>
<script type="module" src="<?= site_url('assets/js/safekat/pages/configuracion/messages/index.js') ?>">
<script src="<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.js') ?>"></script>
< script src = "<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.js') ?>" >
</script>
</script>
<?= $this->endSection() ?>

View File

@ -75,7 +75,7 @@ class Chat {
});
}
if (this.chatHistoryBody.length) {
this.chatHistoryBody.scrollTop(0,this.chatHistoryBody[0].scrollHeight);
this.chatHistoryBody.scrollTop(0, this.chatHistoryBody[0].scrollHeight);
}
}
initDirectMessage() {
@ -650,9 +650,6 @@ class Chat {
<div class="chat-contact-info flex-grow-1 ms-2">
<h6 class="chat-contact-name text-truncate m-0">${contact?.first_name ?? "" + " " +
contact?.last_name ?? ""}</h6>
<p class="chat-contact-status text-muted text-truncate mb-0">
${contact?.cliente_id ? "[CLIENTE]" : ""}${contact.username}
</p>
</div>
</div>
</li>

View File

@ -8,6 +8,8 @@ class MessagesDatatable {
this.datatablePedidoMessageItem = this.item.find("#tablePedidoMessages")
this.datatableFacturaMessageItem = this.item.find("#tableFacturaMessages")
this.datatableOtMessageItem = this.item.find("#tableOtMessages")
this.datatableDirectMessageItem = this.item.find("#tableDirectMessages")
this.focusTable = this.datatableItem
this.columnDefs = [
@ -15,7 +17,7 @@ class MessagesDatatable {
this.datatableColumns = [
{ data: 'created_at', searchable: true, sortable: true },
{ data: 'updated_at', searchable: true, sortable: true },
{ data: 'title', name:"chats.title",searchable: true, sortable: true },
{ data: 'title', name: "chats.title", searchable: true, sortable: true },
{ data: 'message', searchable: false, sortable: true },
{ data: 'creator', searchable: false, sortable: false },
{
@ -59,8 +61,8 @@ class MessagesDatatable {
this.datatable = this.datatableItem.DataTable({
processing: true,
order: [[1, 'desc']],
columnDefs : this.columnDefs,
orderCellsTop : true,
columnDefs: this.columnDefs,
orderCellsTop: true,
layout: {
topStart: 'pageLength',
topEnd: 'search',
@ -79,8 +81,8 @@ class MessagesDatatable {
this.datatablePresupuestoMessage = this.datatablePresupuestoMessageItem.DataTable({
processing: true,
order: [[1, 'desc']],
columnDefs : this.columnDefs,
orderCellsTop : true,
columnDefs: this.columnDefs,
orderCellsTop: true,
layout: {
topStart: 'pageLength',
topEnd: 'search',
@ -97,8 +99,8 @@ class MessagesDatatable {
});
this.datatablePedidoMessage = this.datatablePedidoMessageItem.DataTable({
processing: true,
orderCellsTop : true,
columnDefs : this.columnDefs,
orderCellsTop: true,
columnDefs: this.columnDefs,
order: [[1, 'desc']],
layout: {
topStart: 'pageLength',
@ -116,8 +118,8 @@ class MessagesDatatable {
});
this.datatableFacturaMessage = this.datatableFacturaMessageItem.DataTable({
processing: true,
orderCellsTop : true,
columnDefs : this.columnDefs,
orderCellsTop: true,
columnDefs: this.columnDefs,
order: [[1, 'desc']],
layout: {
topStart: 'pageLength',
@ -136,8 +138,8 @@ class MessagesDatatable {
this.datatableOtMessage = this.datatableOtMessageItem.DataTable({
processing: true,
order: [[1, 'desc']],
columnDefs : this.columnDefs,
orderCellsTop : true,
columnDefs: this.columnDefs,
orderCellsTop: true,
layout: {
topStart: 'pageLength',
topEnd: 'search',
@ -152,6 +154,25 @@ class MessagesDatatable {
columns: this.datatableColumns,
ajax: '/messages/datatable/ots'
});
this.datatableDirectMessage = this.datatableDirectMessageItem.DataTable({
processing: true,
order: [[1, 'desc']],
columnDefs: this.columnDefs,
orderCellsTop: true,
layout: {
topStart: 'pageLength',
topEnd: 'search',
bottomStart: 'info',
bottomEnd: 'paging'
},
serverSide: true,
pageLength: 10,
language: {
url: "/themes/vuexy/vendor/libs/datatables-sk/plugins/i18n/es-ES.json"
},
columns: this.datatableColumns,
ajax: '/messages/datatable/direct'
});
this.datatablePresupuestoMessageItem.on("keyup", ".datatable-message-filter", (event) => {
let columnIndex = this.datatableColumns.findIndex((element) => element.data == $(event.currentTarget).attr("name"))
this.datatablePresupuestoMessage.column(columnIndex).search($(event.currentTarget).val()).draw()
@ -166,7 +187,11 @@ class MessagesDatatable {
})
this.datatableOtMessageItem.on("keyup", ".datatable-message-filter", (event) => {
let columnIndex = this.datatableColumns.findIndex((element) => element.data == $(event.currentTarget).attr("name"))
this.datatableFacturaMessage.column(columnIndex).search($(event.currentTarget).val()).draw()
this.datatableOtMessage.column(columnIndex).search($(event.currentTarget).val()).draw()
})
this.datatableDirectMessageItem.on("keyup", ".datatable-message-filter", (event) => {
let columnIndex = this.datatableColumns.findIndex((element) => element.data == $(event.currentTarget).attr("name"))
this.datatableDirectMessage.column(columnIndex).search($(event.currentTarget).val()).draw()
})
}
@ -197,18 +222,15 @@ class MessagesDatatable {
}
}
handleDropUpError() { }
addDropUpItem(user)
{
addDropUpItem(user) {
return `
<li >
<a type="button" class="d-flex flex-row justify-content-between align-items-center dropdown-item px-2 gap-2" href="javascript:void(0);" >
<span> ${user.userFullName ?? user.userName} </span>
<span class="badge badge-center rounded-pill text-bg-${
user.viewed == 1 ? 'success' : 'danger'
}">
<i class="ti ti-xs ti-${
user.viewed == 1 ? 'eye-check' : 'eye-off'
} "></i>
<span class="badge badge-center rounded-pill text-bg-${user.viewed == 1 ? 'success' : 'danger'
}">
<i class="ti ti-xs ti-${user.viewed == 1 ? 'eye-check' : 'eye-off'
} "></i>
</span>
</a>
</li>`;

View File

@ -38,26 +38,30 @@ class MessagePage {
this.btnSubmitNewDirectMessage.on("click", this.handleSubmitNewMessage.bind(this))
this.btnSubmitNewDirectMessageCliente.on("click", this.handleSubmitNewMessageClient.bind(this))
$("#navs-top-align-all-tab").on("click",()=>{
$("#navs-top-align-all-tab").on("click", () => {
this.messageDatatable.datatable.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatableItem
})
$("#navs-top-align-presupuestos-tab").on("click",()=>{
$("#navs-top-align-presupuestos-tab").on("click", () => {
this.messageDatatable.datatablePresupuestoMessage.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatablePresupuestoMessageItem
})
$("#navs-top-align-pedidos-tab").on("click",()=>{
$("#navs-top-align-pedidos-tab").on("click", () => {
this.messageDatatable.datatablePedidoMessage.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatablePedidoMessageItem
})
$("#navs-top-align-facturas-tab").on("click",()=>{
$("#navs-top-align-facturas-tab").on("click", () => {
this.messageDatatable.datatableFacturaMessage.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatableFacturaMessageItem
})
$("#navs-top-align-ot-tab").on("click",()=>{
$("#navs-top-align-ot-tab").on("click", () => {
this.messageDatatable.datatableOtMessage.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatableOtMessageItem
})
$("#navs-top-align-direct-tab").on("click", () => {
this.messageDatatable.datatableDirectMessage.ajax.reload()
this.messageDatatable.focusTable = this.messageDatatable.datatableDirectMessageItem
})
}
openNewMessageModal() {
@ -68,7 +72,7 @@ class MessagePage {
this.modalNewMessage.toggle()
}
handleSubmitNewMessage() {
handleSubmitNewMessage() {
this.btnNewMessage.addClass("loading")
const ajax = new Ajax("/messages/direct",
this.getNewMessageDataForm(),
@ -92,7 +96,7 @@ class MessagePage {
this.alert.setAsError()
this.alert.setHeadingTitle(error.message)
}
handleSubmitNewMessageClient(){
handleSubmitNewMessageClient() {
this.btnNewMessage.addClass("loading")
const ajax = new Ajax("/messages/direct/client",
this.getNewMessageDataFormClient(),
@ -101,11 +105,11 @@ class MessagePage {
this.handleSubmitNewMessageError.bind(this))
ajax.post()
}
handleSubmitNewMessageClientSuccess(){
handleSubmitNewMessageClientSuccess() {
}
handleSubmitNewMessageClientError(){
handleSubmitNewMessageClientError() {
}
getNewMessageDataForm() {
return {