KanbanPage.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <template>
  2. <div>
  3. <DefaultHeaderPage title="Atividades" :show-filter-icon="false" />
  4. <div v-if="loading" class="flex flex-center q-pa-xl">
  5. <q-spinner color="primary" size="48px" />
  6. </div>
  7. <div
  8. v-else
  9. class="kanban-board q-px-md q-pb-md"
  10. style="
  11. display: flex;
  12. gap: 16px;
  13. overflow-x: auto;
  14. align-items: flex-start;
  15. min-height: calc(100vh - 120px);
  16. "
  17. >
  18. <div
  19. v-for="column in columns"
  20. :key="column.phase"
  21. class="kanban-column"
  22. style="
  23. min-width: 280px;
  24. max-width: 320px;
  25. flex: 1;
  26. display: flex;
  27. flex-direction: column;
  28. gap: 8px;
  29. "
  30. >
  31. <!-- Column header -->
  32. <div
  33. class="kanban-column-header row items-center justify-between q-px-md q-py-sm"
  34. :style="{ backgroundColor: column.color, borderRadius: '8px' }"
  35. >
  36. <span class="text-weight-bold text-white" style="font-size: 14px">
  37. {{ column.label }}
  38. </span>
  39. <q-badge
  40. color="white"
  41. :text-color="column.textColor"
  42. :label="cardsForPhase(column.phase).length"
  43. style="font-size: 11px"
  44. />
  45. </div>
  46. <!-- Cards -->
  47. <div
  48. style="
  49. display: flex;
  50. flex-direction: column;
  51. gap: 8px;
  52. flex: 1;
  53. "
  54. >
  55. <KanbanCard
  56. v-for="card in cardsForPhase(column.phase)"
  57. :key="card.id"
  58. :card="card"
  59. @edit="openDialog(card, column.phase)"
  60. />
  61. </div>
  62. <!-- Add button -->
  63. <q-btn
  64. flat
  65. color="grey-6"
  66. icon="mdi-plus"
  67. label="Adicionar"
  68. class="q-mt-xs full-width"
  69. style="border-radius: 8px; border: 1px dashed #ccc"
  70. @click="openDialog(null, column.phase)"
  71. />
  72. </div>
  73. </div>
  74. </div>
  75. </template>
  76. <script setup>
  77. import { ref, defineAsyncComponent, onMounted } from "vue";
  78. import { useQuasar } from "quasar";
  79. import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
  80. import KanbanCard from "./components/KanbanCard.vue";
  81. import { getKanbans } from "src/api/kanban";
  82. const AddEditKanbanDialog = defineAsyncComponent(
  83. () => import("./components/AddEditKanbanDialog.vue"),
  84. );
  85. const $q = useQuasar();
  86. const loading = ref(false);
  87. const cards = ref([]);
  88. const columns = [
  89. { phase: "a_fazer", label: "A Fazer", color: "#757575", textColor: "grey-9" },
  90. { phase: "em_progresso", label: "Em Progresso", color: "#1976D2", textColor: "blue-9" },
  91. { phase: "em_revisao", label: "Em Revisão", color: "#F57C00", textColor: "orange-9"},
  92. { phase: "concluido", label: "Concluído", color: "#388E3C", textColor: "green-9" },
  93. { phase: "demandas_especiais",label: "Demandas Especiais",color: "#F9A825", textColor: "yellow-9"},
  94. ];
  95. const cardsForPhase = (phase) =>
  96. cards.value.filter((c) => c.phase === phase);
  97. const loadCards = async () => {
  98. loading.value = true;
  99. try {
  100. cards.value = await getKanbans();
  101. } finally {
  102. loading.value = false;
  103. }
  104. };
  105. const openDialog = (card = null, phase = "a_fazer") => {
  106. $q.dialog({
  107. component: AddEditKanbanDialog,
  108. componentProps: { card, initialPhase: phase },
  109. }).onOk(() => {
  110. loadCards();
  111. });
  112. };
  113. onMounted(loadCards);
  114. </script>
  115. <style scoped>
  116. .kanban-board {
  117. padding-top: 12px;
  118. }
  119. </style>