printpro-manager / reports.html
diallo76's picture
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. devise en franc guineen pour tout rapport
359a921 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rapports - PrintPro Manager</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
<style>
.fade-in {
animation: fadeIn 0.5s;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.hover-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.btn-secondary {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-10 text-center">
<h1 class="text-4xl font-bold text-gray-800 mb-2">Rapports 📊</h1>
<p class="text-gray-600">Analyse des ventes et performances</p>
<div class="mt-4 flex justify-center space-x-4">
<button onclick="window.location.href='index.html'" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Accueil
</button>
<button onclick="window.location.href='products.html'" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded">
Gestion des Produits
</button>
<button onclick="window.location.href='reports.html'" class="bg-purple-500 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded">
Rapports
</button>
</div>
</header>
<!-- Statistiques -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<div class="flex items-center">
<div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4">
<i data-feather="calendar" class="w-6 h-6"></i>
</div>
<div>
<p class="text-sm text-gray-600">Ventes hebdomadaires</p>
<p class="text-2xl font-bold text-blue-600" id="weeklySales">0 GNF</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<div class="flex items-center">
<div class="p-3 rounded-full bg-green-100 text-green-600 mr-4">
<i data-feather="calendar" class="w-6 h-6"></i>
</div>
<div>
<p class="text-sm text-gray-600">Ventes mensuelles</p>
<p class="text-2xl font-bold text-green-600" id="monthlySales">0 GNF</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<div class="flex items-center">
<div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4">
<i data-feather="calendar" class="w-6 h-6"></i>
</div>
<div>
<p class="text-sm text-gray-600">Ventes annuelles</p>
<p class="text-2xl font-bold text-purple-600" id="yearlySales">0 GNF</p>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<div class="flex items-center">
<div class="p-3 rounded-full bg-yellow-100 text-yellow-600 mr-4">
<i data-feather="trending-up" class="w-6 h-6"></i>
</div>
<div>
<p class="text-sm text-gray-600">Bénéfice total</p>
<p class="text-2xl font-bold text-yellow-600" id="totalProfit">0 GNF</p>
</div>
</div>
</div>
</div>
<!-- Graphiques -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<h2 class="text-xl font-bold text-gray-800 mb-4">Ventes par Mois</h2>
<canvas id="monthlyChart" height="300"></canvas>
</div>
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<h2 class="text-xl font-bold text-gray-800 mb-4">Types de Transactions</h2>
<canvas id="typeChart" height="300"></canvas>
</div>
</div>
<!-- Liste des produits -->
<div class="bg-white rounded-xl shadow-lg p-6 hover-card transition-all duration-300 fade-in">
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
<i data-feather="database" class="mr-2"></i>Liste des Produits
</h2>
<div class="mt-4 md:mt-0 flex space-x-3">
<div class="relative">
<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">
<i data-feather="search" class="absolute left-3 top-2.5 text-gray-400"></i>
</div>
<button id="printBtn" class="btn-secondary text-white px-4 py-2 rounded-lg flex items-center">
<i data-feather="printer" class="mr-2"></i>Imprimer
</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Produit</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Prix</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantité</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mois</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Stock</th>
</tr>
</thead>
<tbody id="productList" class="bg-white divide-y divide-gray-200">
<!-- Les données seront insérées ici dynamiquement -->
</tbody>
</table>
</div>
</div>
</div>
<script>
// Données en mémoire
let products = JSON.parse(localStorage.getItem('products')) || [];
// Initialisation
document.addEventListener('DOMContentLoaded', function() {
feather.replace();
updateReports();
renderProductList();
document.getElementById('searchInput').addEventListener('input', filterProducts);
document.getElementById('printBtn').addEventListener('click', printData);
});
// Mettre à jour les rapports
function updateReports() {
// Calculer les ventes hebdomadaires (7 derniers jours)
const weeklySales = calculateSalesForPeriod(7);
document.getElementById('weeklySales').textContent = `${Math.round(weeklySales)} GNF`;
// Calculer les ventes mensuelles (30 derniers jours)
const monthlySales = calculateSalesForPeriod(30);
document.getElementById('monthlySales').textContent = `${Math.round(monthlySales)} GNF`;
// Calculer les ventes annuelles (365 derniers jours)
const yearlySales = calculateSalesForPeriod(365);
document.getElementById('yearlySales').textContent = `${Math.round(yearlySales)} GNF`;
// Calculer le bénéfice total
const totalProfit = products.reduce((sum, product) => sum + (Math.round(product.price) * product.quantity), 0);
document.getElementById('totalProfit').textContent = `${Math.round(totalProfit)} GNF`;
// Mettre à jour les graphiques
updateCharts();
}
// Calculer les ventes pour une période donnée
function calculateSalesForPeriod(days) {
const now = new Date();
const startDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
return products
.filter(product => {
const productDate = new Date(product.date);
return productDate >= startDate && productDate <= now;
})
.reduce((sum, product) => sum + (Math.round(product.price) * product.quantity), 0);
}
// Mettre à jour les graphiques
function updateCharts() {
// Graphique des ventes par mois
const monthlyData = getMonthlySalesData();
const monthlyCtx = document.getElementById('monthlyChart').getContext('2d');
new Chart(monthlyCtx, {
type: 'bar',
data: {
labels: monthlyData.labels,
datasets: [{
label: 'Ventes (GNF)',
data: monthlyData.values,
backgroundColor: 'rgba(99, 102, 241, 0.5)',
borderColor: 'rgba(99, 102, 241, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
// Graphique des types de transactions
const typeData = getTypeData();
const typeCtx = document.getElementById('typeChart').getContext('2d');
new Chart(typeCtx, {
type: 'doughnut',
data: {
labels: typeData.labels,
datasets: [{
data: typeData.values,
backgroundColor: [
'rgba(34, 197, 94, 0.5)',
'rgba(239, 68, 68, 0.5)'
],
borderColor: [
'rgba(34, 197, 94, 1)',
'rgba(239, 68, 68, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
}
// Obtenir les données de ventes par mois
function getMonthlySalesData() {
const months = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
const sales = new Array(12).fill(0);
products.forEach(product => {
const monthIndex = months.indexOf(product.month);
if (monthIndex !== -1) {
sales[monthIndex] += Math.round(product.price) * product.quantity;
}
});
return {
labels: months,
values: sales
};
}
// Obtenir les données de types de transactions
function getTypeData() {
const typeCounts = {
'Entrée': 0,
'Sortie': 0
};
products.forEach(product => {
if (typeCounts.hasOwnProperty(product.type)) {
typeCounts[product.type] += Math.round(product.price) * product.quantity;
}
});
return {
labels: Object.keys(typeCounts),
values: Object.values(typeCounts)
};
}
// Afficher la liste des produits
function renderProductList(filteredProducts = null) {
const productList = document.getElementById('productList');
const dataToShow = filteredProducts || products;
if (dataToShow.length === 0) {
productList.innerHTML = `
<tr>
<td colspan="8" class="px-6 py-4 text-center text-gray-500">
Aucun produit trouvé
</td>
</tr>
`;
return;
}
productList.innerHTML = dataToShow.map((product, index) => `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.id}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.name}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${Math.round(product.price)} GNF</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.quantity}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.date}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.month}</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
${product.type === 'Entrée' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}">
${product.type}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${product.stock}</td>
</tr>
`).join('');
feather.replace();
}
// Filtrer les produits
function filterProducts() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
const filtered = products.filter(product =>
product.id.toLowerCase().includes(searchTerm) ||
product.name.toLowerCase().includes(searchTerm) ||
product.month.toLowerCase().includes(searchTerm) ||
product.type.toLowerCase().includes(searchTerm)
);
renderProductList(filtered);
}
// Imprimer les données
function printData() {
window.print();
}
</script>
</body>
</html>