marco.asseto.prototype/inventory.html
Vaibhav Surve 2dfe150a5c feat: AMS V1 — multi-page HTML prototype
- Login page with animated floating stat cards
- Executive dashboard with Chart.js KPIs and activity feed
- Full asset registry (list, search, filter, bulk actions, QR)
- Asset detail page with 6 tabs (financial, maintenance, history…)
- 3-step asset creation wizard with category-specific fields
- Inventory: stock overview, GRN, location tree, physical audit
- Procurement: PR → approval → PO → GRN → asset lifecycle
- Maintenance: Kanban board, PM schedule, AMC contracts
- Reports: depreciation schedule, utilization, compliance gauge
- User management: roles, permission matrix, session control
- Settings: 8 config sections (org, depreciation, security, integrations)
- Premium dark UI with CSS variables, Chart.js 4, toast system
2026-05-28 18:09:32 +05:30

384 lines
21 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Inventory | AMS</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
</head>
<body>
<div class="app-layout">
<aside class="sidebar">
<div class="sidebar-logo"><div class="logo-icon">📦</div><div><div class="logo-title">AMS</div><div class="logo-sub">Asset Management</div></div></div>
<nav class="sidebar-nav">
<div class="nav-section-label">Overview</div>
<a href="dashboard.html" class="nav-item"><span class="nav-icon">📊</span> Dashboard</a>
<div class="nav-section-label">Assets</div>
<a href="assets.html" class="nav-item"><span class="nav-icon">📦</span> All Assets</a>
<a href="asset-create.html" class="nav-item"><span class="nav-icon"></span> Add Asset</a>
<div class="nav-section-label">Supply Chain</div>
<a href="inventory.html" class="nav-item active"><span class="nav-icon">🏪</span> Inventory</a>
<a href="procurement.html" class="nav-item"><span class="nav-icon">🛒</span> Procurement</a>
<div class="nav-section-label">Operations</div>
<a href="maintenance.html" class="nav-item"><span class="nav-icon">🔧</span> Maintenance</a>
<a href="reports.html" class="nav-item"><span class="nav-icon">📈</span> Reports</a>
<div class="nav-section-label">Administration</div>
<a href="users.html" class="nav-item"><span class="nav-icon">👥</span> Users</a>
<a href="settings.html" class="nav-item"><span class="nav-icon">⚙️</span> Settings</a>
</nav>
<div class="sidebar-footer"><div class="user-card"><div class="user-av">AS</div><div style="flex:1;min-width:0"><div class="user-name">Arjun Sharma</div><div class="user-role">Asset Manager</div></div></div></div>
</aside>
<div class="main-wrapper">
<header class="topbar">
<div class="topbar-left"><div class="topbar-title">Inventory Management</div></div>
<div class="topbar-actions">
<button class="btn btn-primary btn-sm" onclick="openModal('grnModal')">📋 Record GRN</button>
<button class="btn btn-secondary btn-sm" onclick="openModal('auditModal')">🔍 Physical Audit</button>
<a href="index.html" class="icon-btn">🚪</a>
</div>
</header>
<main class="content">
<!-- Alerts -->
<div id="invAlerts" class="mb-4"></div>
<!-- KPIs -->
<div class="grid-4 mb-4" id="invStats"></div>
<!-- Tabs -->
<div class="tab-container">
<div class="tabs" data-group="inv">
<button class="tab-btn active" data-tab="tab-stock" data-group="inv">📊 Stock Overview</button>
<button class="tab-btn" data-tab="tab-location" data-group="inv">📍 By Location</button>
<button class="tab-btn" data-tab="tab-movement" data-group="inv">↔ Movement Log</button>
<button class="tab-btn" data-tab="tab-audit" data-group="inv">🔍 Audit Results</button>
</div>
<!-- Stock Overview -->
<div class="tab-content active" id="tab-stock" data-group="inv">
<div class="grid-2 mb-4">
<div class="card">
<div class="card-header"><span class="card-title">📊 Stock by Category</span></div>
<div class="card-body"><canvas id="stockChart" height="240"></canvas></div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">⚠️ Low Stock Alerts</span><span class="badge badge-danger">5 items</span></div>
<div class="card-body" id="lowStockList"></div>
</div>
</div>
<div class="table-wrapper">
<table class="data-table" id="stockTable">
<thead><tr><th>Category</th><th>Total Assets</th><th>Active</th><th>Idle</th><th>Maintenance</th><th>Min Threshold</th><th>Status</th><th>Actions</th></tr></thead>
<tbody id="stockTbody"></tbody>
</table>
</div>
</div>
<!-- By Location -->
<div class="tab-content" id="tab-location" data-group="inv">
<div style="display:grid;grid-template-columns:280px 1fr;gap:16px">
<div class="card">
<div class="card-header"><span class="card-title">📍 Location Tree</span></div>
<div class="card-body">
<ul class="tree-list" id="locationTree"></ul>
</div>
</div>
<div class="card">
<div class="card-header"><span class="card-title" id="locDetailTitle">Select a location</span></div>
<div class="card-body" id="locDetailContent">
<div class="empty-state"><div class="empty-icon">📍</div><div class="empty-title">No location selected</div><div class="empty-text">Click on a location from the tree to view its assets</div></div>
</div>
</div>
</div>
</div>
<!-- Movement Log -->
<div class="tab-content" id="tab-movement" data-group="inv">
<div class="filters-row mb-4">
<div class="search-wrap" style="max-width:280px"><span style="color:var(--text-muted)">🔍</span><input type="text" placeholder="Search movements…" id="movSearch"></div>
<select class="filter-sel"><option>All Types</option><option>Inward (GRN)</option><option>Outward (Issue)</option><option>Transfer</option><option>Disposal</option></select>
<select class="filter-sel"><option>All Departments</option><option>IT</option><option>Finance</option><option>HR</option><option>Operations</option></select>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead><tr><th>Date</th><th>Movement Type</th><th>Asset / Item</th><th>From</th><th>To</th><th>Qty</th><th>Reference</th><th>By</th></tr></thead>
<tbody id="movTbody"></tbody>
</table>
</div>
</div>
<!-- Audit Results -->
<div class="tab-content" id="tab-audit" data-group="inv">
<div class="grid-3 mb-4">
<div class="stat-card" style="--sc-color:var(--success)">
<div class="stat-icon" style="background:var(--success-bg);color:var(--success)"></div>
<div class="stat-label">Assets Found</div>
<div class="stat-value" style="color:var(--success)">1,198</div>
<div class="stat-change up">96.1% of total</div>
</div>
<div class="stat-card" style="--sc-color:var(--danger)">
<div class="stat-icon" style="background:var(--danger-bg);color:var(--danger)"></div>
<div class="stat-label">Not Found</div>
<div class="stat-value" style="color:var(--danger)">49</div>
<div class="stat-change down">3.9% Under investigation</div>
</div>
<div class="stat-card" style="--sc-color:var(--warning)">
<div class="stat-icon" style="background:var(--warning-bg);color:var(--warning)">⚠️</div>
<div class="stat-label">Discrepancies</div>
<div class="stat-value" style="color:var(--warning)">7</div>
<div class="stat-change down">Location mismatches</div>
</div>
</div>
<div class="alert alert-info mb-4">
<div class="alert-icon"></div>
<div><div class="alert-title">Last Physical Audit: Q4 FY 2024-25 (March 2025)</div>
<div class="alert-text">Next scheduled audit: Q2 FY 2025-26 (September 2025). Audited by: Kavya Nair, Deepak Joshi</div>
</div>
<button class="btn btn-primary btn-sm" style="margin-left:auto;flex-shrink:0" onclick="openModal('auditModal')">Start New Audit</button>
</div>
<div class="table-wrapper">
<table class="data-table">
<thead><tr><th>Asset ID</th><th>Asset Name</th><th>System Location</th><th>Physical Location</th><th>Status</th><th>Action</th></tr></thead>
<tbody id="auditTbody"></tbody>
</table>
</div>
</div>
</div>
</main>
</div>
</div>
<!-- GRN Modal -->
<div class="modal-overlay" id="grnModal">
<div class="modal modal-lg">
<div class="modal-header"><span class="modal-title">📋 Record Goods Receipt Note (GRN)</span><button class="modal-close"></button></div>
<div class="modal-body">
<div class="form-row">
<div class="form-group"><label class="form-label">GRN Number</label><input class="form-input" value="GRN-2025-042" readonly></div>
<div class="form-group"><label class="form-label">PO Reference <span class="req">*</span></label><select class="form-select"><option>PO-2025-001 5× Dell Laptops</option><option>PO-2025-002 8× TP-Link WAP</option><option>PO-2025-003 Office Chairs</option></select></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Vendor</label><input class="form-input" value="Dell India Pvt. Ltd." readonly></div>
<div class="form-group"><label class="form-label">Receipt Date <span class="req">*</span></label><input type="date" class="form-input" value="2025-05-28"></div>
</div>
<div class="section-hdr mt-4">Items Received</div>
<table class="data-table" style="margin-bottom:14px">
<thead><tr><th>Item</th><th>Ordered Qty</th><th>Received Qty</th><th>Condition</th><th>Remarks</th></tr></thead>
<tbody>
<tr><td>Dell Latitude 5540 Laptop</td><td>5</td><td><input type="number" class="form-input" value="5" style="width:60px;padding:4px 8px"></td><td><select class="form-select" style="padding:4px 8px"><option>Good</option><option>Damaged</option><option>Partial</option></select></td><td><input class="form-input" placeholder="Notes" style="padding:4px 8px"></td></tr>
</tbody>
</table>
<div class="form-group"><label class="form-label">Received By <span class="req">*</span></label><input class="form-input" value="Arjun Sharma"></div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('grnModal')">Cancel</button>
<button class="btn btn-primary" onclick="saveGRN()">Save GRN & Create Assets</button>
</div>
</div>
</div>
<!-- Audit Modal -->
<div class="modal-overlay" id="auditModal">
<div class="modal">
<div class="modal-header"><span class="modal-title">🔍 Start Physical Audit</span><button class="modal-close"></button></div>
<div class="modal-body">
<div class="form-group"><label class="form-label">Audit Name <span class="req">*</span></label><input class="form-input" value="Q2 FY2025-26 Physical Audit"></div>
<div class="form-row">
<div class="form-group"><label class="form-label">Scope</label><select class="form-select"><option>All Locations</option><option>Floor 2 Only</option><option>Server Room</option><option>Warehouse</option></select></div>
<div class="form-group"><label class="form-label">Assigned Auditors</label><input class="form-input" value="Kavya Nair, Deepak Joshi"></div>
</div>
<div class="form-row">
<div class="form-group"><label class="form-label">Start Date</label><input type="date" class="form-input" value="2025-06-01"></div>
<div class="form-group"><label class="form-label">End Date</label><input type="date" class="form-input" value="2025-06-05"></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('auditModal')">Cancel</button>
<button class="btn btn-primary" onclick="startAudit()">Start Audit</button>
</div>
</div>
</div>
<div class="toast-container" id="toastContainer"></div>
<script src="js/data.js"></script>
<script src="js/app.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
renderAlerts();
renderStats();
renderStockTable();
renderLowStock();
renderMovements();
renderAudit();
renderLocationTree();
renderStockChart();
initTabs();
initTrees();
});
function renderAlerts() {
document.getElementById('invAlerts').innerHTML = `
<div class="alert alert-warning">
<div class="alert-icon">⚠️</div>
<div><div class="alert-title">5 categories below minimum stock threshold</div><div class="alert-text">Toner Cartridges, Projector Lamps, UPS Batteries, Network Cables, Keyboard/Mouse sets need reorder</div></div>
<a href="procurement.html" class="btn btn-warning btn-sm" style="margin-left:auto;flex-shrink:0;color:var(--warning);background:var(--warning-bg);border-color:rgba(245,158,11,.2)">Raise PR →</a>
</div>`;
}
function renderStats() {
const stats = [
{ label:'Total Items', icon:'📦', val:'1,247', color:'var(--primary)' },
{ label:'Active', icon:'✅', val:'1,089', color:'var(--success)' },
{ label:'Low Stock', icon:'📉', val:'5', color:'var(--danger)' },
{ label:'Pending GRNs', icon:'📋', val:'3', color:'var(--warning)' }
];
document.getElementById('invStats').innerHTML = stats.map(s=>`
<div class="stat-card" style="--sc-color:${s.color}">
<div class="stat-icon" style="background:${s.color}18;color:${s.color}">${s.icon}</div>
<div class="stat-label">${s.label}</div>
<div class="stat-value" style="color:${s.color}">${s.val}</div>
</div>`).join('');
}
function renderStockTable() {
document.getElementById('stockTbody').innerHTML = AMS.categories.map(c => {
const idle = Math.floor(c.count * 0.05);
const maint = Math.floor(c.count * 0.04);
const active = c.count - idle - maint;
const below = active < c.minStock;
return `<tr>
<td><div class="flex items-center gap-2">${c.icon} <strong>${c.name}</strong></div></td>
<td><strong>${c.count}</strong></td>
<td style="color:var(--success)">${active}</td>
<td style="color:var(--warning)">${idle}</td>
<td style="color:var(--info)">${maint}</td>
<td>${c.minStock}</td>
<td><span class="badge ${below?'badge-danger':'badge-success'}">${below?'⚠ Low Stock':'✓ OK'}</span></td>
<td><button class="btn btn-ghost btn-sm" onclick="showToast('Threshold','Opening threshold config','info')">⚙️ Config</button></td>
</tr>`;
}).join('');
}
function renderLowStock() {
const low = [
{ name:'Toner Cartridges', cat:'Consumables', current:2, min:10, icon:'🖨️' },
{ name:'Projector Lamps', cat:'AV Equipment',current:0, min:2, icon:'💡' },
{ name:'UPS Batteries', cat:'Power Equip', current:1, min:3, icon:'🔋' },
{ name:'Cat6 Network Cable', cat:'Networking',current:3, min:10, icon:'🔌' },
{ name:'Keyboard & Mouse Sets', cat:'Peripherals',current:4, min:15, icon:'⌨️' }
];
document.getElementById('lowStockList').innerHTML = low.map(l=>`
<div class="flex items-center gap-3 mb-3" style="padding:10px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid rgba(239,68,68,.15)">
<span style="font-size:20px">${l.icon}</span>
<div style="flex:1">
<div style="font-size:13px;font-weight:600">${l.name}</div>
<div style="font-size:11px;color:var(--text-muted)">${l.cat} · Min: ${l.min}</div>
<div class="progress-wrap mt-2" style="height:4px">
<div class="progress-fill" style="width:${Math.round(l.current/l.min*100)}%;background:linear-gradient(90deg,var(--danger),var(--warning))"></div>
</div>
</div>
<div style="text-align:right">
<div style="font-size:16px;font-weight:800;color:var(--danger)">${l.current}</div>
<div style="font-size:10px;color:var(--text-muted)">in stock</div>
</div>
</div>`).join('') + `<a href="procurement.html" class="btn btn-primary btn-sm w-full" style="margin-top:8px">Raise Purchase Request →</a>`;
}
function renderMovements() {
const movs = [
{ date:'2025-05-28', type:'Inward (GRN)', item:'Dell Latitude 5540 Laptop', from:'Vendor', to:'Warehouse', qty:5, ref:'GRN-2025-041', by:'Arjun Sharma' },
{ date:'2025-05-27', type:'Outward (Issue)', item:'TP-Link WAP EAP670 (×8)', from:'Warehouse', to:'IT Dept Floor 3', qty:8, ref:'ISS-2025-022', by:'Kavya Nair' },
{ date:'2025-05-26', type:'Transfer', item:'Epson Projector', from:'Marketing F3', to:'Conference Room A', qty:1, ref:'TRF-2025-015', by:'Deepak Joshi' },
{ date:'2025-05-25', type:'Disposal', item:'HP ProBook 440 G4 (×2)', from:'IT Dept', to:'Disposed', qty:2, ref:'DSP-2025-008', by:'Arjun Sharma' },
{ date:'2025-05-24', type:'Outward (Issue)', item:'Steelcase Chair (×10)', from:'Warehouse', to:'Floor 3 Expansion', qty:10, ref:'ISS-2025-021', by:'Deepak Joshi' },
{ date:'2025-05-22', type:'Inward (GRN)', item:'Cisco IP Phone 8841 (×5)', from:'Vendor', to:'Warehouse', qty:5, ref:'GRN-2025-040', by:'Kavya Nair' }
];
const typeColor = {'Inward (GRN)':'badge-success','Outward (Issue)':'badge-info','Transfer':'badge-primary','Disposal':'badge-danger'};
document.getElementById('movTbody').innerHTML = movs.map(m=>`
<tr>
<td>${fmtDate(m.date)}</td>
<td><span class="badge ${typeColor[m.type]||'badge-neutral'}">${m.type}</span></td>
<td style="font-weight:600;color:var(--text-primary)">${m.item}</td>
<td>${m.from}</td>
<td>${m.to}</td>
<td style="font-weight:700">${m.qty}</td>
<td><code style="font-size:11px;color:var(--primary-light)">${m.ref}</code></td>
<td>${m.by}</td>
</tr>`).join('');
}
function renderAudit() {
const discrepancies = [
{ id:'AST-2025-007', name:'Epson Projector', sysLoc:'Marketing F3', phyLoc:'Conference Room A', status:'Location Mismatch' },
{ id:'AST-2025-015', name:'HP ProDesk 600', sysLoc:'Finance F1', phyLoc:'Not Found', status:'Missing' },
{ id:'AST-2025-012', name:'APC UPS 3KVA', sysLoc:'Server Room B1', phyLoc:'Server Room B1', status:'Found' }
];
document.getElementById('auditTbody').innerHTML = discrepancies.map(d=>`
<tr>
<td><code style="font-size:11px;color:var(--primary-light)">${d.id}</code></td>
<td style="font-weight:600;color:var(--text-primary)">${d.name}</td>
<td>${d.sysLoc}</td>
<td>${d.phyLoc}</td>
<td><span class="badge ${d.status==='Found'?'badge-success':d.status==='Missing'?'badge-danger':'badge-warning'}">${d.status}</span></td>
<td><button class="btn btn-ghost btn-sm" onclick="showToast('Update','Location updated in system','success')">Update</button></td>
</tr>`).join('');
}
function renderLocationTree() {
function buildTree(nodes) {
return `<ul class="tree-list" style="padding-left:0">
${nodes.map(n => `
<li class="tree-node">
<div class="tree-label tree-toggle ${n.children?'':'leaf'}" onclick="${n.children?'':(`selectLocation('${n.id}','${n.name}')`)}" style="${n.children?'':''}" >
${n.children ? `<span class="tree-arrow" style="font-size:10px">▶</span>` : `<span style="font-size:10px;color:var(--text-muted)">•</span>`}
<span>${n.children ? '📁' : '📍'} ${n.name}</span>
</div>
${n.children ? `<div class="tree-children">${buildTree(n.children)}</div>` : ''}
</li>`).join('')}
</ul>`;
}
document.getElementById('locationTree').outerHTML = `<div id="locationTree">${buildTree(AMS.locations)}</div>`;
initTrees();
}
function selectLocation(id, name) {
document.querySelectorAll('.tree-label').forEach(el => el.classList.remove('selected'));
document.getElementById('locDetailTitle').textContent = `📍 ${name}`;
const locAssets = AMS.assets.filter(a => a.loc.includes(name.split('').pop().trim()) || Math.random() > .4).slice(0,6);
document.getElementById('locDetailContent').innerHTML = `
<div style="font-size:12px;color:var(--text-muted);margin-bottom:14px">Showing ${locAssets.length} assets in <strong>${name}</strong></div>
${locAssets.map(a=>`
<div class="flex items-center gap-3 mb-3" style="padding:10px;background:var(--bg-surface);border-radius:var(--radius-md);cursor:pointer" onclick="window.location.href='asset-detail.html?id=${a.id}'">
<span style="font-size:18px">${a.icon}</span>
<div style="flex:1"><div style="font-size:13px;font-weight:600">${a.name}</div><div style="font-size:11px;color:var(--text-muted)">${a.id} · ${a.assignee}</div></div>
<span class="badge ${statusBadge(a.status)}">${a.status}</span>
</div>`).join('')}`;
}
function renderStockChart() {
new Chart(document.getElementById('stockChart'), {
type:'bar',
data:{
labels: AMS.categories.map(c=>c.name),
datasets:[
{ label:'Active', data:AMS.categories.map(c=>Math.floor(c.count*.91)), backgroundColor:'rgba(16,185,129,.7)', borderRadius:4 },
{ label:'Idle', data:AMS.categories.map(c=>Math.floor(c.count*.05)), backgroundColor:'rgba(245,158,11,.7)', borderRadius:4 },
{ label:'Maintenance', data:AMS.categories.map(c=>Math.floor(c.count*.04)), backgroundColor:'rgba(59,130,246,.7)', borderRadius:4 }
]
},
options:{
responsive:true, maintainAspectRatio:false, plugins:{legend:{labels:{color:'#94A3B8',font:{family:'Inter',size:11},usePointStyle:true}}},
scales:{x:{stacked:true,grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:9},maxRotation:45}},
y:{stacked:true,grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:11}}}}
}
});
}
function saveGRN() { closeModal('grnModal'); showToast('GRN Saved','5 assets created from GRN-2025-042','success'); }
function startAudit() { closeModal('auditModal'); showToast('Audit Started','Q2 Physical Audit initiated. Auditors notified.','info'); }
</script>
</body>
</html>