Web UI Ok

This commit is contained in:
Christophe 2025-09-21 11:34:53 +02:00
parent 9be454ca81
commit 9fab9f83ef
8 changed files with 1243 additions and 57 deletions

932
claude2.json Normal file
View File

@ -0,0 +1,932 @@
{
"employees": [
{
"name": "Dr. Marie Dupont",
"skills": ["MEDECIN", "SUPERVISION"],
"unavailableDates": ["2024-12-25", "2024-12-26"],
"undesiredDates": ["2024-12-24", "2024-12-31"],
"desiredDates": ["2024-12-20", "2024-12-23"]
},
{
"name": "Dr. Pierre Moreau",
"skills": ["MEDECIN"],
"unavailableDates": ["2024-12-22"],
"undesiredDates": ["2024-12-29"],
"desiredDates": ["2024-12-21", "2024-12-27"]
},
{
"name": "Dr. Claire Rousseau",
"skills": ["MEDECIN", "SUPERVISION"],
"unavailableDates": [],
"undesiredDates": ["2024-12-25"],
"desiredDates": ["2024-12-24", "2024-12-28"]
},
{
"name": "Inf. Sophie Bernard",
"skills": ["INFIRMIER", "PRELEVEMENT"],
"unavailableDates": ["2024-12-25"],
"undesiredDates": ["2024-12-31"],
"desiredDates": ["2024-12-20", "2024-12-21"]
},
{
"name": "Inf. Jean Leroy",
"skills": ["INFIRMIER", "ACCUEIL"],
"unavailableDates": ["2024-12-24", "2024-12-25"],
"undesiredDates": [],
"desiredDates": ["2024-12-27", "2024-12-30"]
},
{
"name": "Inf. Anne Moreau",
"skills": ["INFIRMIER", "PRELEVEMENT"],
"unavailableDates": ["2024-12-26"],
"undesiredDates": ["2024-12-23"],
"desiredDates": ["2024-12-21", "2024-12-29"]
},
{
"name": "Inf. Luc Petit",
"skills": ["INFIRMIER"],
"unavailableDates": [],
"undesiredDates": ["2024-12-20"],
"desiredDates": ["2024-12-22", "2024-12-28"]
},
{
"name": "Inf. Julie Martin",
"skills": ["INFIRMIER", "ACCUEIL"],
"unavailableDates": ["2024-12-30"],
"undesiredDates": ["2024-12-25"],
"desiredDates": ["2024-12-23", "2024-12-27"]
},
{
"name": "Inf. Thomas Dubois",
"skills": ["INFIRMIER", "PRELEVEMENT"],
"unavailableDates": [],
"undesiredDates": ["2024-12-22"],
"desiredDates": ["2024-12-24", "2024-12-26"]
},
{
"name": "Chauffeur Michel Blanc",
"skills": ["CHAUFFEUR", "TRANSPORT"],
"unavailableDates": ["2024-12-25"],
"undesiredDates": ["2024-12-24"],
"desiredDates": ["2024-12-20", "2024-12-27"]
},
{
"name": "Chauffeur Paul Girard",
"skills": ["CHAUFFEUR", "LOGISTIQUE"],
"unavailableDates": ["2024-12-26"],
"undesiredDates": [],
"desiredDates": ["2024-12-22", "2024-12-29"]
},
{
"name": "Chauffeur Marc Vincent",
"skills": ["CHAUFFEUR"],
"unavailableDates": ["2024-12-31"],
"undesiredDates": ["2024-12-23"],
"desiredDates": ["2024-12-21", "2024-12-28"]
},
{
"name": "Acc. Sylvie Roux",
"skills": ["ACCUEIL", "SECRETARIAT"],
"unavailableDates": ["2024-12-25", "2024-12-26"],
"undesiredDates": ["2024-12-24"],
"desiredDates": ["2024-12-20", "2024-12-30"]
},
{
"name": "Acc. Nathalie Fabre",
"skills": ["ACCUEIL"],
"unavailableDates": ["2024-12-22"],
"undesiredDates": ["2024-12-29"],
"desiredDates": ["2024-12-21", "2024-12-27"]
},
{
"name": "Acc. Patricia Leclerc",
"skills": ["ACCUEIL", "INFORMATIQUE"],
"unavailableDates": [],
"undesiredDates": ["2024-12-25", "2024-12-31"],
"desiredDates": ["2024-12-23", "2024-12-28"]
}
],
"collectes": [
{
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkills": {
"INFIRMIER": 2,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac",
"requiredSkills": {
"INFIRMIER": 2,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers",
"requiredSkills": {
"INFIRMIER": 3,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret",
"requiredSkills": {
"INFIRMIER": 2,
"MEDECIN": 1,
"CHAUFFEUR": 2
}
},
{
"id": "collecte_tournefeuille_20241224",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille",
"requiredSkills": {
"INFIRMIER": 1,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkills": {
"INFIRMIER": 4,
"MEDECIN": 2,
"CHAUFFEUR": 1
}
},
{
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin",
"requiredSkills": {
"INFIRMIER": 2,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkills": {
"INFIRMIER": 3,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
},
{
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkills": {
"INFIRMIER": 3,
"MEDECIN": 1,
"CHAUFFEUR": 2
}
},
{
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkills": {
"INFIRMIER": 2,
"MEDECIN": 1,
"CHAUFFEUR": 1,
"ACCUEIL": 1
}
}
],
"shifts": [
{
"id": "shift_toulouse_centre_20241220_chauffeur",
"start": "2024-12-20T07:00:00",
"end": "2024-12-20T18:00:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre"
}
},
{
"id": "shift_toulouse_centre_20241220_accueil",
"start": "2024-12-20T08:30:00",
"end": "2024-12-20T16:30:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre"
}
},
{
"id": "shift_toulouse_centre_20241220_medecin",
"start": "2024-12-20T08:45:00",
"end": "2024-12-20T16:45:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre"
}
},
{
"id": "shift_toulouse_centre_20241220_infirmier_1",
"start": "2024-12-20T09:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre"
}
},
{
"id": "shift_toulouse_centre_20241220_infirmier_2",
"start": "2024-12-20T09:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_toulouse_centre_20241220",
"start": "2024-12-20T08:00:00",
"end": "2024-12-20T17:00:00",
"location": "Centre de collecte - Toulouse Centre"
}
},
{
"id": "shift_blagnac_20241221_chauffeur",
"start": "2024-12-21T08:00:00",
"end": "2024-12-21T17:00:00",
"location": "Centre de collecte - Blagnac",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac"
}
},
{
"id": "shift_blagnac_20241221_accueil",
"start": "2024-12-21T09:30:00",
"end": "2024-12-21T15:30:00",
"location": "Centre de collecte - Blagnac",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac"
}
},
{
"id": "shift_blagnac_20241221_medecin",
"start": "2024-12-21T09:15:00",
"end": "2024-12-21T15:45:00",
"location": "Centre de collecte - Blagnac",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac"
}
},
{
"id": "shift_blagnac_20241221_infirmier_1",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac"
}
},
{
"id": "shift_blagnac_20241221_infirmier_2",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_blagnac_20241221",
"start": "2024-12-21T09:00:00",
"end": "2024-12-21T16:00:00",
"location": "Centre de collecte - Blagnac"
}
},
{
"id": "shift_colomiers_20241222_chauffeur",
"start": "2024-12-22T07:30:00",
"end": "2024-12-22T18:30:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_colomiers_20241222_accueil",
"start": "2024-12-22T08:00:00",
"end": "2024-12-22T18:00:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_colomiers_20241222_medecin",
"start": "2024-12-22T08:45:00",
"end": "2024-12-22T17:15:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_colomiers_20241222_infirmier_1",
"start": "2024-12-22T09:00:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_colomiers_20241222_infirmier_2",
"start": "2024-12-22T09:00:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_colomiers_20241222_infirmier_3",
"start": "2024-12-22T09:00:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_colomiers_20241222",
"start": "2024-12-22T08:30:00",
"end": "2024-12-22T17:30:00",
"location": "Centre de collecte - Colomiers"
}
},
{
"id": "shift_mobile_muret_20241223_chauffeur_1",
"start": "2024-12-23T07:00:00",
"end": "2024-12-23T19:00:00",
"location": "Collecte mobile - Muret",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret"
}
},
{
"id": "shift_mobile_muret_20241223_chauffeur_2",
"start": "2024-12-23T07:00:00",
"end": "2024-12-23T19:00:00",
"location": "Collecte mobile - Muret",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret"
}
},
{
"id": "shift_mobile_muret_20241223_medecin",
"start": "2024-12-23T08:00:00",
"end": "2024-12-23T18:00:00",
"location": "Collecte mobile - Muret",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret"
}
},
{
"id": "shift_mobile_muret_20241223_infirmier_1",
"start": "2024-12-23T08:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret"
}
},
{
"id": "shift_mobile_muret_20241223_infirmier_2",
"start": "2024-12-23T08:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_mobile_muret_20241223",
"start": "2024-12-23T07:30:00",
"end": "2024-12-23T18:30:00",
"location": "Collecte mobile - Muret"
}
},
{
"id": "shift_tournefeuille_20241224_chauffeur",
"start": "2024-12-24T07:30:00",
"end": "2024-12-24T15:00:00",
"location": "Centre de collecte - Tournefeuille",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_tournefeuille_20241224",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille"
}
},
{
"id": "shift_tournefeuille_20241224_accueil",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_tournefeuille_20241224",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille"
}
},
{
"id": "shift_tournefeuille_20241224_medecin",
"start": "2024-12-24T08:15:00",
"end": "2024-12-24T13:45:00",
"location": "Centre de collecte - Tournefeuille",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_tournefeuille_20241224",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille"
}
},
{
"id": "shift_tournefeuille_20241224_infirmier",
"start": "2024-12-24T08:30:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_tournefeuille_20241224",
"start": "2024-12-24T08:00:00",
"end": "2024-12-24T14:00:00",
"location": "Centre de collecte - Tournefeuille"
}
},
{
"id": "shift_urgence_purpan_20241227_chauffeur",
"start": "2024-12-27T05:30:00",
"end": "2024-12-27T20:30:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_urgence_purpan_20241227_infirmier_3",
"start": "2024-12-27T09:00:00",
"end": "2024-12-27T16:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_urgence_purpan_20241227_infirmier_4",
"start": "2024-12-27T15:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_leguevin_20241228_chauffeur",
"start": "2024-12-28T08:00:00",
"end": "2024-12-28T17:00:00",
"location": "Centre de collecte - Léguevin",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin"
}
},
{
"id": "shift_leguevin_20241228_accueil",
"start": "2024-12-28T09:30:00",
"end": "2024-12-28T15:30:00",
"location": "Centre de collecte - Léguevin",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin"
}
},
{
"id": "shift_leguevin_20241228_medecin",
"start": "2024-12-28T09:15:00",
"end": "2024-12-28T15:45:00",
"location": "Centre de collecte - Léguevin",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin"
}
},
{
"id": "shift_leguevin_20241228_infirmier_1",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin"
}
},
{
"id": "shift_leguevin_20241228_infirmier_2",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_leguevin_20241228",
"start": "2024-12-28T09:00:00",
"end": "2024-12-28T16:00:00",
"location": "Centre de collecte - Léguevin"
}
},
{
"id": "shift_weekend_rangueil_20241229_chauffeur",
"start": "2024-12-29T09:00:00",
"end": "2024-12-29T19:00:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_weekend_rangueil_20241229_accueil",
"start": "2024-12-29T10:30:00",
"end": "2024-12-29T17:30:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_weekend_rangueil_20241229_medecin",
"start": "2024-12-29T10:15:00",
"end": "2024-12-29T17:45:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_weekend_rangueil_20241229_infirmier_1",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_weekend_rangueil_20241229_infirmier_2",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_weekend_rangueil_20241229_infirmier_3",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_weekend_rangueil_20241229",
"start": "2024-12-29T10:00:00",
"end": "2024-12-29T18:00:00",
"location": "Hôpital Rangueil - Weekend"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_chauffeur_1",
"start": "2024-12-30T07:00:00",
"end": "2024-12-30T20:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_chauffeur_2",
"start": "2024-12-30T07:00:00",
"end": "2024-12-30T20:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_medecin",
"start": "2024-12-30T08:30:00",
"end": "2024-12-30T18:30:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_infirmier_1",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_infirmier_2",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_mobile_saint_gaudens_20241230_infirmier_3",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_mobile_saint_gaudens_20241230",
"start": "2024-12-30T08:00:00",
"end": "2024-12-30T19:00:00",
"location": "Collecte mobile - Saint-Gaudens"
}
},
{
"id": "shift_reveillon_toulouse_20241231_chauffeur",
"start": "2024-12-31T13:30:00",
"end": "2024-12-31T22:30:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkill": "CHAUFFEUR",
"collecte": {
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon"
}
},
{
"id": "shift_reveillon_toulouse_20241231_accueil",
"start": "2024-12-31T14:30:00",
"end": "2024-12-31T21:30:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkill": "ACCUEIL",
"collecte": {
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon"
}
},
{
"id": "shift_reveillon_toulouse_20241231_medecin",
"start": "2024-12-31T14:15:00",
"end": "2024-12-31T21:45:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon"
}
},
{
"id": "shift_reveillon_toulouse_20241231_infirmier_1",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon"
}
},
{
"id": "shift_reveillon_toulouse_20241231_infirmier_2",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_reveillon_toulouse_20241231",
"start": "2024-12-31T14:00:00",
"end": "2024-12-31T22:00:00",
"location": "Centre de collecte - Toulouse Réveillon"
}
},
{
"id": "shift_urgence_purpan_20241227_medecin_1",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T14:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_urgence_purpan_20241227_medecin_2",
"start": "2024-12-27T12:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "MEDECIN",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_urgence_purpan_20241227_infirmier_1",
"start": "2024-12-27T06:30:00",
"end": "2024-12-27T13:30:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
},
{
"id": "shift_urgence_purpan_20241227_infirmier_2",
"start": "2024-12-27T13:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence",
"requiredSkill": "INFIRMIER",
"collecte": {
"id": "collecte_urgence_purpan_20241227",
"start": "2024-12-27T06:00:00",
"end": "2024-12-27T20:00:00",
"location": "Hôpital Purpan - Urgence"
}
}
]
}

