diallo76 commited on
Commit
11d4fe2
·
verified ·
1 Parent(s): 3217770

créer un formulaire de saisie un imprimerie dans excel, userform contient 8 champs id du produit, nom du produits,prix du produit,quantite,date et mois,type: entre et sorties, stock, et listView avec entête et quadrillage et avec 5 boutons , ajouter,modifier,rechercher,supprimer,imprimer avec boite de saisie, nom de la feuille base de données, afficher les donnees dans listview en temp reel. et un rapport par semaine , mois et annee et benefice et total de vente.

Browse files
Files changed (2) hide show
  1. README.md +6 -3
  2. index.html +474 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Printpro Manager
3
- emoji: 📊
4
  colorFrom: purple
5
  colorTo: pink
 
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: PrintPro Manager 🖨️
 
3
  colorFrom: purple
4
  colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,475 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>PrintPro Manager</title>
7
+ <link rel="icon" type="image/x-icon" href="/static/favicon.ico">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://unpkg.com/feather-icons"></script>
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
13
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.25/jspdf.plugin.autotable.min.js"></script>
14
+ <style>
15
+ .fade-in {
16
+ animation: fadeIn 0.5s;
17
+ }
18
+ @keyframes fadeIn {
19
+ from { opacity: 0; transform: translateY(10px); }
20
+ to { opacity: 1; transform: translateY(0); }
21
+ }
22
+ .hover-card:hover {
23
+ transform: translateY(-5px);
24
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
25
+ }
26
+ .btn-primary {
27
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
+ }
29
+ .btn-secondary {
30
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
31
+ }
32
+ </style>
33
+ </head>
34
+ <body class="bg-gray-100 min-h-screen">
35
+ <div class="container mx-auto px-4 py-8">
36
+ <!-- Header -->
37
+ <header class="mb-10 text-center">
38
+ <h1 class="text-4xl font-bold text-gray-800 mb-2">PrintPro Manager 🖨️</h1>
39
+ <p class="text-gray-600">Gestion d'imprimerie professionnelle</p>
40
+ </header>
41
+
42
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
43
+ <!-- Formulaire -->
44
+ <div class="lg:col-span-1">
45
+ <div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
46
+ <h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
47
+ <i data-feather="edit-3" class="mr-2"></i>Formulaire Produit
48
+ </h2>
49
+
50
+ <form id="productForm" class="space-y-4">
51
+ <div>
52
+ <label class="block text-sm font-medium text-gray-700 mb-1">ID Produit</label>
53
+ <input type="text" id="productId" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
54
+ </div>
55
+
56
+ <div>
57
+ <label class="block text-sm font-medium text-gray-700 mb-1">Nom du Produit</label>
58
+ <input type="text" id="productName" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
59
+ </div>
60
+
61
+ <div>
62
+ <label class="block text-sm font-medium text-gray-700 mb-1">Prix (€)</label>
63
+ <input type="number" step="0.01" id="productPrice" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
64
+ </div>
65
+
66
+ <div>
67
+ <label class="block text-sm font-medium text-gray-700 mb-1">Quantité</label>
68
+ <input type="number" id="productQuantity" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
69
+ </div>
70
+
71
+ <div>
72
+ <label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
73
+ <input type="date" id="productDate" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
74
+ </div>
75
+
76
+ <div>
77
+ <label class="block text-sm font-medium text-gray-700 mb-1">Mois</label>
78
+ <select id="productMonth" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
79
+ <option value="">Sélectionner un mois</option>
80
+ <option value="Janvier">Janvier</option>
81
+ <option value="Février">Février</option>
82
+ <option value="Mars">Mars</option>
83
+ <option value="Avril">Avril</option>
84
+ <option value="Mai">Mai</option>
85
+ <option value="Juin">Juin</option>
86
+ <option value="Juillet">Juillet</option>
87
+ <option value="Août">Août</option>
88
+ <option value="Septembre">Septembre</option>
89
+ <option value="Octobre">Octobre</option>
90
+ <option value="Novembre">Novembre</option>
91
+ <option value="Décembre">Décembre</option>
92
+ </select>
93
+ </div>
94
+
95
+ <div>
96
+ <label class="block text-sm font-medium text-gray-700 mb-1">Type</label>
97
+ <select id="productType" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
98
+ <option value="">Sélectionner un type</option>
99
+ <option value="Entrée">Entrée</option>
100
+ <option value="Sortie">Sortie</option>
101
+ </select>
102
+ </div>
103
+
104
+ <div>
105
+ <label class="block text-sm font-medium text-gray-700 mb-1">Stock</label>
106
+ <input type="number" id="productStock" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" required>
107
+ </div>
108
+
109
+ <div class="flex space-x-3 pt-4">
110
+ <button type="submit" class="btn-primary text-white px-4 py-2 rounded-lg flex-1 flex items-center justify-center">
111
+ <i data-feather="plus-circle" class="mr-2"></i>Ajouter
112
+ </button>
113
+ <button type="button" id="clearBtn" class="bg-gray-500 text-white px-4 py-2 rounded-lg flex items-center">
114
+ <i data-feather="refresh-cw" class="mr-2"></i>Effacer
115
+ </button>
116
+ </div>
117
+ </form>
118
+ </div>
119
+
120
+ <!-- Rapport -->
121
+ <div class="bg-white rounded-xl shadow-lg p-6 mt-8 hover-card transition-all duration-300 fade-in">
122
+ <h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
123
+ <i data-feather="bar-chart-2" class="mr-2"></i>Rapport
124
+ </h2>
125
+
126
+ <div class="grid grid-cols-2 gap-4">
127
+ <div class="bg-blue-50 p-4 rounded-lg">
128
+ <p class="text-sm text-gray-600">Ventes hebdomadaires</p>
129
+ <p class="text-2xl font-bold text-blue-600" id="weeklySales">0 €</p>
130
+ </div>
131
+ <div class="bg-green-50 p-4 rounded-lg">
132
+ <p class="text-sm text-gray-600">Ventes mensuelles</p>
133
+ <p class="text-2xl font-bold text-green-600" id="monthlySales">0 €</p>
134
+ </div>
135
+ <div class="bg-purple-50 p-4 rounded-lg">
136
+ <p class="text-sm text-gray-600">Ventes annuelles</p>
137
+ <p class="text-2xl font-bold text-purple-600" id="yearlySales">0 €</p>
138
+ </div>
139
+ <div class="bg-yellow-50 p-4 rounded-lg">
140
+ <p class="text-sm text-gray-600">Bénéfice total</p>
141
+ <p class="text-2xl font-bold text-yellow-600" id="totalProfit">0 €</p>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+
147
+ <!-- Liste des produits -->
148
+ <div class="lg:col-span-2">
149
+ <div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
150
+ <div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
151
+ <h2 class="text-2xl font-bold text-gray-800 flex items-center">
152
+ <i data-feather="database" class="mr-2"></i>Liste des Produits
153
+ </h2>
154
+
155
+ <div class="mt-4 md:mt-0 flex space-x-3">
156
+ <div class="relative">
157
+ <input type="text" id="searchInput" placeholder="Rechercher..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent">
158
+ <i data-feather="search" class="absolute left-3 top-2.5 text-gray-400"></i>
159
+ </div>
160
+
161
+ <button id="printBtn" class="btn-secondary text-white px-4 py-2 rounded-lg flex items-center">
162
+ <i data-feather="printer" class="mr-2"></i>Imprimer
163
+ </button>
164
+ </div>
165
+ </div>
166
+
167
+ <div class="overflow-x-auto">
168
+ <table class="min-w-full divide-y divide-gray-200">
169
+ <thead class="bg-gray-50">
170
+ <tr>
171
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
172
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Produit</th>
173
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Prix</th>
174
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantité</th>
175
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
176
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
177
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Stock</th>
178
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
179
+ </tr>
180
+ </thead>
181
+ <tbody id="productList" class="bg-white divide-y divide-gray-200">
182
+ <!-- Les données seront insérées ici dynamiquement -->
183
+ </tbody>
184
+ </table>
185
+ </div>
186
+
187
+ <div class="mt-6 flex flex-wrap gap-2">
188
+ <button id="modifyBtn" class="bg-blue-500 text-white px-4 py-2 rounded-lg flex items-center">
189
+ <i data-feather="edit" class="mr-2"></i>Modifier
190
+ </button>
191
+ <button id="deleteBtn" class="bg-red-500 text-white px-4 py-2 rounded-lg flex items-center">
192
+ <i data-feather="trash-2" class="mr-2"></i>Supprimer
193
+ </button>
194
+ <button id="exportExcelBtn" class="bg-green-500 text-white px-4 py-2 rounded-lg flex items-center">
195
+ <i data-feather="file-text" class="mr-2"></i>Exporter Excel
196
+ </button>
197
+ </div>
198
+ </div>
199
+ </div>
200
+ </div>
201
+ </div>
202
+
203
+ <script>
204
+ // Données en mémoire
205
+ let products = JSON.parse(localStorage.getItem('products')) || [];
206
+ let currentEditId = null;
207
+
208
+ // Initialisation
209
+ document.addEventListener('DOMContentLoaded', function() {
210
+ feather.replace();
211
+ renderProductList();
212
+ updateReports();
213
+
214
+ // Gestion des événements
215
+ document.getElementById('productForm').addEventListener('submit', handleFormSubmit);
216
+ document.getElementById('clearBtn').addEventListener('click', clearForm);
217
+ document.getElementById('printBtn').addEventListener('click', printData);
218
+ document.getElementById('modifyBtn').addEventListener('click', modifySelected);
219
+ document.getElementById('deleteBtn').addEventListener('click', deleteSelected);
220
+ document.getElementById('exportExcelBtn').addEventListener('click', exportToExcel);
221
+ document.getElementById('searchInput').addEventListener('input', filterProducts);
222
+ });
223
+
224
+ // Gestion de la soumission du formulaire
225
+ function handleFormSubmit(e) {
226
+ e.preventDefault();
227
+
228
+ const product = {
229
+ id: document.getElementById('productId').value,
230
+ name: document.getElementById('productName').value,
231
+ price: parseFloat(document.getElementById('productPrice').value),
232
+ quantity: parseInt(document.getElementById('productQuantity').value),
233
+ date: document.getElementById('productDate').value,
234
+ month: document.getElementById('productMonth').value,
235
+ type: document.getElementById('productType').value,
236
+ stock: parseInt(document.getElementById('productStock').value)
237
+ };
238
+
239
+ if (currentEditId !== null) {
240
+ // Modification
241
+ products[currentEditId] = product;
242
+ currentEditId = null;
243
+ showNotification('Produit modifié avec succès!', 'success');
244
+ } else {
245
+ // Ajout
246
+ products.push(product);
247
+ showNotification('Produit ajouté avec succès!', 'success');
248
+ }
249
+
250
+ saveToLocalStorage();
251
+ renderProductList();
252
+ updateReports();
253
+ clearForm();
254
+ }
255
+
256
+ // Effacer le formulaire
257
+ function clearForm() {
258
+ document.getElementById('productForm').reset();
259
+ currentEditId = null;
260
+ }
261
+
262
+ // Afficher la liste des produits
263
+ function renderProductList(filteredProducts = null) {
264
+ const productList = document.getElementById('productList');
265
+ const dataToShow = filteredProducts || products;
266
+
267
+ if (dataToShow.length === 0) {
268
+ productList.innerHTML = `
269
+ <tr>
270
+ <td colspan="8" class="px-6 py-4 text-center text-gray-500">
271
+ Aucun produit trouvé
272
+ </td>
273
+ </tr>
274
+ `;
275
+ return;
276
+ }
277
+
278
+ productList.innerHTML = dataToShow.map((product, index) => `
279
+ <tr class="hover:bg-gray-50" data-index="${index}">
280
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.id}</td>
281
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.name}</td>
282
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.price.toFixed(2)} €</td>
283
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.quantity}</td>
284
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.date}</td>
285
+ <td class="px-6 py-4 whitespace-nowrap">
286
+ <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
287
+ ${product.type === 'Entrée' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">
288
+ ${product.type}
289
+ </span>
290
+ </td>
291
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.stock}</td>
292
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
293
+ <button onclick="editProduct(${index})" class="text-blue-600 hover:text-blue-900 mr-3">
294
+ <i data-feather="edit-2"></i>
295
+ </button>
296
+ <button onclick="deleteProduct(${index})" class="text-red-600 hover:text-red-900">
297
+ <i data-feather="trash-2"></i>
298
+ </button>
299
+ </td>
300
+ </tr>
301
+ `).join('');
302
+
303
+ feather.replace();
304
+ }
305
+
306
+ // Modifier un produit
307
+ function editProduct(index) {
308
+ const product = products[index];
309
+ document.getElementById('productId').value = product.id;
310
+ document.getElementById('productName').value = product.name;
311
+ document.getElementById('productPrice').value = product.price;
312
+ document.getElementById('productQuantity').value = product.quantity;
313
+ document.getElementById('productDate').value = product.date;
314
+ document.getElementById('productMonth').value = product.month;
315
+ document.getElementById('productType').value = product.type;
316
+ document.getElementById('productStock').value = product.stock;
317
+
318
+ currentEditId = index;
319
+ window.scrollTo({ top: 0, behavior: 'smooth' });
320
+ }
321
+
322
+ // Supprimer un produit
323
+ function deleteProduct(index) {
324
+ if (confirm('Êtes-vous sûr de vouloir supprimer ce produit?')) {
325
+ products.splice(index, 1);
326
+ saveToLocalStorage();
327
+ renderProductList();
328
+ updateReports();
329
+ showNotification('Produit supprimé avec succès!', 'success');
330
+ }
331
+ }
332
+
333
+ // Modifier les éléments sélectionnés
334
+ function modifySelected() {
335
+ const selectedRow = document.querySelector('#productList tr.bg-blue-50');
336
+ if (selectedRow) {
337
+ const index = selectedRow.getAttribute('data-index');
338
+ editProduct(parseInt(index));
339
+ } else {
340
+ showNotification('Veuillez sélectionner un produit à modifier', 'warning');
341
+ }
342
+ }
343
+
344
+ // Supprimer les éléments sélectionnés
345
+ function deleteSelected() {
346
+ const selectedRows = document.querySelectorAll('#productList tr.bg-blue-50');
347
+ if (selectedRows.length > 0) {
348
+ if (confirm(`Êtes-vous sûr de vouloir supprimer ${selectedRows.length} produit(s)?`)) {
349
+ // Supprimer dans l'ordre inverse pour éviter les problèmes d'index
350
+ const indices = Array.from(selectedRows).map(row => parseInt(row.getAttribute('data-index')));
351
+ indices.sort((a, b) => b - a);
352
+ indices.forEach(index => products.splice(index, 1));
353
+
354
+ saveToLocalStorage();
355
+ renderProductList();
356
+ updateReports();
357
+ showNotification(`${indices.length} produit(s) supprimé(s) avec succès!`, 'success');
358
+ }
359
+ } else {
360
+ showNotification('Veuillez sélectionner au moins un produit à supprimer', 'warning');
361
+ }
362
+ }
363
+
364
+ // Filtrer les produits
365
+ function filterProducts() {
366
+ const searchTerm = document.getElementById('searchInput').value.toLowerCase();
367
+ const filtered = products.filter(product =>
368
+ product.id.toLowerCase().includes(searchTerm) ||
369
+ product.name.toLowerCase().includes(searchTerm) ||
370
+ product.month.toLowerCase().includes(searchTerm) ||
371
+ product.type.toLowerCase().includes(searchTerm)
372
+ );
373
+ renderProductList(filtered);
374
+ }
375
+
376
+ // Mettre à jour les rapports
377
+ function updateReports() {
378
+ // Calculer les ventes hebdomadaires (7 derniers jours)
379
+ const weeklySales = calculateSalesForPeriod(7);
380
+ document.getElementById('weeklySales').textContent = `${weeklySales.toFixed(2)} €`;
381
+
382
+ // Calculer les ventes mensuelles (30 derniers jours)
383
+ const monthlySales = calculateSalesForPeriod(30);
384
+ document.getElementById('monthlySales').textContent = `${monthlySales.toFixed(2)} €`;
385
+
386
+ // Calculer les ventes annuelles (365 derniers jours)
387
+ const yearlySales = calculateSalesForPeriod(365);
388
+ document.getElementById('yearlySales').textContent = `${yearlySales.toFixed(2)} €`;
389
+
390
+ // Calculer le bénéfice total
391
+ const totalProfit = products.reduce((sum, product) => sum + (product.price * product.quantity), 0);
392
+ document.getElementById('totalProfit').textContent = `${totalProfit.toFixed(2)} €`;
393
+ }
394
+
395
+ // Calculer les ventes pour une période donnée
396
+ function calculateSalesForPeriod(days) {
397
+ const now = new Date();
398
+ const startDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
399
+
400
+ return products
401
+ .filter(product => {
402
+ const productDate = new Date(product.date);
403
+ return productDate >= startDate && productDate <= now;
404
+ })
405
+ .reduce((sum, product) => sum + (product.price * product.quantity), 0);
406
+ }
407
+
408
+ // Imprimer les données
409
+ function printData() {
410
+ window.print();
411
+ }
412
+
413
+ // Exporter vers Excel
414
+ function exportToExcel() {
415
+ const ws = XLSX.utils.json_to_sheet(products.map(p => ({
416
+ 'ID': p.id,
417
+ 'Nom': p.name,
418
+ 'Prix': p.price,
419
+ 'Quantité': p.quantity,
420
+ 'Date': p.date,
421
+ 'Mois': p.month,
422
+ 'Type': p.type,
423
+ 'Stock': p.stock
424
+ })));
425
+
426
+ const wb = XLSX.utils.book_new();
427
+ XLSX.utils.book_append_sheet(wb, ws, "Base de données");
428
+ XLSX.writeFile(wb, "base_donnees_imprimerie.xlsx");
429
+ }
430
+
431
+ // Sauvegarder dans localStorage
432
+ function saveToLocalStorage() {
433
+ localStorage.setItem('products', JSON.stringify(products));
434
+ }
435
+
436
+ // Afficher une notification
437
+ function showNotification(message, type) {
438
+ // Création de l'élément de notification
439
+ const notification = document.createElement('div');
440
+ notification.className = `fixed top-4 right-4 px-6 py-4 rounded-lg shadow-lg text-white z-50 ${
441
+ type === 'success' ? 'bg-green-500' :
442
+ type === 'warning' ? 'bg-yellow-500' : 'bg-red-500'
443
+ }`;
444
+ notification.textContent = message;
445
+
446
+ document.body.appendChild(notification);
447
+
448
+ // Animation d'apparition
449
+ setTimeout(() => {
450
+ notification.style.transition = 'opacity 0.5s';
451
+ notification.style.opacity = '0';
452
+
453
+ // Suppression après l'animation
454
+ setTimeout(() => {
455
+ document.body.removeChild(notification);
456
+ }, 500);
457
+ }, 3000);
458
+ }
459
+
460
+ // Sélectionner une ligne
461
+ document.addEventListener('click', function(e) {
462
+ const row = e.target.closest('#productList tr');
463
+ if (row) {
464
+ // Désélectionner les autres lignes
465
+ document.querySelectorAll('#productList tr').forEach(r => {
466
+ r.classList.remove('bg-blue-50');
467
+ });
468
+
469
+ // Sélectionner la ligne cliquée
470
+ row.classList.add('bg-blue-50');
471
+ }
472
+ });
473
+ </script>
474
+ </body>
475
  </html>