فهرست منبع

feat(support): adiciona funcionalidade de Alterar o Status, Encerrar o Ticket e Validacao do Status para Acoes

ebagabee 4 هفته پیش
والد
کامیت
6c14e46a36

+ 73 - 5
src/pages/support/SupportPage.vue

@@ -5,13 +5,22 @@
       ref="tableRef"
       :columns="columns"
       :api-call="getSupportTickets"
-      :delete-function="deleteSupportTicket"
       add-item
       title="Tickets"
       :female="false"
       description="tickets"
       @on-add-item="openAddEditTicketDialog()"
     >
+      <template #body-cell-status="{ row }">
+        <q-td align="center">
+          <q-badge
+            :color="statusColor(row.status)"
+            :label="statusLabel(row.status)"
+            style="padding: 6px 10px"
+          />
+        </q-td>
+      </template>
+
       <template #body-cell-actions="{ row }">
         <q-btn
           outline
@@ -19,6 +28,22 @@
           style="width: 36px"
           @click.prevent.stop="handleEdit(row)"
         />
+        <q-btn
+          v-if="row.status === 'in_progress'"
+          outline
+          icon="mdi-check-circle-outline"
+          style="width: 36px"
+          color="warning"
+          @click.prevent.stop="handleClose(row)"
+        />
+        <q-btn
+          v-if="row.status === 'in_progress'"
+          outline
+          icon="mdi-trash-can-outline"
+          style="width: 36px"
+          color="negative"
+          @click.prevent.stop="handleDelete(row)"
+        />
       </template>
     </DefaultTable>
   </div>
@@ -36,6 +61,10 @@ const AddEditTicketDialog = defineAsyncComponent(
   () => import("src/pages/support/components/AddEditTicketDialog.vue"),
 );
 
+const CloseTicketDialog = defineAsyncComponent(
+  () => import("src/pages/support/components/CloseTicketDialog.vue"),
+);
+
 const $q = useQuasar();
 const tableRef = useTemplateRef("tableRef");
 
@@ -80,15 +109,15 @@ const columns = [
   },
   {
     name: "title",
-    label: "Descrição",
+    label: "Título",
     field: "title",
     align: "left",
   },
   {
-    name: "support_status_id",
+    name: "status",
     label: "Status",
-    field: "support_status_id",
-    align: "left",
+    field: "status",
+    align: "center",
     sortable: true,
   },
   {
@@ -100,7 +129,46 @@ const columns = [
   },
 ];
 
+const statusLabel = (status) => {
+  const map = {
+    in_progress: "Em andamento",
+    resolved: "Resolvido",
+    unresolved: "Não resolvido",
+  };
+  return map[status] ?? status;
+};
+
+const statusColor = (status) => {
+  const map = {
+    in_progress: "warning",
+    resolved: "positive",
+    unresolved: "negative",
+  };
+  return map[status] ?? "grey";
+};
+
 const handleEdit = (row) => {
   openAddEditTicketDialog(row);
 };
+
+const handleClose = (row) => {
+  $q.dialog({
+    component: CloseTicketDialog,
+    componentProps: { ticket: row },
+  }).onOk(() => {
+    tableRef.value?.refresh();
+  });
+};
+
+const handleDelete = (row) => {
+  $q.dialog({
+    title: "Confirmar exclusão",
+    message: "Tem certeza que deseja excluir este ticket?",
+    ok: { color: "negative", label: "Excluir" },
+    cancel: { color: "primary", outline: true, label: "Cancelar" },
+  }).onOk(async () => {
+    await deleteSupportTicket(row.id);
+    tableRef.value?.refresh();
+  });
+};
 </script>

+ 21 - 4
src/pages/support/components/AddEditTicketDialog.vue

@@ -82,10 +82,7 @@
                   @click="onAddComment"
                 />
               </div>
