montre moi comment quoi où modifier mon code dynamiquement pour voir s'il est id ou fiche pour ensuite entré le bon url lors de la sauvegarde et si l'étudiant fiche n'a pas 7 chiffre de rajouter des 0 :
<script setup>
import { ref, onMounted, computed, watch } from 'vue';
import AppList from '@/components/AppList.vue';
import AppCustomAlert from '@/components/AppCustomAlert.vue';
import apiClient from '@/services/axiosConfig.js';


const appListRef = ref(null);
const subjects = ref([]);
const selectedItem = ref(null);
const showSuccessAlert = ref(false);
const errors = ref({});
const groupedRegistrationsCopy = ref({});

const studentsMap = ref({});

const padFiche = (fiche) => {
  return fiche.toString().padStart(7, '0');
};

const getCurrentSchoolYear = () => 2023; 

const columns = ref([
  { header: 'Nom de la Matière', field: 'description', class: 'col-3 left-align' },
  {
    header: 'Volet',
    field: 'volet_details',
    class: 'col-3 center-align',
    formatter: (item) => item.volet_details
  },
  { header: 'Nombre d\'inscriptions', field: 'registration_details', class: 'col-4 center-align' }
]);

const customActions = ref([
  { name: 'customModal', label: 'Entrer les résultats', icon: 'cil-spreadsheet', tooltip: 'Entrer les résultats', iconClass: 'text-primary' }
]);

const modalForms = ref({
  default: {
    fields: [
      { name: 'subject_info', label: '', type: 'custom', class: 'col-md-12' },
      { name: 'student_info', label: '', type: 'custom', class: 'col-md-12' },
    ]
  }
});

const apiUrls = computed(() => ({
  update: (fiche, studentId) => {
    if (fiche) {
      return `/students/${fiche}/registrations/${getCurrentSchoolYear()}`;
    } else if (studentId) {
      return `/students/${studentId}/registrations/${getCurrentSchoolYear()}`;
    }
    throw new Error("Un numéro de fiche ou un ID d'étudiant est requis pour l'URL.");
  }
}));


const filterRegistrationData = (registration) => {
  const { id, resultField, result } = registration;
  // Ne garder que l'ID d'inscription et les résultats pertinents
  return {
    [resultField]: result,
  };
};

const fetchSubjectsAndRegistrations = async () => {
  try {
    const [registrationsResponse, subjectsResponse] = await Promise.all([
      apiClient.get(`/students/registrations/${getCurrentSchoolYear()}`),
      apiClient.get(`/subjects/${getCurrentSchoolYear()}`)
    ]);

    if (subjectsResponse.data.status === "success" && Array.isArray(subjectsResponse.data.data)) {
      const registrations = registrationsResponse.data.data || [];

      const fiches = [...new Set(registrations.map(reg => reg.fiche).filter(fiche => fiche))];

      const paddedFiches = fiches.map(fiche => padFiche(fiche));

      const studentPromises = paddedFiches.map(fiche => 
        apiClient.get(`/students/${fiche}`).then(res => res.data.data)
      );
      const students = await Promise.all(studentPromises);

      students.forEach(student => {
        if (student.fiche) {
          const paddedFiche = padFiche(student.fiche);
          studentsMap.value[paddedFiche] = student;
        }
      });

      const registrationsWithStudents = registrations.map(reg => {
        const fichePadded = padFiche(reg.fiche);
        return {
          ...reg,
          student: studentsMap.value[fichePadded] || {}
        };
      });

      subjects.value = subjectsResponse.data.data.map(subject => {
        const subjectRegistrations = registrationsWithStudents.filter(reg => reg.subject_id === subject.id);
        return {
          ...subject,
          registrations: subjectRegistrations 
        };
      }).filter(subject => subject.registrations.length > 0);
      
    } else {
      console.error('Failed to fetch subjects:', subjectsResponse);
    }
  } catch (error) {
    console.error('Erreur lors de la récupération des données:', error);
  }
};

const processedSubjects = computed(() => {
  return subjects.value.map(subject => {
    const voletDetailsGeneral = [];

    for (let i = 1; i <= 4; i++) {
      const code = subject[`volet${i}_code`];
      const percentage = subject[`volet${i}_percentage`];

      const hasRegistrations = subject.registrations.some(reg => reg[`volet${i}`]);

      if (code && code.trim() !== '' && hasRegistrations) {
        voletDetailsGeneral.push(`${code} - ${percentage || 0}%`);
      }
    }

    return {
      ...subject,
      volet_details: voletDetailsGeneral.join('<br/>'),
      registration_details: subject.registrations.length
    };
  });
});

const groupedRegistrations = computed(() => {
  if (!selectedItem.value) return {};

  const volets = {};

  selectedItem.value.registrations.forEach(reg => {
    for (let i = 1; i <= 4; i++) {
      if (reg[`volet${i}`]) { 
        const code = selectedItem.value[`volet${i}_code`];
        const percentage = selectedItem.value[`volet${i}_percentage`];

        if (code && code.trim() !== '') {
          if (!volets[code]) {
            volets[code] = {
              code,
              percentage,
              registrations: []
            };
          }

          const resultField = `volet${i}_results`;
          const result = reg[resultField];

          volets[code].registrations.push({
            ...reg,
            student: reg.student,
            result,
            resultField,
            voletIndex: i
          });
        }
      }
    }
  });

  return volets;
});