View File

@ -108,7 +108,7 @@
<li class="nav-item" role="presentation">
<button class="nav-link active" id="byLocationTab" data-bs-toggle="tab"
data-bs-target="#byLocationPanel" type="button" role="tab">
By location
By collecte
</button>
</li>
<li class="nav-item" role="presentation">
@ -163,14 +163,14 @@
// Timefold server URL - modify this to match your server
// Option 1: Direct (nécessite CORS activé sur le serveur)
// const TIMEFOLD_SERVER = 'http://10.0.100.13:8080';
const TIMEFOLD_SERVER = 'http://10.0.100.13:8080';
// Option 2: Via proxy local (démarrez le serveur proxy sur port 3000)
// Option 2: Si vous servez depuis le serveur Timefold même
// const TIMEFOLD_SERVER = window.location.origin;
// Option 3: Via proxy local (si vous utilisez un proxy)
// const TIMEFOLD_SERVER = 'http://localhost:3000/api';
// Option 3: Si vous servez depuis le serveur Timefold
const TIMEFOLD_SERVER = window.location.origin;
// Timeline configuration
const timelineOptions = {
timeAxis: {scale: "hour", step: 6},
@ -270,7 +270,16 @@
const reader = new FileReader();
reader.onload = function(e) {
try {
const jsonData = JSON.parse(e.target.result);
const rawText = e.target.result;
// Debug: montrer les premiers caractères
console.log('Premiers caractères du fichier:', rawText.substring(0, 50));
console.log('Code du premier caractère:', rawText.charCodeAt(0));
// Nettoyer le texte (supprimer BOM et espaces invisibles)
const cleanText = rawText.trim().replace(/^\uFEFF/, '');
const jsonData = JSON.parse(cleanText);
loadedSchedule = jsonData;
// Show file info
@ -285,10 +294,26 @@
showNotification('File loaded successfully!', 'success');
} catch (error) {
showNotification('Error parsing JSON file: ' + error.message, 'danger');
console.error('Erreur détaillée:', error);
console.error('Contenu du fichier:', e.target.result.substring(0, 200));
showNotification(`Error parsing JSON file: ${error.message}`, 'danger');
// Afficher une aide pour résoudre le problème
const helpMessage = `
<div class="alert alert-warning mt-3">
<h6>Conseils pour résoudre le problème:</h6>
<ul class="mb-0">
<li>Vérifiez que le fichier commence bien par { et se termine par }</li>
<li>Sauvegardez le fichier en UTF-8 sans BOM</li>
<li>Vérifiez qu'il n'y a pas de virgules en trop</li>
<li>Testez votre JSON sur <a href="https://jsonlint.com" target="_blank">JSONLint</a></li>
</ul>
</div>
`;
$('#fileInfo').html(helpMessage).show();
}
};
reader.readAsText(file);
reader.readAsText(file, 'UTF-8');
}
function loadDemoData() {
@ -325,15 +350,49 @@
return;
}
$.post(TIMEFOLD_SERVER + '/schedules', JSON.stringify(loadedSchedule))
.done(function(data) {
scheduleId = data;
console.log('Sending data to solve:', loadedSchedule);
$.post({
url: TIMEFOLD_SERVER + '/schedules',
data: JSON.stringify(loadedSchedule),
contentType: 'application/json',
dataType: 'text' // Attendre du texte (l'ID du job)
})
.done(function(data, textStatus, xhr) {
console.log('Solve response:', data);
console.log('Response status:', xhr.status);
console.log('Response headers:', xhr.getAllResponseHeaders());
if (data && data.trim()) {
scheduleId = data.trim();
refreshSolvingButtons(true);
showNotification('Solving started...', 'info');
})
.fail(function(xhr) {
showNotification('Failed to start solving: ' + xhr.responseText, 'danger');
} else {
showNotification('Server returned empty response', 'danger');
}
})
.fail(function(xhr, textStatus, errorThrown) {
console.error('Solve failed:', {
status: xhr.status,
statusText: xhr.statusText,
responseText: xhr.responseText,
textStatus: textStatus,
errorThrown: errorThrown
});
let errorMsg = 'Failed to start solving: ';
if (xhr.status === 0) {
errorMsg += 'Cannot connect to server. Check CORS configuration.';
} else if (xhr.status === 404) {
errorMsg += 'Endpoint not found. Check server URL.';
} else if (xhr.responseText) {
errorMsg += xhr.responseText;
} else {
errorMsg += `${xhr.status} ${xhr.statusText}`;
}
showNotification(errorMsg, 'danger');
});
}
function stopSolving() {
@ -437,14 +496,32 @@
});
});
// Render locations and shifts
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
// Render collectes/shifts as groups in location view
if (schedule.collectes && schedule.shifts) {
// Create individual groups for each shift within collectes
schedule.shifts.forEach((shift, index) => {
const collecte = schedule.collectes.find(c => c.id === shift.collecte?.id);
const collecteInfo = collecte ?
`Collecte: ${collecte.id} - Requis: ${Object.entries(collecte.requiredSkills || {}).map(([skill, count]) => `${count} ${skill}`).join(', ')}` :
'Collecte inconnue';
byLocationGroupDataSet.add({
id: `shift-group-${index}`,
content: `<div><strong>${shift.location}</strong><br/>
<small>${collecteInfo}</small><br/>
<small class="text-primary">Shift ${shift.requiredSkill}</small></div>`
});
});
});
} else if (schedule.shifts) {
// Fallback for old format without collectes
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
});
});
}
// Render shifts
schedule.shifts.forEach((shift, index) => {
@ -461,17 +538,17 @@
byEmployeeItemDataSet.add({
id: `shift-${index}-emp`,
group: shift.employee.name,
content: `<div><strong>${shift.location}</strong><br/>
content: `<div><strong>${shift.collecte?.id || shift.location}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${shiftColor}`
});
// Add to location timeline
// Add to shift-specific timeline (each shift has its own group)
byLocationItemDataSet.add({
id: `shift-${index}-loc`,
group: shift.location,
group: `shift-group-${index}`,
content: `<div><strong>${shift.employee.name}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
@ -482,8 +559,8 @@
// Unassigned shift
byLocationItemDataSet.add({
id: `shift-${index}-unassigned`,
group: shift.location,
content: `<div><strong>Unassigned</strong><br/>
group: `shift-group-${index}`,
content: `<div><strong>Non assigné</strong><br/>
<span class="badge bg-secondary">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
@ -492,6 +569,51 @@
}
});
// Fallback for old format without collectes
if (!schedule.collectes && schedule.shifts) {
// Override groups for old format - use locations instead
byLocationGroupDataSet.clear();
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
});
});
// Re-render shifts with location groups for old format
schedule.shifts.forEach((shift, index) => {
const startTime = new Date(shift.start);
const endTime = new Date(shift.end);
if (shift.employee) {
const hasRequiredSkill = shift.employee.skills.includes(shift.requiredSkill);
const skillColor = hasRequiredSkill ? COLORS.SKILL_MATCH : COLORS.SKILL_MISMATCH;
const shiftColor = getShiftColor(shift, shift.employee);
byLocationItemDataSet.add({
id: `shift-${index}-loc-old`,
group: shift.location,
content: `<div><strong>${shift.employee.name}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${shiftColor}`
});
} else {
byLocationItemDataSet.add({
id: `shift-${index}-unassigned-old`,
group: shift.location,
content: `<div><strong>Non assigné</strong><br/>
<span class="badge bg-secondary">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${COLORS.UNASSIGNED}`
});
}
});
}
// Set timeline window
if (schedule.shifts.length > 0) {
const dates = schedule.shifts.map(shift => new Date(shift.start));

View File

@ -44,3 +44,8 @@ quarkus.swagger-ui.always-include=true
quarkus.log.category."ai.timefold.solver".level=DEBUG
quarkus.log.category."org.acme.employeescheduling".level=DEBUG
# quarkus.http.cors=true
# quarkus.http.cors.origins=*
# quarkus.http.cors.headers=*
# quarkus.http.cors.methods=*

File diff suppressed because one or more lines are too long

View File

@ -108,7 +108,7 @@
<li class="nav-item" role="presentation">
<button class="nav-link active" id="byLocationTab" data-bs-toggle="tab"
data-bs-target="#byLocationPanel" type="button" role="tab">
By location
By collecte
</button>
</li>
<li class="nav-item" role="presentation">
@ -163,14 +163,14 @@
// Timefold server URL - modify this to match your server
// Option 1: Direct (nécessite CORS activé sur le serveur)
// const TIMEFOLD_SERVER = 'http://10.0.100.13:8080';
const TIMEFOLD_SERVER = 'http://10.0.100.13:8080';
// Option 2: Via proxy local (démarrez le serveur proxy sur port 3000)
// Option 2: Si vous servez depuis le serveur Timefold même
// const TIMEFOLD_SERVER = window.location.origin;
// Option 3: Via proxy local (si vous utilisez un proxy)
// const TIMEFOLD_SERVER = 'http://localhost:3000/api';
// Option 3: Si vous servez depuis le serveur Timefold
const TIMEFOLD_SERVER = window.location.origin;
// Timeline configuration
const timelineOptions = {
timeAxis: {scale: "hour", step: 6},
@ -270,7 +270,16 @@
const reader = new FileReader();
reader.onload = function(e) {
try {
const jsonData = JSON.parse(e.target.result);
const rawText = e.target.result;
// Debug: montrer les premiers caractères
console.log('Premiers caractères du fichier:', rawText.substring(0, 50));
console.log('Code du premier caractère:', rawText.charCodeAt(0));
// Nettoyer le texte (supprimer BOM et espaces invisibles)
const cleanText = rawText.trim().replace(/^\uFEFF/, '');
const jsonData = JSON.parse(cleanText);
loadedSchedule = jsonData;
// Show file info
@ -285,10 +294,26 @@
showNotification('File loaded successfully!', 'success');
} catch (error) {
showNotification('Error parsing JSON file: ' + error.message, 'danger');
console.error('Erreur détaillée:', error);
console.error('Contenu du fichier:', e.target.result.substring(0, 200));
showNotification(`Error parsing JSON file: ${error.message}`, 'danger');
// Afficher une aide pour résoudre le problème
const helpMessage = `
<div class="alert alert-warning mt-3">
<h6>Conseils pour résoudre le problème:</h6>
<ul class="mb-0">
<li>Vérifiez que le fichier commence bien par { et se termine par }</li>
<li>Sauvegardez le fichier en UTF-8 sans BOM</li>
<li>Vérifiez qu'il n'y a pas de virgules en trop</li>
<li>Testez votre JSON sur <a href="https://jsonlint.com" target="_blank">JSONLint</a></li>
</ul>
</div>
`;
$('#fileInfo').html(helpMessage).show();
}
};
reader.readAsText(file);
reader.readAsText(file, 'UTF-8');
}
function loadDemoData() {
@ -325,15 +350,49 @@
return;
}
$.post(TIMEFOLD_SERVER + '/schedules', JSON.stringify(loadedSchedule))
.done(function(data) {
scheduleId = data;
console.log('Sending data to solve:', loadedSchedule);
$.post({
url: TIMEFOLD_SERVER + '/schedules',
data: JSON.stringify(loadedSchedule),
contentType: 'application/json',
dataType: 'text' // Attendre du texte (l'ID du job)
})
.done(function(data, textStatus, xhr) {
console.log('Solve response:', data);
console.log('Response status:', xhr.status);
console.log('Response headers:', xhr.getAllResponseHeaders());
if (data && data.trim()) {
scheduleId = data.trim();
refreshSolvingButtons(true);
showNotification('Solving started...', 'info');
})
.fail(function(xhr) {
showNotification('Failed to start solving: ' + xhr.responseText, 'danger');
} else {
showNotification('Server returned empty response', 'danger');
}
})
.fail(function(xhr, textStatus, errorThrown) {
console.error('Solve failed:', {
status: xhr.status,
statusText: xhr.statusText,
responseText: xhr.responseText,
textStatus: textStatus,
errorThrown: errorThrown
});
let errorMsg = 'Failed to start solving: ';
if (xhr.status === 0) {
errorMsg += 'Cannot connect to server. Check CORS configuration.';
} else if (xhr.status === 404) {
errorMsg += 'Endpoint not found. Check server URL.';
} else if (xhr.responseText) {
errorMsg += xhr.responseText;
} else {
errorMsg += `${xhr.status} ${xhr.statusText}`;
}
showNotification(errorMsg, 'danger');
});
}
function stopSolving() {
@ -437,14 +496,32 @@
});
});
// Render locations and shifts
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
// Render collectes/shifts as groups in location view
if (schedule.collectes && schedule.shifts) {
// Create individual groups for each shift within collectes
schedule.shifts.forEach((shift, index) => {
const collecte = schedule.collectes.find(c => c.id === shift.collecte?.id);
const collecteInfo = collecte ?
`Collecte: ${collecte.id} - Requis: ${Object.entries(collecte.requiredSkills || {}).map(([skill, count]) => `${count} ${skill}`).join(', ')}` :
'Collecte inconnue';
byLocationGroupDataSet.add({
id: `shift-group-${index}`,
content: `<div><strong>${shift.location}</strong><br/>
<small>${collecteInfo}</small><br/>
<small class="text-primary">Shift ${shift.requiredSkill}</small></div>`
});
});
});
} else if (schedule.shifts) {
// Fallback for old format without collectes
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
});
});
}
// Render shifts
schedule.shifts.forEach((shift, index) => {
@ -461,17 +538,17 @@
byEmployeeItemDataSet.add({
id: `shift-${index}-emp`,
group: shift.employee.name,
content: `<div><strong>${shift.location}</strong><br/>
content: `<div><strong>${shift.collecte?.id || shift.location}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${shiftColor}`
});
// Add to location timeline
// Add to shift-specific timeline (each shift has its own group)
byLocationItemDataSet.add({
id: `shift-${index}-loc`,
group: shift.location,
group: `shift-group-${index}`,
content: `<div><strong>${shift.employee.name}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
@ -482,8 +559,8 @@
// Unassigned shift
byLocationItemDataSet.add({
id: `shift-${index}-unassigned`,
group: shift.location,
content: `<div><strong>Unassigned</strong><br/>
group: `shift-group-${index}`,
content: `<div><strong>Non assigné</strong><br/>
<span class="badge bg-secondary">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
@ -492,6 +569,51 @@
}
});
// Fallback for old format without collectes
if (!schedule.collectes && schedule.shifts) {
// Override groups for old format - use locations instead
byLocationGroupDataSet.clear();
const locations = [...new Set(schedule.shifts.map(shift => shift.location))];
locations.forEach(location => {
byLocationGroupDataSet.add({
id: location,
content: location
});
});
// Re-render shifts with location groups for old format
schedule.shifts.forEach((shift, index) => {
const startTime = new Date(shift.start);
const endTime = new Date(shift.end);
if (shift.employee) {
const hasRequiredSkill = shift.employee.skills.includes(shift.requiredSkill);
const skillColor = hasRequiredSkill ? COLORS.SKILL_MATCH : COLORS.SKILL_MISMATCH;
const shiftColor = getShiftColor(shift, shift.employee);
byLocationItemDataSet.add({
id: `shift-${index}-loc-old`,
group: shift.location,
content: `<div><strong>${shift.employee.name}</strong><br/>
<span class="badge" style="background-color:${skillColor}">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${shiftColor}`
});
} else {
byLocationItemDataSet.add({
id: `shift-${index}-unassigned-old`,
group: shift.location,
content: `<div><strong>Non assigné</strong><br/>
<span class="badge bg-secondary">${shift.requiredSkill}</span></div>`,
start: startTime,
end: endTime,
style: `background-color: ${COLORS.UNASSIGNED}`
});
}
});
}
// Set timeline window
if (schedule.shifts.length > 0) {
const dates = schedule.shifts.map(shift => new Date(shift.start));

View File

@ -44,3 +44,8 @@ quarkus.swagger-ui.always-include=true
quarkus.log.category."ai.timefold.solver".level=DEBUG
quarkus.log.category."org.acme.employeescheduling".level=DEBUG
# quarkus.http.cors=true
# quarkus.http.cors.origins=*
# quarkus.http.cors.headers=*
# quarkus.http.cors.methods=*

Binary file not shown.