NonInventPurchasingSystem/CPRNIMS.WebApps/Views/Components/Inventory/TabPage/Reports.cshtml
2026-06-18 16:51:31 +08:00

531 lines
12 KiB
Plaintext

<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0,0,0,0)
}
.page {
background: var(--color-background-primary);
border: 0.5px solid var(--color-border-tertiary);
border-radius: var(--border-radius-lg);
margin-bottom: 24px;
overflow: hidden
}
.page-tab {
display: flex;
gap: 0;
border-bottom: 0.5px solid var(--color-border-tertiary);
background: var(--color-background-secondary)
}
.tab-btn {
padding: 10px 18px;
font-size: 13px;
font-weight: 500;
color: var(--color-text-secondary);
border: none;
background: none;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all .15s
}
.tab-btn.active {
color: var(--color-text-primary);
border-bottom-color: var(--color-text-primary);
background: var(--color-background-primary)
}
.report-page {
display: none;
padding: 0
}
.report-page.active {
display: block
}
/* Report header band */
.rpt-header {
padding: 20px 24px 16px;
border-bottom: 0.5px solid var(--color-border-tertiary)
}
.rpt-header-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 14px
}
.rpt-company {
font-size: 11px;
font-weight: 500;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .08em;
margin-bottom: 4px
}
.rpt-title {
font-size: 20px;
font-weight: 500;
color: var(--color-text-primary);
margin-bottom: 2px
}
.rpt-subtitle {
font-size: 12px;
color: var(--color-text-secondary)
}
.rpt-logo {
width: 40px;
height: 40px;
border-radius: var(--border-radius-md);
background: var(--color-background-info);
display: flex;
align-items: center;
justify-content: center
}
.rpt-logo i {
font-size: 20px;
color: var(--color-text-info)
}
.rpt-meta {
display: flex;
gap: 20px
}
.rpt-meta-item {
display: flex;
flex-direction: column;
gap: 2px
}
.rpt-meta-lbl {
font-size: 10px;
font-weight: 500;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .07em
}
.rpt-meta-val {
font-size: 12px;
font-weight: 500;
color: var(--color-text-primary)
}
/* KPI strip */
.kpi-strip {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 0;
border-bottom: 0.5px solid var(--color-border-tertiary)
}
.kpi-cell {
padding: 14px 18px;
border-right: 0.5px solid var(--color-border-tertiary)
}
.kpi-cell:last-child {
border-right: none
}
.kpi-lbl {
font-size: 10px;
font-weight: 500;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .07em;
margin-bottom: 4px;
display: flex;
align-items: center;
gap: 5px
}
.kpi-lbl i {
font-size: 13px
}
.kpi-val {
font-size: 22px;
font-weight: 500;
color: var(--color-text-primary);
line-height: 1.1
}
.kpi-sub {
font-size: 11px;
color: var(--color-text-secondary);
margin-top: 3px
}
.kpi-badge {
display: inline-flex;
align-items: center;
gap: 3px;
font-size: 10px;
font-weight: 500;
padding: 2px 7px;
border-radius: var(--border-radius-md);
margin-top: 4px
}
.badge-up {
background: #EAF3DE;
color: #3B6D11
}
.badge-dn {
background: #FCEBEB;
color: #A32D2D
}
.badge-neu {
background: var(--color-background-secondary);
color: var(--color-text-secondary)
}
/* Section */
.rpt-section {
padding: 16px 24px
}
.rpt-section + .rpt-section {
border-top: 0.5px solid var(--color-border-tertiary)
}
.rpt-section-title {
font-size: 11px;
font-weight: 500;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .08em;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px
}
.rpt-section-title i {
font-size: 14px
}
/* Table */
.rpt-table {
width: 100%;
border-collapse: collapse;
font-size: 12px
}
.rpt-table th {
text-align: left;
font-size: 10px;
font-weight: 500;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .07em;
padding: 6px 10px;
border-bottom: 0.5px solid var(--color-border-tertiary);
white-space: nowrap
}
.rpt-table td {
padding: 8px 10px;
border-bottom: 0.5px solid var(--color-border-tertiary);
color: var(--color-text-primary);
vertical-align: middle
}
.rpt-table tr:last-child td {
border-bottom: none
}
.rpt-table tr:hover td {
background: var(--color-background-secondary)
}
.rpt-table .num {
text-align: right;
font-variant-numeric: tabular-nums
}
.rpt-table .total-row td {
font-weight: 500;
background: var(--color-background-secondary)
}
/* Status pill */
.pill {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: var(--border-radius-md);
font-size: 10px;
font-weight: 500
}
.pill-draft {
background: #F1EFE8;
color: #5F5E5A
}
.pill-approved {
background: #EAF3DE;
color: #3B6D11
}
.pill-cancelled {
background: #FCEBEB;
color: #A32D2D
}
/* Mini bar */
.mini-bar-wrap {
display: flex;
align-items: center;
gap: 8px
}
.mini-bar-track {
flex: 1;
height: 5px;
border-radius: 3px;
background: var(--color-border-tertiary);
overflow: hidden
}
.mini-bar-fill {
height: 100%;
border-radius: 3px
}
.fill-teal {
background: #1D9E75
}
.fill-coral {
background: #D85A30
}
.fill-amber {
background: #EF9F27
}
.fill-blue {
background: #378ADD
}
/* Signature block */
.sig-block {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 16px;
margin-top: 4px
}
.sig-item {
border-top: 0.5px solid var(--color-border-tertiary);
padding-top: 8px
}
.sig-role {
font-size: 10px;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: .07em;
margin-bottom: 16px
}
.sig-name {
font-size: 11px;
font-weight: 500;
color: var(--color-text-primary)
}
/* 2-col layout */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0;
border-top: 0.5px solid var(--color-border-tertiary)
}
.col-left {
padding: 16px 24px;
border-right: 0.5px solid var(--color-border-tertiary)
}
.col-right {
padding: 16px 24px
}
/* Timeline strip for MRS condition */
.cond-row {
display: flex;
align-items: center;
gap: 10px;
padding: 5px 0;
border-bottom: 0.5px solid var(--color-border-tertiary)
}
.cond-row:last-child {
border-bottom: none
}
.cond-name {
font-size: 12px;
color: var(--color-text-primary);
min-width: 70px
}
.cond-bar-track {
flex: 1;
height: 6px;
border-radius: 3px;
background: var(--color-border-tertiary);
overflow: hidden
}
.cond-bar-fill {
height: 100%;
border-radius: 3px
}
.cond-count {
font-size: 11px;
font-weight: 500;
color: var(--color-text-secondary);
min-width: 40px;
text-align: right
}
/* Footer */
.rpt-footer {
padding: 10px 24px;
border-top: 0.5px solid var(--color-border-tertiary);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--color-background-secondary)
}
.rpt-footer-lbl {
font-size: 10px;
color: var(--color-text-secondary)
}
/* Inventory specific */
.inv-row-hd {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr 1fr 80px;
gap: 0
}
.stock-level {
display: flex;
flex-direction: column;
gap: 3px
}
.stock-pct {
font-size: 10px;
color: var(--color-text-secondary);
text-align: right
}
</style>
<h2 class="sr-only">Finance department inventory report designs — three report templates: RIS report, MRS report, and inventory summary</h2>
<div class="page-tab">
<button class="tab-btn active" onclick="showTab('ris')">Return Issuance Slip report</button>
<button class="tab-btn" onclick="showTab('mrs')">Material Return Slip report</button>
<button class="tab-btn" onclick="showTab('inv')">Inventory summary report</button>
</div>
<script>
(function () {
"use strict";
// ── Prevent re-initialization on cache restore ──
if (window.__invTab1Initialized) return;
window.__invTab1Initialized = true;
const tabContent = document.getElementById("inv-tab-content");
const tabBtns = document.querySelectorAll(".inv-tab-btn");
// Cache stores the raw HTML string per tab id
const cache = {};
let activeTabId = null;
async function loadTab(tabId) {
if (activeTabId === tabId) return;
activeTabId = tabId;
// Mark active button
tabBtns.forEach(b => b.classList.toggle("active", b.dataset.tabId === String(tabId)));
if (cache[tabId]) {
// ── FIX: inject cached HTML then re-run its <script> blocks ──────
injectHtml(tabContent, cache[tabId]);
return;
}
tabContent.innerHTML = `<div class="inv-tab-loading">
<div class="inv-spinner"></div><span>Loading…</span></div>`;
try {
const res = await fetch(`/InventoryMgmt/GetInventoryTabPage?id=${tabId}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const html = await res.text();
cache[tabId] = html;
injectHtml(tabContent, html);
} catch (err) {
console.error("Tab load error:", err);
tabContent.innerHTML = `
<div class="inv-placeholder">
<i class="fas fa-exclamation-triangle" style="color:#ff5c5c"></i>
<h3>Failed to load</h3>
<p>Please try again or refresh the page.</p>
</div>`;
}
}
/**
* Set innerHTML then re-execute every <script> block so IIFEs inside
* ViewComponent views fire correctly — both on first load AND cache restore.
*/
function injectHtml(container, html) {
container.innerHTML = html;
container.querySelectorAll("script").forEach(oldScript => {
const newScript = document.createElement("script");
Array.from(oldScript.attributes).forEach(attr =>
newScript.setAttribute(attr.name, attr.value));
newScript.textContent = oldScript.textContent;
oldScript.replaceWith(newScript);
});
}
// Wire tab clicks
tabBtns.forEach(btn =>
btn.addEventListener("click", () => loadTab(parseInt(btn.dataset.tabId, 10)))
);
// Auto-load the first tab on page ready
loadTab(1);
})();
</script>