Web UI Ok
This commit is contained in:
parent
9be454ca81
commit
9fab9f83ef
932
claude2.json
Normal file
932
claude2.json
Normal 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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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));
|
||||
@ -609,4 +731,4 @@
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -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
@ -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));
|
||||
@ -609,4 +731,4 @@
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -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.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user