197 lines
7.4 KiB
Vue
197 lines
7.4 KiB
Vue
<template>
|
|
<div class="intro-y flex flex-col sm:flex-row items-center mt-8">
|
|
<h2 class="text-lg font-medium mr-auto">{{ $t("TICKET_LIST") }}</h2>
|
|
<div class="w-full sm:w-auto flex mt-4 sm:mt-0">
|
|
<button class="btn btn-primary shadow-md mr-2" @click="onCreateTicket">{{ $t("CREATE_TICKET") }}</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div class="intro-y chat grid grid-cols-12 gap-5 mt-5">
|
|
<!-- BEGIN: Chat Side Menu -->
|
|
<div class="col-span-12 lg:col-span-4 2xl:col-span-3">
|
|
<div class="chat__chat-list overflow-y-auto scrollbar-hidden pr-1 pt-1">
|
|
<div v-for="(ticket, ticketKey) in ticketList" :key="ticketKey"
|
|
class="intro-x cursor-pointer box relative flex items-center p-5"
|
|
:class="[{ 'mt-5': ticketKey }, active == ticket.id ? ['bg-slate-200', 'pointer-events-none'] : '']"
|
|
@click.capture="goToTicket(ticket.id)">
|
|
<div class="ml-2 overflow-hidden w-full">
|
|
<div class="flex items-center justify-between">
|
|
<a href="javascript:;" class="font-medium">{{ ticket.title }}</a>
|
|
<div class="text-xs text-slate-400 ml-3">{{ $t('CREATED') }} {{ normalizeDate(ticket.created_at) }}</div>
|
|
</div>
|
|
<div class="w-full truncate text-slate-500 mt-0.5">
|
|
{{ $t('STATUS') }}: {{ $t(ticket.status.toUpperCase()) }}
|
|
</div>
|
|
</div>
|
|
<div v-if="ticket.last_sender === 'admin'"
|
|
class="w-5 h-5 flex items-center justify-center absolute top-0 right-0 text-xs text-white rounded-full bg-primary font-medium -mt-1 -mr-1">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END: Chat Side Menu -->
|
|
|
|
<!-- BEGIN: Chat Content -->
|
|
<div class="intro-y col-span-12 lg:col-span-8 2xl:col-span-9">
|
|
<div class="chat__box box">
|
|
<!-- BEGIN: Chat Active -->
|
|
<div v-show="chatBox" class="h-full flex flex-col">
|
|
<div class="flex flex-col sm:flex-row border-b border-slate-200/60 dark:border-darkmode-400 px-5 py-4">
|
|
<div class="flex items-center">
|
|
<div class="ml-3 mr-auto">
|
|
<div class="font-medium text-base">{{ $t("TMEX_ADMINS_TEAM") }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-y-scroll scrollbar-hidden px-5 pt-5 flex-1 chat_area-inner" ref="chatAreaRef">
|
|
<template v-for="ticketMessage in ticketMessageList" :key="ticketMessage.id">
|
|
<template v-if="ticketMessage.is_client">
|
|
<div class="chat__box__text-box flex items-end float-right mb-4">
|
|
<div class="bg-primary px-4 py-3 text-white rounded-l-md rounded-t-md">
|
|
{{ ticketMessage.content }}
|
|
<div class="mt-1 text-xs text-white text-opacity-80">
|
|
{{ normalizeDate(ticketMessage.created_at) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="clear-both"></div>
|
|
</template>
|
|
<template v-else>
|
|
<div class="chat__box__text-box flex items-end float-left mb-4">
|
|
<div class="bg-slate-100 dark:bg-darkmode-400 px-4 py-3 text-slate-500 rounded-r-md rounded-t-md">
|
|
{{ ticketMessage.content }}
|
|
<div class="mt-1 text-xs text-slate-500">{{ normalizeDate(ticketMessage.created_at) }}</div>
|
|
</div>
|
|
</div>
|
|
<div class="clear-both"></div>
|
|
</template>
|
|
</template>
|
|
</div>
|
|
<div class="pt-4 pb-10 sm:py-4 flex items-center border-t border-slate-200/60 dark:border-darkmode-400">
|
|
<textarea
|
|
class="chat__box__input form-control dark:bg-darkmode-600 h-16 resize-none border-transparent px-5 py-3 shadow-none focus:border-transparent focus:ring-0"
|
|
rows="1" :placeholder="$t('TYPE_TICKET_MESSAGE')" v-model="content"></textarea>
|
|
|
|
<a href="javascript:;"
|
|
class="w-8 h-8 sm:w-10 sm:h-10 block bg-primary text-white rounded-full flex-none flex items-center justify-center mr-5"
|
|
:class="[content === '' ? ['opacity-50', 'pointer-events-none'] : '']" @click="sendMessage">
|
|
<SendIcon class="w-4 h-4" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<!-- END: Chat Active -->
|
|
<!-- BEGIN: Chat loading -->
|
|
<div v-show="isTicketLoading" class="h-full flex items-center">
|
|
<div class="mx-auto text-center">
|
|
<div class="mt-3">
|
|
<div class="font-medium">
|
|
<LoadingIcon icon="oval" color="#003197" class="w-20 h-20" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END: Chat loading -->
|
|
<!-- BEGIN: Chat Default -->
|
|
<div v-show="!chatBox && !isTicketLoading" class="h-full flex items-center">
|
|
<div class="mx-auto text-center">
|
|
<div class="w-16 h-16 flex-none image-fit rounded-full overflow-hidden mx-auto">
|
|
<img alt="TMEX ICON" src="@/assets/images/fav_icon.svg" />
|
|
</div>
|
|
<div class="mt-3">
|
|
<div v-if="user" class="font-medium">
|
|
{{ $t("SIMPLE_HELLO") }}, {{ user.firstname }} {{ user.lastname }}!
|
|
</div>
|
|
<div class="text-slate-500 mt-1" v-html="$t('PLEASE_SELECT_TICKET')">
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END: Chat Default -->
|
|
</div>
|
|
</div>
|
|
<!-- END: Chat Content -->
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onBeforeMount, watch, computed } from "vue";
|
|
import router from "@/router";
|
|
import { useAuthStore, useTicketsStore } from "@/stores";
|
|
import { storeToRefs } from 'pinia';
|
|
import { normalizeDate } from "@/helpers";
|
|
import { useRoute } from "vue-router";
|
|
|
|
const route = useRoute();
|
|
|
|
const authStore = useAuthStore();
|
|
const ticketsStore = useTicketsStore();
|
|
const { user } = storeToRefs(authStore);
|
|
const { ticketList, ticketMessageList } = storeToRefs(ticketsStore);
|
|
|
|
const chatBox = ref(false);
|
|
const active = ref(0);
|
|
|
|
const isTicketLoading = ref(false);
|
|
|
|
const content = ref("");
|
|
|
|
const chatAreaRef = ref(); // div element chat
|
|
|
|
const onCreateTicket = () => router.push({ path: "/ticket-list/create" });
|
|
|
|
const goToTicket = (ticketId) => router.push({ name: "ticket-list", query: { ticketId: ticketId } });
|
|
|
|
const showChatBox = async (ticketId) => {
|
|
|
|
chatBox.value = false;
|
|
isTicketLoading.value = true;
|
|
|
|
await ticketsStore.getTicketMessages(ticketId);
|
|
|
|
isTicketLoading.value = false;
|
|
chatBox.value = true;
|
|
|
|
active.value = ticketId
|
|
|
|
scrollToLastMessage();
|
|
};
|
|
|
|
const scrollToLastMessage = () => {
|
|
setTimeout(() => {
|
|
chatAreaRef.value.scrollTop = chatAreaRef.value.scrollHeight;
|
|
}, 0);
|
|
};
|
|
|
|
const sendMessage = async () => {
|
|
|
|
await ticketsStore.sendMessage(content.value, active.value);
|
|
|
|
content.value = "";
|
|
|
|
scrollToLastMessage();
|
|
};
|
|
|
|
onBeforeMount(async () => {
|
|
await ticketsStore.getTickets();
|
|
if (route.query.ticketId) {
|
|
showChatBox(route.query.ticketId);
|
|
}
|
|
});
|
|
|
|
watch(
|
|
computed(() => route.query),
|
|
() => {
|
|
if (route.query.ticketId) {
|
|
console.log(route.query);
|
|
showChatBox(route.query.ticketId);
|
|
|
|
}
|
|
//console.log(route.query.ticketId);
|
|
}
|
|
);
|
|
</script>
|