531 lines
12 KiB
Plaintext
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> |