- 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
370 lines
22 KiB
HTML
370 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||
<title>Procurement | 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">
|
||
</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"><span class="nav-icon">🏪</span> Inventory</a>
|
||
<a href="procurement.html" class="nav-item active"><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">Procurement <span class="topbar-sub">PR → Approval → PO → GRN → Asset</span></div></div>
|
||
<div class="topbar-actions">
|
||
<button class="btn btn-primary btn-sm" onclick="openModal('prModal')">+ New Purchase Request</button>
|
||
<a href="index.html" class="icon-btn">🚪</a>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="content">
|
||
<!-- Workflow Visualization -->
|
||
<div class="card mb-4">
|
||
<div class="card-body">
|
||
<div style="font-size:11px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.6px;margin-bottom:12px">Procurement Workflow</div>
|
||
<div class="wf-steps">
|
||
<div class="wf-step done">✅ PR Raised</div><div class="wf-arr">→</div>
|
||
<div class="wf-step done">✅ Dept Approval</div><div class="wf-arr">→</div>
|
||
<div class="wf-step active">⏳ Finance Approval</div><div class="wf-arr">→</div>
|
||
<div class="wf-step">📋 PO Generated</div><div class="wf-arr">→</div>
|
||
<div class="wf-step">📦 GRN</div><div class="wf-arr">→</div>
|
||
<div class="wf-step">🧾 Invoice Match</div><div class="wf-arr">→</div>
|
||
<div class="wf-step">🏷️ Asset Created</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stats -->
|
||
<div class="grid-4 mb-4" id="procStats"></div>
|
||
|
||
<!-- Tabs -->
|
||
<div class="tab-container">
|
||
<div class="tabs" data-group="proc">
|
||
<button class="tab-btn active" data-tab="tab-prs" data-group="proc">📋 Purchase Requests <span class="badge badge-danger" style="margin-left:4px;font-size:9px">8</span></button>
|
||
<button class="tab-btn" data-tab="tab-pos" data-group="proc">📄 Purchase Orders</button>
|
||
<button class="tab-btn" data-tab="tab-grn" data-group="proc">📦 GRN</button>
|
||
<button class="tab-btn" data-tab="tab-vendors" data-group="proc">🏭 Vendors</button>
|
||
</div>
|
||
|
||
<!-- PRs Tab -->
|
||
<div class="tab-content active" id="tab-prs" data-group="proc">
|
||
<div class="filters-row mb-3">
|
||
<div class="search-wrap" style="max-width:280px"><span style="color:var(--text-muted)">🔍</span><input type="text" id="prSearch" placeholder="Search PRs…"></div>
|
||
<select class="filter-sel" id="prStatusFilter">
|
||
<option value="">All Statuses</option>
|
||
<option>Draft</option><option>Submitted</option><option>Approved</option><option>Rejected</option><option>PO Raised</option>
|
||
</select>
|
||
<select class="filter-sel"><option>All Departments</option><option>IT</option><option>Finance</option><option>HR</option><option>Operations</option><option>Marketing</option></select>
|
||
</div>
|
||
<div class="table-wrapper">
|
||
<table class="data-table" id="prTable">
|
||
<thead><tr><th>PR No.</th><th>Item Description</th><th>Dept</th><th>Qty</th><th>Est. Cost</th><th>Requester</th><th>Date</th><th>Status</th><th>Actions</th></tr></thead>
|
||
<tbody id="prTbody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- POs Tab -->
|
||
<div class="tab-content" id="tab-pos" data-group="proc">
|
||
<div class="table-wrapper">
|
||
<table class="data-table">
|
||
<thead><tr><th>PO Number</th><th>Vendor</th><th>Items</th><th>Total Value</th><th>Date</th><th>Status</th><th>GRN Status</th><th>Actions</th></tr></thead>
|
||
<tbody id="poTbody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GRN Tab -->
|
||
<div class="tab-content" id="tab-grn" data-group="proc">
|
||
<div class="table-wrapper">
|
||
<table class="data-table">
|
||
<thead><tr><th>GRN No.</th><th>PO Ref.</th><th>Vendor</th><th>Items</th><th>Received Qty</th><th>Date</th><th>Received By</th><th>3-Way Match</th></tr></thead>
|
||
<tbody id="grnTbody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Vendors Tab -->
|
||
<div class="tab-content" id="tab-vendors" data-group="proc">
|
||
<div class="flex justify-between mb-4">
|
||
<div class="search-wrap" style="max-width:280px"><span style="color:var(--text-muted)">🔍</span><input type="text" placeholder="Search vendors…"></div>
|
||
<button class="btn btn-primary btn-sm" onclick="openModal('vendorModal')">+ Add Vendor</button>
|
||
</div>
|
||
<div class="grid-3" id="vendorGrid"></div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PR Modal -->
|
||
<div class="modal-overlay" id="prModal">
|
||
<div class="modal modal-lg">
|
||
<div class="modal-header"><span class="modal-title">New Purchase Request</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">PR Number</label><input class="form-input" value="PR-2025-009" readonly></div>
|
||
<div class="form-group"><label class="form-label">Department <span class="req">*</span></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>
|
||
<div class="form-group"><label class="form-label">Item Description <span class="req">*</span></label><input class="form-input" placeholder="e.g. Dell Laptop i7 Gen 13 (×5)"></div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Quantity <span class="req">*</span></label><input type="number" class="form-input" placeholder="0" min="1"></div>
|
||
<div class="form-group"><label class="form-label">Estimated Unit Cost (₹) <span class="req">*</span></label><input type="number" class="form-input" placeholder="0.00"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Budget Code</label><input class="form-input" placeholder="CC-IT-001"></div>
|
||
<div class="form-group"><label class="form-label">Required By Date</label><input type="date" class="form-input"></div>
|
||
</div>
|
||
<div class="form-group"><label class="form-label">Business Justification <span class="req">*</span></label><textarea class="form-textarea" placeholder="Why is this purchase needed? Link to business objective or ticket…" rows="3"></textarea></div>
|
||
<div class="form-group"><label class="form-label">Attachments</label><input type="file" class="form-input" multiple accept=".pdf,.doc,.jpg,.png"></div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-ghost" onclick="closeModal('prModal')">Cancel</button>
|
||
<button class="btn btn-secondary" onclick="savePR('Draft')">Save Draft</button>
|
||
<button class="btn btn-primary" onclick="savePR('Submitted')">Submit for Approval</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Vendor Modal -->
|
||
<div class="modal-overlay" id="vendorModal">
|
||
<div class="modal modal-lg">
|
||
<div class="modal-header"><span class="modal-title">Add Vendor</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Company Name <span class="req">*</span></label><input class="form-input" placeholder="Vendor company name"></div>
|
||
<div class="form-group"><label class="form-label">Contact Person</label><input class="form-input" placeholder="Primary contact name"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">Email</label><input type="email" class="form-input" placeholder="vendor@company.com"></div>
|
||
<div class="form-group"><label class="form-label">Phone</label><input class="form-input" placeholder="+91-XXXXX-XXXXX"></div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group"><label class="form-label">GST Number</label><input class="form-input" placeholder="29XXXXXXXXXX1ZX"></div>
|
||
<div class="form-group"><label class="form-label">Category</label><select class="form-select"><option>IT Hardware</option><option>Networking</option><option>Furniture</option><option>HVAC</option><option>Vehicles</option><option>AV Equipment</option><option>Other</option></select></div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn btn-ghost" onclick="closeModal('vendorModal')">Cancel</button>
|
||
<button class="btn btn-primary" onclick="saveVendor()">Add Vendor</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PR Detail Modal -->
|
||
<div class="modal-overlay" id="prDetailModal">
|
||
<div class="modal modal-lg">
|
||
<div class="modal-header"><span class="modal-title" id="prDetailTitle">PR Details</span><button class="modal-close">✕</button></div>
|
||
<div class="modal-body" id="prDetailBody"></div>
|
||
<div class="modal-footer" id="prDetailFooter"></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', () => {
|
||
renderStats();
|
||
renderPRs();
|
||
renderPOs();
|
||
renderGRNs();
|
||
renderVendors();
|
||
initTabs();
|
||
document.getElementById('prSearch').addEventListener('input', applyPRFilter);
|
||
document.getElementById('prStatusFilter').addEventListener('change', applyPRFilter);
|
||
});
|
||
|
||
function renderStats() {
|
||
const prs = AMS.purchaseRequests;
|
||
const pending = prs.filter(p=>p.status==='Submitted'||p.status==='Pending').length;
|
||
const approved = prs.filter(p=>p.status==='Approved'||p.status==='PO Raised').length;
|
||
const totalVal = prs.filter(p=>p.status!=='Rejected').reduce((a,p)=>a+p.estCost,0);
|
||
document.getElementById('procStats').innerHTML = [
|
||
{label:'Total PRs',icon:'📋',val:prs.length,color:'var(--primary)'},
|
||
{label:'Pending Approval',icon:'⏳',val:pending,color:'var(--warning)'},
|
||
{label:'Approved / PO Raised',icon:'✅',val:approved,color:'var(--success)'},
|
||
{label:'Total Value',icon:'💰',val:fmt(totalVal),color:'var(--cyan)'}
|
||
].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 renderPRs(data) {
|
||
const prs = data || AMS.purchaseRequests;
|
||
document.getElementById('prTbody').innerHTML = prs.map(p=>`
|
||
<tr onclick="showPRDetail('${p.id}')" style="cursor:pointer">
|
||
<td><code style="color:var(--primary-light);font-size:11.5px">${p.id}</code></td>
|
||
<td><div style="font-weight:600;color:var(--text-primary)">${p.item}</div><div style="font-size:11px;color:var(--text-muted)">${p.justification.substring(0,50)}…</div></td>
|
||
<td><span class="badge badge-neutral">${p.dept}</span></td>
|
||
<td style="font-weight:700">${p.qty}</td>
|
||
<td style="font-weight:700">${fmt(p.estCost)}</td>
|
||
<td>${p.requester}</td>
|
||
<td>${fmtDate(p.date)}</td>
|
||
<td><span class="badge ${statusBadge(p.status)}">${p.status}</span></td>
|
||
<td onclick="event.stopPropagation()">
|
||
<div class="flex gap-1">
|
||
${p.status==='Submitted'||p.status==='Pending' ? `
|
||
<button class="btn btn-success btn-sm" onclick="approvePR('${p.id}')">✓</button>
|
||
<button class="btn btn-danger btn-sm" onclick="rejectPR('${p.id}')">✕</button>` :
|
||
p.status==='Approved' ? `<button class="btn btn-primary btn-sm" onclick="raisePO('${p.id}')">PO →</button>` :
|
||
`<button class="btn btn-ghost btn-sm" onclick="showPRDetail('${p.id}')">View</button>`
|
||
}
|
||
</div>
|
||
</td>
|
||
</tr>`).join('');
|
||
}
|
||
|
||
function applyPRFilter() {
|
||
const q = document.getElementById('prSearch').value.toLowerCase();
|
||
const st = document.getElementById('prStatusFilter').value;
|
||
const filtered = AMS.purchaseRequests.filter(p =>
|
||
(!q || p.item.toLowerCase().includes(q) || p.id.toLowerCase().includes(q) || p.requester.toLowerCase().includes(q)) &&
|
||
(!st || p.status === st)
|
||
);
|
||
renderPRs(filtered);
|
||
}
|
||
|
||
function showPRDetail(id) {
|
||
const p = AMS.purchaseRequests.find(x=>x.id===id);
|
||
if(!p) return;
|
||
document.getElementById('prDetailTitle').textContent = p.id + ' – ' + p.item;
|
||
document.getElementById('prDetailBody').innerHTML = `
|
||
<div class="info-grid mb-4">
|
||
<div class="info-item"><div class="info-label">Status</div><div class="info-value"><span class="badge ${statusBadge(p.status)}">${p.status}</span></div></div>
|
||
<div class="info-item"><div class="info-label">Department</div><div class="info-value">${p.dept}</div></div>
|
||
<div class="info-item"><div class="info-label">Requester</div><div class="info-value">${p.requester}</div></div>
|
||
<div class="info-item"><div class="info-label">Date</div><div class="info-value">${fmtDate(p.date)}</div></div>
|
||
<div class="info-item"><div class="info-label">Quantity</div><div class="info-value">${p.qty}</div></div>
|
||
<div class="info-item"><div class="info-label">Estimated Cost</div><div class="info-value" style="font-weight:700">${fmt(p.estCost)}</div></div>
|
||
</div>
|
||
<div class="form-group"><div class="info-label">Business Justification</div><div class="info-value" style="background:var(--bg-surface);padding:12px;border-radius:var(--radius-md);font-size:13px;margin-top:4px">${p.justification}</div></div>
|
||
${p.poRef ? `<div class="alert alert-success mt-4"><div class="alert-icon">✅</div><div><div class="alert-title">PO Generated</div><div class="alert-text">Reference: ${p.poRef}</div></div></div>` : ''}
|
||
<div class="section-hdr mt-4">Approval 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">Requester: ${p.requester}</div><div class="tl-desc">PR Submitted</div><div class="tl-time">${fmtDate(p.date)}</div></div></div>
|
||
<div class="timeline-item"><div class="tl-icon-wrap"><div class="tl-icon" style="background:${p.status!=='Draft'?'var(--success-bg)':'var(--bg-elevated)'};color:${p.status!=='Draft'?'var(--success)':'var(--text-muted)'}">${p.status!=='Draft'?'✅':'⏳'}</div><div class="tl-line"></div></div><div class="tl-content"><div class="tl-title">Dept Head Approval</div><div class="tl-desc">${p.dept} Head Review</div></div></div>
|
||
<div class="timeline-item"><div class="tl-icon-wrap"><div class="tl-icon" style="background:${['Approved','PO Raised','GRN Done'].includes(p.status)?'var(--success-bg)':'var(--bg-elevated)'};color:${['Approved','PO Raised','GRN Done'].includes(p.status)?'var(--success)':'var(--text-muted)'}">${['Approved','PO Raised','GRN Done'].includes(p.status)?'✅':'⏳'}</div></div><div class="tl-content"><div class="tl-title">Finance Approval</div><div class="tl-desc">Budget verification</div></div></div>
|
||
</div>`;
|
||
document.getElementById('prDetailFooter').innerHTML = p.status==='Submitted' ? `
|
||
<button class="btn btn-ghost" onclick="closeModal('prDetailModal')">Close</button>
|
||
<button class="btn btn-danger" onclick="rejectPR('${p.id}');closeModal('prDetailModal')">Reject</button>
|
||
<button class="btn btn-primary" onclick="approvePR('${p.id}');closeModal('prDetailModal')">Approve PR</button>` :
|
||
`<button class="btn btn-ghost" onclick="closeModal('prDetailModal')">Close</button>
|
||
${p.status==='Approved'?`<button class="btn btn-primary" onclick="raisePO('${p.id}');closeModal('prDetailModal')">Generate PO →</button>`:''}`;
|
||
openModal('prDetailModal');
|
||
}
|
||
|
||
function approvePR(id) {
|
||
const p = AMS.purchaseRequests.find(x=>x.id===id);
|
||
if(p) p.status = 'Approved';
|
||
renderPRs();
|
||
showToast('PR Approved',`${id} approved. Now raise a PO.`,'success');
|
||
}
|
||
|
||
function rejectPR(id) {
|
||
const p = AMS.purchaseRequests.find(x=>x.id===id);
|
||
if(p) p.status = 'Rejected';
|
||
renderPRs();
|
||
showToast('PR Rejected',`${id} has been rejected`,'warning');
|
||
}
|
||
|
||
function raisePO(prId) {
|
||
const p = AMS.purchaseRequests.find(x=>x.id===prId);
|
||
if(p) { p.status = 'PO Raised'; p.poRef = 'PO-2025-00' + Math.floor(Math.random()*9+1); }
|
||
renderPRs();
|
||
showToast('PO Generated',`Purchase Order ${p?.poRef} sent to vendor`,'success');
|
||
}
|
||
|
||
function renderPOs() {
|
||
const pos = [
|
||
{ id:'PO-2025-001', vendor:'Dell India Pvt. Ltd.', items:'5× Dell Latitude 5540', value:425000, date:'2025-05-12', status:'GRN Done', grn:'GRN-2025-041' },
|
||
{ id:'PO-2025-002', vendor:'TP-Link India', items:'8× WAP EAP670', value:96000, date:'2025-05-19', status:'PO Sent', grn:null },
|
||
{ id:'PO-2025-003', vendor:'Schneider Electric', items:'1× UPS Battery Set', value:18000, date:'2025-05-28', status:'PO Sent', grn:null }
|
||
];
|
||
document.getElementById('poTbody').innerHTML = pos.map(p=>`
|
||
<tr>
|
||
<td><code style="color:var(--primary-light);font-size:11.5px">${p.id}</code></td>
|
||
<td>${p.vendor}</td>
|
||
<td>${p.items}</td>
|
||
<td style="font-weight:700">${fmt(p.value)}</td>
|
||
<td>${fmtDate(p.date)}</td>
|
||
<td><span class="badge ${statusBadge(p.status)}">${p.status}</span></td>
|
||
<td>${p.grn ? `<code style="font-size:11px;color:var(--success)">${p.grn}</code>` : '<span class="text-muted">Pending</span>'}</td>
|
||
<td>
|
||
<button class="btn btn-ghost btn-sm" onclick="showToast('Download','PO PDF downloaded','info')">📥 PDF</button>
|
||
${!p.grn?`<button class="btn btn-secondary btn-sm" onclick="showToast('GRN','Record GRN for this PO','info')">Record GRN</button>`:''}
|
||
</td>
|
||
</tr>`).join('');
|
||
}
|
||
|
||
function renderGRNs() {
|
||
const grns = [
|
||
{ id:'GRN-2025-041', po:'PO-2025-001', vendor:'Dell India', items:'Dell Latitude 5540', qty:'5/5', date:'2025-05-14', by:'Arjun Sharma', match:'✅ Matched' },
|
||
{ id:'GRN-2025-040', po:'PO-2024-098', vendor:'Cisco Systems', items:'Cisco IP Phone 8841', qty:'5/5', date:'2025-05-22', by:'Kavya Nair', match:'✅ Matched' },
|
||
{ id:'GRN-2025-039', po:'PO-2024-095', vendor:'HP India', items:'HP LaserJet Pro M404', qty:'2/2', date:'2025-05-18', by:'Arjun Sharma', match:'⚠️ Invoice Pending' }
|
||
];
|
||
document.getElementById('grnTbody').innerHTML = grns.map(g=>`
|
||
<tr>
|
||
<td><code style="color:var(--primary-light);font-size:11.5px">${g.id}</code></td>
|
||
<td><code style="font-size:11px;color:var(--cyan-light)">${g.po}</code></td>
|
||
<td>${g.vendor}</td>
|
||
<td>${g.items}</td>
|
||
<td style="font-weight:700">${g.qty}</td>
|
||
<td>${fmtDate(g.date)}</td>
|
||
<td>${g.by}</td>
|
||
<td>${g.match}</td>
|
||
</tr>`).join('');
|
||
}
|
||
|
||
function renderVendors() {
|
||
document.getElementById('vendorGrid').innerHTML = AMS.vendors.map(v=>`
|
||
<div class="card" style="cursor:default">
|
||
<div class="card-body">
|
||
<div class="flex items-center gap-3 mb-3">
|
||
<div style="width:40px;height:40px;border-radius:var(--radius-md);background:var(--primary-glow);display:flex;align-items:center;justify-content:center;font-size:18px">🏭</div>
|
||
<div><div style="font-weight:700;font-size:13.5px">${v.name}</div><div style="font-size:11px;color:var(--text-muted)">${v.cat}</div></div>
|
||
</div>
|
||
<div class="info-grid" style="gap:8px;margin-bottom:14px">
|
||
<div class="info-item"><div class="info-label">Contact</div><div class="info-value" style="font-size:12px">${v.contact}</div></div>
|
||
<div class="info-item"><div class="info-label">GST</div><div class="info-value" style="font-size:11px">${v.gst}</div></div>
|
||
<div class="info-item"><div class="info-label">Rating</div><div class="info-value">⭐ ${v.rating}/5</div></div>
|
||
<div class="info-item"><div class="info-label">Active Contracts</div><div class="info-value">${v.contracts}</div></div>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<a href="mailto:${v.email}" class="btn btn-ghost btn-sm flex-1">📧 Email</a>
|
||
<button class="btn btn-secondary btn-sm flex-1" onclick="showToast('RFQ','RFQ sent to ${v.name}','success')">Send RFQ</button>
|
||
</div>
|
||
</div>
|
||
</div>`).join('');
|
||
}
|
||
|
||
function savePR(status) {
|
||
closeModal('prModal');
|
||
showToast(`PR ${status}`, status==='Submitted' ? 'PR sent for Dept Head approval' : 'Draft saved', status==='Submitted'?'success':'info');
|
||
}
|
||
|
||
function saveVendor() { closeModal('vendorModal'); showToast('Vendor Added','Vendor added to directory','success'); }
|
||
</script>
|
||
</body>
|
||
</html>
|