OpenTicketsDialog.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <q-card style="width: 800px; max-width: 95vw; border-radius: 12px">
  4. <q-bar class="bg-transparent q-px-md" style="height: 55px">
  5. <span class="text-h6 text-dark" style="font-weight: 600"
  6. >Tickets em Aberto</span
  7. >
  8. <q-space />
  9. <q-btn dense flat icon="mdi-close" @click="onDialogCancel" />
  10. </q-bar>
  11. <q-card-section class="q-pt-none q-pb-md q-px-md">
  12. <q-card flat bordered style="border-radius: 8px">
  13. <q-card-section class="q-pb-sm">
  14. <q-input
  15. v-model="search"
  16. dense
  17. borderless
  18. placeholder="Busque por ticket, nome, data , setor"
  19. >
  20. <template #prepend>
  21. <q-icon name="mdi-magnify" color="grey-6" />
  22. </template>
  23. </q-input>
  24. </q-card-section>
  25. <q-separator />
  26. <div class="list-header q-px-md q-py-xs">
  27. <span class="text-caption text-grey-7">Ticket</span>
  28. <span class="text-caption text-grey-7">Prioridade</span>
  29. <span class="text-caption text-grey-7">Data</span>
  30. <span class="text-caption text-grey-7">Setor</span>
  31. <span class="text-caption text-grey-7">Status</span>
  32. </div>
  33. <q-separator />
  34. <div style="max-height: 320px; overflow-y: auto">
  35. <div v-if="filteredTickets.length === 0" class="text-grey-6 text-center q-pa-lg">
  36. Nenhum ticket aberto encontrado.
  37. </div>
  38. <template v-for="(ticket, index) in filteredTickets" :key="ticket.id">
  39. <div
  40. class="list-row q-px-md q-py-sm"
  41. :class="{ 'row-selected': index === selectedIndex }"
  42. @click="selectedIndex = index"
  43. >
  44. <span class="text-body2 text-dark">{{ ticket.number }}</span>
  45. <q-badge
  46. :label="priorityLabel(ticket.priority)"
  47. :color="priorityColor(ticket.priority)"
  48. style="border-radius: 8px; font-size: 11px; padding: 4px 8px; width: max-content"
  49. />
  50. <span class="text-caption text-dark">{{ ticket.date }}</span>
  51. <span class="text-caption text-dark">{{ ticket.sector }}</span>
  52. <q-badge
  53. :label="statusLabel(ticket.status)"
  54. :color="statusColor(ticket.status)"
  55. style="border-radius: 8px; font-size: 11px; padding: 4px 8px; width: max-content"
  56. />
  57. </div>
  58. <q-separator v-if="index < filteredTickets.length - 1" />
  59. </template>
  60. </div>
  61. </q-card>
  62. </q-card-section>
  63. </q-card>
  64. </q-dialog>
  65. </template>
  66. <script setup>
  67. import { ref, computed } from "vue";
  68. import { useDialogPluginComponent } from "quasar";
  69. defineEmits([...useDialogPluginComponent.emits]);
  70. const { dialogRef, onDialogHide, onDialogCancel } = useDialogPluginComponent();
  71. const props = defineProps({
  72. tickets: {
  73. type: Array,
  74. default: () => [],
  75. },
  76. });
  77. const search = ref("");
  78. const selectedIndex = ref(0);
  79. const priorityLabel = (priority) =>
  80. ({ high: "Alta", medium: "Média", low: "Baixa" })[priority] ?? priority;
  81. const priorityColor = (priority) => {
  82. if (priority === "high") return "negative";
  83. if (priority === "medium") return "warning";
  84. return "orange";
  85. };
  86. const statusColor = (s) => {
  87. if (s === "resolved") return "positive";
  88. if (s === "in_progress") return "warning";
  89. return "negative";
  90. };
  91. const statusLabel = (status) =>
  92. ({
  93. in_progress: "Em andamento",
  94. resolved: "Resolvido",
  95. unresolved: "Não resolvido",
  96. })[status] ?? status;
  97. const filteredTickets = computed(() => {
  98. if (!search.value) return props.tickets;
  99. const q = search.value.toLowerCase();
  100. return props.tickets.filter(
  101. (t) =>
  102. t.number.toLowerCase().includes(q) ||
  103. t.title.toLowerCase().includes(q) ||
  104. t.date.includes(q) ||
  105. t.sector.toLowerCase().includes(q) ||
  106. t.status.toLowerCase().includes(q),
  107. );
  108. });
  109. </script>
  110. <style scoped>
  111. .list-header {
  112. display: grid;
  113. grid-template-columns: 90px 100px 110px 1fr 140px;
  114. align-items: center;
  115. }
  116. .list-row {
  117. display: grid;
  118. grid-template-columns: 90px 100px 110px 1fr 140px;
  119. align-items: center;
  120. cursor: pointer;
  121. transition: background-color 0.15s;
  122. }
  123. .list-row:hover {
  124. background-color: #f5f5f5;
  125. }
  126. .row-selected {
  127. background-color: #b2dfdb !important;
  128. }
  129. </style>