Răsfoiți Sursa

feat(StudentPage): add date filters for student list and enhance DefaultHeaderPage integration

ebagabee 3 săptămâni în urmă
părinte
comite
f86693b24b

+ 2 - 2
src/api/student.js

@@ -1,7 +1,7 @@
 import api from "src/api";
 
-export const getStudents = async () => {
-  const { data } = await api.get("/student");
+export const getStudents = async (params = {}) => {
+  const { data } = await api.get("/student", { params });
   return data.payload;
 };
 

+ 16 - 4
src/components/layout/DefaultHeaderPage.vue

@@ -27,10 +27,16 @@
         <q-icon
           v-if="showFilterIcon"
           name="mdi-filter-outline"
-          color="background"
+          :color="filterOpen ? 'background' : 'primary'"
           size="sm"
-          class="q-ml-sm bg-primary"
-          style="border-radius: 8px; padding: 2px"
+          class="q-ml-sm cursor-pointer"
+          :class="filterOpen ? 'bg-primary' : ''"
+          :style="
+            filterOpen
+              ? 'border-radius: 8px; padding: 2px'
+              : 'border-radius: 8px; padding: 2px; border: 1.5px solid var(--q-primary)'
+          "
+          @click="$emit('show-filter')"
         />
       </div>
       <div
@@ -291,11 +297,15 @@ import {
 } from "src/api/notification";
 import { socket, joinRoom, leaveRoom } from "src/boot/socket.io";
 
-const { breadcrumbs, showFilterIcon, title } = defineProps({
+const { breadcrumbs, filterOpen, showFilterIcon, title } = defineProps({
   breadcrumbs: {
     type: Array,
     default: null,
   },
+  filterOpen: {
+    type: Boolean,
+    default: false,
+  },
   showFilterIcon: {
     type: Boolean,
     default: false,
@@ -306,6 +316,8 @@ const { breadcrumbs, showFilterIcon, title } = defineProps({
   },
 });
 
+defineEmits(["show-filter"]);
+
 const route = useRoute();
 const router = useRouter();
 const { t } = useI18n();

+ 86 - 3
src/pages/students/StudentPage.vue

@@ -1,6 +1,45 @@
 <template>
   <div>
-    <DefaultHeaderPage title="Alunos" show-filter-icon />
+    <DefaultHeaderPage
+      title="Alunos"
+      show-filter-icon
+      :filter-open="showFilter"
+      @show-filter="showFilter = !showFilter"
+    />
+
+    <div class="q-pa-sm">
+      <div class="filter-row">
+        <template v-if="showFilter">
+          <DefaultInputDatePicker
+            v-model="startDate"
+            v-model:untreated-date="startDateRaw"
+            dense
+            label="Data Inicial"
+            color="secondary"
+            class="filter-item"
+          />
+
+          <DefaultInputDatePicker
+            v-model="endDate"
+            v-model:untreated-date="endDateRaw"
+            dense
+            label="Data Final"
+            color="secondary"
+            class="filter-item"
+          />
+
+          <q-btn
+            v-if="hasDateFilter"
+            flat
+            no-caps
+            color="secondary"
+            icon="mdi-filter-remove-outline"
+            label="Limpar"
+            @click="clearFilters"
+          />
+        </template>
+      </div>
+    </div>
 
     <div class="q-px-sm">
       <DefaultTable
@@ -56,10 +95,11 @@
 </template>
 
 <script setup>
-import { defineAsyncComponent, ref, onMounted, watch } from "vue";
+import { computed, defineAsyncComponent, ref, onMounted, watch } from "vue";
 import { useQuasar } from "quasar";
 import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
 import DefaultTable from "src/components/defaults/DefaultTable.vue";
+import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
 import { getStudents, deleteStudent } from "src/api/student";
 import { userStore } from "src/stores/user";
 
@@ -76,6 +116,13 @@ const store = userStore();
 
 const rows = ref([]);
 const isLoading = ref(false);
+const showFilter = ref(false);
+const startDate = ref(null);
+const endDate = ref(null);
+const startDateRaw = ref(null);
+const endDateRaw = ref(null);
+
+const hasDateFilter = computed(() => !!startDateRaw.value || !!endDateRaw.value);
 
 const columns = ref([
   {
@@ -107,7 +154,10 @@ const columns = ref([
 async function loadStudents() {
   isLoading.value = true;
   try {
-    rows.value = await getStudents();
+    rows.value = await getStudents({
+      contract_start_date: startDateRaw.value,
+      contract_end_date: endDateRaw.value,
+    });
   } catch (error) {
     console.error("Failed to load students:", error);
   } finally {
@@ -115,6 +165,13 @@ async function loadStudents() {
   }
 }
 
+function clearFilters() {
+  startDate.value = null;
+  endDate.value = null;
+  startDateRaw.value = null;
+  endDateRaw.value = null;
+}
+
 function onAddStudent() {
   $q.dialog({
     component: AddEditStudentDialog,
@@ -157,5 +214,31 @@ watch(
   },
 );
 
+watch([startDateRaw, endDateRaw], () => {
+  loadStudents();
+});
+
 onMounted(loadStudents);
 </script>
+
+<style scoped>
+.filter-row {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 12px;
+  align-items: center;
+}
+
+.filter-item {
+  flex: 1 1 200px;
+  min-width: 180px;
+  max-width: 300px;
+}
+
+@media (max-width: 599px) {
+  .filter-item {
+    flex: 1 1 100%;
+    max-width: 100%;
+  }
+}
+</style>