- 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
495 lines
29 KiB
HTML
495 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Asset Detail | 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">
|
||
<!-- SIDEBAR -->
|
||
<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 active"><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"><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>
|
||
|
||
<!-- MAIN -->
|
||
<div class="main-wrapper">
|
||
<header class="topbar">
|
||
<div class="topbar-left">
|
||
<button onclick="history.back()" class="btn btn-ghost btn-sm" style="margin-right:6px">← Back</button>
|
||
<div class="topbar-title" id="assetHeaderTitle">Asset Detail</div>
|
||
</div>
|
||
<div class="topbar-actions">
|
||
<button class="btn btn-secondary btn-sm" onclick="openModal('editModal')">✏️ Edit</button>
|
||
<button class="btn btn-secondary btn-sm" onclick="openModal('assignModal')">👤 Assign</button>
|
||
<button class="btn btn-secondary btn-sm" onclick="openModal('transferModal')">↔ Transfer</button>
|
||
<button class="btn btn-danger btn-sm" onclick="confirmDispose()">🗑️ Dispose</button>
|
||
<a href="index.html" class="icon-btn">🚪</a>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="content">
|
||
<!-- Asset Header -->
|
||
<div class="card mb-4" id="assetHeader"></div>
|
||
|
||
<!-- Tabs -->
|
||
<div class="tab-container">
|
||
<div class="tabs" data-group="detail">
|
||
<button class="tab-btn active" data-tab="tab-overview" data-group="detail">📋 Overview</button>
|
||
<button class="tab-btn" data-tab="tab-financial" data-group="detail">💰 Financial</button>
|
||
<button class="tab-btn" data-tab="tab-assignments" data-group="detail">👤 Assignments</button>
|
||
<button class="tab-btn" data-tab="tab-maintenance" data-group="detail">🔧 Maintenance</button>
|
||
<button class="tab-btn" data-tab="tab-documents" data-group="detail">📄 Documents</button>
|
||
<button class="tab-btn" data-tab="tab-history" data-group="detail">🕐 History</button>
|
||
</div>
|
||
|
||
<!-- Overview Tab -->
|
||
<div class="tab-content active" id="tab-overview" data-group="detail">
|
||
<div class="grid-2">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">📋 Asset Information</span></div>
|
||
<div class="card-body" id="assetInfoGrid"></div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">📍 Location & Assignment</span></div>
|
||
<div class="card-body" id="assetLocationGrid"></div>
|
||
</div>
|
||
</div>
|
||
<div class="grid-2 mt-4">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">📱 QR Code</span>
|
||
<button class="btn btn-secondary btn-sm" onclick="printQR()">🖨️ Print</button></div>
|
||
<div class="card-body" style="text-align:center" id="assetQR"></div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">🔧 Custom Fields</span></div>
|
||
<div class="card-body" id="assetCustomFields"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Financial Tab -->
|
||
<div class="tab-content" id="tab-financial" data-group="detail">
|
||
<div class="grid-2">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">💰 Depreciation</span></div>
|
||
<div class="card-body">
|
||
<div id="depreciationInfo"></div>
|
||
<canvas id="depChart" height="180"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">📊 Value Summary</span></div>
|
||
<div class="card-body" id="valueSummary"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Assignments Tab -->
|
||
<div class="tab-content" id="tab-assignments" data-group="detail">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">👤 Assignment History</span>
|
||
<button class="btn btn-primary btn-sm" onclick="openModal('assignModal')">+ New Assignment</button>
|
||
</div>
|
||
<div class="card-body" id="assignmentHistory"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Maintenance Tab -->
|
||
<div class="tab-content" id="tab-maintenance" data-group="detail">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">🔧 Maintenance Records</span>
|
||
<a href="maintenance.html" class="btn btn-secondary btn-sm">+ Raise Ticket</a>
|
||
</div>
|
||
<div class="card-body" id="maintenanceRecords"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Documents Tab -->
|
||
<div class="tab-content" id="tab-documents" data-group="detail">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">📄 Documents</span>
|
||
<button class="btn btn-primary btn-sm" onclick="showToast('Upload','Document upload dialog','info')">📎 Upload</button>
|
||
</div>
|
||
<div class="card-body" id="assetDocs"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- History Tab -->
|
||
<div class="tab-content" id="tab-history" data-group="detail">
|
||
<div class="card">
|
||
<div class="card-header"><span class="card-title">🕐 Audit Trail</span></div>
|
||
<div class="card-body" id="auditTrail"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Edit Modal -->
|
||
<div class="modal-overlay" id="editModal">
|
||
<div class="modal modal-lg">
|
||
<div class="modal-header"><span class="modal-title">Edit Asset</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Asset Name <span class="req">*</span></label><input class="form-input" id="editName"></div>
|
||
<div class="form-group"><label class="form-label">Serial Number</label><input class="form-input" id="editSerial"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Category</label><select class="form-select" id="editCat"><option>Laptops</option><option>Desktops</option><option>Printers</option><option>Networking</option><option>Vehicles</option><option>Furniture</option><option>HVAC</option></select></div>
|
||
<div class="form-group"><label class="form-label">Status</label><select class="form-select" id="editStatus"><option>Active</option><option>Idle</option><option>Under Maintenance</option><option>Disposed</option></select></div>
|
||
</div>
|
||
<div class="form-group"><label class="form-label">Change Reason (for audit trail) <span class="req">*</span></label><textarea class="form-textarea" rows="2" placeholder="Why is this being updated?"></textarea></div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-ghost" onclick="closeModal('editModal')">Cancel</button>
|
||
<button class="btn btn-primary" onclick="saveEdit()">Save Changes</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Assign Modal -->
|
||
<div class="modal-overlay" id="assignModal">
|
||
<div class="modal">
|
||
<div class="modal-header"><span class="modal-title">Assign Asset</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="form-group"><label class="form-label">Employee <span class="req">*</span></label>
|
||
<select class="form-select"><option value="">Select…</option><option>Priya Kumar – IT</option><option>Rahul Mehta – Finance</option><option>Anita Singh – HR</option><option>Vikram Reddy – Operations</option><option>Sneha Patel – Marketing</option></select>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">From Date</label><input type="date" class="form-input" value="2025-05-28"></div>
|
||
<div class="form-group"><label class="form-label">Return By (optional)</label><input type="date" class="form-input"></div>
|
||
</div>
|
||
<div class="form-group"><label class="form-label">Acknowledgment</label>
|
||
<select class="form-select"><option>Yes – Send email confirmation</option><option>No – Direct assignment</option></select>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-ghost" onclick="closeModal('assignModal')">Cancel</button>
|
||
<button class="btn btn-primary" onclick="doAssign()">Assign</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Transfer Modal -->
|
||
<div class="modal-overlay" id="transferModal">
|
||
<div class="modal">
|
||
<div class="modal-header"><span class="modal-title">Transfer Asset</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">To Department</label>
|
||
<select class="form-select"><option>IT</option><option>Finance</option><option>HR</option><option>Operations</option><option>Marketing</option><option>Admin</option></select>
|
||
</div>
|
||
<div class="form-group"><label class="form-label">To Location</label>
|
||
<select class="form-select"><option>IT Dept – Floor 2</option><option>Finance – Floor 1</option><option>Server Room – B1</option><option>HR – Floor 2</option><option>Marketing – Floor 3</option></select>
|
||
</div>
|
||
</div>
|
||
<div class="form-group"><label class="form-label">Reason</label>
|
||
<select class="form-select"><option>Department Restructuring</option><option>Employee Transfer</option><option>Better Utilization</option><option>Other</option></select>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-ghost" onclick="closeModal('transferModal')">Cancel</button>
|
||
<button class="btn btn-primary" onclick="doTransfer()">Transfer</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-overlay" id="confirmModal">
|
||
<div class="modal" style="max-width:400px">
|
||
<div class="modal-header"><span class="modal-title confirm-title">Confirm</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body"><p class="confirm-message" style="color:var(--text-secondary)"></p></div>
|
||
<div class="modal-footer"><button class="btn btn-ghost" onclick="closeModal('confirmModal')">Cancel</button><button class="btn btn-danger confirm-ok">Confirm</button></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toast-container" id="toastContainer"></div>
|
||
<script src="js/data.js"></script>
|
||
<script src="js/app.js"></script>
|
||
<script>
|
||
const params = new URLSearchParams(window.location.search);
|
||
const assetId = params.get('id') || 'AST-2025-001';
|
||
let asset = AMS.assets.find(a => a.id === assetId) || AMS.assets[0];
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
document.title = `${asset.name} | AMS`;
|
||
renderHeader();
|
||
renderOverview();
|
||
renderFinancial();
|
||
renderAssignments();
|
||
renderMaintenance();
|
||
renderDocuments();
|
||
renderHistory();
|
||
initTabs();
|
||
});
|
||
|
||
function renderHeader() {
|
||
document.getElementById('assetHeaderTitle').textContent = asset.name;
|
||
const depPct = Math.round((asset.cost - asset.value)/asset.cost*100);
|
||
document.getElementById('assetHeader').innerHTML = `
|
||
<div class="card-body">
|
||
<div class="flex items-center gap-4 flex-wrap">
|
||
<div style="width:64px;height:64px;border-radius:16px;background:var(--primary-glow);display:flex;align-items:center;justify-content:center;font-size:30px;border:1px solid var(--border-accent);flex-shrink:0">${asset.icon}</div>
|
||
<div style="flex:1;min-width:0">
|
||
<div style="font-size:20px;font-weight:800;margin-bottom:4px">${asset.name}</div>
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center">
|
||
<span class="badge badge-neutral" style="font-size:11px">${asset.id}</span>
|
||
<span class="badge ${statusBadge(asset.status)}"><span class="badge-dot-ind" style="background:${statusDot(asset.status)}"></span>${asset.status}</span>
|
||
<span class="badge badge-neutral" style="font-size:11px">${asset.cat}</span>
|
||
<span style="font-size:12px;color:var(--text-muted)">${asset.serial}</span>
|
||
</div>
|
||
</div>
|
||
<div class="flex gap-5 flex-wrap">
|
||
<div style="text-align:right">
|
||
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Purchase Cost</div>
|
||
<div style="font-size:18px;font-weight:800">${fmt(asset.cost)}</div>
|
||
</div>
|
||
<div style="text-align:right">
|
||
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Net Book Value</div>
|
||
<div style="font-size:18px;font-weight:800;color:${depPct>60?'var(--warning)':'var(--success)'}">${fmt(asset.value)}</div>
|
||
</div>
|
||
<div style="text-align:right">
|
||
<div style="font-size:10px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px">Depreciated</div>
|
||
<div style="font-size:18px;font-weight:800;color:var(--danger)">${depPct}%</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top:16px;background:var(--bg-surface);border-radius:var(--radius-md);overflow:hidden;height:6px">
|
||
<div style="height:100%;width:${100-depPct}%;background:linear-gradient(90deg,var(--primary),var(--cyan));transition:width .6s ease;border-radius:var(--radius-md)"></div>
|
||
</div>
|
||
<div style="display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted);margin-top:5px">
|
||
<span>Net Value: ${fmt(asset.value)}</span>
|
||
<span>Fully Depreciated by: ~${new Date(new Date(asset.purchase).getFullYear() + Math.ceil(asset.cost/asset.value),0,1).getFullYear()}</span>
|
||
<span>Purchased: ${fmtDate(asset.purchase)}</span>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
function renderOverview() {
|
||
document.getElementById('assetInfoGrid').innerHTML = `
|
||
<div class="info-grid">
|
||
<div class="info-item"><div class="info-label">Asset ID</div><div class="info-value">${asset.id}</div></div>
|
||
<div class="info-item"><div class="info-label">Serial Number</div><div class="info-value">${asset.serial}</div></div>
|
||
<div class="info-item"><div class="info-label">Category</div><div class="info-value">${asset.cat}</div></div>
|
||
<div class="info-item"><div class="info-label">Status</div><div class="info-value"><span class="badge ${statusBadge(asset.status)}">${asset.status}</span></div></div>
|
||
<div class="info-item"><div class="info-label">Vendor / Supplier</div><div class="info-value">${asset.vendor}</div></div>
|
||
<div class="info-item"><div class="info-label">Purchase Date</div><div class="info-value">${fmtDate(asset.purchase)}</div></div>
|
||
<div class="info-item"><div class="info-label">Warranty Expiry</div><div class="info-value">${fmtDate(asset.warranty)}</div></div>
|
||
<div class="info-item"><div class="info-label">Depreciation Method</div><div class="info-value">${asset.depM} @ ${asset.depR}% p.a.</div></div>
|
||
</div>`;
|
||
|
||
document.getElementById('assetLocationGrid').innerHTML = `
|
||
<div class="info-grid">
|
||
<div class="info-item" style="grid-column:span 2"><div class="info-label">Current Location</div><div class="info-value">🏢 ${asset.loc}</div></div>
|
||
<div class="info-item"><div class="info-label">Department</div><div class="info-value">${asset.dept}</div></div>
|
||
<div class="info-item"><div class="info-label">Assigned To</div><div class="info-value">${asset.assignee}</div></div>
|
||
</div>
|
||
<hr class="divider">
|
||
<div style="font-size:12px;color:var(--text-muted);margin-bottom:8px">Custody Chain</div>
|
||
<div class="timeline">
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--success-bg);color:var(--success)">👤</div><div class="tl-line"></div></div>
|
||
<div class="tl-content"><div class="tl-title">${asset.assignee} (Current)</div><div class="tl-desc">${asset.dept} · ${asset.loc}</div><div class="tl-time">From ${fmtDate(asset.purchase)}</div></div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--bg-elevated);color:var(--text-muted)">🏪</div></div>
|
||
<div class="tl-content"><div class="tl-title">Warehouse (Initial Stock)</div><div class="tl-desc">Goods Receipt Note created</div><div class="tl-time">${fmtDate(asset.purchase)}</div></div>
|
||
</div>
|
||
</div>`;
|
||
|
||
// QR code
|
||
const cells = generateQRPattern(asset.id);
|
||
document.getElementById('assetQR').innerHTML = `
|
||
<div class="qr-box" style="margin:0 auto">
|
||
<div style="display:grid;grid-template-columns:repeat(7,11px);grid-template-rows:repeat(7,11px);gap:2px;padding:8px;background:#fff">
|
||
${cells.map(c=>`<div style="background:${c?'#000':'#fff'};border-radius:1px"></div>`).join('')}
|
||
</div>
|
||
<div style="font-size:9px;color:#333;font-weight:700;font-family:monospace">${asset.id}</div>
|
||
<div style="font-size:8px;color:#555;max-width:100px">${asset.name.substring(0,24)}</div>
|
||
</div>
|
||
<div style="margin-top:12px;font-size:12px;color:var(--text-muted)">Scan to view asset details</div>`;
|
||
|
||
// Custom fields by category
|
||
const fieldsByCategory = {
|
||
'Laptops': [['Processor','Intel Core i7 13th Gen'],['RAM','16 GB DDR5'],['Storage','512 GB NVMe SSD'],['OS','Windows 11 Pro'],['Screen Size','14 inch FHD']],
|
||
'Servers': [['CPU','2× Xeon Gold 5218'],['RAM','128 GB ECC'],['Storage','4× 1.8 TB SAS'],['RAID','RAID 10'],['OS','Ubuntu Server 22.04']],
|
||
'Vehicles': [['Registration No.',asset.serial],['Fuel Type','Petrol / Electric'],['Engine CC','1498 CC'],['Insurance Expiry','2026-01-15'],['Next Service','50,000 KM']],
|
||
'HVAC': [['Capacity','1.5 Ton'],['Type','Inverter Split'],['Refrigerant','R-32'],['Star Rating','5 Star'],['Installation Date',fmtDate(asset.purchase)]],
|
||
'Printers': [['Print Speed','40 ppm'],['Print Technology','Laser'],['Paper Sizes','A4, A5, Letter'],['Connectivity','USB, Network, Wi-Fi'],['Monthly Duty Cycle','80,000 pages']]
|
||
};
|
||
const fields = fieldsByCategory[asset.cat] || [['Brand',asset.vendor],['Part Number','N/A'],['Model Year','2024'],['Color','Black / Silver']];
|
||
document.getElementById('assetCustomFields').innerHTML = `
|
||
<div class="info-grid">
|
||
${fields.map(([k,v])=>`<div class="info-item"><div class="info-label">${k}</div><div class="info-value">${v}</div></div>`).join('')}
|
||
</div>`;
|
||
}
|
||
|
||
function renderFinancial() {
|
||
const depPct = Math.round((asset.cost - asset.value)/asset.cost*100);
|
||
const years = Math.floor((new Date() - new Date(asset.purchase))/(365.25*24*3600*1000));
|
||
const annualDep = asset.depM === 'SLM' ? Math.round(asset.cost * asset.depR/100) : Math.round((asset.cost - asset.value) / Math.max(1,years));
|
||
|
||
document.getElementById('depreciationInfo').innerHTML = `
|
||
<div class="dep-bar-wrap">
|
||
<div class="dep-nums">
|
||
<span>Net Book Value: <strong>${fmt(asset.value)}</strong></span>
|
||
<span>Total Dep.: <strong style="color:var(--danger)">${fmt(asset.cost - asset.value)}</strong></span>
|
||
</div>
|
||
<div class="progress-wrap"><div class="progress-fill" style="width:${100-depPct}%"></div></div>
|
||
<div class="dep-nums" style="margin-top:6px;margin-bottom:0">
|
||
<span style="font-size:11px">${100-depPct}% remaining value</span>
|
||
<span style="font-size:11px">${depPct}% depreciated</span>
|
||
</div>
|
||
</div>
|
||
<div class="info-grid mb-4">
|
||
<div class="info-item"><div class="info-label">Method</div><div class="info-value">${asset.depM} (${asset.depM==='SLM'?'Straight Line':'Written Down Value'})</div></div>
|
||
<div class="info-item"><div class="info-label">Rate</div><div class="info-value">${asset.depR}% per annum</div></div>
|
||
<div class="info-item"><div class="info-label">Annual Depreciation</div><div class="info-value" style="color:var(--danger)">${fmt(annualDep)}</div></div>
|
||
<div class="info-item"><div class="info-label">Asset Age</div><div class="info-value">${years} year${years!==1?'s':''}</div></div>
|
||
</div>`;
|
||
|
||
// Depreciation chart
|
||
const purchaseYear = new Date(asset.purchase).getFullYear();
|
||
const labels=[], values=[];
|
||
let val = asset.cost;
|
||
for(let i=0;i<=5;i++){
|
||
labels.push(purchaseYear+i);
|
||
values.push(Math.max(0, Math.round(val)));
|
||
if(asset.depM==='SLM') val -= asset.cost*asset.depR/100;
|
||
else val *= (1-asset.depR/100);
|
||
}
|
||
new Chart(document.getElementById('depChart'),{
|
||
type:'line',
|
||
data:{ labels, datasets:[{label:'Book Value',data:values,borderColor:'#6366F1',backgroundColor:'rgba(99,102,241,.1)',fill:true,tension:.3,pointRadius:4,borderWidth:2}] },
|
||
options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false}},
|
||
scales:{x:{grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:11}}},
|
||
y:{grid:{color:'rgba(255,255,255,.04)'},ticks:{color:'#4B5563',font:{family:'Inter',size:11},callback:v=>'₹'+(v/1000).toFixed(0)+'K'}}}}
|
||
});
|
||
|
||
document.getElementById('valueSummary').innerHTML = `
|
||
<div class="info-grid">
|
||
<div class="info-item"><div class="info-label">Purchase Cost</div><div class="info-value" style="font-size:18px;font-weight:800">${fmt(asset.cost)}</div></div>
|
||
<div class="info-item"><div class="info-label">Current Book Value</div><div class="info-value" style="font-size:18px;font-weight:800;color:var(--success)">${fmt(asset.value)}</div></div>
|
||
<div class="info-item"><div class="info-label">Total Depreciation</div><div class="info-value" style="color:var(--danger)">${fmt(asset.cost-asset.value)}</div></div>
|
||
<div class="info-item"><div class="info-label">Residual Value</div><div class="info-value">${fmt(Math.round(asset.cost*0.05))}</div></div>
|
||
</div>
|
||
<hr class="divider">
|
||
<div class="section-hdr">Year-wise Depreciation</div>
|
||
<table class="data-table" style="font-size:12px">
|
||
<thead><tr><th>Year</th><th>Opening Value</th><th>Depreciation</th><th>Closing Value</th></tr></thead>
|
||
<tbody>
|
||
${(()=>{
|
||
let v=asset.cost, rows=''; const py=new Date(asset.purchase).getFullYear();
|
||
for(let i=0;i<Math.min(5,Math.ceil(100/asset.depR));i++){
|
||
const dep = asset.depM==='SLM' ? asset.cost*asset.depR/100 : v*asset.depR/100;
|
||
const close = Math.max(0,v-dep);
|
||
rows+=`<tr><td>${py+i}</td><td>${fmt(Math.round(v))}</td><td style="color:var(--danger)">-${fmt(Math.round(dep))}</td><td>${fmt(Math.round(close))}</td></tr>`;
|
||
v=close;
|
||
}
|
||
return rows;
|
||
})()}
|
||
</tbody>
|
||
</table>`;
|
||
}
|
||
|
||
function renderAssignments() {
|
||
document.getElementById('assignmentHistory').innerHTML = `
|
||
<div class="timeline">
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--success-bg);color:var(--success)">✅</div><div class="tl-line"></div></div>
|
||
<div class="tl-content"><div class="tl-title">${asset.assignee} (Current)</div><div class="tl-desc">${asset.dept} Department · ${asset.loc}</div><div class="tl-time">Since ${fmtDate(asset.purchase)} · Acknowledged via email</div></div>
|
||
</div>
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--bg-elevated);color:var(--text-muted)">🏪</div><div class="tl-line"></div></div>
|
||
<div class="tl-content"><div class="tl-title">Warehouse (Initial)</div><div class="tl-desc">Asset received via GRN • PO-2024-038</div><div class="tl-time">${fmtDate(asset.purchase)}</div></div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
function renderMaintenance() {
|
||
const rel = AMS.tickets.filter(t => t.asset === asset.id);
|
||
if (!rel.length) {
|
||
document.getElementById('maintenanceRecords').innerHTML = `<div class="empty-state"><div class="empty-icon">🔧</div><div class="empty-title">No maintenance records</div><div class="empty-text">No tickets raised for this asset</div><a href="maintenance.html" class="btn btn-primary btn-sm">Raise Ticket</a></div>`;
|
||
return;
|
||
}
|
||
document.getElementById('maintenanceRecords').innerHTML = `
|
||
<div class="timeline">
|
||
${rel.map(t=>`
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:var(--${statusBadge(t.status).includes('danger')?'danger':'info'}-bg);color:var(--${statusBadge(t.status).includes('danger')?'danger':'info'})">🔧</div><div class="tl-line"></div></div>
|
||
<div class="tl-content">
|
||
<div class="tl-title">${t.title||t.name} <span class="badge ${statusBadge(t.status)}" style="margin-left:6px">${t.status}</span></div>
|
||
<div class="tl-desc">${t.category} · Assigned to: ${t.assignedTo}</div>
|
||
<div class="tl-time">Created: ${fmtDate(t.created)} · Priority: <span class="badge ${statusBadge(t.priority)}">${t.priority}</span></div>
|
||
</div>
|
||
</div>`).join('')}
|
||
</div>`;
|
||
}
|
||
|
||
function renderDocuments() {
|
||
const docs = [
|
||
{ name:'Purchase Invoice', type:'PDF', size:'240 KB', date:'2024-01-15', icon:'📄' },
|
||
{ name:'Delivery Challan', type:'PDF', size:'85 KB', date:'2024-01-16', icon:'📋' },
|
||
{ name:'Warranty Card', type:'PDF', size:'120 KB', date:'2024-01-15', icon:'🛡️' },
|
||
{ name:'Asset Photo', type:'JPG', size:'1.2 MB', date:'2024-01-18', icon:'📷' }
|
||
];
|
||
document.getElementById('assetDocs').innerHTML = docs.map(d=>`
|
||
<div class="flex items-center gap-3 mb-3" style="padding:12px;background:var(--bg-surface);border-radius:var(--radius-md);border:1px solid var(--border)">
|
||
<div style="font-size:22px">${d.icon}</div>
|
||
<div style="flex:1"><div style="font-weight:600;font-size:13px">${d.name}</div><div style="font-size:11px;color:var(--text-muted)">${d.type} · ${d.size} · Uploaded ${fmtDate(d.date)}</div></div>
|
||
<button class="btn btn-ghost btn-sm" onclick="showToast('Download','Downloading ${d.name}…','info')">📥</button>
|
||
<button class="btn btn-ghost btn-sm" onclick="showToast('Delete','File deleted','success')">🗑️</button>
|
||
</div>`).join('');
|
||
}
|
||
|
||
function renderHistory() {
|
||
const events = [
|
||
{ icon:'📦', bg:'var(--primary-glow)', color:'var(--primary-light)', title:'Asset Created', desc:`Imported via GRN · PO: PO-2024-038 · Vendor: ${asset.vendor}`, time:fmtDate(asset.purchase) },
|
||
{ icon:'📱', bg:'var(--info-bg)', color:'var(--info)', title:'QR Code Generated', desc:'Printed on A4 label sheet (8-up format)', time:fmtDate(asset.purchase) },
|
||
{ icon:'👤', bg:'var(--success-bg)', color:'var(--success)', title:'Assigned to '+asset.assignee, desc:`Dept: ${asset.dept} · Acknowledgment received`, time:fmtDate(asset.purchase) },
|
||
{ icon:'📝', bg:'var(--bg-elevated)', color:'var(--text-muted)', title:'Field Updated: Location', desc:'Previous: Warehouse → Current: '+asset.loc, time:'2024-02-01' }
|
||
];
|
||
document.getElementById('auditTrail').innerHTML = `
|
||
<div class="timeline">
|
||
${events.map(e=>`
|
||
<div class="timeline-item">
|
||
<div class="tl-icon-wrap"><div class="tl-icon" style="background:${e.bg};color:${e.color}">${e.icon}</div><div class="tl-line"></div></div>
|
||
<div class="tl-content"><div class="tl-title">${e.title}</div><div class="tl-desc">${e.desc}</div><div class="tl-time">By Arjun Sharma · ${e.time}</div></div>
|
||
</div>`).join('')}
|
||
</div>`;
|
||
}
|
||
|
||
function saveEdit() { closeModal('editModal'); showToast('Asset Updated','Changes saved with audit trail entry','success'); }
|
||
function doAssign() { closeModal('assignModal'); showToast('Assigned','Acknowledgment email sent','success'); }
|
||
function doTransfer() { closeModal('transferModal'); showToast('Transfer Initiated','Pending Department Head approval','info'); }
|
||
function confirmDispose() {
|
||
confirmAction('Dispose Asset',`Mark "${asset.name}" as disposed? This action is permanent and will generate a write-off entry.`,()=>{
|
||
showToast('Asset Disposed','Write-off entry created. Finance notified.','success');
|
||
setTimeout(()=>window.location.href='assets.html',1500);
|
||
});
|
||
}
|
||
function printQR() { showToast('Print','QR label sent to printer','info'); }
|
||
</script>
|
||
</body>
|
||
</html>
|