Initial commit, 90% there
This commit is contained in:
376
ui/templates/alerts.html
Normal file
376
ui/templates/alerts.html
Normal file
@@ -0,0 +1,376 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 80rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(0.95rem, 0.9vw + 0.25rem, 1.25rem);
|
||||
--fs-body: clamp(0.8rem, 0.7vw + 0.28rem, 1rem);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* HEADER: maintain title weight + spacing */
|
||||
.page-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-page-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* QUICK ALERTS: button row stays balanced on any width */
|
||||
.quick-alerts {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(13.75rem, 1fr));
|
||||
gap: var(--section-gap);
|
||||
padding: var(--card-pad);
|
||||
}
|
||||
|
||||
.quick-alert-btn {
|
||||
background: linear-gradient(180deg, #32ff7e 0%, #2fd289 100%);
|
||||
box-shadow: 0 0 1.25rem rgba(36, 208, 111, .5), inset 0 0.0625rem 0 rgba(255, 255, 255, .1);
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 700;
|
||||
padding: clamp(1.1rem, 1.8vw, 1.4rem);
|
||||
cursor: pointer;
|
||||
transition: 0.16s transform, 0.16s filter;
|
||||
}
|
||||
|
||||
.quick-alert-btn:hover {
|
||||
transform: translateY(-0.05rem);
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.quick-alert-btn:active {
|
||||
transform: none;
|
||||
filter: brightness(0.96);
|
||||
}
|
||||
|
||||
/* FORM CARD: consistent padding + typography */
|
||||
.alert-card {
|
||||
padding: var(--card-pad);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.9rem, 1vw, 1.1rem);
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-size: var(--fs-section-title);
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
background: #121c28;
|
||||
border: 1px solid #243244;
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
padding: 0.8rem 0.9rem;
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 7.5rem;
|
||||
}
|
||||
|
||||
.alert-send {
|
||||
align-self: flex-end;
|
||||
background: linear-gradient(180deg, #32ff7e 0%, #2fd289 100%);
|
||||
box-shadow: 0 0 1.25rem rgba(36, 208, 111, .5), inset 0 0.0625rem 0 rgba(255, 255, 255, .1);
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 700;
|
||||
padding: 0.8rem 1.4rem;
|
||||
cursor: pointer;
|
||||
transition: 0.16s transform, 0.16s filter;
|
||||
}
|
||||
|
||||
.alert-send:hover {
|
||||
transform: translateY(-0.05rem);
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.alert-send:active {
|
||||
transform: none;
|
||||
filter: brightness(0.96);
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn active" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="page-heading">
|
||||
<h1 class="page-title">Alerts</h1>
|
||||
</section>
|
||||
|
||||
<section class="card quick-alerts">
|
||||
<button class="quick-alert-btn" data-alert="Machine stopped">Machine stopped</button>
|
||||
<button class="quick-alert-btn" data-alert="Fault in machine">Fault in machine</button>
|
||||
<button class="quick-alert-btn" data-alert="No material">No material</button>
|
||||
</section>
|
||||
|
||||
<section class="card alert-card">
|
||||
<div class="form-group">
|
||||
<label for="alert-type">Alert type</label>
|
||||
<select id="alert-type">
|
||||
<option>Machine stopped</option>
|
||||
<option>Fault in machine</option>
|
||||
<option>No material</option>
|
||||
<option>Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="alert-description">Description</label>
|
||||
<textarea id="alert-description" rows="5" placeholder="Add context or instructions (optional)"></textarea>
|
||||
</div>
|
||||
<button id="alert-send" class="alert-send" type="button">Send Alert</button>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
|
||||
var quickButtons = document.querySelectorAll('[data-alert]');
|
||||
quickButtons.forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var type = btn.getAttribute('data-alert');
|
||||
scope.send({ action: 'alert', type: type });
|
||||
});
|
||||
});
|
||||
|
||||
var sendButton = document.getElementById('alert-send');
|
||||
if (sendButton) {
|
||||
sendButton.addEventListener('click', function() {
|
||||
var type = document.getElementById('alert-type').value;
|
||||
var description = (document.getElementById('alert-description').value || '').trim();
|
||||
scope.send({ action: 'alert', type: type, description: description });
|
||||
});
|
||||
}
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(function() {});
|
||||
</script>
|
||||
290
ui/templates/graphs.html
Normal file
290
ui/templates/graphs.html
Normal file
@@ -0,0 +1,290 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 100rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(0.95rem, 0.9vw + 0.25rem, 1.25rem);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* HEADER: maintain title styling */
|
||||
.page-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-page-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* CHART GRID: preserve 2x2 symmetry without wrapping glitches */
|
||||
.chart-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.85rem, 1vw, 1rem);
|
||||
padding: var(--card-pad);
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-section-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
flex: 1;
|
||||
border-radius: var(--radius);
|
||||
background: #121c28;
|
||||
border: 1px dashed rgba(58, 96, 136, 0.35);
|
||||
min-height: 13.75rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn active" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="page-heading">
|
||||
<h1 class="page-title">Graphs</h1>
|
||||
</section>
|
||||
|
||||
<section class="chart-grid">
|
||||
<article class="card chart-card">
|
||||
<h2 class="chart-title">OEE – Last 24h</h2>
|
||||
<div class="chart-placeholder" id="chart-oee"></div>
|
||||
</article>
|
||||
<article class="card chart-card">
|
||||
<h2 class="chart-title">Availability – Last 7 days</h2>
|
||||
<div class="chart-placeholder" id="chart-availability"></div>
|
||||
</article>
|
||||
<article class="card chart-card">
|
||||
<h2 class="chart-title">Performance – Last 7 days</h2>
|
||||
<div class="chart-placeholder" id="chart-performance"></div>
|
||||
</article>
|
||||
<article class="card chart-card">
|
||||
<h2 class="chart-title">Quality – Last 7 days</h2>
|
||||
<div class="chart-placeholder" id="chart-quality"></div>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(function() {});
|
||||
</script>
|
||||
276
ui/templates/help.html
Normal file
276
ui/templates/help.html
Normal file
@@ -0,0 +1,276 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 70rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(1rem, 0.9vw + 0.3rem, 1.35rem);
|
||||
--fs-body: clamp(0.85rem, 0.7vw + 0.3rem, 1.05rem);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* HEADER: maintain title styling */
|
||||
.page-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-page-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* HELP CARDS: keep text hierarchy + spacing clean */
|
||||
.help-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.9rem, 1vw, 1.1rem);
|
||||
padding: var(--card-pad);
|
||||
}
|
||||
|
||||
.help-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-section-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.help-body {
|
||||
margin: 0;
|
||||
line-height: 1.65;
|
||||
color: var(--muted);
|
||||
font-size: var(--fs-body);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn active" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="page-heading">
|
||||
<h1 class="page-title">Help</h1>
|
||||
</section>
|
||||
|
||||
<section class="card help-card">
|
||||
<h2 class="help-title">About this Dashboard</h2>
|
||||
<p class="help-body">This interface centralizes Overall Equipment Effectiveness metrics, real-time production details, and critical status indicators. Each tab follows a unified layout so operators can scan performance, alerts, and configuration without relearning navigation.</p>
|
||||
</section>
|
||||
|
||||
<section class="card help-card">
|
||||
<h2 class="help-title">How to Start / Stop Production</h2>
|
||||
<p class="help-body">Navigate to the Work Orders tab, select the required job, and use the primary controls to begin or end production. Always log the reason for stoppages using the Alerts tab, and confirm machine readiness before resuming. Follow your facility’s standard operating procedure for approvals and sign-off.</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(function() {});
|
||||
</script>
|
||||
606
ui/templates/home.html
Normal file
606
ui/templates/home.html
Normal file
@@ -0,0 +1,606 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 100rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--card-pad-lg: clamp(1.1rem, 1.2vw, 1.35rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(0.95rem, 0.9vw + 0.25rem, 1.25rem);
|
||||
--fs-label: clamp(0.85rem, 0.7vw + 0.3rem, 1.05rem);
|
||||
--fs-label-lg: clamp(0.95rem, 0.8vw + 0.32rem, 1.15rem);
|
||||
--fs-kpi: clamp(2.25rem, 2.5vw, 3.25rem);
|
||||
--fs-kpi-unit: clamp(1.25rem, 1.4vw, 1.5rem);
|
||||
--fs-body: clamp(0.8rem, 0.7vw + 0.28rem, 1rem);
|
||||
--progress-height: 0.875rem;
|
||||
--start-min-height: 9.375rem;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
font-weight: 700;
|
||||
font-size: var(--fs-label);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(11.25rem, 1fr));
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.kpi {
|
||||
height: 6.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: var(--card-pad);
|
||||
}
|
||||
|
||||
.kpi .label {
|
||||
font-size: var(--fs-label-lg);
|
||||
}
|
||||
|
||||
.kval {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 0.3rem;
|
||||
color: var(--good);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.knum {
|
||||
font-size: var(--fs-kpi);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.kunit {
|
||||
font-size: var(--fs-kpi-unit);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.panel {
|
||||
padding: var(--card-pad-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.75rem, 0.9vw, 0.95rem);
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: var(--fs-section-title);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.panel-strip {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.row-3 {
|
||||
display: flex;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.mini {
|
||||
flex: 1;
|
||||
min-height: 6.25rem;
|
||||
padding: var(--card-pad);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.mini .val {
|
||||
font-size: var(--fs-body);
|
||||
color: var(--text);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.progress {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.track {
|
||||
flex: 1;
|
||||
height: var(--progress-height);
|
||||
background: #111a24;
|
||||
border-radius: 999px;
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
}
|
||||
|
||||
.fill {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background: var(--good);
|
||||
transition: width 0.35s ease;
|
||||
}
|
||||
|
||||
.pct {
|
||||
min-width: 3rem;
|
||||
text-align: right;
|
||||
color: var(--text);
|
||||
font-weight: 700;
|
||||
font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.gparts,
|
||||
.status,
|
||||
.start-wrap {
|
||||
min-height: clamp(9.375rem, 18vw, 11.25rem);
|
||||
padding: var(--card-pad-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.gnum {
|
||||
font-size: clamp(2.5rem, 3.2vw, 3.5rem);
|
||||
color: var(--good);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.gmeta {
|
||||
color: var(--muted);
|
||||
font-size: clamp(0.75rem, 0.9vw, 0.85rem);
|
||||
}
|
||||
|
||||
.status {
|
||||
justify-content: center;
|
||||
gap: clamp(0.75rem, 1vw, 1rem);
|
||||
}
|
||||
|
||||
.st-row {
|
||||
background: #121c28;
|
||||
border-radius: 0.625rem;
|
||||
border: 1px solid #243244;
|
||||
padding: 0.9rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.st-name {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
.st-val {
|
||||
font-weight: 700;
|
||||
font-size: clamp(1.25rem, 1.4vw, 1.5rem);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.st-on {
|
||||
color: var(--good);
|
||||
}
|
||||
|
||||
.st-off {
|
||||
color: var(--bad);
|
||||
}
|
||||
|
||||
.start-wrap {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.start {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: var(--start-min-height);
|
||||
border-radius: var(--radius);
|
||||
border: none;
|
||||
background: linear-gradient(180deg, #32ff7e 0%, #2fd289 100%);
|
||||
color: var(--text);
|
||||
font-weight: 700;
|
||||
font-size: clamp(1.4rem, 2vw, 2rem);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
box-shadow: 0 0 1.25rem rgba(36, 208, 111, .5), inset 0 0.0625rem 0 rgba(255, 255, 255, .1);
|
||||
cursor: pointer;
|
||||
transition: 0.16s transform, 0.16s filter;
|
||||
}
|
||||
|
||||
.start:hover {
|
||||
transform: translateY(-0.05rem);
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.start:active {
|
||||
transform: none;
|
||||
filter: brightness(0.96);
|
||||
}
|
||||
|
||||
@media (max-width: 68.75rem) {
|
||||
.kpis {
|
||||
grid-template-columns: repeat(2, minmax(11.25rem, 1fr));
|
||||
}
|
||||
.row-3 {
|
||||
flex-direction: column;
|
||||
}
|
||||
.bottom {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn active" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="kpis">
|
||||
<article class="card kpi">
|
||||
<div class="label">OEE</div>
|
||||
<div class="kval"><span id="kpi-oee-value" class="knum">0</span><span class="kunit">%</span></div>
|
||||
</article>
|
||||
<article class="card kpi">
|
||||
<div class="label">Availability</div>
|
||||
<div class="kval"><span id="kpi-availability-value" class="knum">0</span><span class="kunit">%</span></div>
|
||||
</article>
|
||||
<article class="card kpi">
|
||||
<div class="label">Performance</div>
|
||||
<div class="kval"><span id="kpi-performance-value" class="knum">0</span><span class="kunit">%</span></div>
|
||||
</article>
|
||||
<article class="card kpi">
|
||||
<div class="label">Quality</div>
|
||||
<div class="kval"><span id="kpi-quality-value" class="knum">0</span><span class="kunit">%</span></div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="card panel">
|
||||
<div class="panel-strip"><h2 class="panel-title">Current Work Order</h2></div>
|
||||
<div class="row-3">
|
||||
<div class="card mini">
|
||||
<div class="label">Work Order ID</div>
|
||||
<div id="workorder-id" class="val"> </div>
|
||||
</div>
|
||||
<div class="card mini">
|
||||
<div class="label">SKU</div>
|
||||
<div id="workorder-sku" class="val"> </div>
|
||||
</div>
|
||||
<div class="card mini">
|
||||
<div class="label">Cycle Time</div>
|
||||
<div id="workorder-cycle" class="val">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="track"><div id="workorder-progress-fill" class="fill"></div></div>
|
||||
<div id="workorder-progress-percent" class="pct">0%</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="bottom">
|
||||
<article class="card gparts">
|
||||
<div class="label">Good Parts</div>
|
||||
<div id="good-parts-value" class="gnum">0</div>
|
||||
<div id="good-parts-meta" class="gmeta">out of 0</div>
|
||||
</article>
|
||||
|
||||
<article class="card status">
|
||||
<div class="st-row"><span class="st-name">Machine</span><span id="machine-state" class="st-val st-off">OFFLINE</span></div>
|
||||
<div class="st-row"><span class="st-name">Production</span><span id="production-state" class="st-val st-off">STOPPED</span></div>
|
||||
</article>
|
||||
|
||||
<article class="card start-wrap">
|
||||
<button id="start-button" type="button" class="start">START</button>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
|
||||
window.kpiOeePercent = window.kpiOeePercent || 0;
|
||||
window.kpiAvailabilityPercent = window.kpiAvailabilityPercent || 0;
|
||||
window.kpiPerformancePercent = window.kpiPerformancePercent || 0;
|
||||
window.kpiQualityPercent = window.kpiQualityPercent || 0;
|
||||
window.currentWorkOrderId = window.currentWorkOrderId || "";
|
||||
window.currentSku = window.currentSku || "";
|
||||
window.currentCycleTime = window.currentCycleTime || 0;
|
||||
window.currentProgressPercent = window.currentProgressPercent || 0;
|
||||
window.goodPartsCount = window.goodPartsCount || 0;
|
||||
window.goodPartsTarget = window.goodPartsTarget || 0;
|
||||
window.machineOnline = typeof window.machineOnline === "boolean" ? window.machineOnline : false;
|
||||
window.productionStarted = typeof window.productionStarted === "boolean" ? window.productionStarted : false;
|
||||
|
||||
var elements = {
|
||||
kpiOee: document.getElementById("kpi-oee-value"),
|
||||
kpiAvailability: document.getElementById("kpi-availability-value"),
|
||||
kpiPerformance: document.getElementById("kpi-performance-value"),
|
||||
kpiQuality: document.getElementById("kpi-quality-value"),
|
||||
workOrderId: document.getElementById("workorder-id"),
|
||||
workOrderSku: document.getElementById("workorder-sku"),
|
||||
workOrderCycle: document.getElementById("workorder-cycle"),
|
||||
progressFill: document.getElementById("workorder-progress-fill"),
|
||||
progressPercent: document.getElementById("workorder-progress-percent"),
|
||||
goodPartsValue: document.getElementById("good-parts-value"),
|
||||
goodPartsMeta: document.getElementById("good-parts-meta"),
|
||||
machineState: document.getElementById("machine-state"),
|
||||
productionState: document.getElementById("production-state"),
|
||||
startButton: document.getElementById("start-button")
|
||||
};
|
||||
|
||||
function setText(el, value) {
|
||||
if (el) {
|
||||
el.textContent = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setNumber(el, value) {
|
||||
setText(el, String(Math.max(0, Math.round(Number(value) || 0))));
|
||||
}
|
||||
|
||||
function clampPercent(value) {
|
||||
var num = Number(value) || 0;
|
||||
return Math.max(0, Math.min(100, Math.round(num)));
|
||||
}
|
||||
|
||||
function updateState(el, isActive, onLabel, offLabel) {
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
el.textContent = isActive ? onLabel : offLabel;
|
||||
el.classList.remove("st-on", "st-off");
|
||||
el.classList.add(isActive ? "st-on" : "st-off");
|
||||
}
|
||||
|
||||
function renderDashboard() {
|
||||
setNumber(elements.kpiOee, window.kpiOeePercent);
|
||||
setNumber(elements.kpiAvailability, window.kpiAvailabilityPercent);
|
||||
setNumber(elements.kpiPerformance, window.kpiPerformancePercent);
|
||||
setNumber(elements.kpiQuality, window.kpiQualityPercent);
|
||||
|
||||
setText(elements.workOrderId, window.currentWorkOrderId || "");
|
||||
setText(elements.workOrderSku, window.currentSku || "");
|
||||
setText(elements.workOrderCycle, window.currentCycleTime ? String(window.currentCycleTime) : "0");
|
||||
|
||||
var progress = clampPercent(window.currentProgressPercent);
|
||||
if (elements.progressFill) {
|
||||
elements.progressFill.style.width = progress + "%";
|
||||
}
|
||||
setText(elements.progressPercent, progress + "%");
|
||||
|
||||
setText(elements.goodPartsValue, String(window.goodPartsCount || 0));
|
||||
setText(elements.goodPartsMeta, "out of " + String(window.goodPartsTarget || 0));
|
||||
|
||||
updateState(elements.machineState, !!window.machineOnline, "ONLINE", "OFFLINE");
|
||||
updateState(elements.productionState, !!window.productionStarted, "STARTED", "STOPPED");
|
||||
}
|
||||
|
||||
scope.renderDashboard = renderDashboard;
|
||||
|
||||
renderDashboard();
|
||||
|
||||
if (elements.startButton) {
|
||||
elements.startButton.addEventListener("click", function() {
|
||||
scope.send({ action: "start" });
|
||||
});
|
||||
}
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(scope.renderDashboard);
|
||||
</script>
|
||||
338
ui/templates/settings.html
Normal file
338
ui/templates/settings.html
Normal file
@@ -0,0 +1,338 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 70rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(1rem, 0.9vw + 0.3rem, 1.35rem);
|
||||
--fs-body: clamp(0.8rem, 0.7vw + 0.28rem, 1rem);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* HEADER: maintain title styling */
|
||||
.page-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-page-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-section-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* SETTINGS CARDS: clean grid + balanced inputs */
|
||||
.mold-card,
|
||||
.integrations-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.9rem, 1vw, 1.1rem);
|
||||
padding: var(--card-pad);
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(13.75rem, 1fr));
|
||||
gap: clamp(0.75rem, 1vw, 1rem);
|
||||
}
|
||||
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
font-size: var(--fs-body);
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.form-field input {
|
||||
background: #121c28;
|
||||
border: 1px solid #243244;
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
padding: 0.75rem 0.9rem;
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
.integrations-button {
|
||||
width: fit-content;
|
||||
background: #121c28;
|
||||
border: 1px dashed rgba(150, 165, 183, .45);
|
||||
border-radius: var(--radius);
|
||||
color: rgba(150, 165, 183, .8);
|
||||
padding: 0.75rem 1.5rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn active" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="page-heading">
|
||||
<h1 class="page-title">Settings</h1>
|
||||
</section>
|
||||
|
||||
<section class="card mold-card">
|
||||
<h2 class="section-title">Mold Configuration</h2>
|
||||
<div class="form-grid">
|
||||
<div class="form-field">
|
||||
<label for="mold-total">Total Cavities</label>
|
||||
<input id="mold-total" type="number" readonly />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="mold-active">Active Cavities</label>
|
||||
<input id="mold-active" type="number" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card integrations-card">
|
||||
<h2 class="section-title">Integrations</h2>
|
||||
<button class="integrations-button" type="button" disabled>Connect to ERP (coming soon)</button>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
|
||||
window.moldTotalCavities = window.moldTotalCavities || 0;
|
||||
window.moldActiveCavities = window.moldActiveCavities || 0;
|
||||
|
||||
function renderSettings() {
|
||||
var totalInput = document.getElementById('mold-total');
|
||||
var activeInput = document.getElementById('mold-active');
|
||||
if (totalInput) {
|
||||
totalInput.value = Number(window.moldTotalCavities || 0);
|
||||
}
|
||||
if (activeInput) {
|
||||
activeInput.value = Number(window.moldActiveCavities || 0);
|
||||
}
|
||||
}
|
||||
|
||||
scope.renderSettings = renderSettings;
|
||||
renderSettings();
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(scope.renderSettings);
|
||||
</script>
|
||||
529
ui/templates/work-orders.html
Normal file
529
ui/templates/work-orders.html
Normal file
@@ -0,0 +1,529 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700&display=swap');
|
||||
|
||||
/* SCALE: align 100% zoom with prior 125% appearance */
|
||||
:root {
|
||||
font-size: 125%;
|
||||
--bg-0: #0c1117;
|
||||
--bg-1: #131a23;
|
||||
--panel: #151e2b;
|
||||
--panel-hi: #1a2433;
|
||||
--text: #ecf3ff;
|
||||
--muted: #96a5b7;
|
||||
--accent: #2ea3ff;
|
||||
--accent-2: #1f8cf3;
|
||||
--good: #24d06f;
|
||||
--warn: #ffd100;
|
||||
--bad: #ff4d4f;
|
||||
--radius: 0.75rem;
|
||||
--shadow: 0 0.5rem 1rem rgba(0, 0, 0, .35), inset 0 0.0625rem 0 rgba(255, 255, 255, .05);
|
||||
--sidebar-width: 3.75rem;
|
||||
--sidebar-gap: clamp(0.75rem, 1.2vh, 1rem);
|
||||
--content-max: 100rem;
|
||||
--content-pad: clamp(1rem, 1.2vw, 1.4rem);
|
||||
--section-gap: clamp(0.75rem, 1vw, 1rem);
|
||||
--card-pad: clamp(1rem, 1.1vw, 1.25rem);
|
||||
--card-pad-lg: clamp(1.1rem, 1.2vw, 1.35rem);
|
||||
--fs-page-title: clamp(1.2rem, 1vw + 0.35rem, 1.7rem);
|
||||
--fs-section-title: clamp(0.95rem, 0.9vw + 0.25rem, 1.25rem);
|
||||
--fs-label: clamp(0.85rem, 0.7vw + 0.3rem, 1.05rem);
|
||||
--fs-body: clamp(0.8rem, 0.7vw + 0.28rem, 1rem);
|
||||
--progress-height: 0.875rem;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#oee {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
background: var(--bg-0);
|
||||
color: var(--text);
|
||||
font-family: 'Poppins', system-ui, 'Segoe UI', 'Roboto', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body > md-content,
|
||||
body > md-content > md-content,
|
||||
.nr-dashboard-template,
|
||||
.nr-dashboard-template md-content,
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-content {
|
||||
background: transparent !important;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nr-dashboard-cardpanel,
|
||||
.nr-dashboard-cardpanel md-card,
|
||||
.nr-dashboard-cardpanel md-card-content {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* LAYOUT: lock sidebar + content grid across tabs */
|
||||
#oee {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: var(--sidebar-width);
|
||||
background: #0b1119;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: clamp(0.625rem, 1.4vh, 0.9rem) clamp(0.5rem, 0.8vw, 0.75rem);
|
||||
}
|
||||
|
||||
.side-top {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sidebar-gap);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-btn {
|
||||
width: 2.75rem;
|
||||
height: 2.75rem;
|
||||
border-radius: 0.75rem;
|
||||
background: #0f1721;
|
||||
border: 1px solid #19222e;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #8fb3d9;
|
||||
cursor: pointer;
|
||||
transition: 0.16s box-shadow, 0.16s transform, 0.16s border-color;
|
||||
}
|
||||
|
||||
.sb-btn.active {
|
||||
border-color: #2fd289;
|
||||
box-shadow: 0 0 0 0.125rem rgba(36, 208, 111, .25), 0 0.625rem 1.125rem rgba(36, 208, 111, .28);
|
||||
color: #2fd289;
|
||||
}
|
||||
|
||||
.sb-ico {
|
||||
font-size: clamp(1.1rem, 1.2vw, 1.25rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.sb-foot {
|
||||
font-size: clamp(0.6rem, 0.6vw, 0.7rem);
|
||||
color: #6c7b8d;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: var(--content-pad);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--section-gap);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(160deg, var(--panel) 0%, var(--panel-hi) 100%);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
/* HEADER: keep title and CTA row on one line */
|
||||
.page-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--section-gap);
|
||||
padding: 0 0.25rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: var(--fs-page-title);
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
gap: clamp(0.65rem, 1vw, 0.9rem);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
background: linear-gradient(180deg, #32ff7e 0%, #2fd289 100%);
|
||||
box-shadow: 0 0 1.25rem rgba(36, 208, 111, .5), inset 0 0.0625rem 0 rgba(255, 255, 255, .1);
|
||||
border: none;
|
||||
border-radius: var(--radius);
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 700;
|
||||
padding: clamp(0.75rem, 1vw, 0.9rem) clamp(1rem, 1.4vw, 1.25rem);
|
||||
cursor: pointer;
|
||||
transition: 0.16s transform, 0.16s filter;
|
||||
min-width: clamp(8.75rem, 12vw, 10rem);
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: translateY(-0.05rem);
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
transform: none;
|
||||
filter: brightness(0.96);
|
||||
}
|
||||
|
||||
/* TABLE: keep density + typography aligned with Home */
|
||||
.table-card {
|
||||
padding: var(--card-pad-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(0.75rem, 0.9vw, 0.95rem);
|
||||
}
|
||||
|
||||
.table-scroll {
|
||||
overflow: auto;
|
||||
border-radius: 0.625rem;
|
||||
}
|
||||
|
||||
.workorders-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
min-width: 45rem;
|
||||
}
|
||||
|
||||
.workorders-table thead th {
|
||||
color: var(--text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
font-size: clamp(0.75rem, 0.9vw, 0.85rem);
|
||||
padding: clamp(0.75rem, 1vw, 1rem);
|
||||
background: rgba(21, 30, 43, 0.85);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.workorders-table tbody td {
|
||||
padding: clamp(0.75rem, 1vw, 1rem);
|
||||
color: var(--text);
|
||||
border-bottom: 1px solid rgba(31, 44, 60, 0.55);
|
||||
font-size: var(--fs-body);
|
||||
}
|
||||
|
||||
.workorders-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.progress-cell {
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: var(--progress-height);
|
||||
border-radius: 999px;
|
||||
background: #111a24;
|
||||
border: 1px solid #243244;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar__fill {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
transition: width 0.4s ease;
|
||||
}
|
||||
|
||||
.progress-bar__fill--pending {
|
||||
background: linear-gradient(90deg, rgba(150, 165, 183, .5), rgba(150, 165, 183, .8));
|
||||
}
|
||||
|
||||
.progress-bar__fill--running {
|
||||
background: linear-gradient(90deg, rgba(46, 163, 255, .6), rgba(46, 163, 255, .85));
|
||||
}
|
||||
|
||||
.progress-bar__fill--done {
|
||||
background: linear-gradient(90deg, rgba(36, 208, 111, .75), rgba(36, 208, 111, .95));
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.375rem 0.875rem;
|
||||
border-radius: 999px;
|
||||
font-size: clamp(0.75rem, 0.9vw, 0.85rem);
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.status-badge--pending {
|
||||
color: var(--muted);
|
||||
background: rgba(20, 28, 40, .65);
|
||||
border: 1px solid rgba(150, 165, 183, .35);
|
||||
}
|
||||
|
||||
.status-badge--running {
|
||||
color: var(--text);
|
||||
background: rgba(30, 52, 73, .7);
|
||||
border: 1px solid rgba(46, 163, 255, .45);
|
||||
}
|
||||
|
||||
.status-badge--done {
|
||||
color: var(--good);
|
||||
background: rgba(20, 56, 44, .7);
|
||||
border: 1px solid rgba(36, 208, 111, .45);
|
||||
}
|
||||
|
||||
.table-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
font-size: clamp(0.75rem, 0.9vw, 0.85rem);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
@media (max-width: 68.75rem) {
|
||||
.page-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="styles/oee-theme-override.css">
|
||||
|
||||
<div id="oee">
|
||||
<aside class="sidebar">
|
||||
<div class="side-top">
|
||||
<button class="sb-btn" data-label="Home" ng-click="gotoTab('Home')"><span class="sb-ico">🏠</span></button>
|
||||
<button class="sb-btn active" data-label="Work Orders" ng-click="gotoTab('Work Orders')"><span class="sb-ico">📋</span></button>
|
||||
<button class="sb-btn" data-label="Alerts" ng-click="gotoTab('Alerts')"><span class="sb-ico">⚠️</span></button>
|
||||
<button class="sb-btn" data-label="Graphs" ng-click="gotoTab('Graphs')"><span class="sb-ico">📊</span></button>
|
||||
<button class="sb-btn" data-label="Help" ng-click="gotoTab('Help')"><span class="sb-ico">❓</span></button>
|
||||
<button class="sb-btn" data-label="Settings" ng-click="gotoTab('Settings')"><span class="sb-ico">⚙️</span></button>
|
||||
</div>
|
||||
<div class="sb-foot">OEE V1.0</div>
|
||||
</aside>
|
||||
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<section class="page-heading">
|
||||
<h1 class="page-title">Work Orders</h1>
|
||||
<div class="page-actions">
|
||||
<button class="action-btn" data-action="upload-excel">Upload Excel</button>
|
||||
<button class="action-btn" data-action="start-work-order">Start</button>
|
||||
<button class="action-btn" data-action="complete-work-order">Done</button>
|
||||
<button class="action-btn" data-action="refresh-work-orders">Refresh</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card table-card">
|
||||
<div class="table-scroll">
|
||||
<table class="workorders-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>SKU</th>
|
||||
<th>TARGET</th>
|
||||
<th>GOOD</th>
|
||||
<th>SCRAP</th>
|
||||
<th>PROGRESS</th>
|
||||
<th>STATUS</th>
|
||||
<th>LAST UPDATE</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="workorders-body"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-footer"><span id="workorders-count">0 items</span></div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function(scope) {
|
||||
scope.gotoTab = function(tabName) {
|
||||
scope.send({ ui_control: { tab: tabName } });
|
||||
};
|
||||
|
||||
window.workOrders = window.workOrders || [
|
||||
{ id:"WO-101", sku:"ST-003", target:250, good:0, scrap:0, progressPercent:0, status:"PENDING", lastUpdateIso:"" }
|
||||
];
|
||||
|
||||
var elements = {
|
||||
tbody: document.getElementById('workorders-body'),
|
||||
count: document.getElementById('workorders-count'),
|
||||
buttons: document.querySelectorAll('[data-action]')
|
||||
};
|
||||
|
||||
function formatNumber(value) {
|
||||
var num = Number(value);
|
||||
return Number.isFinite(num) ? num.toLocaleString() : '0';
|
||||
}
|
||||
|
||||
function formatDate(isoString) {
|
||||
if (!isoString) {
|
||||
return '—';
|
||||
}
|
||||
var date = new Date(isoString);
|
||||
if (Number.isNaN(date.valueOf())) {
|
||||
return isoString;
|
||||
}
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
function progressFillClass(status) {
|
||||
switch ((status || '').toUpperCase()) {
|
||||
case 'DONE': return 'progress-bar__fill--done';
|
||||
case 'RUNNING': return 'progress-bar__fill--running';
|
||||
default: return 'progress-bar__fill--pending';
|
||||
}
|
||||
}
|
||||
|
||||
function statusBadgeClass(status) {
|
||||
switch ((status || '').toUpperCase()) {
|
||||
case 'DONE': return 'status-badge status-badge--done';
|
||||
case 'RUNNING': return 'status-badge status-badge--running';
|
||||
default: return 'status-badge status-badge--pending';
|
||||
}
|
||||
}
|
||||
|
||||
function renderWorkOrders() {
|
||||
var orders = Array.isArray(window.workOrders) ? window.workOrders : [];
|
||||
if (elements.tbody) {
|
||||
elements.tbody.textContent = '';
|
||||
orders.forEach(function(order) {
|
||||
var tr = document.createElement('tr');
|
||||
|
||||
function appendCell(content) {
|
||||
var td = document.createElement('td');
|
||||
if (content instanceof Node) {
|
||||
td.appendChild(content);
|
||||
} else {
|
||||
td.textContent = content;
|
||||
}
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
appendCell(order.id || '—');
|
||||
appendCell(order.sku || '—');
|
||||
appendCell(formatNumber(order.target));
|
||||
appendCell(formatNumber(order.good));
|
||||
appendCell(formatNumber(order.scrap));
|
||||
|
||||
var progressCell = document.createElement('td');
|
||||
progressCell.className = 'progress-cell';
|
||||
var bar = document.createElement('div');
|
||||
bar.className = 'progress-bar';
|
||||
var fill = document.createElement('div');
|
||||
fill.className = 'progress-bar__fill ' + progressFillClass(order.status);
|
||||
var percent = Math.max(0, Math.min(100, Math.round(Number(order.progressPercent) || 0)));
|
||||
fill.style.width = percent + '%';
|
||||
bar.appendChild(fill);
|
||||
progressCell.appendChild(bar);
|
||||
tr.appendChild(progressCell);
|
||||
|
||||
var statusCell = document.createElement('td');
|
||||
var badge = document.createElement('span');
|
||||
badge.className = statusBadgeClass(order.status);
|
||||
badge.textContent = (order.status || 'PENDING').toUpperCase();
|
||||
statusCell.appendChild(badge);
|
||||
tr.appendChild(statusCell);
|
||||
|
||||
appendCell(formatDate(order.lastUpdateIso));
|
||||
|
||||
elements.tbody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
|
||||
if (elements.count) {
|
||||
var countText = orders.length + (orders.length === 1 ? ' item' : ' items');
|
||||
elements.count.textContent = countText;
|
||||
}
|
||||
}
|
||||
|
||||
scope.renderWorkOrders = renderWorkOrders;
|
||||
renderWorkOrders();
|
||||
|
||||
if (elements.buttons) {
|
||||
elements.buttons.forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var action = btn.getAttribute('data-action');
|
||||
scope.send({ action: action });
|
||||
});
|
||||
});
|
||||
}
|
||||
})(scope);
|
||||
|
||||
(function ensureNoMaterialTint(){
|
||||
setTimeout(() => {
|
||||
const root = document.getElementById('oee') || document.body;
|
||||
|
||||
const targets = root.querySelectorAll([
|
||||
'.md-toolbar','md-toolbar',
|
||||
'.md-subheader','md-subheader',
|
||||
'.md-toolbar-tools','.md-card-title'
|
||||
].join(','));
|
||||
|
||||
targets.forEach(el => {
|
||||
if (el && el.style) {
|
||||
el.style.background = 'transparent';
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
if (el && el.classList) {
|
||||
el.classList.remove(
|
||||
'md-whiteframe-1dp','md-whiteframe-2dp','md-whiteframe-3dp',
|
||||
'md-whiteframe-z1','md-whiteframe-z2','md-whiteframe-z3'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (!document.getElementById('oee-theme-sentinel')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'oee-theme-sentinel';
|
||||
style.textContent = `
|
||||
#oee .md-toolbar::before, #oee .md-toolbar::after,
|
||||
#oee .md-subheader::before, #oee .md-subheader::after,
|
||||
#oee md-toolbar::before, #oee md-toolbar::after,
|
||||
#oee md-subheader::before, #oee md-subheader::after {
|
||||
display: none !important;
|
||||
content: none !important;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
}, 300);
|
||||
})();
|
||||
|
||||
|
||||
// optional render trigger
|
||||
scope.$evalAsync(scope.renderWorkOrders);
|
||||
</script>
|
||||
Reference in New Issue
Block a user