const handleCustomAction = async (actionName, item) => {
  selectedItem.value = JSON.parse(JSON.stringify(item));
  console.log('Selected Item:', selectedItem.value); 
};

const validateResults = (updates) => {
  let isValid = true;
  errors.value = {};

  for (const registrationId in updates) {
    const data = updates[registrationId];

    for (const field in data) {
      const result = data[field];
      if (result === null || result === undefined || result === '') {
        errors.value[registrationId] = 'Le résultat est requis.';
        isValid = false;
      } else if (result < 0 || result > 100) {
        errors.value[registrationId] = 'Le résultat doit être entre 0 et 100.';
        isValid = false;
      }
    }
  }
  
  groupedRegistrationsCopy.value = JSON.parse(JSON.stringify(groupedRegistrations.value));
  return isValid;
};

const handleCustomSave = async (currentItem) => {
  // Votre logique de préparation des données à mettre à jour
  const updates = {};

  // Récupération des résultats pour chaque inscription
  Object.values(groupedRegistrations.value).forEach(volet => {
    volet.registrations.forEach(reg => {
      const registrationId = reg.id;
      const resultField = reg.resultField;
      const result = reg.result;

      if (!updates[registrationId]) {
        updates[registrationId] = {};
      }

      if (result !== null && result !== undefined) {
        updates[registrationId][resultField] = result;
      }
    });
  });

  // Validation des résultats avant envoi
  if (!validateResults(updates)) {
    return;
  }

  try {
    for (const registrationId in updates) {
      const dataToUpdate = updates[registrationId];
      const registration = Object.values(groupedRegistrations.value).flatMap(volet => volet.registrations).find(reg => reg.id == registrationId);
      const fiche = registration?.student?.fiche;

      // Construire l'URL de la mise à jour en utilisant la fiche ou l'ID d'inscription
      const updateUrl = apiUrls.value.update(fiche, registrationId);

      // Envoyer uniquement les champs de résultats pour cette inscription
      await apiClient.post(updateUrl, dataToUpdate);
    }

    showSuccessAlert.value = true;
    selectedItem.value = null;
    // Fermer le modal en appelant la fonction via appListRef
    appListRef.value.closeModal();
  } catch (error) {
    console.error('Erreur lors de la mise à jour des résultats:', error);
    handleError(error);
  }
};


const handleSuccess = (message) => {
  successMessage.value = message;
  showSuccessAlert.value = true;
  setTimeout(() => {
    showSuccessAlert.value = false;
  }, 3000);
};

const handleError = (error) => {
  console.error('Opération échouée :', error);
};

const validateAndCorrectResults = () => {
  subjects.value.forEach(subject => {
    subject.registrations.forEach(registration => {
      for (let i = 1; i <=4; i++) {
        const result = registration[`volet${i}_results`];
        if (result !== null && (isNaN(parseInt(result, 10)) || result > 100)) {
          registration[`volet${i}_results`] = result > 100 ? 100 : parseInt(result, 10);
        }
      }
    });
  });
};

watch(() => subjects.value, validateAndCorrectResults, { deep: true });

onMounted(fetchSubjectsAndRegistrations);
</script>

<template>
  <div>
    <AppCustomAlert v-if="showSuccessAlert" :message="'Les résultats ont été enregistrés avec succès!'" type="success" />
    <AppList
      ref="appListRef"
      :title="'Liste des Matières'"
      :columns="columns"
      :items="processedSubjects"
      :customModalTitle="'Entrer'"
      :itemType="'les Résultats'"
      :customButtonLabel="'Enregistrer'"
      :customActions="customActions"
      :modalForms="modalForms"
      :showAddButton="false"
      :shouldFetchData="false"
      :apiUrls="apiUrls"
      :modalType="'customModal'"
      @itemSaved="handleCustomSave"
      @itemDeleted="handleSuccess('Les résultats ont été supprimés avec succès.')"
      @operationFailed="handleError"
      @customAction="handleCustomAction"
    >
      <template v-slot:modal-body="{ currentItem }">
        <div v-if="selectedItem">
          <h3>{{ selectedItem.description }}</h3>
          <div v-for="(volet, code) in groupedRegistrations" :key="code" class="volet-section">
            <h4>{{ code }}</h4>
            <div v-for="reg in volet.registrations" :key="reg.id" class="student-result-container">
              <div class="student-info">
                <span class="student-name">{{ reg.student.first_name }} {{ reg.student.last_name }}</span>
                <span class="student-fiche">(#{{ reg.fiche }})</span>
              </div>
              <div class="result-input">
                <input
                  type="number"
                  v-model="reg.result"
                  min="0"
                  max="100"
                  placeholder="Résultat"
                  class="result-input-field"
                />
                <div v-if="errors[reg.id]" class="error-message">
                  {{ errors[reg.id] }}
                </div>
              </div>
            </div>
          </div>
        </div>
      </template>
    </AppList>
  </div>
</template>

<style scoped>
@import "@/styles/_results.scss";

.volet-section {
  margin-bottom: 20px;
  padding: 10px;
  border: none; /* Supprime la bordure */
  border-radius: 5px;
}

.volet-section h4 {
  margin-bottom: 5px;
  color: #333;
}

.volet-section p {
  margin-bottom: 10px;
  color: #555;
}

.student-result-container {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.student-info {
  flex: 1;
}

.student-name {
  font-weight: bold;
}

.student-fiche {
  margin-left: 10px;
  color: #666;
}

.result-input {
  flex: 1;
}

.result-input label {
  margin-right: 5px;
}
</style>