-              <div
-                class="column q-gutter-y-sm overflow-y-auto"
-                style="max-height: 340px"
-              >
+              <div style="max-height: 340px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px;">
                 <TicketCommentCard
                   v-for="comment in mockComments"
                   :key="comment.id"
@@ -105,6 +102,14 @@
               @click="onDialogCancel"
             />
             <q-btn
+              v-if="ticket?.id && ticket?.status === 'in_progress'"
+              outline
+              color="negative"
+              label="Encerrar"
+              @click="onCloseTicket"
+            />
+            <q-btn
+              v-if="!ticket?.id || ticket?.status === 'in_progress'"
               color="primary"
               label="Salvar"
               type="submit"
@@ -128,7 +133,9 @@ import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
 import UnitSelect from "src/components/selects/UnitSelect.vue";
 import TicketCommentCard from "./TicketCommentCard.vue";
 import { userStore } from "src/stores/user";
+import { useQuasar } from "quasar";
 import { createSupportTicket, updateSupportTicket } from "src/api/support_ticket";
+import CloseTicketDialog from "./CloseTicketDialog.vue";
 
 defineEmits([...useDialogPluginComponent.emits]);
 
@@ -142,6 +149,7 @@ const { ticket } = defineProps({
 const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
   useDialogPluginComponent();
 
+const $q = useQuasar();
 const { user } = userStore();
 
 const formRef = ref(null);
@@ -215,6 +223,15 @@ const onAddComment = () => {
   // TODO: implement add comment
 };
 
+const onCloseTicket = () => {
+  $q.dialog({
+    component: CloseTicketDialog,
+    componentProps: { ticket },
+  }).onOk(() => {
+    onDialogOK(true);
+  });
+};
+
 const onOKClick = async () => {
   loading.value = true;
   try {

+ 84 - 0
src/pages/support/components/CloseTicketDialog.vue

@@ -0,0 +1,84 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <div style="width: 100%; max-width: 500px">
+      <q-card class="overflow-hidden" style="width: 100%">
+        <DefaultDialogHeader title="Encerrar Ticket" @close="onDialogCancel" />
+
+        <q-card-section class="q-pt-sm column q-gutter-y-md">
+          <DefaultSelect
+            v-model="resolved"
+            label="A solicitação foi resolvida?"
+            :options="resolvedOptions"
+            emit-value
+            map-options
+          />
+
+          <p v-if="resolved !== null" class="text-body2 q-mb-none">
+            <template v-if="resolved">
+              Sua solicitação foi resolvida com sucesso, hora de finalizar este suporte.
+            </template>
+            <template v-else>
+              Sua solicitação não foi resolvida, finalize o suporte.
+            </template>
+          </p>
+        </q-card-section>
+
+        <q-card-actions align="right" class="q-px-md q-pb-md">
+          <q-btn
+            outline
+            color="primary"
+            label="Cancelar"
+            @click="onDialogCancel"
+          />
+          <q-btn
+            v-if="resolved !== null && ticket.status === 'in_progress'"
+            color="primary"
+            label="Encerrar"
+            :loading="loading"
+            @click="onOKClick"
+          />
+        </q-card-actions>
+      </q-card>
+    </div>
+  </q-dialog>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { useDialogPluginComponent } from "quasar";
+
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
+import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
+import { updateSupportTicket } from "src/api/support_ticket";
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const { ticket } = defineProps({
+  ticket: {
+    type: Object,
+    required: true,
+  },
+});
+
+const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
+  useDialogPluginComponent();
+
+const loading = ref(false);
+const resolved = ref(null);
+
+const resolvedOptions = [
+  { label: "Sim", value: true },
+  { label: "Não", value: false },
+];
+
+const onOKClick = async () => {
+  loading.value = true;
+  try {
+    const status = resolved.value ? "resolved" : "unresolved";
+    await updateSupportTicket(ticket.id, { status });
+    onDialogOK(true);
+  } finally {
+    loading.value = false;
+  }
+};
+</script>