Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Quản trị báo cáo - Hệ thống kho hàng</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <script> | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#3b82f6', | |
| secondary: '#10b981', | |
| danger: '#ef4444', | |
| warning: '#f59e0b', | |
| info: '#06b6d4', | |
| dark: '#1e293b', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style> | |
| /* Hide inventory sections when daily report is active */ | |
| #dailyReportContent:not(.hidden) ~ .inventory-sections { | |
| display: none; | |
| } | |
| .chart-container { | |
| position: relative; | |
| height: 300px; | |
| width: 100%; | |
| } | |
| .sidebar { | |
| transition: all 0.3s ease; | |
| } | |
| @media (max-width: 768px) { | |
| .sidebar { | |
| transform: translateX(-100%); | |
| position: absolute; | |
| z-index: 100; | |
| height: 100vh; | |
| } | |
| .sidebar.active { | |
| transform: translateX(0); | |
| } | |
| } | |
| /* Custom scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| height: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #c1c1c1; | |
| border-radius: 10px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #a8a8a8; | |
| } | |
| /* Animation for cards */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .animate-fade-in { | |
| animation: fadeIn 0.3s ease-out forwards; | |
| } | |
| /* Loading spinner */ | |
| .spinner { | |
| width: 24px; | |
| height: 24px; | |
| border: 3px solid rgba(255,255,255,0.3); | |
| border-radius: 50%; | |
| border-top-color: #fff; | |
| animation: spin 1s ease-in-out infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <div class="flex h-screen overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div class="sidebar bg-white w-64 border-r border-gray-200 flex flex-col"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h1 class="text-xl font-bold text-primary flex items-center"> | |
| <i class="fas fa-warehouse mr-2"></i> | |
| KHO HÀNG ABC | |
| </h1> | |
| <p class="text-xs text-gray-500">Hệ thống quản trị báo cáo</p> | |
| </div> | |
| <div class="flex-1 overflow-y-auto"> | |
| <div class="p-4"> | |
| <h2 class="text-sm uppercase font-semibold text-gray-500 mb-2">Báo cáo tổng quan</h2> | |
| <ul class="space-y-1 mb-6 pb-4 border-b border-gray-200"> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md bg-blue-50 text-primary"> | |
| <i class="fas fa-calendar-day mr-2"></i> | |
| Báo cáo hàng ngày | |
| </a> | |
| </li> | |
| </ul> | |
| <h2 class="text-sm uppercase font-semibold text-gray-500 mb-2">Báo cáo tồn kho</h2> | |
| <ul class="space-y-1"> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-boxes mr-2 text-orange-500"></i> | |
| <span class="text-orange-500">Tồn kho theo khách hàng</span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-warehouse mr-2 text-amber-600"></i> | |
| <span class="text-amber-600">Tồn kho theo kho</span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-store mr-2 text-yellow-500"></i> | |
| <span class="text-yellow-500">Smart Store</span> | |
| </a> | |
| </li> | |
| </ul> | |
| <h2 class="text-sm uppercase font-semibold text-gray-500 mt-4 mb-2">Báo cáo tài chính</h2> | |
| <ul class="space-y-1"> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-file-invoice-dollar mr-2 text-emerald-500"></i> | |
| <span class="text-emerald-500">Công nợ</span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-chart-line mr-2 text-green-600"></i> | |
| <span class="text-green-600">Doanh thu</span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" class="flex items-center px-3 py-2 text-sm font-medium rounded-md hover:bg-gray-100"> | |
| <i class="fas fa-coins mr-2 text-lime-500"></i> | |
| <span class="text-lime-500">Lợi nhuận</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="p-4 border-t border-gray-200"> | |
| <div class="flex items-center"> | |
| <img src="https://randomuser.me/api/portraits/men/1.jpg" alt="User" class="w-8 h-8 rounded-full mr-2"> | |
| <div> | |
| <p class="text-sm font-medium">Admin User</p> | |
| <p class="text-xs text-gray-500">Quản trị hệ thống</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="flex-1 flex flex-col overflow-hidden"> | |
| <!-- Header --> | |
| <header class="bg-white border-b border-gray-200"> | |
| <div class="flex items-center justify-between px-6 py-4"> | |
| <div class="flex items-center"> | |
| <button id="sidebarToggle" class="md:hidden mr-4 text-gray-500"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| <h2 class="text-lg font-semibold text-gray-800"> | |
| <i class="fas fa-boxes mr-2 text-primary"></i> | |
| Báo cáo tồn kho theo khách hàng | |
| </h2> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <div class="relative"> | |
| <input type="text" placeholder="Tìm kiếm..." class="pl-8 pr-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i> | |
| </div> | |
| <button class="p-2 rounded-full hover:bg-gray-100 relative"> | |
| <i class="fas fa-bell text-gray-500"></i> | |
| <span class="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500"></span> | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Dashboard Content --> | |
| <main class="flex-1 overflow-y-auto p-6"> | |
| <!-- Daily Report Content --> | |
| <div id="dailyReportContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 border-l-4 border-blue-500 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">📦 Báo cáo hàng ngày</h1> | |
| <p class="text-sm text-gray-500">Thống kê hoạt động xe trong ngày</p> | |
| </div> | |
| <!-- KPI cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <p class="text-sm text-gray-500">🚛 Lượt xe vào hôm nay</p> | |
| <h2 class="text-3xl font-bold text-blue-600">36</h2> | |
| <div class="flex items-center mt-2"> | |
| <span class="text-xs text-green-500 bg-green-50 px-2 py-1 rounded-full"> | |
| <i class="fas fa-arrow-up mr-1"></i> 12% | |
| </span> | |
| <span class="text-xs text-gray-500 ml-2">so với hôm qua</span> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <p class="text-sm text-gray-500">⚖️ Tổng khối lượng hôm nay</p> | |
| <h2 class="text-3xl font-bold text-green-600">182,360 kg</h2> | |
| <div class="flex items-center mt-2"> | |
| <span class="text-xs text-red-500 bg-red-50 px-2 py-1 rounded-full"> | |
| <i class="fas fa-arrow-down mr-1"></i> 5% | |
| </span> | |
| <span class="text-xs text-gray-500 ml-2">so với hôm qua</span> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <p class="text-sm text-gray-500">⏱️ Thời gian trung bình</p> | |
| <h2 class="text-3xl font-bold text-purple-600">42 phút</h2> | |
| <div class="flex items-center mt-2"> | |
| <span class="text-xs text-green-500 bg-green-50 px-2 py-1 rounded-full"> | |
| <i class="fas fa-arrow-down mr-1"></i> 8% | |
| </span> | |
| <span class="text-xs text-gray-500 ml-2">so với hôm qua</span> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <p class="text-sm text-gray-500">👷 Nhân viên làm việc</p> | |
| <h2 class="text-3xl font-bold text-amber-600">12</h2> | |
| <div class="flex items-center mt-2"> | |
| <span class="text-xs text-gray-500">Đang hoạt động</span> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Charts & Top data --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6"> | |
| <!-- Simplified Weight Chart --> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200 col-span-2"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <p class="font-semibold">📊 Trọng lượng hàng theo thời gian</p> | |
| <select id="weightTimeRange" class="border border-gray-300 rounded-md px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <option>Hôm nay</option> | |
| <option>7 ngày</option> | |
| <option>30 ngày</option> | |
| </select> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="weightChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Top hàng nặng --> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <p class="font-semibold mb-2">🏆 Top 5 xe có hàng nặng nhất</p> | |
| <ul class="text-sm space-y-3"> | |
| <li class="flex items-center"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full mr-2">1</span> | |
| <span>51C-123.45</span> | |
| <span class="ml-auto font-medium">10,200 kg</span> | |
| </li> | |
| <li class="flex items-center"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full mr-2">2</span> | |
| <span>51D-678.90</span> | |
| <span class="ml-auto font-medium">9,850 kg</span> | |
| </li> | |
| <li class="flex items-center"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full mr-2">3</span> | |
| <span>60A-123.78</span> | |
| <span class="ml-auto font-medium">9,740 kg</span> | |
| </li> | |
| <li class="flex items-center"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full mr-2">4</span> | |
| <span>61B-332.18</span> | |
| <span class="ml-auto font-medium">9,300 kg</span> | |
| </li> | |
| <li class="flex items-center"> | |
| <span class="bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded-full mr-2">5</span> | |
| <span>50F-999.99</span> | |
| <span class="ml-auto font-medium">9,100 kg</span> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| <!-- Table recent trucks --> | |
| <div class="bg-white rounded-2xl shadow p-4 hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <p class="font-semibold">🕑 Xe vào gần đây</p> | |
| <button class="text-sm text-primary hover:text-blue-700 flex items-center"> | |
| <i class="fas fa-sync-alt mr-1"></i> Làm mới | |
| </button> | |
| </div> | |
| <div class="overflow-auto"> | |
| <table class="table-auto w-full text-sm"> | |
| <thead> | |
| <tr class="bg-gray-100"> | |
| <th class="p-2 text-left">Biển số</th> | |
| <th class="p-2 text-left">Giờ vào</th> | |
| <th class="p-2 text-left">Trọng lượng</th> | |
| <th class="p-2 text-left">Nhân viên</th> | |
| <th class="p-2 text-left">Trạng thái</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr class="border-t hover:bg-gray-50"> | |
| <td class="p-2">51C-123.45</td> | |
| <td class="p-2">09:15</td> | |
| <td class="p-2">10,200 kg</td> | |
| <td class="p-2">Nguyễn Văn A</td> | |
| <td class="p-2"> | |
| <span class="bg-green-100 text-green-800 text-xs px-2 py-0.5 rounded-full">Hoàn thành</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t hover:bg-gray-50"> | |
| <td class="p-2">51D-678.90</td> | |
| <td class="p-2">09:45</td> | |
| <td class="p-2">9,850 kg</td> | |
| <td class="p-2">Trần Thị B</td> | |
| <td class="p-2"> | |
| <span class="bg-green-100 text-green-800 text-xs px-2 py-0.5 rounded-full">Hoàn thành</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t hover:bg-gray-50"> | |
| <td class="p-2">60A-123.78</td> | |
| <td class="p-2">10:15</td> | |
| <td class="p-2">9,740 kg</td> | |
| <td class="p-2">Lê Văn C</td> | |
| <td class="p-2"> | |
| <span class="bg-yellow-100 text-yellow-800 text-xs px-2 py-0.5 rounded-full">Đang xử lý</span> | |
| </td> | |
| </tr> | |
| <tr class="border-t hover:bg-gray-50"> | |
| <td class="p-2">61B-332.18</td> | |
| <td class="p-2">10:30</td> | |
| <td class="p-2">9,300 kg</td> | |
| <td class="p-2">Phạm Thị D</td> | |
| <td class="p-2"> | |
| <span class="bg-blue-100 text-blue-800 text-xs px-2 py-0.5 rounded-full">Chờ kiểm tra</span> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Customer Inventory Report --> | |
| <div id="customerInventoryContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-orange-500 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">📊 Tồn kho theo khách hàng</h1> | |
| <p class="text-sm text-gray-500">Thống kê chi tiết tồn kho theo từng khách hàng</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="customerInventoryChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Warehouse Inventory Report --> | |
| <div id="warehouseInventoryContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-amber-600 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">🏭 Tồn kho theo tổng kho</h1> | |
| <p class="text-sm text-gray-500">Thống kê tồn kho phân bổ theo các kho</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="warehouseInventoryChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Smart Store Report --> | |
| <div id="smartStoreContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-yellow-500 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">🛍️ Smart Store Remaining</h1> | |
| <p class="text-sm text-gray-500">Thống kê hàng tồn tại các cửa hàng Smart Store</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="smartStoreChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Debt Report --> | |
| <div id="debtContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-emerald-500 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">💰 Công nợ khách hàng</h1> | |
| <p class="text-sm text-gray-500">Thống kê công nợ theo từng khách hàng</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="debtChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Revenue Report --> | |
| <div id="revenueContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-green-600 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">📈 Doanh thu theo kho</h1> | |
| <p class="text-sm text-gray-500">Thống kê doanh thu phân bổ theo các kho</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="warehouseRevenueChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Profit Report --> | |
| <div id="profitContent" class="bg-white rounded-lg shadow-sm p-6 mb-6 hidden border-l-4 border-lime-500 animate-fade-in"> | |
| <div class="mb-6"> | |
| <h1 class="text-2xl font-bold">👥 Doanh thu theo khách hàng</h1> | |
| <p class="text-sm text-gray-500">Thống kê doanh thu theo từng khách hàng</p> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="customerRevenueChart"></canvas> | |
| </div> | |
| </div> | |
| <!-- Inventory Sections (Hidden in Daily Report) --> | |
| <div class="inventory-sections"> | |
| <div class="inventory-sections"> | |
| <!-- Filters --> | |
| <div class="bg-white rounded-lg shadow-sm p-4 mb-6"> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-4"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Kho hàng</label> | |
| <select class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <option>Tất cả kho</option> | |
| <option>Kho miền Bắc</option> | |
| <option>Kho miền Trung</option> | |
| <option>Kho miền Nam</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Khách hàng</label> | |
| <select class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <option>Tất cả khách hàng</option> | |
| <option>Công ty A</option> | |
| <option>Công ty B</option> | |
| <option>Công ty C</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Từ ngày</label> | |
| <input type="date" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Đến ngày</label> | |
| <input type="date" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| </div> | |
| </div> | |
| <div class="flex justify-end mt-4 space-x-2"> | |
| <button class="bg-gray-200 text-gray-700 px-4 py-2 rounded-md text-sm font-medium hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400"> | |
| <i class="fas fa-redo mr-2"></i> Đặt lại | |
| </button> | |
| <button class="bg-primary text-white px-4 py-2 rounded-md text-sm font-medium hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"> | |
| <i class="fas fa-filter mr-2"></i> Lọc dữ liệu | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Summary Cards --> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6"> | |
| <div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-primary hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm font-medium text-gray-500">Tổng tồn kho</p> | |
| <p class="text-2xl font-bold mt-1">1,245</p> | |
| </div> | |
| <div class="bg-blue-50 p-3 rounded-full"> | |
| <i class="fas fa-box text-primary text-xl"></i> | |
| </div> | |
| </div> | |
| <p class="text-xs text-green-500 mt-2"> | |
| <i class="fas fa-arrow-up mr-1"></i> 12% so với tháng trước | |
| </p> | |
| </div> | |
| <div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-secondary hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm font-medium text-gray-500">Khách hàng</p> | |
| <p class="text-2xl font-bold mt-1">28</p> | |
| </div> | |
| <div class="bg-green-50 p-3 rounded-full"> | |
| <i class="fas fa-users text-secondary text-xl"></i> | |
| </div> | |
| </div> | |
| <p class="text-xs text-green-500 mt-2"> | |
| <i class="fas fa-arrow-up mr-1"></i> 3 khách hàng mới | |
| </p> | |
| </div> | |
| <div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-warning hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm font-medium text-gray-500">Hàng sắp hết</p> | |
| <p class="text-2xl font-bold mt-1">56</p> | |
| </div> | |
| <div class="bg-yellow-50 p-3 rounded-full"> | |
| <i class="fas fa-exclamation-triangle text-warning text-xl"></i> | |
| </div> | |
| </div> | |
| <p class="text-xs text-red-500 mt-2"> | |
| <i class="fas fa-arrow-up mr-1"></i> 5% so với tháng trước | |
| </p> | |
| </div> | |
| <div class="bg-white rounded-lg shadow-sm p-4 border-l-4 border-danger hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm font-medium text-gray-500">Hàng quá hạn</p> | |
| <p class="text-2xl font-bold mt-1">12</p> | |
| </div> | |
| <div class="bg-red-50 p-3 rounded-full"> | |
| <i class="fas fa-calendar-times text-danger text-xl"></i> | |
| </div> | |
| </div> | |
| <p class="text-xs text-green-500 mt-2"> | |
| <i class="fas fa-arrow-down mr-1"></i> 2% so với tháng trước | |
| </p> | |
| </div> | |
| </div> | |
| <!-- Charts --> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6"> | |
| <div class="bg-white rounded-lg shadow-sm p-4 hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h3 class="font-medium">Tồn kho theo khách hàng</h3> | |
| <select id="timeRangeSelect" class="border border-gray-300 rounded-md px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <option>7 ngày</option> | |
| <option>30 ngày</option> | |
| <option>3 tháng</option> | |
| <option>6 tháng</option> | |
| </select> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="customerInventoryChart"></canvas> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow-sm p-4 hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between mb-4"> | |
| <h3 class="font-medium">Phân bổ tồn kho</h3> | |
| <select id="distributionSelect" class="border border-gray-300 rounded-md px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"> | |
| <option>Theo kho</option> | |
| <option>Theo loại hàng</option> | |
| <option>Theo khu vực</option> | |
| </select> | |
| </div> | |
| <div class="chart-container"> | |
| <canvas id="inventoryDistributionChart"></canvas> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Data Table --> | |
| <div class="bg-white rounded-lg shadow-sm overflow-hidden mb-6 hover:shadow-md transition-shadow duration-200"> | |
| <div class="flex items-center justify-between p-4 border-b border-gray-200"> | |
| <h3 class="font-medium">Chi tiết tồn kho</h3> | |
| <div class="flex space-x-2"> | |
| <button class="bg-gray-100 text-gray-700 px-3 py-1 rounded-md text-sm font-medium hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-300"> | |
| <i class="fas fa-print mr-1"></i> In | |
| </button> | |
| <button class="bg-primary text-white px-3 py-1 rounded-md text-sm font-medium hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"> | |
| <i class="fas fa-download mr-1"></i> Xuất Excel | |
| </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 scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Khách hàng</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mã hàng</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tên hàng</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kho</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Số lượng</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ĐVT</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">HSD</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Trạng thái</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Công ty A</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">SP001</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Bột giặt OMO</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kho miền Bắc</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">245</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Thùng</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">15/12/2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Tốt</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Công ty B</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">SP002</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Nước rửa chén Sunlight</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kho miền Nam</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">180</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Thùng</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">20/11/2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">Sắp hết</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Công ty C</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">SP003</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Dầu gội Clear</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kho miền Trung</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">320</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Thùng</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">05/01/2024</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Tốt</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Công ty A</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">SP004</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Sữa tươi Vinamilk</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kho miền Bắc</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">150</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Thùng</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">25/10/2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Hết hạn</span> | |
| </td> | |
| </tr> | |
| <tr class="hover:bg-gray-50"> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">Công ty D</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">SP005</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kẹo dẻo Hồng Hà</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Kho miền Nam</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">90</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Thùng</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">30/09/2023</td> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Hết hạn</span> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="bg-gray-50 px-6 py-3 flex items-center justify-between border-t border-gray-200"> | |
| <div class="text-sm text-gray-500"> | |
| Hiển thị <span class="font-medium">1</span> đến <span class="font-medium">5</span> của <span class="font-medium">1245</span> kết quả | |
| </div> | |
| <div class="flex space-x-2"> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50"> | |
| Trước | |
| </button> | |
| <button class="px-3 py-1 border border-primary bg-primary text-white rounded-md text-sm font-medium"> | |
| 1 | |
| </button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50"> | |
| 2 | |
| </button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50"> | |
| 3 | |
| </button> | |
| <button class="px-3 py-1 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50"> | |
| Sau | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Recent Activities --> | |
| <div class="bg-white rounded-lg shadow-sm p-4 hover:shadow-md transition-shadow duration-200"> | |
| <h3 class="font-medium mb-4">Hoạt động gần đây</h3> | |
| <div class="space-y-4"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0 mr-3"> | |
| <div class="bg-blue-100 p-2 rounded-full"> | |
| <i class="fas fa-ship text-primary"></i> | |
| </div> | |
| </div> | |
| <div class="flex-1 border-b border-gray-200 pb-4"> | |
| <div class="flex items-center justify-between"> | |
| <p class="text-sm font-medium text-gray-900">Nhập hàng từ cảng</p> | |
| <span class="text-xs text-gray-500">2 giờ trước</span> | |
| </div> | |
| <p class="text-sm text-gray-500 mt-1">Đã nhập 50 container hàng hóa từ cảng Hải Phòng vào kho miền Bắc</p> | |
| </div> | |
| </div> | |
| <div class="flex"> | |
| <div class="flex-shrink-0 mr-3"> | |
| <div class="bg-green-100 p-2 rounded-full"> | |
| <i class="fas fa-truck text-secondary"></i> | |
| </div> | |
| </div> | |
| <div class="flex-1 border-b border-gray-200 pb-4"> | |
| <div class="flex items-center justify-between"> | |
| <p class="text-sm font-medium text-gray-900">Xuất hàng cho khách</p> | |
| <span class="text-xs text-gray-500">5 giờ trước</span> | |
| </div> | |
| <p class="text-sm text-gray-500 mt-1">Xuất 20 thùng hàng cho Công ty A từ kho miền Bắc</p> | |
| </div> | |
| </div> | |
| <div class="flex"> | |
| <div class="flex-shrink-0 mr-3"> | |
| <div class="bg-yellow-100 p-2 rounded-full"> | |
| <i class="fas fa-exclamation-triangle text-warning"></i> | |
| </div> | |
| </div> | |
| <div class="flex-1"> | |
| <div class="flex items-center justify-between"> | |
| <p class="text-sm font-medium text-gray-900">Cảnh báo tồn kho</p> | |
| <span class="text-xs text-gray-500">1 ngày trước</span> | |
| </div> | |
| <p class="text-sm text-gray-500 mt-1">5 mặt hàng sắp hết tồn kho tại kho miền Nam</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </div> | |
| </div> | |
| <script> | |
| // Toggle sidebar on mobile | |
| document.getElementById('sidebarToggle').addEventListener('click', function() { | |
| document.querySelector('.sidebar').classList.toggle('active'); | |
| }); | |
| // Close sidebar when clicking outside on mobile | |
| document.addEventListener('click', function(event) { | |
| const sidebar = document.querySelector('.sidebar'); | |
| const sidebarToggle = document.getElementById('sidebarToggle'); | |
| if (window.innerWidth <= 768 && | |
| !sidebar.contains(event.target) && | |
| event.target !== sidebarToggle && | |
| !sidebarToggle.contains(event.target)) { | |
| sidebar.classList.remove('active'); | |
| } | |
| }); | |
| // Global chart variables | |
| let customerInventoryChart; | |
| let inventoryDistributionChart; | |
| let warehouseInventoryChart; | |
| let smartStoreChart; | |
| let debtChart; | |
| let warehouseRevenueChart; | |
| let customerRevenueChart; | |
| let weightChart; | |
| // Sample data for different time ranges and tabs | |
| const tabData = { | |
| 'Báo cáo hàng ngày': { | |
| 'Hôm nay': { | |
| labels: ['6h', '8h', '10h', '12h', '14h', '16h', '18h'], | |
| data: [25000, 45000, 60000, 75000, 90000, 110000, 125000] | |
| }, | |
| '7 ngày': { | |
| labels: ['Thứ 2', 'Thứ 3', 'Thứ 4', 'Thứ 5', 'Thứ 6', 'Thứ 7', 'Chủ nhật'], | |
| data: [120000, 135000, 142000, 126000, 160000, 182000, 172000] | |
| }, | |
| '30 ngày': { | |
| labels: Array.from({length: 30}, (_, i) => `Ngày ${i+1}`), | |
| data: Array.from({length: 30}, () => Math.floor(Math.random() * 200000) + 100000) | |
| } | |
| }, | |
| 'Tồn kho theo khách hàng': { | |
| '7 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C', 'Công ty D', 'Công ty E'], | |
| data: [245, 180, 320, 150, 90] | |
| }, | |
| '30 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C', 'Công ty D', 'Công ty E', 'Công ty F'], | |
| data: [500, 350, 420, 280, 150, 200] | |
| } | |
| }, | |
| 'Tồn kho theo tổng kho': { | |
| '7 ngày': { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam'], | |
| data: [1200, 800, 1500] | |
| }, | |
| '30 ngày': { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam', 'Kho Tây Nguyên'], | |
| data: [4500, 2800, 5200, 1500] | |
| } | |
| }, | |
| 'Smart Store Remaining': { | |
| '7 ngày': { | |
| labels: ['Store Hà Nội', 'Store HCM', 'Store Đà Nẵng'], | |
| data: [350, 420, 280] | |
| }, | |
| '30 ngày': { | |
| labels: ['Store Hà Nội', 'Store HCM', 'Store Đà Nẵng', 'Store Hải Phòng'], | |
| data: [1500, 1800, 1200, 800] | |
| } | |
| }, | |
| 'Công nợ': { | |
| '7 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C'], | |
| data: [50000000, 35000000, 42000000] | |
| }, | |
| '30 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C', 'Công ty D'], | |
| data: [150000000, 120000000, 180000000, 80000000] | |
| } | |
| }, | |
| 'Doanh thu theo kho': { | |
| '7 ngày': { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam'], | |
| data: [120000000, 80000000, 150000000] | |
| }, | |
| '30 ngày': { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam'], | |
| data: [450000000, 280000000, 520000000] | |
| } | |
| }, | |
| 'Doanh thu theo khách hàng': { | |
| '7 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C'], | |
| data: [80000000, 65000000, 90000000] | |
| }, | |
| '30 ngày': { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C', 'Công ty D'], | |
| data: [250000000, 180000000, 300000000, 150000000] | |
| } | |
| } | |
| }; | |
| // Sample data for different distribution types | |
| const distributionData = { | |
| 'Theo kho': { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam', 'Smart Store'], | |
| data: [35, 25, 30, 10] | |
| }, | |
| 'Theo loại hàng': { | |
| labels: ['Hàng tiêu dùng', 'Hàng điện tử', 'Hàng thực phẩm', 'Hàng may mặc'], | |
| data: [40, 20, 25, 15] | |
| }, | |
| 'Theo khu vực': { | |
| labels: ['Miền Bắc', 'Miền Trung', 'Miền Nam'], | |
| data: [45, 20, 35] | |
| } | |
| }; | |
| // Format number as VND currency | |
| function formatVND(num) { | |
| return new Intl.NumberFormat('vi-VN').format(num) + 'đ'; | |
| } | |
| // Format weight in kg | |
| function formatWeight(kg) { | |
| if (kg >= 1000) { | |
| return (kg / 1000).toFixed(1) + ' tấn'; | |
| } | |
| return kg + ' kg'; | |
| } | |
| // Update weight chart based on time range | |
| function updateWeightChart() { | |
| const timeRange = document.getElementById('weightTimeRange').value; | |
| const data = tabData['Báo cáo hàng ngày'][timeRange]; | |
| weightChart.data.labels = data.labels; | |
| weightChart.data.datasets[0].data = data.data; | |
| weightChart.update(); | |
| } | |
| // Update chart based on active tab and time range | |
| function updateChart() { | |
| const activeTab = document.querySelector('.sidebar a.bg-blue-50').textContent.trim(); | |
| const timeRange = document.getElementById('timeRangeSelect')?.value || '7 ngày'; | |
| const data = tabData[activeTab][timeRange]; | |
| let chart; | |
| if (activeTab === 'Tồn kho theo khách hàng') { | |
| chart = customerInventoryChart; | |
| } else if (activeTab === 'Tồn kho theo tổng kho') { | |
| chart = warehouseInventoryChart; | |
| } else if (activeTab === 'Smart Store') { | |
| chart = smartStoreChart; | |
| } else if (activeTab === 'Công nợ') { | |
| chart = debtChart; | |
| } else if (activeTab === 'Doanh thu theo kho') { | |
| chart = warehouseRevenueChart; | |
| } else if (activeTab === 'Doanh thu theo khách hàng') { | |
| chart = customerRevenueChart; | |
| } else { | |
| chart = customerInventoryChart; | |
| } | |
| if (chart) { | |
| if (activeTab.includes('Doanh thu') || activeTab.includes 'Công nợ') { | |
| // Format as currency for financial tabs | |
| chart.data.datasets[0].label = activeTab.includes('Doanh thu') ? 'Doanh thu (VND)' : 'Công nợ (VND)'; | |
| chart.options.scales.y.ticks.callback = function(value) { | |
| return formatVND(value); | |
| }; | |
| chart.options.plugins.tooltip.callbacks.label = function(context) { | |
| return context.dataset.label + ': ' + formatVND(context.raw); | |
| }; | |
| } else { | |
| // Format as quantity for inventory tabs | |
| chart.data.datasets[0].label = 'Số lượng'; | |
| chart.options.scales.y.ticks.callback = function(value) { | |
| return value + (activeTab.includes('Smart Store') ? ' sản phẩm' : ' thùng'); | |
| }; | |
| chart.options.plugins.tooltip.callbacks.label = function(context) { | |
| return context.dataset.label + ': ' + context.raw + (activeTab.includes('Smart Store') ? ' sản phẩm' : ' thùng'); | |
| }; | |
| } | |
| chart.data.labels = data.labels; | |
| chart.data.datasets[0].data = data.data; | |
| chart.update(); | |
| } | |
| } | |
| // Update inventory distribution chart | |
| function updateInventoryDistributionChart(distributionType) { | |
| const data = distributionData[distributionType]; | |
| inventoryDistributionChart.data.labels = data.labels; | |
| inventoryDistributionChart.data.datasets[0].data = data.data; | |
| inventoryDistributionChart.update(); | |
| } | |
| // Initialize charts | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Weight Chart | |
| const weightCtx = document.getElementById('weightChart').getContext('2d'); | |
| weightChart = new Chart(weightCtx, { | |
| type: 'line', | |
| data: { | |
| labels: ['6h', '8h', '10h', '12h', '14h', '16h', '18h'], | |
| datasets: [{ | |
| label: 'Tổng trọng lượng', | |
| data: [25000, 45000, 60000, 75000, 90000, 110000, 125000], | |
| borderColor: '#3b82f6', | |
| backgroundColor: 'rgba(59, 130, 246, 0.1)', | |
| tension: 0.4, | |
| fill: true | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return 'Trọng lượng: ' + formatWeight(context.raw); | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return formatWeight(value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Customer Inventory Chart (Bar) | |
| const customerCtx = document.getElementById('customerInventoryChart').getContext('2d'); | |
| customerInventoryChart = new Chart(customerCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C', 'Công ty D', 'Công ty E'], | |
| datasets: [{ | |
| label: 'Tồn kho (thùng)', | |
| data: [245, 180, 320, 150, 90], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(99, 102, 241, 0.7)', | |
| 'rgba(245, 158, 11, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(99, 102, 241, 1)', | |
| 'rgba(245, 158, 11, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': ' + context.raw + ' thùng'; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return value + ' thùng'; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Warehouse Inventory Chart | |
| const warehouseCtx = document.getElementById('warehouseInventoryChart').getContext('2d'); | |
| warehouseInventoryChart = new Chart(warehouseCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam'], | |
| datasets: [{ | |
| label: 'Tồn kho (thùng)', | |
| data: [1200, 800, 1500], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true | |
| } | |
| } | |
| } | |
| }); | |
| // Smart Store Chart | |
| const smartStoreCtx = document.getElementById('smartStoreChart').getContext('2d'); | |
| smartStoreChart = new Chart(smartStoreCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Store Hà Nội', 'Store HCM', 'Store Đà Nẵng'], | |
| datasets: [{ | |
| label: 'Tồn kho (sản phẩm)', | |
| data: [350, 420, 280], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true | |
| } | |
| } | |
| } | |
| }); | |
| // Debt Chart | |
| const debtCtx = document.getElementById('debtChart').getContext('2d'); | |
| debtChart = new Chart(debtCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C'], | |
| datasets: [{ | |
| label: 'Công nợ (VND)', | |
| data: [50000000, 35000000, 42000000], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': ' + formatVND(context.raw); | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return formatVND(value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Warehouse Revenue Chart | |
| const warehouseRevenueCtx = document.getElementById('warehouseRevenueChart').getContext('2d'); | |
| warehouseRevenueChart = new Chart(warehouseRevenueCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam'], | |
| datasets: [{ | |
| label: 'Doanh thu (VND)', | |
| data: [120000000, 80000000, 150000000], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': ' + formatVND(context.raw); | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return formatVND(value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Customer Revenue Chart | |
| const customerRevenueCtx = document.getElementById('customerRevenueChart').getContext('2d'); | |
| customerRevenueChart = new Chart(customerRevenueCtx, { | |
| type: 'bar', | |
| data: { | |
| labels: ['Công ty A', 'Công ty B', 'Công ty C'], | |
| datasets: [{ | |
| label: 'Doanh thu (VND)', | |
| data: [80000000, 65000000, 90000000], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| display: false | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| return context.dataset.label + ': ' + formatVND(context.raw); | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| beginAtZero: true, | |
| ticks: { | |
| callback: function(value) { | |
| return formatVND(value); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Inventory Distribution Chart (Doughnut) | |
| const distributionCtx = document.getElementById('inventoryDistributionChart').getContext('2d'); | |
| inventoryDistributionChart = new Chart(distributionCtx, { | |
| type: 'doughnut', | |
| data: { | |
| labels: ['Kho miền Bắc', 'Kho miền Trung', 'Kho miền Nam', 'Smart Store'], | |
| datasets: [{ | |
| label: 'Phân bổ tồn kho', | |
| data: [35, 25, 30, 10], | |
| backgroundColor: [ | |
| 'rgba(59, 130, 246, 0.7)', | |
| 'rgba(16, 185, 129, 0.7)', | |
| 'rgba(239, 68, 68, 0.7)', | |
| 'rgba(245, 158, 11, 0.7)' | |
| ], | |
| borderColor: [ | |
| 'rgba(59, 130, 246, 1)', | |
| 'rgba(16, 185, 129, 1)', | |
| 'rgba(239, 68, 68, 1)', | |
| 'rgba(245, 158, 11, 1)' | |
| ], | |
| borderWidth: 1 | |
| }] | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| legend: { | |
| position: 'right', | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| const label = context.label || ''; | |
| const value = context.raw || 0; | |
| const total = context.dataset.data.reduce((a, b) => a + b, 0); | |
| const percentage = Math.round((value / total) * 100); | |
| return `${label}: ${value}% (${percentage}% tổng kho)`; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| // Add event listeners | |
| if (document.getElementById('timeRangeSelect')) { | |
| document.getElementById('timeRangeSelect').addEventListener('change', updateChart); | |
| } | |
| if (document.getElementById('distributionSelect')) { | |
| document.getElementById('distributionSelect').addEventListener('change', function() { | |
| updateInventoryDistributionChart(this.value); | |
| }); | |
| } | |
| if (document.getElementById('weightTimeRange')) { | |
| document.getElementById('weightTimeRange').addEventListener('change', updateWeightChart); | |
| } | |
| }); | |
| // Add active class to clicked nav items and show corresponding content | |
| const navItems = document.querySelectorAll('.sidebar a'); | |
| navItems.forEach(item => { | |
| item.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| navItems.forEach(i => i.classList.remove('bg-blue-50', 'text-primary')); | |
| this.classList.add('bg-blue-50', 'text-primary'); | |
| // Update main title | |
| const mainTitle = document.querySelector('header h2'); | |
| const iconClass = this.querySelector('i').className.split(' ')[1]; | |
| const textColor = this.querySelector('span')?.className.includes('text-') ? | |
| this.querySelector('span').className.match(/text-(.*?)-|text-(.*?)\s/)[1] || 'primary' : | |
| 'primary'; | |
| mainTitle.innerHTML = `<i class="fas ${iconClass} mr-2 text-${textColor}"></i> ${this.textContent.trim()}`; | |
| // Hide all content sections | |
| document.querySelectorAll('[id$="Content"]').forEach(section => { | |
| section.classList.add('hidden'); | |
| }); | |
| // Show the corresponding content section | |
| const tabText = this.textContent.trim(); | |
| let contentId; | |
| switch(tabText) { | |
| case 'Tồn kho theo khách hàng': | |
| contentId = 'customerInventoryContent'; | |
| break; | |
| case 'Tồn kho theo kho': | |
| contentId = 'warehouseInventoryContent'; | |
| break; | |
| case 'Smart Store': | |
| contentId = 'smartStoreContent'; | |
| break; | |
| case 'Công nợ': | |
| contentId = 'debtContent'; | |
| break; | |
| case 'Doanh thu': | |
| contentId = 'revenueContent'; | |
| break; | |
| case 'Lợi nhuận': | |
| contentId = 'profitContent'; | |
| break; | |
| case 'Báo cáo hàng ngày': | |
| default: | |
| contentId = 'dailyReportContent'; | |
| } | |
| document.getElementById(contentId).classList.remove('hidden'); | |
| // Update chart if needed | |
| if (typeof updateChart === 'function') { | |
| updateChart(); | |
| } | |
| }); | |
| }); | |
| // Initialize by showing daily report | |
| document.querySelector('.sidebar a.bg-blue-50').click(); | |
| // Add loading effect to buttons | |
| document.querySelectorAll('button').forEach(button => { | |
| button.addEventListener('click', function() { | |
| if (this.classList.contains('bg-primary') || this.classList.contains('bg-gray-200')) { | |
| const originalContent = this.innerHTML; | |
| this.innerHTML = `<span class="spinner"></span> ${this.textContent.trim()}`; | |
| this.disabled = true; | |
| // Simulate loading | |
| setTimeout(() => { | |
| this.innerHTML = originalContent; | |
| this.disabled = false; | |
| }, 1500); | |
| } | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dangchauky/test" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |