static planning
This commit is contained in:
4
ressources.csv
Normal file
4
ressources.csv
Normal file
@ -0,0 +1,4 @@
|
||||
ressource,profil,7/14/2025,7/15/2025,7/16/2025,7/17/2025,7/18/2025,7/19/2025,7/20/2025,7/21/2025,7/22/2025
|
||||
Simon BOYER,dev,0,0.5,0.5,0.5,0.5,0,0.5,0.5,0.5
|
||||
Fatima BROUM,dev,0,1,1,1,1,0,1,1,1
|
||||
Need Dev,dev,0,0,0,0,0,0,1,1,1
|
||||
|
46
svar-gantt-app/scripts/init-db.js
Normal file
46
svar-gantt-app/scripts/init-db.js
Normal file
@ -0,0 +1,46 @@
|
||||
// scripts/init-db.ts
|
||||
import Database from 'better-sqlite3';
|
||||
import { mkdirSync, existsSync } from 'fs';
|
||||
|
||||
if (!existsSync('data')) {
|
||||
mkdirSync('data');
|
||||
}
|
||||
|
||||
const db = new Database('data.db');
|
||||
|
||||
db.exec(`
|
||||
DROP TABLE IF EXISTS tasks;
|
||||
DROP TABLE IF EXISTS links;
|
||||
|
||||
CREATE TABLE tasks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
text TEXT NOT NULL,
|
||||
start TEXT NOT NULL,
|
||||
end TEXT NOT NULL,
|
||||
duration INTEGER,
|
||||
progress INTEGER,
|
||||
type TEXT,
|
||||
parent INTEGER,
|
||||
lazy BOOLEAN DEFAULT 0 -- ✅ Ajout ici
|
||||
);
|
||||
|
||||
CREATE TABLE links (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
source INTEGER,
|
||||
target INTEGER,
|
||||
type TEXT
|
||||
);
|
||||
`);
|
||||
// table pour les ressources
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS resource_planning (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ressource TEXT NOT NULL,
|
||||
profil TEXT NOT NULL,
|
||||
date TEXT NOT NULL,
|
||||
disponibilite REAL NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
|
||||
console.log('✅ Base de données initialisée avec succès.');
|
||||
127
svar-gantt-app/src/routes/planning/+page.svelte
Normal file
127
svar-gantt-app/src/routes/planning/+page.svelte
Normal file
@ -0,0 +1,127 @@
|
||||
<script lang="ts">
|
||||
import Papa from 'papaparse';
|
||||
import { writable, get } from 'svelte/store';
|
||||
|
||||
const planning = writable<any[]>([]);
|
||||
const dates = writable<string[]>([]);
|
||||
|
||||
let file: File | null = null;
|
||||
|
||||
const joursFeries = [
|
||||
'2025-01-01', '2025-04-21', '2025-05-01', '2025-05-08', '2025-05-29',
|
||||
'2025-07-14', '2025-08-15', '2025-11-01', '2025-11-11', '2025-12-25'
|
||||
];
|
||||
|
||||
function isWeekend(date: string) {
|
||||
const d = new Date(date);
|
||||
return d.getDay() === 0 || d.getDay() === 6;
|
||||
}
|
||||
|
||||
function isJourFerie(date: string) {
|
||||
return joursFeries.includes(date);
|
||||
}
|
||||
|
||||
function formatDateFr(dateStr: string) {
|
||||
const d = new Date(dateStr);
|
||||
return d.toLocaleDateString('fr-FR', {
|
||||
weekday: 'short',
|
||||
day: '2-digit',
|
||||
month: 'short'
|
||||
});
|
||||
}
|
||||
|
||||
function handleFileUpload() {
|
||||
if (!file) return;
|
||||
|
||||
Papa.parse(file, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
complete: (result) => {
|
||||
const rows = result.data as any[];
|
||||
|
||||
const colonnesDates = Object.keys(rows[0]).filter(k => /^\d/.test(k));
|
||||
dates.set(colonnesDates);
|
||||
|
||||
planning.set(rows.map(row => ({
|
||||
ressource: row.ressource,
|
||||
profil: row.profil,
|
||||
disponibilites: colonnesDates.reduce((acc, date) => {
|
||||
acc[date] = parseFloat(row[date] || 0);
|
||||
return acc;
|
||||
}, {} as Record<string, number>)
|
||||
})));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateCell(rowIndex: number, date: string, value: string) {
|
||||
const val = parseFloat(value);
|
||||
if (![0, 0.5, 1].includes(val)) return;
|
||||
|
||||
planning.update(current => {
|
||||
current[rowIndex].disponibilites[date] = val;
|
||||
return current;
|
||||
});
|
||||
}
|
||||
|
||||
function totalByDate(date: string) {
|
||||
const rows = get(planning);
|
||||
return rows.reduce((sum, r) => sum + (r.disponibilites[date] || 0), 0);
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1 class="text-xl font-bold mb-4">📅 Planning Ressources</h1>
|
||||
|
||||
<input type="file" accept=".csv" on:change={(e) => file = e.target.files?.[0]} />
|
||||
<button on:click={handleFileUpload} class="ml-2 bg-blue-600 text-white px-3 py-1 rounded">Charger</button>
|
||||
|
||||
{#if $planning.length > 0}
|
||||
<table class="mt-6 border-collapse border w-full text-sm text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border px-2 py-1 bg-white text-left">Ressource</th>
|
||||
<th class="border px-2 py-1 bg-white text-left">Profil</th>
|
||||
{#each $dates as date}
|
||||
<th
|
||||
class="border px-2 py-1"
|
||||
class:bg-red-100={isJourFerie(date)}
|
||||
class:bg-gray-100={!isJourFerie(date) && isWeekend(date)}
|
||||
>
|
||||
{formatDateFr(date)}
|
||||
</th>
|
||||
{/each}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each $planning as row, i}
|
||||
<tr>
|
||||
<td class="border px-2 py-1 text-left">{row.ressource}</td>
|
||||
<td class="border px-2 py-1 text-left">{row.profil}</td>
|
||||
{#each $dates as date}
|
||||
<td class="border p-0">
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.5"
|
||||
value={row.disponibilites[date]}
|
||||
class="w-full text-center py-1 bg-transparent"
|
||||
on:change={(e) => updateCell(i, date, e.target.value)}
|
||||
/>
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class="border font-semibold text-right px-2 py-1" colspan="2">Total</td>
|
||||
{#each $dates as date}
|
||||
<td class="border px-2 py-1 font-semibold">
|
||||
{totalByDate(date)}
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user