static planning

This commit is contained in:
Bastien COIGNOUX
2025-07-14 17:44:07 +02:00
parent 62c6bb5fa5
commit 9fad10e7b7
3 changed files with 177 additions and 0 deletions

View 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.');

View 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}