|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Advanced AutoParts Tariff Dashboard</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: '#1d4ed8', |
|
|
secondary: '#3b82f6', |
|
|
accent: '#10b981', |
|
|
dark: '#0f172a', |
|
|
light: '#f8fafc' |
|
|
}, |
|
|
animation: { |
|
|
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite', |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
</script> |
|
|
<style> |
|
|
.grid-stack { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); |
|
|
grid-auto-rows: minmax(150px, auto); |
|
|
gap: 1.5rem; |
|
|
} |
|
|
|
|
|
.scorecard { |
|
|
transition: all 0.3s ease; |
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05); |
|
|
} |
|
|
|
|
|
.scorecard:hover { |
|
|
transform: translateY(-5px); |
|
|
box-shadow: 0 10px 15px rgba(0,0,0,0.1); |
|
|
} |
|
|
|
|
|
.chart-container { |
|
|
transition: all 0.3s ease; |
|
|
background-color: white; |
|
|
border-radius: 0.75rem; |
|
|
overflow: hidden; |
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.05); |
|
|
} |
|
|
|
|
|
.chart-container:hover { |
|
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1); |
|
|
transform: scale(1.005); |
|
|
} |
|
|
|
|
|
.filter-card { |
|
|
transition: all 0.2s ease; |
|
|
} |
|
|
|
|
|
.filter-card:hover { |
|
|
background-color: #eff6ff; |
|
|
} |
|
|
|
|
|
.sidebar { |
|
|
scrollbar-width: thin; |
|
|
scrollbar-color: #cbd5e1 #f1f5f9; |
|
|
} |
|
|
|
|
|
.sidebar::-webkit-scrollbar { |
|
|
width: 6px; |
|
|
} |
|
|
|
|
|
.sidebar::-webkit-scrollbar-thumb { |
|
|
background-color: #cbd5e1; |
|
|
border-radius: 10px; |
|
|
} |
|
|
|
|
|
.animate-pulse { |
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; |
|
|
} |
|
|
|
|
|
@keyframes pulse { |
|
|
0%, 100% { opacity: 1; } |
|
|
50% { opacity: 0.5; } |
|
|
} |
|
|
|
|
|
.dropdown-menu { |
|
|
transition: all 0.3s ease; |
|
|
max-height: 0; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.dropdown-menu.active { |
|
|
max-height: 300px; |
|
|
} |
|
|
|
|
|
.data-table-container { |
|
|
max-height: 500px; |
|
|
overflow-y: auto; |
|
|
} |
|
|
|
|
|
table.data-table thead tr th { |
|
|
position: sticky; |
|
|
top: 0; |
|
|
background-color: #f1f5f9; |
|
|
z-index: 10; |
|
|
} |
|
|
|
|
|
.highlight-row { |
|
|
background-color: #e0f2fe !important; |
|
|
} |
|
|
|
|
|
.fade-in { |
|
|
animation: fadeIn 0.5s ease-in; |
|
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; } |
|
|
to { opacity: 1; } |
|
|
} |
|
|
|
|
|
.notification { |
|
|
position: fixed; |
|
|
top: 80px; |
|
|
right: 20px; |
|
|
z-index: 1000; |
|
|
transform: translateX(120%); |
|
|
transition: transform 0.5s ease; |
|
|
} |
|
|
|
|
|
.notification.show { |
|
|
transform: translateX(0); |
|
|
} |
|
|
|
|
|
.interactive-scorecard { |
|
|
transition: all 0.3s ease; |
|
|
position: relative; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.interactive-scorecard::after { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: -50%; |
|
|
left: -50%; |
|
|
width: 200%; |
|
|
height: 200%; |
|
|
background: linear-gradient(to bottom right, transparent 30%, rgba(255,255,255,0.2), transparent 70%); |
|
|
transform: rotate(45deg); |
|
|
transition: transform 0.7s ease; |
|
|
pointer-events: none; |
|
|
} |
|
|
|
|
|
.interactive-scorecard:hover::after { |
|
|
transform: rotate(45deg) translate(20px, 20px); |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 text-gray-800"> |
|
|
|
|
|
<div id="notification" class="notification bg-primary text-white px-5 py-3 rounded-lg shadow-lg"> |
|
|
<span class="mr-2"><i class="fas fa-sync-alt"></i> Dashboard updated with new filters!</span> |
|
|
</div> |
|
|
|
|
|
|
|
|
<header class="bg-white shadow-sm sticky top-0 z-50"> |
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
|
|
<div class="flex justify-between h-16 items-center"> |
|
|
<div class="flex items-center"> |
|
|
<div class="flex-shrink-0 flex items-center"> |
|
|
<i class="fas fa-car text-primary text-2xl mr-2"></i> |
|
|
<h1 class="text-xl font-bold text-dark">AutoParts <span class="text-primary">301 Tariff</span> Dashboard</h1> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex items-center space-x-4"> |
|
|
<div class="relative"> |
|
|
<i class="fas fa-bell text-gray-500 text-xl"></i> |
|
|
<span class="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full"></span> |
|
|
</div> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<span class="text-sm text-gray-600">John Smith</span> |
|
|
<div class="relative"> |
|
|
<div class="bg-gray-200 border-2 border-dashed rounded-xl w-10 h-10"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
<div class="flex h-[calc(100vh-4rem)]"> |
|
|
|
|
|
<div class="sidebar w-72 bg-white border-r border-gray-200 overflow-y-auto py-6 px-4"> |
|
|
<h2 class="text-lg font-semibold mb-4 text-dark flex items-center"> |
|
|
<i class="fas fa-filter text-secondary mr-2"></i> |
|
|
Data Filters |
|
|
</h2> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<button class="flex justify-between w-full py-2 text-left font-medium text-gray-700 dropdown-toggle"> |
|
|
<span>Date Range</span> |
|
|
<i class="fas fa-chevron-down text-sm"></i> |
|
|
</button> |
|
|
<div class="dropdown-menu pl-2"> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">From Date</label> |
|
|
<input id="fromDate" type="date" class="w-full px-3 py-2 border border-gray-300 rounded-md" value="2023-01-01"> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">To Date</label> |
|
|
<input id="toDate" type="date" class="w-full px-3 py-2 border border-gray-300 rounded-md" value="2023-12-31"> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<button class="flex justify-between w-full py-2 text-left font-medium text-gray-700 dropdown-toggle"> |
|
|
<span>Supplier Details</span> |
|
|
<i class="fas fa-chevron-down text-sm"></i> |
|
|
</button> |
|
|
<div class="dropdown-menu pl-2"> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Supplier Name</label> |
|
|
<select id="supplierName" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Suppliers</option> |
|
|
<option>Global Auto Parts Co.</option> |
|
|
<option>Precision Components Inc.</option> |
|
|
<option>DynaParts International</option> |
|
|
<option>EuroAuto Components</option> |
|
|
<option>TechAuto Solutions</option> |
|
|
</select> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Supplier Country</label> |
|
|
<select id="supplierCountry" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Countries</option> |
|
|
<option>China</option> |
|
|
<option>Germany</option> |
|
|
<option>Mexico</option> |
|
|
<option>Japan</option> |
|
|
<option>South Korea</option> |
|
|
<option>India</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<button class="flex justify-between w-full py-2 text-left font-medium text-gray-700 dropdown-toggle"> |
|
|
<span>Product Information</span> |
|
|
<i class="fas fa-chevron-down text-sm"></i> |
|
|
</button> |
|
|
<div class="dropdown-menu pl-2"> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Product Category</label> |
|
|
<select id="productCategory" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Categories</option> |
|
|
<option>Engine Components</option> |
|
|
<option>Electrical Systems</option> |
|
|
<option>Chassis Parts</option> |
|
|
<option>Interior Components</option> |
|
|
<option>Transmission Parts</option> |
|
|
<option>Braking Systems</option> |
|
|
</select> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">HS Code</label> |
|
|
<input id="hsCode" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="e.g., 8708.99"> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Product Value Range ($)</label> |
|
|
<div class="flex items-center space-x-2 mb-2"> |
|
|
<input id="minValue" type="number" class="w-1/2 px-3 py-2 border border-gray-300 rounded-md" placeholder="Min" value="500"> |
|
|
<span class="text-gray-500">to</span> |
|
|
<input id="maxValue" type="number" class="w-1/2 px-3 py-2 border border-gray-300 rounded-md" placeholder="Max" value="10000"> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<button class="flex justify-between w-full py-2 text-left font-medium text-gray-700 dropdown-toggle"> |
|
|
<span>Tariff Details</span> |
|
|
<i class="fas fa-chevron-down text-sm"></i> |
|
|
</button> |
|
|
<div class="dropdown-menu pl-2"> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Tariff Rate</label> |
|
|
<input id="tariffRate" type="range" min="0" max="25" step="1" value="10" class="w-full"> |
|
|
<div class="flex justify-between text-xs"> |
|
|
<span>0%</span> |
|
|
<span id="tariffRateValue">10%</span> |
|
|
<span>25%</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Tariff Status</label> |
|
|
<select id="tariffStatus" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Status</option> |
|
|
<option>Paid</option> |
|
|
<option>Pending</option> |
|
|
<option>Exempted</option> |
|
|
<option>Under Appeal</option> |
|
|
</select> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Tariff Amount Range ($)</label> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<input id="minTariffAmount" type="number" class="w-1/2 px-3 py-2 border border-gray-300 rounded-md" placeholder="Min" value="50"> |
|
|
<span class="text-gray-500">to</span> |
|
|
<input id="maxTariffAmount" type="number" class="w-1/2 px-3 py-2 border border-gray-300 rounded-md" placeholder="Max" value="2500"> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<button class="flex justify-between w-full py-2 text-left font-medium text-gray-700 dropdown-toggle"> |
|
|
<span>Import Details</span> |
|
|
<i class="fas fa-chevron-down text-sm"></i> |
|
|
</button> |
|
|
<div class="dropdown-menu pl-2"> |
|
|
<div class="filter-card p极3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Port of Entry</label> |
|
|
<select id="portEntry" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Ports</option> |
|
|
<option>Los Angeles</option> |
|
|
<option>New York</option> |
|
|
<option>Chicago</option> |
|
|
<option>Houston</option> |
|
|
极 <option>Miami</option> |
|
|
</select> |
|
|
</div> |
|
|
<div class="filter-card p-3 rounded-lg"> |
|
|
<label class="block text-sm font-medium mb-1">Shipping Method</label> |
|
|
<select id="shippingMethod" class="w-full px-3 py-2 border border-gray-300 rounded-md"> |
|
|
<option value="all">All Methods</option> |
|
|
<option>Air Freight</option> |
|
|
<option>Sea Freight</option> |
|
|
<option>Ground Transport</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-8 flex flex-col space-y-3"> |
|
|
<button id="applyFilters" class="bg-primary hover:bg-blue-700 text-white py-2 px-4 rounded-lg font-medium flex items-center justify-center transition-all"> |
|
|
<i class="fas fa-sync-alt mr-2"></i> Apply Filters |
|
|
</button> |
|
|
<button id="resetFilters" class="border border-gray-300 py-2 px-4 rounded-lg font-medium hover:bg-gray-100 transition-all"> |
|
|
<i class="fas fa-redo mr-2"></i> Reset Filters |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="flex-1 overflow-y-auto p-6"> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-6 gap-5 mb-6"> |
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-primary md:col-span-3 lg:col-span-2"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-blue-100 p-3 mr-4"> |
|
|
<i class="fas fa-dollar-sign text-blue-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Total Tariff Spend</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">$2.84M</h3> |
|
|
</div> |
|
|
</div> |
|
|
<p class="mt-3 text-sm text-gray-600"> |
|
|
<span class="text-green-500"><i class="fas fa-arrow-up"></i> 12.3%</span> from last quarter |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-green-500 md:col-span-3 lg:col-span-2"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-green-100 p-3 mr-4"> |
|
|
<i class="fas fa-boxes text-green-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Impacted Products</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">187</h3> |
|
|
</div> |
|
|
</div> |
|
|
<p class="mt-3 text-sm text-gray-600"> |
|
|
<span class="text-red-500"><i class="fas fa-arrow-down"></i> 5.2%</span> since last year |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-purple-500 md:col-span-3 lg:col-span-2"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-purple-100 p-3 mr-4"> |
|
|
<i class="fas fa-industry text-purple-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Active Suppliers</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">24</h3> |
|
|
</div> |
|
|
</div> |
|
|
<p class="mt-3 text-sm text-gray-600"> |
|
|
<span class="text-green-500"><i class="fas fa-arrow-up"></i> 2 new</span> this quarter |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-yellow-500 md:col-span-3 lg:col-span-2"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-yellow-100 p-3 mr-4"> |
|
|
<i class="fas fa-percentage text-yellow-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Avg. Tariff Rate</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">8.7%</h3> |
|
|
</div> |
|
|
</div> |
|
|
<p class="mt-3 text-sm text-gray-600"> |
|
|
<span class="text-red-500"><i class="fas fa-arrow-up"></i> 1.2%</span> since last month |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-indigo-500 md:col-span-3 lg:col-span-2 interactive-scorecard"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-indigo-100 p-3 mr-4"> |
|
|
<i class="fas fa-chart-line text-indigo-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Cost Reduction Opportunities</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">$420K</h3> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mt-2"> |
|
|
<div class="w-full bg-indigo-100 rounded-full h-2.5"> |
|
|
<div class="bg-indigo-600 h-2.5 rounded-full" style="width: 65%"></div> |
|
|
</div> |
|
|
</div> |
|
|
<p class="mt-3 text-sm text-gray-600"> |
|
|
<span class="text-indigo-500"><i class="fas fa-info-circle"></i> Potential savings from optimization</span> |
|
|
</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="scorecard bg-white rounded-xl p-5 shadow-sm border-l-4 border-pink-500 md:col-span-3 lg:col-span-2 interactive-scorecard"> |
|
|
<div class="flex items-center"> |
|
|
<div class="rounded-lg bg-pink-100 p-3 mr-4"> |
|
|
<i class="fas fa-trophy text-pink-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-500 text-sm">Tariff Mitigation Success</p> |
|
|
<h3 class="text-2xl font-bold text-gray-800">87%</h3> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mt-3 flex justify-between text-sm"> |
|
|
<span class="text-gray-500">This quarter</span> |
|
|
<span class="bg-pink-100 text-pink-800 px-2 py-1 rounded-full text-xs">+12%</span> |
|
|
</div> |
|
|
<p class="mt-2 text-sm text-gray-600"> |
|
|
<span class="text-pink-500"><i class="fas fa-star"></i> Exceeded target by 7%</span> |
|
|
</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="grid grid-cols-1 xl:grid-cols-4 gap-5 mb-6"> |
|
|
|
|
|
<div class="xl:col-span-3"> |
|
|
<div class="grid-stack"> |
|
|
<div class="chart-container col-span-2"> |
|
|
<div class="p-4 border-b flex justify-between items-center"> |
|
|
<h3 class="font-semibold text-dark">Monthly Tariff Spend Analysis</h3> |
|
|
<div class="flex"> |
|
|
<button class="text-xs py-1 px-2 mr-1 rounded bg-blue-50 text-blue-600">2023</button> |
|
|
<button class="text-xs py-1 px-2 rounded bg-gray-100 text-gray-600">2022</button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="lineChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Spend by Product Category</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="doughnutChart" height="250"></canvas> |
|
|
</极div> |
|
|
</div> |
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Supplier Tariff Distribution</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="barChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container col-span-2"> |
|
|
<div class="p-4 border-b flex justify-between items-center"> |
|
|
<h3 class="font-semibold text-dark">Tariff Spend Forecast</h3> |
|
|
<div class="text-xs text-gray-500"> |
|
|
<span class="inline-block w-3 h-3 bg-blue-500 rounded-full mr-1"></span> Actual |
|
|
<span class="inline-block w-3 h-3 bg-green-500 rounded-full ml-3 mr-1"></span> Forecast |
|
|
</div> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="forecastChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Tariff by Country of Origin</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="polarChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">HS Code Analysis</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="pieChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container col-span-2"> |
|
|
<div class="p-4 border-b flex justify-between items-center"> |
|
|
<h3 class="font-semibold text-dark">Value vs Tariff Correlation</h3> |
|
|
<div class="text-xs text-gray-500"> |
|
|
<span class="inline-block w-4 h-4 bg-blue-500 rounded-full mr-1"></span> Each dot represents a product |
|
|
</div> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="correlationChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="xl:col-span-1"> |
|
|
<div class="flex flex-col gap-5"> |
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Top 5 Tariff Rates</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="horizBarChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Tariff by Port of Entry</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="portChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Compliance Status</极h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="complianceChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Monthly Average Spend</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="avgSpendChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Cost Distribution by Category</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="costDistributionChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="chart-container"> |
|
|
<div class="p-4 border-b"> |
|
|
<h3 class="font-semibold text-dark">Top Suppliers by Volume</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<canvas id="supplierVolumeChart" height="250"></canvas> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-sm p-4 mt-6"> |
|
|
<div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-4"> |
|
|
<h3 class="font-semibold text-dark text-lg mb-3 md:mb-0">Tariff Spend Details</h3> |
|
|
<div class="flex flex-col sm:flex-row gap-3 w-full md:w-auto"> |
|
|
<div class="relative w-full"> |
|
|
<i class="fas fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i> |
|
|
<input type="text" id="searchInput" placeholder="Search by supplier, product, or HS code..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-md w-full"> |
|
|
</div> |
|
|
<select id="categoryFilter" class="border border-gray-300 rounded-md px-4 py-2"> |
|
|
<option value="all">All Categories</option> |
|
|
<option>Engine Components</option> |
|
|
<option>Electrical Systems</option> |
|
|
<option>Chassis Parts</option> |
|
|
<option>Interior Components</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="data-table-container"> |
|
|
<table class="min-w-full divide-y divide-gray-200 data-table"> |
|
|
<thead class="bg-gray-50"> |
|
|
<tr> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Product ID</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Product Name</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Category</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Supplier</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Origin</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">HS Code</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Value ($)</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tariff Rate</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tariff Amount</th> |
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> |
|
|
</tr> |
|
|
</thead> |
|
|
<tbody class="bg-white divide-y divide-gray-200" id="tableBody"> |
|
|
|
|
|
</tbody> |
|
|
</table> |
|
|
</div> |
|
|
|
|
|
<div class="flex justify-between items-center mt-4"> |
|
|
<span class="text-sm text-gray-700">Showing <span id="visibleRows">10</span> of <span id="totalRows">25</span> entries</span> |
|
|
<div class="flex space-x-2"> |
|
|
<button class="px-3 py-1 rounded-md border bg-white text-sm"><i class="fas fa-chevron-left"></i></button> |
|
|
<button class="px-3 py-1 rounded-md border bg-blue-500 text-white text-sm">1</button> |
|
|
<button class="px-3 py-1 rounded-md border bg-white text-sm">2</button> |
|
|
<button class="px-3 py-1 rounded-md border bg-white text-sm"><i class="fas fa-chevron-right"></i></button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
let lineChart, doughnutChart, barChart, polarChart, pieChart; |
|
|
let horizBarChart, portChart, complianceChart, forecastChart; |
|
|
let avgSpendChart, costDistributionChart, supplierVolumeChart, correlationChart; |
|
|
|
|
|
|
|
|
document.querySelectorAll('.dropdown-toggle').forEach(toggle => { |
|
|
toggle.addEventListener('click', () => { |
|
|
const menu = toggle.nextElementSibling; |
|
|
menu.classList.toggle('active'); |
|
|
const icon = toggle.querySelector('i'); |
|
|
if (icon.classList.contains('fa-chevron-down')) { |
|
|
icon.classList.remove('fa-chevron-down'); |
|
|
icon.classList.add('fa-chevron-up'); |
|
|
} else { |
|
|
icon.classList.remove('fa-chevron-up'); |
|
|
icon.classList.add('fa-chevron-down'); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const tariffRateSlider = document.getElementById('tariffRate'); |
|
|
const tariffRateValue = document.getElementById('tariffRateValue'); |
|
|
tariffRateSlider.addEventListener('input', () => { |
|
|
tariffRateValue.textContent = `${tariffRateSlider.value}%`; |
|
|
}); |
|
|
|
|
|
|
|
|
function showNotification() { |
|
|
const notification = document.getElementById('notification'); |
|
|
notification.classList.add('show'); |
|
|
setTimeout(() => { |
|
|
notification.classList.remove('show'); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
|
|
|
const applyBtn = document.getElementById('applyFilters'); |
|
|
applyBtn.addEventListener('click', function() { |
|
|
this.classList.add('animate-pulse-slow'); |
|
|
this.innerHTML = '<i class="fas fa-spinner animate-spin mr-2"></i> Applying Filters'; |
|
|
|
|
|
setTimeout(() => { |
|
|
updateDashboard(); |
|
|
this.classList.remove('animate-pulse-slow'); |
|
|
this.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Apply Filters'; |
|
|
showNotification(); |
|
|
}, 1500); |
|
|
}); |
|
|
|
|
|
|
|
|
const resetBtn = document.getElementById('resetFilters'); |
|
|
resetBtn.addEventListener('click', function() { |
|
|
this.innerHTML = '<i class="fas fa-spinner animate-spin mr-2"></i> Resetting'; |
|
|
|
|
|
|
|
|
document.getElementById('fromDate').value = '2023-01-01'; |
|
|
document.getElementById('toDate').value = '2023-12-31'; |
|
|
document.getElementById('supplierName').value = 'all'; |
|
|
document.getElementById('supplierCountry').value = 'all'; |
|
|
document.getElementById('productCategory').value = 'all'; |
|
|
document.getElementById('hsCode').value = ''; |
|
|
document.getElementById('minValue').value = '500'; |
|
|
document.getElementById('maxValue').value = '10000'; |
|
|
document.getElementById('tariffRate').value = '10'; |
|
|
document.getElementById('tariffRateValue').textContent = '10%'; |
|
|
document.getElementById('tariffStatus').value = 'all'; |
|
|
document.getElementById('minTariffAmount').value = '50'; |
|
|
document.getElementById('maxTariffAmount').value = '2500'; |
|
|
document.getElementById('portEntry').value = 'all'; |
|
|
document.getElementById('shippingMethod').value = 'all'; |
|
|
|
|
|
setTimeout(() => { |
|
|
updateDashboard(true); |
|
|
this.innerHTML = '<i class="fas fa-redo mr-2"></i> Reset Filters'; |
|
|
showNotification(); |
|
|
}, 1500); |
|
|
}); |
|
|
|
|
|
|
|
|
function updateDashboard(reset = false) { |
|
|
if (reset) { |
|
|
|
|
|
resetChartData(); |
|
|
} else { |
|
|
|
|
|
const filteredData = generateFilteredData(); |
|
|
|
|
|
|
|
|
updateScorecards(filteredData); |
|
|
|
|
|
|
|
|
updateChartData(filteredData); |
|
|
|
|
|
|
|
|
updateTable(filteredData.tableData); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function generateFilteredData() { |
|
|
|
|
|
const data = { |
|
|
totalSpend: 2840000, |
|
|
impactedProducts: 187, |
|
|
activeSuppliers: 24, |
|
|
avgTariffRate: 8.7, |
|
|
monthlySpend: [210000, 180000, 240000, 300000, 280000, 310000, 350000, 320000, 380000, 420000, 400000, 450000], |
|
|
costReduction: 420000, |
|
|
mitigationSuccess: 87 |
|
|
}; |
|
|
|
|
|
|
|
|
const minTariff = parseInt(document.getElementById('minValue').value) || 0; |
|
|
const maxTariff = parseInt(document.getElementById('maxValue').value) || 10000; |
|
|
const tariffRate = parseInt(document.getElementById('tariffRate').value) || 10; |
|
|
|
|
|
|
|
|
const factor = 1 - (tariffRate - 10) / 30; |
|
|
data.totalSpend = data.totalSpend * factor; |
|
|
data.impactedProducts = Math.floor(data.impactedProducts * factor); |
|
|
data.avgTariffRate = data.avgTariffRate * factor; |
|
|
data.costReduction = data.costReduction * factor; |
|
|
data.mitigationSuccess = data.mitigationSuccess * factor; |
|
|
|
|
|
return { |
|
|
...data, |
|
|
tableData: [...tableData] |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
function resetChartData() { |
|
|
|
|
|
lineChart.data.datasets[0].data = [210000, 180000, 240000, 300000, 280000, 310000, 350000, 320000, 380000, 420000, 400000, 450000]; |
|
|
lineChart.update(); |
|
|
|
|
|
|
|
|
doughnutChart.data.datasets[0].data = [35, 25, 20, 15, 3, 2]; |
|
|
doughnutChart.update(); |
|
|
|
|
|
|
|
|
barChart.data.datasets[0].data = [125, 90, 80, 70, 50]; |
|
|
barChart.update(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.querySelector('.scorecard:nth-child(1) h3').textContent = '$2.84M'; |
|
|
document.querySelector('.scorecard:nth-child(2) h3').textContent = '187'; |
|
|
document.querySelector('.scorecard:nth-child(3) h3').textContent = '24'; |
|
|
document.querySelector('.scorecard:nth-child(4) h3').textContent = '8.7%'; |
|
|
document.querySelector('.scorecard:nth-child(5) h3').textContent = '$420K'; |
|
|
document.querySelector('.scorecard:nth-child(6) h3').textContent = '87%'; |
|
|
|
|
|
|
|
|
const tbody = document.getElementById('tableBody'); |
|
|
tbody.innerHTML = ''; |
|
|
tableData.forEach(row => { |
|
|
const tr = createTableRow(row); |
|
|
tbody.appendChild(tr); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const tableData = [ |
|
|
{id: 'AP-8708-102', name: 'Fuel Injector', category: 'Engine', supplier: 'DynaParts', origin: 'China', hscode: '8708.99.1560', value: 2450, rate: 15, amount: 367.50, status: 'Paid'}, |
|
|
{id: 'AP-8701-405', name: 'Transmission Gear', category: 'Transmission', supplier: 'TechAuto', origin: 'Japan', hscode: '8701.20.0040', value: 3250, rate: 2.5, amount: 81.25, status: 'Exempted'}, |
|
|
{id: 'AP-8708-230', name: 'Brake Caliper', category: 'Braking', supplier: 'EuroAuto', origin: 'Germany', hscode: '8708.30.5010', value极: 1850, rate: 7.5, amount: 138.75, status: 'Pending'}, |
|
|
{id: 'AP-8708-101', name: 'Spark Plug', category: 'Engine', supplier: 'DynaParts', origin: 'China', hscode: '8708.99.1560', value: 850, rate: 15, amount: 127.50, status: 'Paid'}, |
|
|
{id: 'AP-8708-520', name: 'Headlight Assembly', category: 'Electrical', supplier: 'Precision', origin: 'Mexico', hscode: '8708.29.0030', value: 750, rate: 10, amount: 75.00, status: 'Under Appeal'}, |
|
|
{id: 'AP-8708-330', name: 'Control Arm', category: 'Chassis', supplier: 'Global', origin: 'India', hscode: '8708.50.6080', value: 1200, rate: 7.5, amount: 90.00, status: 'Paid'}, |
|
|
{id: 'AP-8708-455', name: 'Seat Frame', category: 'Interior', supplier: 'Precision', origin: 'South Korea', hscode: '8708.50.4560', value: 1850, rate: 12.5, amount: 231.25, status: 'Pending'}, |
|
|
{id: 'AP-8708-670', name: 'ECU Module', category: 'Electrical', supplier: 'TechAuto', origin: 'Japan', hscode: '8708.29.0050', value: 3250, rate: 5, amount: 162.50, status: 'Exempted'}, |
|
|
{id: 'AP-8708-770', name: 'Steering Rack', category: 'Chassis', supplier: 'Global', origin: 'China', hscode: '8708.50.7090', value: 2100, rate: 15, amount: 315.00, status: 'Paid'}, |
|
|
{id: 'AP-8701-310', name: 'Clutch Assembly', category: 'Transmission', supplier: 'Precision', origin: 'Mexico', hscode: '8708.99.1120', value: 1550, rate: 7.5, amount: 116.25, status: 'Pending'}, |
|
|
{id: 'AP-8708-999', name: 'Alternator', category: 'Electrical', supplier: 'Global', origin: 'Mexico', hscode: '8708.29.0040', value: 950, rate: 10, amount: 95.00, status: 'Paid'}, |
|
|
{id: 'AP-8708-777', name: 'Fuel Pump', category: 'Engine', supplier: 'DynaParts', origin: 'China', hscode: '8708.99.1580', value: 1250, rate: 15, amount: 187.50, status: 'Paid'}, |
|
|
{id: 'AP-8708-345', name: 'Shock Absorber', category: 'Chassis', supplier: 'TechAuto', origin: 'South Korea', hscode: '8708.50.7010', value: 850, rate: 7.5, amount: 63.75, status: 'Pending'}, |
|
|
{id: 'AP-8708-122', name: 'Radiator', category: 'Engine', supplier: 'EuroAuto', origin: 'Germany', hscode: '8708.99.1230', value: 1800, rate: 5, amount: 90.00, status: 'Exempted'}, |
|
|
{id: 'AP-8708-876', name: 'Dashboard Panel', category: 'Interior', supplier: 'Precision', origin: 'India', hscode: '8708.50.5010', value: 2100, rate: 12.5, amount: 262.50, status: 'Paid'} |
|
|
]; |
|
|
|
|
|
|
|
|
function createTableRow(row) { |
|
|
const tr = document.createElement('tr'); |
|
|
tr.innerHTML = ` |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${row.id}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.name}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.category}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.supplier}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.origin}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.hscode}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$${row.value.toLocaleString()}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${row.rate}%</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$${row.amount.toLocaleString()}</td> |
|
|
<td class="px-6 py-4 whitespace-nowrap"> |
|
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full |
|
|
${row.status === 'Paid' ? 'bg-green-100 text-green-800' : |
|
|
row.status === 'Pending' ? 'bg-yellow-100 text-yellow-800' : |
|
|
row.status === 'Exempted' ? 'bg-blue-100 text-blue-800' : |
|
|
'bg-red-100 text-red-800'}"> |
|
|
${row.status} |
|
|
</span> |
|
|
</td> |
|
|
`; |
|
|
|
|
|
|
|
|
tr.addEventListener('mouseenter', () => { |
|
|
tr.classList.add('highlight-row'); |
|
|
}); |
|
|
tr.addEventListener('mouseleave', () => { |
|
|
tr.classList.remove('highlight-row'); |
|
|
}); |
|
|
|
|
|
return tr; |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const lineCtx = document.getElementById('lineChart').getContext('2d'); |
|
|
lineChart = new Chart(lineCtx, { |
|
|
type: 'line', |
|
|
data: { |
|
|
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
|
|
datasets: [{ |
|
|
label: 'Tariff Spend ($)', |
|
|
data: [210000, 180000, 240000, 300000, 280000, 310000, 350000, 320000, 380000, 420000, 400000, 450000], |
|
|
borderColor: '#1d4ed8', |
|
|
backgroundColor: 'rgba(29, 78, 216, 0.05)', |
|
|
tension: 0.4, |
|
|
fill: true, |
|
|
borderWidth: 2 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return `$${context.parsed.y.toLocaleString()}`; |
|
|
} |
|
|
} |
|
|
} |
|
|
}, |
|
|
scales: { |
|
|
y: { |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return '$' + (value/1000).toFixed(0) + 'K'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const doughnutCtx = document.getElementById('doughnutChart').getContext('2d'); |
|
|
doughnutChart = new Chart(doughnutCtx, { |
|
|
type: 'doughnut', |
|
|
data: { |
|
|
labels: ['Engine', 'Electrical', 'Chassis', 'Interior', 'Transmission', 'Braking'], |
|
|
datasets: [{ |
|
|
data: [35, 25, 20, 15, 3, 2], |
|
|
backgroundColor: ['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#bfdbfe', '#dbeafe'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
cutout: '70%', |
|
|
plugins: { |
|
|
legend: { |
|
|
position: 'right' |
|
|
}, |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const barCtx = document.getElementById('barChart').getContext('2d'); |
|
|
barChart = new Chart(barCtx, { |
|
|
type: 'bar', |
|
|
data: { |
|
|
labels: ['Supplier A', 'Supplier B', 'Supplier C', 'Supplier D', 'Supplier E'], |
|
|
datasets: [{ |
|
|
label: 'Spend ($K)', |
|
|
data: [125, 90, 80, 70, 50], |
|
|
backgroundColor: '#10b981', |
|
|
borderRadius: 5, |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
scales: { |
|
|
y: { |
|
|
beginAtZero: true, |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return '$' + value + 'K'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const polarCtx = document.getElementById('polarChart').getContext('2d'); |
|
|
polarChart = new Chart(polarCtx, { |
|
|
type: 'polarArea', |
|
|
data: { |
|
|
labels: ['China', 'Germany', 'Mexico', 'Japan', 'South Korea', 'India'], |
|
|
datasets: [{ |
|
|
data: [65, 15, 10, 5, 4, 1], |
|
|
backgroundColor: ['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#bfdbfe', '#dbeafe'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const pieCtx = document.getElementById('pieChart').getContext('2极'); |
|
|
pieChart = new Chart(pieCtx, { |
|
|
type: 'pie', |
|
|
data: { |
|
|
labels: ['8708.10', '8708.29', '8708.50', '8708.70', '8708.99', '8701.20'], |
|
|
datasets: [{ |
|
|
data: [30, 25, 20, 15, 8, 2], |
|
|
backgroundColor: ['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#bfdbfe', '#dbeafe'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
legend: { |
|
|
position: 'right' |
|
|
}, |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const forecastCtx = document.getElementById('forecastChart').getContext('2d'); |
|
|
forecastChart = new Chart(forecastCtx, { |
|
|
type: 'line', |
|
|
data: { |
|
|
labels: ['Q1', 'Q2', 'Q3', 'Q4'], |
|
|
datasets: [ |
|
|
{ |
|
|
label: 'Actual', |
|
|
data: [530000, 730000, 650000, 950000], |
|
|
borderColor: '#1d4ed8', |
|
|
backgroundColor: 'rgba(29, 78, 216, 0.05)', |
|
|
tension: 0.4, |
|
|
fill: false, |
|
|
borderWidth: 2 |
|
|
}, |
|
|
{ |
|
|
label: 'Forecast', |
|
|
data: [null, null, null, 950000, 980000, 1020000, 1050000, 1100000], |
|
|
borderColor: '#10b981', |
|
|
borderDash: [5, 5], |
|
|
tension: 0.4, |
|
|
borderWidth: 2 |
|
|
} |
|
|
] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return `${context.dataset.label}: $${context.parsed.y.toLocaleString()}`; |
|
|
} |
|
|
} |
|
|
} |
|
|
}, |
|
|
scales: { |
|
|
y: { |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return '$' + (value/1000).toFixed(0) + 'K'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const correlationCtx = document.getElementById('correlationChart').getContext('2d'); |
|
|
correlationChart = new Chart(correlationCtx, { |
|
|
type: 'scatter', |
|
|
data: { |
|
|
datasets: [{ |
|
|
label: 'Value vs Tariff Paid', |
|
|
data: [ |
|
|
{x: 2450, y: 367.50}, |
|
|
{x: 3250, y: 81.25}, |
|
|
{x: 1850, y: 138.75}, |
|
|
{x: 850, y: 127.50}, |
|
|
{x: 750, y: 75.00}, |
|
|
{x: 1200, y: 90.00}, |
|
|
{x: 1850, y: 231.25}, |
|
|
{x: 3250, y: 162.50}, |
|
|
{x: 2100, y: 315.00}, |
|
|
{x: 1550, y: 116.25}, |
|
|
{x: 950, y: 95.00}, |
|
|
{x: 1250, y: 187.50}, |
|
|
{x: 850, y: 63.75}, |
|
|
{x: 1800, y: 90.00}, |
|
|
{x: 2100, y: 262.50} |
|
|
], |
|
|
backgroundColor: '#1d4ed8', |
|
|
pointRadius: 6, |
|
|
pointHoverRadius: 8 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return `Value: $${context.parsed.x}, Tariff: $${context.parsed.y}`; |
|
|
} |
|
|
} |
|
|
} |
|
|
}, |
|
|
scales: { |
|
|
x: { |
|
|
title: { |
|
|
display: true, |
|
|
text: 'Product Value ($)' |
|
|
}, |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return '$' + value; |
|
|
} |
|
|
} |
|
|
}, |
|
|
y: { |
|
|
title: { |
|
|
display: true, |
|
|
text: 'Tariff Amount ($)' |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const horizCtx = document.getElementById('horizBarChart').getContext('2d'); |
|
|
horizBarChart = new Chart(horizCtx, { |
|
|
type: 'bar', |
|
|
data: { |
|
|
labels: ['15%', '12.5%', '10%', '7.5%', '5%'], |
|
|
datasets: [{ |
|
|
label: 'Products Count', |
|
|
data: [20, 35, 75, 45, 12], |
|
|
backgroundColor: '#3b82f6', |
|
|
borderRadius: 5, |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
indexAxis: 'y', |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
scales: { |
|
|
x: { |
|
|
beginAtZero: true |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const portCtx = document.getElementById('portChart').getContext('2d'); |
|
|
portChart = new Chart(portCtx, { |
|
|
type: 'pie', |
|
|
data: { |
|
|
labels: ['Los Angeles', 'New York', 'Chicago', 'Houston', 'Miami'], |
|
|
datasets: [{ |
|
|
data: [52, 22, 12, 8, 6], |
|
|
backgroundColor: ['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd', '#bfdbfe'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
plugins: { |
|
|
legend: { |
|
|
position: 'right' |
|
|
}, |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const complianceCtx = document.getElementById('complianceChart').getContext('2d'); |
|
|
complianceChart = new Chart(complianceCtx, { |
|
|
type: 'doughnut', |
|
|
data: { |
|
|
labels: ['Paid', 'Pending', 'Exempted', 'Under Appeal'], |
|
|
datasets: [{ |
|
|
data: [62, 25, 8, 5], |
|
|
backgroundColor: ['#10b981', '#f59e0b', '#3b82f6', '#ef4444'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
cutout: '70%', |
|
|
plugins: { |
|
|
legend: { |
|
|
position: 'right' |
|
|
}, |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const avgSpendCtx = document.getElementById('avgSpendChart').getContext('2d'); |
|
|
avgSpendChart = new Chart(avgSpendCtx, { |
|
|
type: 'bar', |
|
|
data: { |
|
|
labels: ['Q1', 'Q2', 'Q3', 'Q4'], |
|
|
datasets: [{ |
|
|
label: 'Avg Tariff Spend', |
|
|
data: [87500, 101250, 89250, 105750], |
|
|
backgroundColor: '#8b5cf6', |
|
|
borderRadius: 5, |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
scales: { |
|
|
y: { |
|
|
beginAtZero: true, |
|
|
ticks: { |
|
|
callback: function(value) { |
|
|
return '$' + value.toLocaleString(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const costDistCtx = document.getElementById('costDistributionChart').getContext('2d'); |
|
|
costDistributionChart = new Chart(costDistCtx, { |
|
|
type: 'radar', |
|
|
data: { |
|
|
labels: ['Engine', 'Electrical', 'Chassis', 'Interior', 'Transmission', 'Braking'], |
|
|
datasets: [{ |
|
|
label: 'Cost Distribution', |
|
|
data: [35, 25, 20, 15, 3, 2], |
|
|
backgroundColor: 'rgba(59, 130, 246, 0.2)', |
|
|
borderColor: '#3b82f6', |
|
|
pointBackgroundColor: '#3b82f6', |
|
|
pointBorderColor: '#fff', |
|
|
pointHoverBackgroundColor: '#fff', |
|
|
pointHoverBorderColor: '#3b82f6' |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
scales: { |
|
|
r: { |
|
|
min: 极, |
|
|
max: 40, |
|
|
ticks: { |
|
|
stepSize: 10 |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const supplierVolCtx = document.getElementById('supplierVolumeChart').getContext('2d'); |
|
|
supplierVolumeChart = new Chart(supplierVolCtx, { |
|
|
type: 'doughnut', |
|
|
data: { |
|
|
labels: ['Supplier A', 'Supplier B', 'Supplier C', 'Others'], |
|
|
datasets: [{ |
|
|
data: [35, 25, 20, 20], |
|
|
backgroundColor: ['#1d4ed8', '#3b82f6', '#60a5fa', '#93c5fd'], |
|
|
borderWidth: 0 |
|
|
}] |
|
|
}, |
|
|
options: { |
|
|
responsive: true, |
|
|
maintainAspectRatio: false, |
|
|
cutout: '70%', |
|
|
plugins: { |
|
|
legend: { |
|
|
position: 'right' |
|
|
}, |
|
|
tooltip: { |
|
|
callbacks: { |
|
|
label: function(context) { |
|
|
return context.label + ': ' + context.parsed + '%'; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
const tableBody = document.getElementById('tableBody'); |
|
|
tableData.forEach(row => { |
|
|
const tr = createTableRow(row); |
|
|
tableBody.appendChild(tr); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('visibleRows').textContent = tableData.length; |
|
|
document.getElementById('totalRows').textContent = '25'; |
|
|
|
|
|
|
|
|
const searchInput = document.getElementById('searchInput'); |
|
|
const categoryFilter = document.getElementById('categoryFilter'); |
|
|
|
|
|
function filterTable() { |
|
|
const searchValue = searchInput.value.toLowerCase(); |
|
|
const categoryValue = categoryFilter.value; |
|
|
|
|
|
document.querySelectorAll('#tableBody tr').forEach(row => { |
|
|
const categoryCell = row.querySelector('td:nth-child(3)').textContent; |
|
|
const supplierCell = row.querySelector('td:nth-child(4)').textContent.toLowerCase(); |
|
|
const hscodeCell = row.querySelector('td:nth-child(6)').textContent.toLowerCase(); |
|
|
|
|
|
const matchesCategory = categoryValue === 'all' || categoryCell === categoryValue; |
|
|
const matchesSearch = !searchValue || |
|
|
supplierCell.includes(searchValue) || |
|
|
hscodeCell.includes(searchValue) || |
|
|
row.textContent.toLowerCase().includes(searchValue); |
|
|
|
|
|
row.style.display = (matchesCategory && matchesSearch) ? '' : 'none'; |
|
|
}); |
|
|
} |
|
|
|
|
|
searchInput.addEventListener('input', filterTable); |
|
|
categoryFilter.addEventListener('change', filterTable); |
|
|
}); |
|
|
|
|
|
|
|
|
function updateChartData(data) { |
|
|
|
|
|
const factor = 1 - (parseInt(document.getElementById('tariffRate').value) - 10) / 30; |
|
|
const filteredLineData = data.monthlySpend.map(val => Math.round(val * factor)); |
|
|
lineChart.data.datasets[0].data = filteredLineData; |
|
|
lineChart.update(); |
|
|
|
|
|
|
|
|
horizBarChart.data.datasets[0].data = [20, 35, 75, 45, 12].map(val => Math.round(val * factor)); |
|
|
horizBarChart.update(); |
|
|
|
|
|
|
|
|
const variationFactor = Math.max(0.8, factor); |
|
|
|
|
|
|
|
|
doughnutChart.data.datasets[0].data = [35, 25, 20, 15, 3, 2].map(val => Math.round(val * variationFactor)); |
|
|
doughnutChart.update(); |
|
|
|
|
|
|
|
|
barChart.data.datasets[0].data = [125, 90, 80, 70, 50].map(val => Math.round(val * variationFactor)); |
|
|
barChart.update(); |
|
|
|
|
|
|
|
|
polarChart.data.datasets[0].data = [65, 15, 10, 5, 4, 1].map(val => Math.round(val * variationFactor)); |
|
|
polarChart.update(); |
|
|
|
|
|
|
|
|
pieChart.data.datasets[0].data = [30, 25, 20, 15, 8, 2].map(val => Math.round(val * variationFactor)); |
|
|
pieChart.update(); |
|
|
|
|
|
|
|
|
forecastChart.data.datasets[0].data = [530000, 730000, 650000, 950000].map(val => Math.round(val * factor)); |
|
|
forecastChart.data.datasets[1].data = [null, null, null, 950000, 980000, 1020000, 1050000, 1100000].map(val => |
|
|
val ? Math.round(val * factor) : null |
|
|
); |
|
|
forecastChart.update(); |
|
|
|
|
|
|
|
|
correlationChart.data.datasets[0].data = correlationChart.data.datasets[0].data.map(point => ({ |
|
|
x: Math.round(point.x * variationFactor), |
|
|
y: Math.round(point.y * variationFactor) |
|
|
})); |
|
|
correlationChart.update(); |
|
|
|
|
|
|
|
|
document.querySelector('.scorecard:nth-child(1) h3').textContent = '$' + (data.totalSpend/1000000).toFixed(2) + 'M'; |
|
|
document.querySelector('.scorecard:nth-child(2) h3').textContent = data.impactedProducts; |
|
|
document.querySelector('.scorecard:nth-child(3) h3').textContent = data.activeSuppliers; |
|
|
document.querySelector('.scorecard:nth-child(4) h3').textContent = data.avgTariffRate.toFixed(1) + '%'; |
|
|
document.querySelector('.scorecard:nth-child(5) h3').textContent = '$' + (data.costReduction/1000).toFixed(0) + 'K'; |
|
|
document.querySelector('.scorecard:nth-child(6) h3').textContent = data.mitigationSuccess.toFixed(0) + '%'; |
|
|
|
|
|
|
|
|
complianceChart.data.datasets[0].data = [62, 25, 8, 5].map(val => Math.round(val * variationFactor)); |
|
|
complianceChart.update(); |
|
|
|
|
|
|
|
|
costDistributionChart.data.datasets[0].data = [35, 25, 20, 15, 3, 2].map(val => Math.round(val * variationFactor)); |
|
|
costDistributionChart.update(); |
|
|
|
|
|
|
|
|
avgSpendChart.data.datasets[0].data = [87500, 101250, 89250, 105750].map(val => Math.round(val * variationFactor)); |
|
|
avgSpendChart.update(); |
|
|
|
|
|
|
|
|
supplierVolumeChart.data.datasets[0].data = [35, 25, 20, 20].map(val => Math.round(val * variationFactor)); |
|
|
supplierVolumeChart.update(); |
|
|
|
|
|
|
|
|
const minValue = parseInt(document.getElementById('minValue').value) || 0; |
|
|
const maxValue = parseInt(document.getElementById('maxValue').value) || 10000; |
|
|
const minTariff = parseInt(document.getElementById('minTariffAmount').value) || 0; |
|
|
const maxTariff = parseInt(document.getElementById('maxTariffAmount').value) || 2500; |
|
|
const supplierName = document.getElementById('supplierName').value; |
|
|
const supplierCountry = document.getElementById('supplierCountry').value; |
|
|
const tariffStatus = document.getElementById('tariffStatus').value; |
|
|
const portEntry = document.getElementById('portEntry').value; |
|
|
const shippingMethod = document.getElementById('shippingMethod').value; |
|
|
const productCategory = document.getElementById('productCategory').value; |
|
|
const hsCode = document.getElementById('hsCode').value.toLowerCase(); |
|
|
|
|
|
|
|
|
const filteredTableData = tableData.filter(row => { |
|
|
const matchesValue = row.value >= minValue && row.value <= maxValue; |
|
|
const matchesTariffAmount = row.amount >= minTariff && row.amount <= maxTariff; |
|
|
const matchesSupplier = supplierName === 'all' || row.supplier === supplierName; |
|
|
const matchesCountry = supplierCountry === 'all' || row.origin === supplierCountry; |
|
|
const matchesStatus = tariffStatus === 'all' || row.status === tariffStatus; |
|
|
const matchesPort = portEntry === 'all' || true; |
|
|
const matchesMethod = shippingMethod === 'all' || true; |
|
|
const matchesCategory = productCategory === 'all' || row.category === productCategory; |
|
|
const matchesHSCode = !hsCode || row.hscode.includes(hsCode); |
|
|
|
|
|
return matchesValue && matchesTariffAmount && matchesSupplier && matchesCountry && |
|
|
matchesStatus && matchesPort && matchesMethod && matchesCategory && matchesHSCode; |
|
|
}); |
|
|
|
|
|
|
|
|
const tbody = document.getElementById('tableBody'); |
|
|
tbody.innerHTML = ''; |
|
|
filteredTableData.forEach(row => { |
|
|
const tr = createTableRow(row); |
|
|
tbody.appendChild(tr); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('visibleRows').textContent = filteredTableData.length; |
|
|
} |
|
|
|
|
|
|
|
|
function updateScorecards(data) { |
|
|
document.querySelector('.scorecard:nth-child(1) h3').textContent = '$' + (data.totalSpend/1000000).toFixed(2) + 'M'; |
|
|
document.querySelector('.scorecard:nth-child(2) h3').textContent = data.impactedProducts; |
|
|
document.querySelector('.scorecard:nth-child(3) h3').textContent = data.activeSuppliers; |
|
|
document.querySelector('.scorecard:nth-child(4) h3').textContent = data.avgTariffRate.toFixed(1) + '%'; |
|
|
document.querySelector('.scorecard:nth-child(5) h3').textContent = '$' + (data.costReduction/1000).toFixed(0) + 'K'; |
|
|
document.querySelector('.scorecard:nth-child(6) h3').textContent = data.mitigationSuccess.toFixed(0) + '%'; |
|
|
} |
|
|
</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://huggingface.co/proxy/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://huggingface.co/proxy/enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://huggingface.co/proxy/enzostvs-deepsite.hf.space?remix=anonymous111110987654321/autoparts-tariff-tracker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |